def generate_token_file(oauth_verifier):
    with open(withing_temp_file, 'r') as withing_auth_file:
        auth = pickle.load(withing_auth_file)
    creds = auth.get_credentials(oauth_verifier)
    client = WithingsApi(creds)
    user = client.get_user()
    if user == None :
        flash(gettext(u"Error while getting token from Withign code check you client id/secret redirect url or oauth_verifier"),"error")
    else:
        withing_user_file = os.path.join(os.path.dirname(__file__), '../data/'+creds.user_id+'-withings.json')
        with open(withing_user_file, 'w') as withing_token_file:
            pickle.dump(creds, withing_token_file)
            flash(gettext(u"Successfully generate token. Please restart the plugin."), "success")
예제 #2
0
class TestWithingsApi(unittest.TestCase):
    def setUp(self):
        self.mock_api = True
        if self.mock_api:
            self.creds = WithingsCredentials()
        else:
            config = ConfigParser.ConfigParser()
            config.read('withings.conf')
            self.creds = WithingsCredentials(
                consumer_key=config.get('withings', 'consumer_key'),
                consumer_secret=config.get('withings', 'consumer_secret'),
                access_token=config.get('withings', 'access_token'),
                access_token_secret=config.get('withings',
                                               'access_token_secret'),
                user_id=config.get('withings', 'user_id'))
        self.api = WithingsApi(self.creds)

    def test_attributes(self):
        """ Make sure the WithingsApi objects have the right attributes """
        assert hasattr(WithingsApi, 'URL')
        creds = WithingsCredentials(user_id='FAKEID')
        api = WithingsApi(creds)
        assert hasattr(api, 'credentials')
        assert hasattr(api, 'oauth')
        assert hasattr(api, 'client')

    def test_attribute_defaults(self):
        """
        Make sure WithingsApi object attributes have the correct defaults
        """
        self.assertEqual(WithingsApi.URL, 'http://wbsapi.withings.net')
        creds = WithingsCredentials(user_id='FAKEID')
        api = WithingsApi(creds)
        self.assertEqual(api.credentials, creds)
        self.assertEqual(api.client.auth, api.oauth)
        self.assertEqual(api.client.params, {'userid': creds.user_id})

    def test_request(self):
        """
        Make sure the request method builds the proper URI and returns the
        request body as a python dict.
        """
        self.mock_request({})
        resp = self.api.request('fake_service', 'fake_action')
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/fake_service',
            params={'action': 'fake_action'})
        self.assertEqual(resp, {})

    def test_request_params(self):
        """
        Check that the request method passes along extra params and works
        with different HTTP methods
        """
        self.mock_request({})
        resp = self.api.request('user', 'getbyuserid', params={'p2': 'p2'},
                                method='POST')
        Session.request.assert_called_once_with(
            'POST', 'http://wbsapi.withings.net/user',
            params={'p2': 'p2', 'action': 'getbyuserid'})
        self.assertEqual(resp, {})

    def test_request_error(self):
        """ Check that requests raises an exception when there is an error """
        self.mock_request('', status=1)
        self.assertRaises(Exception, self.api.request, ('user', 'getbyuserid'))

    def test_get_user(self):
        """ Check that the get_user method fetches the right URL """
        self.mock_request({
            'users': [
                {'id': 1111111, 'birthdate': 364305600, 'lastname': 'Baggins',
                 'ispublic': 255, 'firstname': 'Frodo', 'fatmethod': 131,
                 'gender': 0, 'shortname': 'FRO'}
            ]
        })
        resp = self.api.get_user()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/user',
            params={'action': 'getbyuserid'})
        self.assertEqual(type(resp), dict)
        assert 'users' in resp
        self.assertEqual(type(resp['users']), list)
        self.assertEqual(len(resp['users']), 1)
        self.assertEqual(resp['users'][0]['firstname'], 'Frodo')
        self.assertEqual(resp['users'][0]['lastname'], 'Baggins')

    def test_get_sleep(self):
        """
        Check that get_sleep fetches the appropriate URL, the response looks
        correct, and the return value is a WithingsSleep object with the
        correct attributes
        """
        body = {
            "series": [{
                "startdate": 1387235398,
                "state": 0,
                "enddate": 1387235758
            }, {
                "startdate": 1387243618,
                "state": 1,
                "enddate": 1387244518
            }],
            "model": 16
        }
        self.mock_request(body)
        resp = self.api.get_sleep()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/v2/sleep',
            params={'action': 'get'})
        self.assertEqual(type(resp), WithingsSleep)
        self.assertEqual(resp.model, body['model'])
        self.assertEqual(type(resp.series), list)
        self.assertEqual(len(resp.series), 2)
        self.assertEqual(type(resp.series[0]), WithingsSleepSeries)
        self.assertEqual(time.mktime(resp.series[0].startdate.timetuple()),
                         body['series'][0]['startdate'])
        self.assertEqual(time.mktime(resp.series[0].enddate.timetuple()),
                         body['series'][0]['enddate'])
        self.assertEqual(resp.series[1].state, 1)


    def test_get_activities(self):
        """
        Check that get_activities fetches the appropriate URL, the response
        looks correct, and the return value is a list of WithingsActivity
        objects
        """
        body = {
           "date": "2013-04-10",
           "steps": 6523,
           "distance": 4600,
           "calories": 408.52,
           "elevation": 18.2,
           "soft": 5880,
           "moderate": 1080,
           "intense": 540,
           "timezone": "Europe/Berlin"
        }
        self.mock_request(body)
        resp = self.api.get_activities()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/v2/measure',
            params={'action': 'getactivity'})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 1)
        self.assertEqual(type(resp[0]), WithingsActivity)
        # No need to assert all attributes, that happens elsewhere
        self.assertEqual(resp[0].data, body)

        # Test multiple activities
        new_body = {
            'activities': [
                body, {
                   "date": "2013-04-11",
                   "steps": 223,
                   "distance": 400,
                   "calories": 108.52,
                   "elevation": 1.2,
                   "soft": 160,
                   "moderate": 42,
                   "intense": 21,
                   "timezone": "Europe/Berlin"
                }
            ]
        }
        self.mock_request(new_body)
        resp = self.api.get_activities()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/v2/measure',
            params={'action': 'getactivity'})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 2)
        self.assertEqual(type(resp[0]), WithingsActivity)
        self.assertEqual(type(resp[1]), WithingsActivity)
        self.assertEqual(resp[0].data, new_body['activities'][0])
        self.assertEqual(resp[1].data, new_body['activities'][1])

    def test_get_measures(self):
        """
        Check that get_measures fetches the appriate URL, the response looks
        correct, and the return value is a WithingsMeasures object
        """
        body = {
            'updatetime': 1409596058,
            'measuregrps': [
                {'attrib': 2, 'measures': [
                    {'unit': -1, 'type': 1, 'value': 860}
                ], 'date': 1409361740, 'category': 1, 'grpid': 111111111},
                {'attrib': 2, 'measures': [
                    {'unit': -2, 'type': 4, 'value': 185}
                ], 'date': 1409361740, 'category': 1, 'grpid': 111111112}
            ]
        }
        self.mock_request(body)
        resp = self.api.get_measures()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/measure',
            params={'action': 'getmeas'})
        self.assertEqual(type(resp), WithingsMeasures)
        self.assertEqual(len(resp), 2)
        self.assertEqual(type(resp[0]), WithingsMeasureGroup)
        self.assertEqual(resp[0].weight, 86.0)
        self.assertEqual(resp[1].height, 1.85)

        # Test limit=1
        body['measuregrps'].pop()
        self.mock_request(body)
        resp = self.api.get_measures(limit=1)
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/measure',
            params={'action': 'getmeas', 'limit': 1})
        self.assertEqual(len(resp), 1)
        self.assertEqual(resp[0].weight, 86.0)

    def test_subscribe(self):
        """
        Check that subscribe fetches the right URL and returns the expected
        results
        """
        self.mock_request(None)
        resp = self.api.subscribe('http://www.example.com/', 'fake_comment')
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'subscribe', 'appli': 1,
                    'comment': 'fake_comment',
                    'callbackurl': 'http://www.example.com/'})
        self.assertEqual(resp, None)

    def test_unsubscribe(self):
        """
        Check that unsubscribe fetches the right URL and returns the expected
        results
        """
        self.mock_request(None)
        resp = self.api.unsubscribe('http://www.example.com/')
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'revoke', 'appli': 1,
                    'callbackurl': 'http://www.example.com/'})
        self.assertEqual(resp, None)


    def test_is_subscribed(self):
        """
        Check that is_subscribed fetches the right URL and returns the
        expected results
        """
        url = 'http://wbsapi.withings.net/notify'
        params = {
            'callbackurl': 'http://www.example.com/',
            'action': 'get',
            'appli': 1
        }
        self.mock_request({'expires': 2147483647, 'comment': 'fake_comment'})
        resp = self.api.is_subscribed('http://www.example.com/')
        Session.request.assert_called_once_with('GET', url, params=params)
        self.assertEquals(resp, True)

        # Not subscribed
        self.mock_request(None, status=343)
        resp = self.api.is_subscribed('http://www.example.com/')
        Session.request.assert_called_once_with('GET', url, params=params)
        self.assertEquals(resp, False)

    def test_list_subscriptions(self):
        """
        Check that list_subscriptions fetches the right URL and returns the
        expected results
        """
        self.mock_request({'profiles': [
            {'comment': 'fake_comment', 'expires': 2147483647}
        ]})
        resp = self.api.list_subscriptions()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'list', 'appli': 1})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 1)
        self.assertEqual(resp[0]['comment'], 'fake_comment')
        self.assertEqual(resp[0]['expires'], 2147483647)

        # No subscriptions
        self.mock_request({'profiles': []})
        resp = self.api.list_subscriptions()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'list', 'appli': 1})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 0)

    def mock_request(self, body, status=0):
        if self.mock_api:
            json_content = {'status': status}
            if body != None:
                json_content['body'] = body
            response = MagicMock()
            response.content = json.dumps(json_content).encode('utf8')
            Session.request = MagicMock(return_value=response)
