def setUp(self):
        self.client_id = 'device_client_id'
        self.device_id = 'device_device_id'
        self.access_token = 'device_access_token'
        self.refresh_token = 'device_refresh_token'
        self.expires_in = 200
        self.tag = 'device_tag'

        self.geotrigger_headers = {
            'X-GT-Client-Name': 'geotrigger-python',
            'X-GT-Client-Version': __version__,
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + self.access_token
        }

        with patch.object(GeotriggerDevice, 'register') as mock_register:
            mock_register.return_value = {
                'device_id': self.device_id,
                'access_token': self.access_token,
                'refresh_token': self.refresh_token,
                'expires_in': self.expires_in
            }

            with patch.object(GeotriggerSession, 'post') as mock_post:
                self.client = GeotriggerDevice(self.client_id)
class GeotriggerDeviceTestCase(TestCase):
    """
    Tests for the `GeotriggerDevice` class.
    """

    def setUp(self):
        self.client_id = 'device_client_id'
        self.device_id = 'device_device_id'
        self.access_token = 'device_access_token'
        self.refresh_token = 'device_refresh_token'
        self.expires_in = 200
        self.tag = 'device_tag'

        self.geotrigger_headers = {
            'X-GT-Client-Name': 'geotrigger-python',
            'X-GT-Client-Version': __version__,
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + self.access_token
        }

        with patch.object(GeotriggerDevice, 'register') as mock_register:
            mock_register.return_value = {
                'device_id': self.device_id,
                'access_token': self.access_token,
                'refresh_token': self.refresh_token,
                'expires_in': self.expires_in
            }

            with patch.object(GeotriggerSession, 'post') as mock_post:
                self.client = GeotriggerDevice(self.client_id)

    @patch.object(GeotriggerDevice, 'register')
    @patch.object(GeotriggerSession, 'post')
    def test_register(self, mock_post, mock_register):
        """
        Test device registration with ArcGIS Online.
        """
        # Device should be registered from setUp
        device = self.client

        # Sanity
        self.assertTrue(device.is_device())
        self.assertFalse(device.is_application())

        # Make sure we set all properties from registration response
        self.assertEqual(device.device_id, self.device_id)
        self.assertEqual(device.access_token, self.access_token)
        self.assertEqual(device.refresh_token, self.refresh_token)
        self.assertEqual(device.expires_in, self.expires_in)
        self.assertIsNotNone(device.expires_at)

        # Ensure `register` is only called once
        device.register.assert_called_once()

        # Device credentials given, registration should not occur
        device2 = GeotriggerDevice(self.client_id, 'device_id',
                                   'access_token', 'refresh_token',
                                   300)

        # `register` should not have been called
        self.assertEqual(device2.register.call_count, 0)

    @patch.object(GeotriggerSession, 'post')
    def test_geotrigger_request(self, mock_post):
        """
        Test creation of Geotrigger API requests.
        """
        # make a call via the `geotrigger_post` method
        data = {'tags': self.tag}
        url = 'trigger/list'
        self.client.geotrigger_request(url, data=data)

        # ensure that the `request` method is called with the correct parameters
        self.client.post.assert_called_once_with(
            GEOTRIGGER_BASE_URL + url,
            data=json.dumps(data),
            headers=self.geotrigger_headers
        )

    @patch.object(GeotriggerSession, 'post')
    @patch.object(GeotriggerSession, 'ago_request')
    def test_refresh(self, mock_ago_request, mock_post):
        """
        Test refresh of expired access tokens.
        """
        first_token = 'new_token'
        first_expires = 400
        second_token = 'newer_token'
        second_expires = 401

        mock_ago_request.return_value = {
            'access_token': first_token,
            'expires_in': first_expires
        }

        old_token = self.client.access_token
        old_expires = self.client.expires_in

        # sanity
        self.assertEqual(self.access_token, old_token)
        self.assertEqual(self.expires_in, old_expires)

        # call refresh
        self.client.refresh()

        # check refresh request
        self.client.ago_request.assert_called_once_with(
            AGO_TOKEN_ROUTE,
            {
                'client_id': self.client_id,
                'refresh_token': self.refresh_token,
                'grant_type': 'refresh_token',
                'f': 'json'
            }
        )

        # check token
        self.assertEqual(self.client.access_token, first_token)
        self.assertEqual(self.client.expires_in, first_expires)

        # make a geotrigger request to ensure that we call refresh again
        with patch.object(GeotriggerDevice, 'refresh') as mock_refresh:
            mock_refresh.return_value = {
                'access_token': second_token,
                'expires_in': second_expires
            }

            # force expire credentials
            self.client.set_expires(0)

            # sanity
            self.assertEqual(self.client.refresh.call_count, 0)

            # make a geotrigger request, which should call refresh
            self.client.geotrigger_request('dummy/url')

            # check refresh call count
            self.assertEqual(self.client.refresh.call_count, 1)