예제 #3
0
class WITHINGclass:
    """
    Get informations about withing
    """
    # -------------------------------------------------------------------------------------------------
    def __init__(self, log, api_id, api_secret, period, dataPath):
        try:
            """
            Create a withing instance, allowing to use withing api
            """
            self._log = log
            self.api_id = api_id
            self.api_secret = api_secret
            self.period = period
	    self._sensors = []

	    self._dataPath = dataPath 

            if not os.path.exists(self._dataPath) :
                self._log.info(u"Directory data not exist, trying create : %s" , self._dataPath)
                try :
                    os.mkdir(self._dataPath)
                    self._log.info(u"Withings data directory created : %s"  %self._dataPath)
                except Exception as e:
                    self._log.error(e.message)
                    raise withingException ("Withings data directory not exist : %s" % self._dataPath)
	    if not os.access(self._dataPath, os.W_OK) :
                self._log.error("User %s haven't write access on data directory : %s"  %(user,  self._dataPath))
    	        raise withingException ("User %s haven't write access on data directory : %s"  %(user,  self._dataPath))

            self.withing_config_file = os.path.join(os.path.dirname(__file__), '../data/withings.json')
	    self.auth = WithingsAuth(self.api_id, self.api_secret)
#	    self.open_token(self.auth)

            try:
    	        with open(self.withing_config_file, 'r') as withing_token_file:
                    self._log.debug(u"Opening File")
                    self.creds = pickle.load(withing_token_file)
                    self._log.debug(u"Getting user")
		    self.client = WithingsApi(self.creds)
		    self.user = self.client.get_user()
                    if self.user == None :
                        self.auth = WithingsAuth(self.api_key, self.api_secret)
		        self.authorize_url = self.auth.get_authorize_url()
		        print("Go to %s allow the app and copy your oauth_verifier" %self.authorize_url)
		        self.oauth_verifier = raw_input('Please enter your oauth_verifier: ')
		        self.creds = auth.get_credentials(self.oauth_verifier)
		        self.client = WithingsApi(creds)
		        self.user = self.client.get_user()
                        if user == None :
                            self._log.error(u"Error getting user, from code")
                            self._log.error(error)
                            sys.exit("refreshing token failed from refresh_token")
                            #TODO stop plugin
                        else :
                            self._log.warning(u"Token succesfully refresh with token_refresh from file")
                with open(self.withing_config_file, 'w') as withing_token_file:
                    pickle.dump(self.creds, withing_token_file)

            except ValueError:
                self._log.error(u"error reading Withing.")
                return
        except ValueError:
            self._log.error(u"error reading Withing.")


    def open_token(self, auth):
            try:
    	        with open(withing_config_file, 'r') as withing_token_file:
                    self._log.debug(u"Opening File")
                    self.creds = pickle.load(withing_token_file)
                    self._log.debug(u"Getting user")
		    self.client = WithingsApi(self.creds)
		    self.user = self.client.get_user()
                    if user == None :
                        self.auth = WithingsAuth(self.api_key, self.api_secret)
		        self.authorize_url = self.auth.get_authorize_url()
		        print("Go to %s allow the app and copy your oauth_verifier" %self.authorize_url)
		        self.oauth_verifier = raw_input('Please enter your oauth_verifier: ')
		        self.creds = auth.get_credentials(self.oauth_verifier)
		        self.client = WithingsApi(creds)
		        self.user = self.client.get_user()
                        if user == None :
                            self._log.error(u"Error getting user, from code")
                            self._log.error(error)
                            sys.exit("refreshing token failed from refresh_token")
                            #TODO stop plugin
                        else :
                            self._log.warning(u"Token succesfully refresh with token_refresh from file")
                with open(withing_config_file, 'w') as withing_token_file:
                    pickle.dump(self.creds, withing_token_file)

            except:
                self._log.error(u"Error with file saved or no file saved")
                self._log.error(u"Go to Advanced page to generate a new token file")
                #TODO stop plugin

    # -------------------------------------------------------------------------------------------------
    def add_sensor(self, device_id, device_name, device_type, user_id):
        """
        Add a sensor to sensors list.
        """
        self._sensors.append({'device_id': device_id, 'device_name': device_name, 'device_type': device_type,
                              'user_id': user_id})


    # -------------------------------------------------------------------------------------------------
    def readWithingApi(self, userid):
        """
        read the withing api for user information
        """
        try:
            user = self.client.get_user()
            self._log.debug(user)
            return user
        except AttributeError:
            self._log.error(u"### USERid '%s', ERROR while reading client value." % userid)
            return "failed"

    # -------------------------------------------------------------------------------------------------
    def readWithingMeasureApi(self, userid):
        """
        read the withing measure api information
        """
        try:
            measures = self.client.get_measures()
            return measures[0].data
        except AttributeError:
            self._log.error(u"### USERid '%s', ERROR while reading measure value." % userid)
            return "failed"


    # -------------------------------------------------------------------------------------------------
    def loop_read_sensor(self, send, send_sensor, stop):
        """
        """
        while not stop.isSet():
	    for sensor in self._sensors:
		self._log.debug(sensor)
                if sensor['device_type'] == "withing.user":
                    val = self.readWithingApi(sensor['user_id'])
		    self._log.debug(val)
                    if val != "failed":
			self._log.debug(val)
			self._log.debug(sensor)
                        send(sensor['device_id'], {'firstname': val['users'][0]['firstname'], 'lastname': val['users'][0]['lastname'], 'id': val['users'][0]['id']})
                elif sensor['device_type'] == "withing.measure":
                    val = self.readWithingMeasureApi(sensor['user_id'])
		    self._log.debug(val)
                    if val != "failed":
			timestamp = val['date']
			for measure in val['measures']:
                            sensor_name = u''
			    self._log.debug(measure)
                            if measure['type'] == 1:
                                sensor_name = "weight"
                            elif measure['type'] == 4:
                                sensor_name = "height"
                            elif measure['type'] == 5:
                                sensor_name = "fat_free_mass"
                            elif measure['type'] == 6:
                                sensor_name = "fat_ratio"
                            elif measure['type'] == 8:
                                sensor_name = "fat_free_mass"
                            elif measure['type'] == 9:
                                sensor_name = "diastolic_blood_pressure"
                            elif measure['type'] == 10:
                                sensor_name = "systolic_blood_pressure"
                            elif measure['type'] == 11:
                                sensor_name = "heart_pulse"
                            if sensor_name != u'':
                                #timestamp = calendar.timegm(sensors.date.timetuple())
				#timestamp=time.time()
				self._log.debug("Sending value to binary")
				value=float(measure['value'])/pow(10, abs(measure['unit']))
			        send_sensor(sensor['device_id'], sensor_name, value, timestamp)

                self._log.debug(u"=> '{0}' : wait for {1} seconds".format(sensor['device_name'], self.period))
    	    stop.wait(self.period)
class TestWithingsApi(unittest.TestCase):
    def setUp(self):
        self.mock_api = True
        if self.mock_api:
            self.creds = WithingsCredentials()
        else:
            config = ConfigParser.ConfigParser()
            config.read('withings.conf')
            self.creds = WithingsCredentials(
                consumer_key=config.get('withings', 'consumer_key'),
                consumer_secret=config.get('withings', 'consumer_secret'),
                access_token=config.get('withings', 'access_token'),
                access_token_secret=config.get('withings',
                                               'access_token_secret'),
                user_id=config.get('withings', 'user_id'))
        self.api = WithingsApi(self.creds)

    def test_attributes(self):
        """ Make sure the WithingsApi objects have the right attributes """
        assert hasattr(WithingsApi, 'URL')
        creds = WithingsCredentials(user_id='FAKEID')
        api = WithingsApi(creds)
        assert hasattr(api, 'credentials')
        assert hasattr(api, 'oauth')
        assert hasattr(api, 'client')

    def test_attribute_defaults(self):
        """
        Make sure WithingsApi object attributes have the correct defaults
        """
        self.assertEqual(WithingsApi.URL, 'http://wbsapi.withings.net')
        creds = WithingsCredentials(user_id='FAKEID')
        api = WithingsApi(creds)
        self.assertEqual(api.credentials, creds)
        self.assertEqual(api.client.auth, api.oauth)
        self.assertEqual(api.client.params, {'userid': creds.user_id})

    def test_request(self):
        """
        Make sure the request method builds the proper URI and returns the
        request body as a python dict.
        """
        self.mock_request({})
        resp = self.api.request('fake_service', 'fake_action')
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/fake_service',
            params={'action': 'fake_action'})
        self.assertEqual(resp, {})

    def test_request_params(self):
        """
        Check that the request method passes along extra params and works
        with different HTTP methods
        """
        self.mock_request({})
        resp = self.api.request('user', 'getbyuserid', params={'p2': 'p2'},
                                method='POST')
        Session.request.assert_called_once_with(
            'POST', 'http://wbsapi.withings.net/user',
            params={'p2': 'p2', 'action': 'getbyuserid'})
        self.assertEqual(resp, {})

    def test_request_error(self):
        """ Check that requests raises an exception when there is an error """
        self.mock_request('', status=1)
        self.assertRaises(Exception, self.api.request, ('user', 'getbyuserid'))

    def test_get_user(self):
        """ Check that the get_user method fetches the right URL """
        self.mock_request({
            'users': [
                {'id': 1111111, 'birthdate': 364305600, 'lastname': 'Baggins',
                 'ispublic': 255, 'firstname': 'Frodo', 'fatmethod': 131,
                 'gender': 0, 'shortname': 'FRO'}
            ]
        })
        resp = self.api.get_user()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/user',
            params={'action': 'getbyuserid'})
        self.assertEqual(type(resp), dict)
        assert 'users' in resp
        self.assertEqual(type(resp['users']), list)
        self.assertEqual(len(resp['users']), 1)
        self.assertEqual(resp['users'][0]['firstname'], 'Frodo')
        self.assertEqual(resp['users'][0]['lastname'], 'Baggins')

    def test_get_sleep(self):
        """
        Check that get_sleep fetches the appropriate URL, the response looks
        correct, and the return value is a WithingsSleep object with the
        correct attributes
        """
        body = {
            "series": [{
                "startdate": 1387235398,
                "state": 0,
                "enddate": 1387235758
            }, {
                "startdate": 1387243618,
                "state": 1,
                "enddate": 1387244518
            }],
            "model": 16
        }
        self.mock_request(body)
        resp = self.api.get_sleep()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/v2/sleep',
            params={'action': 'get'})
        self.assertEqual(type(resp), WithingsSleep)
        self.assertEqual(resp.model, body['model'])
        self.assertEqual(type(resp.series), list)
        self.assertEqual(len(resp.series), 2)
        self.assertEqual(type(resp.series[0]), WithingsSleepSeries)
        self.assertEqual(resp.series[0].startdate.timestamp,
                         body['series'][0]['startdate'])
        self.assertEqual(resp.series[0].enddate.timestamp,
                         body['series'][0]['enddate'])
        self.assertEqual(resp.series[1].state, 1)


    def test_get_activities(self):
        """
        Check that get_activities fetches the appropriate URL, the response
        looks correct, and the return value is a list of WithingsActivity
        objects
        """
        body = {
           "date": "2013-04-10",
           "steps": 6523,
           "distance": 4600,
           "calories": 408.52,
           "elevation": 18.2,
           "soft": 5880,
           "moderate": 1080,
           "intense": 540,
           "timezone": "Europe/Berlin"
        }
        self.mock_request(body)
        resp = self.api.get_activities()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/v2/measure',
            params={'action': 'getactivity'})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 1)
        self.assertEqual(type(resp[0]), WithingsActivity)
        # No need to assert all attributes, that happens elsewhere
        self.assertEqual(resp[0].data, body)

        # Test multiple activities
        new_body = {
            'activities': [
                body, {
                   "date": "2013-04-11",
                   "steps": 223,
                   "distance": 400,
                   "calories": 108.52,
                   "elevation": 1.2,
                   "soft": 160,
                   "moderate": 42,
                   "intense": 21,
                   "timezone": "Europe/Berlin"
                }
            ]
        }
        self.mock_request(new_body)
        resp = self.api.get_activities()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/v2/measure',
            params={'action': 'getactivity'})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 2)
        self.assertEqual(type(resp[0]), WithingsActivity)
        self.assertEqual(type(resp[1]), WithingsActivity)
        self.assertEqual(resp[0].data, new_body['activities'][0])
        self.assertEqual(resp[1].data, new_body['activities'][1])

    def test_get_measures(self):
        """
        Check that get_measures fetches the appriate URL, the response looks
        correct, and the return value is a WithingsMeasures object
        """
        body = {
            'updatetime': 1409596058,
            'measuregrps': [
                {'attrib': 2, 'measures': [
                    {'unit': -1, 'type': 1, 'value': 860}
                ], 'date': 1409361740, 'category': 1, 'grpid': 111111111},
                {'attrib': 2, 'measures': [
                    {'unit': -2, 'type': 4, 'value': 185}
                ], 'date': 1409361740, 'category': 1, 'grpid': 111111112}
            ]
        }
        self.mock_request(body)
        resp = self.api.get_measures()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/measure',
            params={'action': 'getmeas'})
        self.assertEqual(type(resp), WithingsMeasures)
        self.assertEqual(len(resp), 2)
        self.assertEqual(type(resp[0]), WithingsMeasureGroup)
        self.assertEqual(resp[0].weight, 86.0)
        self.assertEqual(resp[1].height, 1.85)

        # Test limit=1
        body['measuregrps'].pop()
        self.mock_request(body)
        resp = self.api.get_measures(limit=1)
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/measure',
            params={'action': 'getmeas', 'limit': 1})
        self.assertEqual(len(resp), 1)
        self.assertEqual(resp[0].weight, 86.0)

    def test_subscribe(self):
        """
        Check that subscribe fetches the right URL and returns the expected
        results
        """
        # Unspecified appli
        self.mock_request(None)
        resp = self.api.subscribe('http://www.example.com/', 'fake_comment')
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'subscribe', 'comment': 'fake_comment',
                    'callbackurl': 'http://www.example.com/'})
        self.assertEqual(resp, None)

        # appli=1
        self.mock_request(None)
        resp = self.api.subscribe('http://www.example.com/', 'fake_comment',
                                  appli=1)
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'subscribe', 'appli': 1,
                    'comment': 'fake_comment',
                    'callbackurl': 'http://www.example.com/'})
        self.assertEqual(resp, None)

    def test_unsubscribe(self):
        """
        Check that unsubscribe fetches the right URL and returns the expected
        results
        """
        # Unspecified appli
        self.mock_request(None)
        resp = self.api.unsubscribe('http://www.example.com/')
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'revoke',
                    'callbackurl': 'http://www.example.com/'})
        self.assertEqual(resp, None)

        # appli=1
        self.mock_request(None)
        resp = self.api.unsubscribe('http://www.example.com/', appli=1)
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'revoke', 'appli': 1,
                    'callbackurl': 'http://www.example.com/'})
        self.assertEqual(resp, None)


    def test_is_subscribed(self):
        """
        Check that is_subscribed fetches the right URL and returns the
        expected results
        """
        url = 'http://wbsapi.withings.net/notify'
        params = {
            'callbackurl': 'http://www.example.com/',
            'action': 'get',
            'appli': 1
        }
        self.mock_request({'expires': 2147483647, 'comment': 'fake_comment'})
        resp = self.api.is_subscribed('http://www.example.com/')
        Session.request.assert_called_once_with('GET', url, params=params)
        self.assertEquals(resp, True)

        # Not subscribed
        self.mock_request(None, status=343)
        resp = self.api.is_subscribed('http://www.example.com/')
        Session.request.assert_called_once_with('GET', url, params=params)
        self.assertEquals(resp, False)

    def test_list_subscriptions(self):
        """
        Check that list_subscriptions fetches the right URL and returns the
        expected results
        """
        self.mock_request({'profiles': [
            {'comment': 'fake_comment', 'expires': 2147483647}
        ]})
        resp = self.api.list_subscriptions()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'list', 'appli': 1})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 1)
        self.assertEqual(resp[0]['comment'], 'fake_comment')
        self.assertEqual(resp[0]['expires'], 2147483647)

        # No subscriptions
        self.mock_request({'profiles': []})
        resp = self.api.list_subscriptions()
        Session.request.assert_called_once_with(
            'GET', 'http://wbsapi.withings.net/notify',
            params={'action': 'list', 'appli': 1})
        self.assertEqual(type(resp), list)
        self.assertEqual(len(resp), 0)

    def mock_request(self, body, status=0):
        if self.mock_api:
            json_content = {'status': status}
            if body != None:
                json_content['body'] = body
            response = MagicMock()
            response.content = json.dumps(json_content).encode('utf8')
            Session.request = MagicMock(return_value=response)