Exemplo n.º 1
0
class RequestTest(unittest.TestCase):

    def setUp(self):
        self.client = Client()

    @istest
    def it_raises_resource_not_found(self):
        resp = mock_response(None, status_code=404)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ResourceNotFound):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_authentication_error_unauthorized(self):
        resp = mock_response(None, status_code=401)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.AuthenticationError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_authentication_error_forbidden(self):
        resp = mock_response(None, status_code=403)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.AuthenticationError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_server_error(self):
        resp = mock_response(None, status_code=500)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ServerError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_bad_gateway_error(self):
        resp = mock_response(None, status_code=502)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.BadGatewayError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_service_unavailable_error(self):
        resp = mock_response(None, status_code=503)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ServiceUnavailableError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_an_unexpected_typed_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'hopper',
                    'message': 'The first compiler.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            try:
                self.client.get('/users', {})
                self.fail('UnexpectedError not raised.')
            except (UnexpectedError) as err:
                ok_("The error of type 'hopper' is not recognized" in err.message)  # noqa
                eq_(err.context['http_code'], 200)
                eq_(err.context['application_error_code'], 'hopper')

    @istest
    def it_raises_an_unexpected_untyped_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'message': 'UNIVAC'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            try:
                self.client.get('/users', {})
                self.fail('UnexpectedError not raised.')
            except (UnexpectedError) as err:
                ok_("An unexpected error occured." in err.message)
                eq_(err.context['application_error_code'], None)

    @istest
    def it_raises_a_bad_request_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': None,
                    'message': 'email is required'
                }
            ]
        }

        for code in ['missing_parameter', 'parameter_invalid', 'bad_request']:
            payload['errors'][0]['type'] = code

            content = json.dumps(payload).encode('utf-8')
            resp = mock_response(content)
            with patch('requests.request') as mock_method:
                mock_method.return_value = resp
                with assert_raises(intercom.BadRequestError):
                    self.client.get('/users', {})

    @istest
    def it_raises_an_authentication_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'unauthorized',
                    'message': 'Your name\'s not down.'
                }
            ]
        }
        for code in ['unauthorized', 'forbidden']:
            payload['errors'][0]['type'] = code

            content = json.dumps(payload).encode('utf-8')
            resp = mock_response(content)
            with patch('requests.request') as mock_method:
                mock_method.return_value = resp
                with assert_raises(intercom.AuthenticationError):
                    self.client.get('/users', {})

    @istest
    def it_raises_resource_not_found_by_type(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'not_found',
                    'message': 'Waaaaally?'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ResourceNotFound):
                self.client.get('/users', {})

    @istest
    def it_raises_rate_limit_exceeded(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'rate_limit_exceeded',
                    'message': 'Fair use please.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.RateLimitExceeded):
                self.client.get('/users', {})

    @istest
    def it_raises_a_service_unavailable_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'service_unavailable',
                    'message': 'Zzzzz.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ServiceUnavailableError):
                self.client.get('/users', {})

    @istest
    def it_raises_a_multiple_matching_users_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'conflict',
                    'message': 'Two many cooks.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.MultipleMatchingUsersError):
                self.client.get('/users', {})

    @istest
    def it_handles_no_error_type(self):
        payload = {
            'errors': [
                {
                    'code': 'unique_user_constraint',
                    'message': 'User already exists.'
                }
            ],
            'request_id': '00000000-0000-0000-0000-000000000000',
            'type': 'error.list'
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.MultipleMatchingUsersError):
                self.client.get('/users', {})

        payload = {
            'errors': [
                {
                    'code': 'parameter_not_found',
                    'message': 'missing data parameter'
                }
            ],
            'request_id': None,
            'type': 'error.list'
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.BadRequestError):
                self.client.get('/users', {})

    @istest
    def it_handles_empty_responses(self):
        resp = mock_response('', status_code=202)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            request = Request('GET', 'events')
            request.send_request_to_path('', ('x', 'y'), resp)

        resp = mock_response(' ', status_code=202)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            request = Request('GET', 'events')
            request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_handles_no_encoding(self):
        resp = mock_response(
            ' ', status_code=200, encoding=None, headers=None)
        resp.apparent_encoding = 'utf-8'

        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            request = Request('GET', 'events')
            request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_needs_encoding_or_apparent_encoding(self):
        payload = '{}'

        if not hasattr(payload, 'decode'):
            # python 3
            payload = payload.encode('utf-8')

        resp = mock_response(
            payload, status_code=200, encoding=None, headers=None)

        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(TypeError):
                request = Request('GET', 'events')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_allows_the_timeout_to_be_changed(self):
        from intercom.request import Request
        eq_(10, Request.timeout)
        Request.timeout = 3
        eq_(3, Request.timeout)
Exemplo n.º 2
0
class UserTest(unittest.TestCase):

    def setUp(self):
        self.client = Client()

    @istest
    def it_to_dict_itself(self):
        created_at = datetime.utcnow()
        user = User(
            email="*****@*****.**", user_id="12345",
            created_at=created_at, name="Jim Bob")
        as_dict = user.to_dict()
        eq_(as_dict["email"], "*****@*****.**")
        eq_(as_dict["user_id"], "12345")
        eq_(as_dict["created_at"], calendar.timegm(created_at.utctimetuple()))
        eq_(as_dict["name"], "Jim Bob")

    @istest
    def it_presents_created_at_and_last_impression_at_as_datetime(self):
        now = datetime.utcnow()
        now_ts = calendar.timegm(now.utctimetuple())
        user = User.from_api(
            {'created_at': now_ts, 'last_impression_at': now_ts})
        self.assertIsInstance(user.created_at, datetime)
        eq_(now.strftime('%c'), user.created_at.strftime('%c'))
        self.assertIsInstance(user.last_impression_at, datetime)
        eq_(now.strftime('%c'), user.last_impression_at.strftime('%c'))

    @istest
    def it_throws_an_attribute_error_on_trying_to_access_an_attribute_that_has_not_been_set(self):  # noqa
        with assert_raises(AttributeError):
            user = User()
            user.foo_property

    @istest
    def it_presents_a_complete_user_record_correctly(self):
        user = User.from_api(get_user())
        eq_('id-from-customers-app', user.user_id)
        eq_('*****@*****.**', user.email)
        eq_('Joe Schmoe', user.name)
        eq_('the-app-id', user.app_id)
        eq_(123, user.session_count)
        eq_(1401970114, calendar.timegm(user.created_at.utctimetuple()))
        eq_(1393613864, calendar.timegm(user.remote_created_at.utctimetuple()))
        eq_(1401970114, calendar.timegm(user.updated_at.utctimetuple()))

        Avatar = define_lightweight_class('avatar', 'Avatar')  # noqa
        Company = define_lightweight_class('company', 'Company')  # noqa
        SocialProfile = define_lightweight_class('social_profile', 'SocialProfile')  # noqa
        LocationData = define_lightweight_class('locaion_data', 'LocationData')  # noqa
        self.assertIsInstance(user.avatar.__class__, Avatar.__class__)
        img_url = 'https://graph.facebook.com/1/picture?width=24&height=24'
        eq_(img_url, user.avatar.image_url)

        self.assertIsInstance(user.companies, list)
        eq_(1, len(user.companies))
        self.assertIsInstance(user.companies[0].__class__, Company.__class__)
        eq_('123', user.companies[0].company_id)
        eq_('bbbbbbbbbbbbbbbbbbbbbbbb', user.companies[0].id)
        eq_('the-app-id', user.companies[0].app_id)
        eq_('Company 1', user.companies[0].name)
        eq_(1390936440, calendar.timegm(
            user.companies[0].remote_created_at.utctimetuple()))
        eq_(1401970114, calendar.timegm(
            user.companies[0].created_at.utctimetuple()))
        eq_(1401970114, calendar.timegm(
            user.companies[0].updated_at.utctimetuple()))
        eq_(1401970113, calendar.timegm(
            user.companies[0].last_request_at.utctimetuple()))
        eq_(0, user.companies[0].monthly_spend)
        eq_(0, user.companies[0].session_count)
        eq_(1, user.companies[0].user_count)
        eq_([], user.companies[0].tag_ids)

        self.assertIsInstance(user.custom_attributes, FlatStore)
        eq_('b', user.custom_attributes["a"])
        eq_(2, user.custom_attributes["b"])

        eq_(4, len(user.social_profiles))
        twitter_account = user.social_profiles[0]
        self.assertIsInstance(twitter_account.__class__, SocialProfile.__class__)
        eq_('twitter', twitter_account.name)
        eq_('abc', twitter_account.username)
        eq_('http://twitter.com/abc', twitter_account.url)

        self.assertIsInstance(user.location_data.__class__, LocationData.__class__)
        eq_('Dublin', user.location_data.city_name)
        eq_('EU', user.location_data.continent_code)
        eq_('Ireland', user.location_data.country_name)
        eq_('90', user.location_data.latitude)
        eq_('10', user.location_data.longitude)
        eq_('IRL', user.location_data.country_code)

        ok_(user.unsubscribed_from_emails)
        eq_("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", user.user_agent_data)  # noqa

    @istest
    def it_allows_update_last_request_at(self):
        payload = {
            'user_id': '1224242',
            'update_last_request_at': True,
            'custom_attributes': {}
        }
        with patch.object(Client, 'post', return_value=payload) as mock_method:
            self.client.users.create(
                user_id='1224242', update_last_request_at=True)
            mock_method.assert_called_once_with(
                '/users/',
                {'update_last_request_at': True, 'user_id': '1224242'})

    @istest
    def it_allows_easy_setting_of_custom_data(self):
        now = datetime.utcnow()
        now_ts = calendar.timegm(now.utctimetuple())

        user = User()
        user.custom_attributes["mad"] = 123
        user.custom_attributes["other"] = now_ts
        user.custom_attributes["thing"] = "yay"
        attrs = {"mad": 123, "other": now_ts, "thing": "yay"}
        eq_(user.to_dict()["custom_attributes"], attrs)

    @istest
    def it_allows_easy_setting_of_multiple_companies(self):
        user = User()
        companies = [
            {"name": "Intercom", "company_id": "6"},
            {"name": "Test", "company_id": "9"},
        ]
        user.companies = companies
        eq_(user.to_dict()["companies"], companies)

    @istest
    def it_rejects_nested_data_structures_in_custom_attributes(self):
        user = User()
        with assert_raises(ValueError):
            user.custom_attributes["thing"] = [1]

        with assert_raises(ValueError):
            user.custom_attributes["thing"] = {1: 2}

        with assert_raises(ValueError):
            user.custom_attributes = {1: {2: 3}}

        user = User.from_api(get_user())
        with assert_raises(ValueError):
            user.custom_attributes["thing"] = [1]

    @istest
    def it_fetches_a_user(self):
        with patch.object(Client, 'get', return_value=get_user()) as mock_method:  # noqa
            user = self.client.users.find(email='*****@*****.**')
            eq_(user.email, '*****@*****.**')
            eq_(user.name, 'Joe Schmoe')
            mock_method.assert_called_once_with(
                '/users', {'email': '*****@*****.**'})  # noqa

    @istest
    def it_gets_users_by_tag(self):
        with patch.object(Client, 'get', return_value=page_of_users(False)):
            users = self.client.users.by_tag(124)
            for user in users:
                ok_(hasattr(user, 'avatar'))

    @istest
    def it_saves_a_user_always_sends_custom_attributes(self):

        body = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'custom_attributes': {}
        }

        with patch.object(Client, 'post', return_value=body) as mock_method:
            user = User(email="*****@*****.**", user_id="i-1224242")
            self.client.users.save(user)
            eq_(user.email, '*****@*****.**')
            eq_(user.custom_attributes, {})
            mock_method.assert_called_once_with(
                '/users',
                {'email': "*****@*****.**", 'user_id': "i-1224242",
                 'custom_attributes': {}})

    @istest
    def it_saves_a_user_with_a_company(self):
        body = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'companies': [{
                'company_id': 6,
                'name': 'Intercom'
            }]
        }
        with patch.object(Client, 'post', return_value=body) as mock_method:
            user = User(
                email="*****@*****.**", user_id="i-1224242",
                company={'company_id': 6, 'name': 'Intercom'})
            self.client.users.save(user)
            eq_(user.email, '*****@*****.**')
            eq_(len(user.companies), 1)
            mock_method.assert_called_once_with(
                '/users',
                {'email': "*****@*****.**", 'user_id': "i-1224242",
                 'company': {'company_id': 6, 'name': 'Intercom'},
                 'custom_attributes': {}})

    @istest
    def it_saves_a_user_with_companies(self):
        body = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'companies': [{
                'company_id': 6,
                'name': 'Intercom'
            }]
        }
        with patch.object(Client, 'post', return_value=body) as mock_method:
            user = User(
                email="*****@*****.**", user_id="i-1224242",
                companies=[{'company_id': 6, 'name': 'Intercom'}])
            self.client.users.save(user)
            eq_(user.email, '*****@*****.**')
            eq_(len(user.companies), 1)
            mock_method.assert_called_once_with(
                '/users',
                {'email': "*****@*****.**", 'user_id': "i-1224242",
                 'companies': [{'company_id': 6, 'name': 'Intercom'}],
                 'custom_attributes': {}})

    @istest
    def it_can_save_a_user_with_a_none_email(self):
        user = User(
            email=None, user_id="i-1224242",
            companies=[{'company_id': 6, 'name': 'Intercom'}])
        body = {
            'custom_attributes': {},
            'email': None,
            'user_id': 'i-1224242',
            'companies': [{
                'company_id': 6,
                'name': 'Intercom'
            }]
        }
        with patch.object(Client, 'post', return_value=body) as mock_method:
            self.client.users.save(user)
            ok_(user.email is None)
            eq_(user.user_id, 'i-1224242')
            mock_method.assert_called_once_with(
                '/users',
                {'email': None, 'user_id': "i-1224242",
                 'companies': [{'company_id': 6, 'name': 'Intercom'}],
                 'custom_attributes': {}})

    @istest
    def it_deletes_a_user(self):
        user = User(id="1")
        with patch.object(Client, 'delete', return_value={}) as mock_method:
            user = self.client.users.delete(user)
            eq_(user.id, "1")
            mock_method.assert_called_once_with('/users/1', {})

    @istest
    def it_can_use_user_create_for_convenience(self):
        payload = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'custom_attributes': {}
        }
        with patch.object(Client, 'post', return_value=payload) as mock_method:  # noqa
            user = self.client.users.create(email="*****@*****.**", user_id="i-1224242")  # noqa
            eq_(payload, user.to_dict())
            mock_method.assert_called_once_with(
                '/users/', {'email': "*****@*****.**", 'user_id': "i-1224242"})  # noqa

    @istest
    def it_updates_the_user_with_attributes_set_by_the_server(self):
        payload = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'custom_attributes': {},
            'session_count': 4
        }
        with patch.object(Client, 'post', return_value=payload) as mock_method:  # noqa
            user = self.client.users.create(email="*****@*****.**", user_id="i-1224242")  # noqa
            eq_(payload, user.to_dict())
            mock_method.assert_called_once_with(
                '/users/',
                {'email': "*****@*****.**", 'user_id': "i-1224242"})  # noqa

    @istest
    def it_allows_setting_dates_to_none_without_converting_them_to_0(self):
        payload = {
            'email': '*****@*****.**',
            'custom_attributes': {},
            'remote_created_at': None
        }
        with patch.object(Client, 'post', return_value=payload) as mock_method:
            user = self.client.users.create(email="*****@*****.**", remote_created_at=None)  # noqa
            ok_(user.remote_created_at is None)
            mock_method.assert_called_once_with('/users/', {'email': "*****@*****.**", 'remote_created_at': None})  # noqa

    @istest
    def it_gets_sets_rw_keys(self):
        created_at = datetime.utcnow()
        payload = {
            'email': '*****@*****.**',
            'user_id': 'abc123',
            'name': 'Bob Smith',
            'last_seen_ip': '1.2.3.4',
            'last_seen_user_agent': 'ie6',
            'created_at': calendar.timegm(created_at.utctimetuple())
        }
        user = User(**payload)
        expected_keys = ['custom_attributes']
        expected_keys.extend(list(payload.keys()))
        eq_(sorted(expected_keys), sorted(user.to_dict().keys()))
        for key in list(payload.keys()):
            eq_(payload[key], user.to_dict()[key])

    @istest
    def it_will_allow_extra_attributes_in_response_from_api(self):
        user = User.from_api({'new_param': 'some value'})
        eq_('some value', user.new_param)

    @istest
    def it_returns_a_collectionproxy_for_all_without_making_any_requests(self):
        with mock.patch('intercom.request.Request.send_request_to_path', new_callable=mock.NonCallableMock):  # noqa
            res = self.client.users.all()
            self.assertIsInstance(res, CollectionProxy)

    @istest
    def it_raises_a_multiple_matching_users_error_when_receiving_a_conflict(self):  # noqa
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'code': 'conflict',
                    'message': 'Multiple existing users match this email address - must be more specific using user_id'  # noqa
                }
            ]
        }
        # create bytes content
        content = json.dumps(payload).encode('utf-8')
        # create mock response
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(MultipleMatchingUsersError):
                self.client.get('/users', {})

    @istest
    def it_handles_accented_characters(self):
        # create a user dict with a name that contains accented characters
        payload = get_user(name='Jóe Schmö')
        # create bytes content
        content = json.dumps(payload).encode('utf-8')
        # create mock response
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            user = self.client.users.find(email='*****@*****.**')
            try:
                # Python 2
                eq_(unicode('Jóe Schmö', 'utf-8'), user.name)
            except NameError:
                # Python 3
                eq_('Jóe Schmö', user.name)
Exemplo n.º 3
0
class UserTest(unittest.TestCase):
    def setUp(self):
        self.client = Client()

    @istest
    def it_to_dict_itself(self):
        created_at = datetime.utcnow()
        user = User(email="*****@*****.**",
                    user_id="12345",
                    created_at=created_at,
                    name="Jim Bob")
        as_dict = user.to_dict()
        eq_(as_dict["email"], "*****@*****.**")
        eq_(as_dict["user_id"], "12345")
        eq_(as_dict["created_at"], calendar.timegm(created_at.utctimetuple()))
        eq_(as_dict["name"], "Jim Bob")

    @istest
    def it_presents_created_at_and_last_impression_at_as_datetime(self):
        now = datetime.utcnow()
        now_ts = calendar.timegm(now.utctimetuple())
        user = User.from_api({
            'created_at': now_ts,
            'last_impression_at': now_ts
        })
        self.assertIsInstance(user.created_at, datetime)
        eq_(now.strftime('%c'), user.created_at.strftime('%c'))
        self.assertIsInstance(user.last_impression_at, datetime)
        eq_(now.strftime('%c'), user.last_impression_at.strftime('%c'))

    @istest
    def it_throws_an_attribute_error_on_trying_to_access_an_attribute_that_has_not_been_set(
            self):  # noqa
        with assert_raises(AttributeError):
            user = User()
            user.foo_property

    @istest
    def it_presents_a_complete_user_record_correctly(self):
        user = User.from_api(get_user())
        eq_('id-from-customers-app', user.user_id)
        eq_('*****@*****.**', user.email)
        eq_('Joe Schmoe', user.name)
        eq_('the-app-id', user.app_id)
        eq_(123, user.session_count)
        eq_(1401970114, calendar.timegm(user.created_at.utctimetuple()))
        eq_(1393613864, calendar.timegm(user.remote_created_at.utctimetuple()))
        eq_(1401970114, calendar.timegm(user.updated_at.utctimetuple()))

        Avatar = define_lightweight_class('avatar', 'Avatar')  # noqa
        Company = define_lightweight_class('company', 'Company')  # noqa
        SocialProfile = define_lightweight_class('social_profile',
                                                 'SocialProfile')  # noqa
        LocationData = define_lightweight_class('locaion_data',
                                                'LocationData')  # noqa
        self.assertIsInstance(user.avatar.__class__, Avatar.__class__)
        img_url = 'https://graph.facebook.com/1/picture?width=24&height=24'
        eq_(img_url, user.avatar.image_url)

        self.assertIsInstance(user.companies, list)
        eq_(1, len(user.companies))
        self.assertIsInstance(user.companies[0].__class__, Company.__class__)
        eq_('123', user.companies[0].company_id)
        eq_('bbbbbbbbbbbbbbbbbbbbbbbb', user.companies[0].id)
        eq_('the-app-id', user.companies[0].app_id)
        eq_('Company 1', user.companies[0].name)
        eq_(
            1390936440,
            calendar.timegm(
                user.companies[0].remote_created_at.utctimetuple()))
        eq_(1401970114,
            calendar.timegm(user.companies[0].created_at.utctimetuple()))
        eq_(1401970114,
            calendar.timegm(user.companies[0].updated_at.utctimetuple()))
        eq_(1401970113,
            calendar.timegm(user.companies[0].last_request_at.utctimetuple()))
        eq_(0, user.companies[0].monthly_spend)
        eq_(0, user.companies[0].session_count)
        eq_(1, user.companies[0].user_count)
        eq_([], user.companies[0].tag_ids)

        self.assertIsInstance(user.custom_attributes, FlatStore)
        eq_('b', user.custom_attributes["a"])
        eq_(2, user.custom_attributes["b"])

        eq_(4, len(user.social_profiles))
        twitter_account = user.social_profiles[0]
        self.assertIsInstance(twitter_account.__class__,
                              SocialProfile.__class__)
        eq_('twitter', twitter_account.name)
        eq_('abc', twitter_account.username)
        eq_('http://twitter.com/abc', twitter_account.url)

        self.assertIsInstance(user.location_data.__class__,
                              LocationData.__class__)
        eq_('Dublin', user.location_data.city_name)
        eq_('EU', user.location_data.continent_code)
        eq_('Ireland', user.location_data.country_name)
        eq_('90', user.location_data.latitude)
        eq_('10', user.location_data.longitude)
        eq_('IRL', user.location_data.country_code)

        ok_(user.unsubscribed_from_emails)
        eq_("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
            user.user_agent_data)  # noqa

    @istest
    def it_allows_update_last_request_at(self):
        payload = {
            'user_id': '1224242',
            'update_last_request_at': True,
            'custom_attributes': {}
        }
        with patch.object(Client, 'post', return_value=payload) as mock_method:
            self.client.users.create(user_id='1224242',
                                     update_last_request_at=True)
            mock_method.assert_called_once_with('/users/', {
                'update_last_request_at': True,
                'user_id': '1224242'
            })

    @istest
    def it_allows_easy_setting_of_custom_data(self):
        now = datetime.utcnow()
        now_ts = calendar.timegm(now.utctimetuple())

        user = User()
        user.custom_attributes["mad"] = 123
        user.custom_attributes["other"] = now_ts
        user.custom_attributes["thing"] = "yay"
        attrs = {"mad": 123, "other": now_ts, "thing": "yay"}
        eq_(user.to_dict()["custom_attributes"], attrs)

    @istest
    def it_allows_easy_setting_of_multiple_companies(self):
        user = User()
        companies = [
            {
                "name": "Intercom",
                "company_id": "6"
            },
            {
                "name": "Test",
                "company_id": "9"
            },
        ]
        user.companies = companies
        eq_(user.to_dict()["companies"], companies)

    @istest
    def it_rejects_nested_data_structures_in_custom_attributes(self):
        user = User()
        with assert_raises(ValueError):
            user.custom_attributes["thing"] = [1]

        with assert_raises(ValueError):
            user.custom_attributes["thing"] = {1: 2}

        with assert_raises(ValueError):
            user.custom_attributes = {1: {2: 3}}

        user = User.from_api(get_user())
        with assert_raises(ValueError):
            user.custom_attributes["thing"] = [1]

    @istest
    def it_fetches_a_user(self):
        with patch.object(Client, 'get',
                          return_value=get_user()) as mock_method:  # noqa
            user = self.client.users.find(email='*****@*****.**')
            eq_(user.email, '*****@*****.**')
            eq_(user.name, 'Joe Schmoe')
            mock_method.assert_called_once_with(
                '/users', {'email': '*****@*****.**'})  # noqa

    @istest
    def it_gets_users_by_tag(self):
        with patch.object(Client, 'get', return_value=page_of_users(False)):
            users = self.client.users.by_tag(124)
            for user in users:
                ok_(hasattr(user, 'avatar'))

    @istest
    def it_saves_a_user_always_sends_custom_attributes(self):

        body = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'custom_attributes': {}
        }

        with patch.object(Client, 'post', return_value=body) as mock_method:
            user = User(email="*****@*****.**", user_id="i-1224242")
            self.client.users.save(user)
            eq_(user.email, '*****@*****.**')
            eq_(user.custom_attributes, {})
            mock_method.assert_called_once_with(
                '/users', {
                    'email': "*****@*****.**",
                    'user_id': "i-1224242",
                    'custom_attributes': {}
                })

    @istest
    def it_saves_a_user_with_a_company(self):
        body = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'companies': [{
                'company_id': 6,
                'name': 'Intercom'
            }]
        }
        with patch.object(Client, 'post', return_value=body) as mock_method:
            user = User(email="*****@*****.**",
                        user_id="i-1224242",
                        company={
                            'company_id': 6,
                            'name': 'Intercom'
                        })
            self.client.users.save(user)
            eq_(user.email, '*****@*****.**')
            eq_(len(user.companies), 1)
            mock_method.assert_called_once_with(
                '/users', {
                    'email': "*****@*****.**",
                    'user_id': "i-1224242",
                    'company': {
                        'company_id': 6,
                        'name': 'Intercom'
                    },
                    'custom_attributes': {}
                })

    @istest
    def it_saves_a_user_with_companies(self):
        body = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'companies': [{
                'company_id': 6,
                'name': 'Intercom'
            }]
        }
        with patch.object(Client, 'post', return_value=body) as mock_method:
            user = User(email="*****@*****.**",
                        user_id="i-1224242",
                        companies=[{
                            'company_id': 6,
                            'name': 'Intercom'
                        }])
            self.client.users.save(user)
            eq_(user.email, '*****@*****.**')
            eq_(len(user.companies), 1)
            mock_method.assert_called_once_with(
                '/users', {
                    'email': "*****@*****.**",
                    'user_id': "i-1224242",
                    'companies': [{
                        'company_id': 6,
                        'name': 'Intercom'
                    }],
                    'custom_attributes': {}
                })

    @istest
    def it_can_save_a_user_with_a_none_email(self):
        user = User(email=None,
                    user_id="i-1224242",
                    companies=[{
                        'company_id': 6,
                        'name': 'Intercom'
                    }])
        body = {
            'custom_attributes': {},
            'email': None,
            'user_id': 'i-1224242',
            'companies': [{
                'company_id': 6,
                'name': 'Intercom'
            }]
        }
        with patch.object(Client, 'post', return_value=body) as mock_method:
            self.client.users.save(user)
            ok_(user.email is None)
            eq_(user.user_id, 'i-1224242')
            mock_method.assert_called_once_with(
                '/users', {
                    'email': None,
                    'user_id': "i-1224242",
                    'companies': [{
                        'company_id': 6,
                        'name': 'Intercom'
                    }],
                    'custom_attributes': {}
                })

    @istest
    def it_deletes_a_user(self):
        user = User(id="1")
        with patch.object(Client, 'delete', return_value={}) as mock_method:
            user = self.client.users.delete(user)
            eq_(user.id, "1")
            mock_method.assert_called_once_with('/users/1', {})

    @istest
    def it_can_use_user_create_for_convenience(self):
        payload = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'custom_attributes': {}
        }
        with patch.object(Client, 'post',
                          return_value=payload) as mock_method:  # noqa
            user = self.client.users.create(email="*****@*****.**",
                                            user_id="i-1224242")  # noqa
            eq_(payload, user.to_dict())
            mock_method.assert_called_once_with('/users/', {
                'email': "*****@*****.**",
                'user_id': "i-1224242"
            })  # noqa

    @istest
    def it_updates_the_user_with_attributes_set_by_the_server(self):
        payload = {
            'email': '*****@*****.**',
            'user_id': 'i-1224242',
            'custom_attributes': {},
            'session_count': 4
        }
        with patch.object(Client, 'post',
                          return_value=payload) as mock_method:  # noqa
            user = self.client.users.create(email="*****@*****.**",
                                            user_id="i-1224242")  # noqa
            eq_(payload, user.to_dict())
            mock_method.assert_called_once_with('/users/', {
                'email': "*****@*****.**",
                'user_id': "i-1224242"
            })  # noqa

    @istest
    def it_allows_setting_dates_to_none_without_converting_them_to_0(self):
        payload = {
            'email': '*****@*****.**',
            'custom_attributes': {},
            'remote_created_at': None
        }
        with patch.object(Client, 'post', return_value=payload) as mock_method:
            user = self.client.users.create(email="*****@*****.**",
                                            remote_created_at=None)  # noqa
            ok_(user.remote_created_at is None)
            mock_method.assert_called_once_with('/users/', {
                'email': "*****@*****.**",
                'remote_created_at': None
            })  # noqa

    @istest
    def it_gets_sets_rw_keys(self):
        created_at = datetime.utcnow()
        payload = {
            'email': '*****@*****.**',
            'user_id': 'abc123',
            'name': 'Bob Smith',
            'last_seen_ip': '1.2.3.4',
            'last_seen_user_agent': 'ie6',
            'created_at': calendar.timegm(created_at.utctimetuple())
        }
        user = User(**payload)
        expected_keys = ['custom_attributes']
        expected_keys.extend(list(payload.keys()))
        eq_(sorted(expected_keys), sorted(user.to_dict().keys()))
        for key in list(payload.keys()):
            eq_(payload[key], user.to_dict()[key])

    @istest
    def it_will_allow_extra_attributes_in_response_from_api(self):
        user = User.from_api({'new_param': 'some value'})
        eq_('some value', user.new_param)

    @istest
    def it_returns_a_collectionproxy_for_all_without_making_any_requests(self):
        with mock.patch('intercom.request.Request.send_request_to_path',
                        new_callable=mock.NonCallableMock):  # noqa
            res = self.client.users.all()
            self.assertIsInstance(res, CollectionProxy)

    @istest
    def it_raises_a_multiple_matching_users_error_when_receiving_a_conflict(
            self):  # noqa
        payload = {
            'type':
            'error.list',
            'errors': [{
                'code':
                'conflict',
                'message':
                'Multiple existing users match this email address - must be more specific using user_id'  # noqa
            }]
        }
        # create bytes content
        content = json.dumps(payload).encode('utf-8')
        # create mock response
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(MultipleMatchingUsersError):
                self.client.get('/users', {})

    @istest
    def it_handles_accented_characters(self):
        # create a user dict with a name that contains accented characters
        payload = get_user(name='Jóe Schmö')
        # create bytes content
        content = json.dumps(payload).encode('utf-8')
        # create mock response
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            user = self.client.users.find(email='*****@*****.**')
            try:
                # Python 2
                eq_(unicode('Jóe Schmö', 'utf-8'), user.name)
            except NameError:
                # Python 3
                eq_('Jóe Schmö', user.name)
Exemplo n.º 4
0
class RequestTest(unittest.TestCase):

    def setUp(self):
        self.client = Client()

    @istest
    def it_raises_resource_not_found(self):
        resp = mock_response(None, status_code=404)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ResourceNotFound):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_authentication_error_unauthorized(self):
        resp = mock_response(None, status_code=401)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.AuthenticationError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_authentication_error_forbidden(self):
        resp = mock_response(None, status_code=403)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.AuthenticationError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_server_error(self):
        resp = mock_response(None, status_code=500)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ServerError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_bad_gateway_error(self):
        resp = mock_response(None, status_code=502)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.BadGatewayError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_service_unavailable_error(self):
        resp = mock_response(None, status_code=503)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ServiceUnavailableError):
                request = Request('GET', 'notes')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_raises_an_unexpected_typed_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'hopper',
                    'message': 'The first compiler.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            try:
                self.client.get('/users', {})
                self.fail('UnexpectedError not raised.')
            except (UnexpectedError) as err:
                ok_("The error of type 'hopper' is not recognized" in err.message)  # noqa
                eq_(err.context['http_code'], 200)
                eq_(err.context['application_error_code'], 'hopper')

    @istest
    def it_raises_an_unexpected_untyped_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'message': 'UNIVAC'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            try:
                self.client.get('/users', {})
                self.fail('UnexpectedError not raised.')
            except (UnexpectedError) as err:
                ok_("An unexpected error occured." in err.message)
                eq_(err.context['application_error_code'], None)

    @istest
    def it_raises_a_bad_request_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': None,
                    'message': 'email is required'
                }
            ]
        }

        for code in ['missing_parameter', 'parameter_invalid', 'bad_request']:
            payload['errors'][0]['type'] = code

            content = json.dumps(payload).encode('utf-8')
            resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
                mock_method.return_value = resp
                with assert_raises(intercom.BadRequestError):
                    self.client.get('/users', {})

    @istest
    def it_raises_an_authentication_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'unauthorized',
                    'message': 'Your name\'s not down.'
                }
            ]
        }
        for code in ['unauthorized', 'forbidden']:
            payload['errors'][0]['type'] = code

            content = json.dumps(payload).encode('utf-8')
            resp = mock_response(content)
            with patch('requests.sessions.Session.request') as mock_method:
                mock_method.return_value = resp
                with assert_raises(intercom.AuthenticationError):
                    self.client.get('/users', {})

    @istest
    def it_raises_resource_not_found_by_type(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'not_found',
                    'message': 'Waaaaally?'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ResourceNotFound):
                self.client.get('/users', {})

    @istest
    def it_raises_rate_limit_exceeded(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'rate_limit_exceeded',
                    'message': 'Fair use please.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.RateLimitExceeded):
                self.client.get('/users', {})

    @istest
    def it_raises_a_service_unavailable_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'service_unavailable',
                    'message': 'Zzzzz.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.ServiceUnavailableError):
                self.client.get('/users', {})

    @istest
    def it_raises_a_multiple_matching_users_error(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'conflict',
                    'message': 'Two many cooks.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.MultipleMatchingUsersError):
                self.client.get('/users', {})

    @istest
    def it_raises_token_unauthorized(self):
        payload = {
            'type': 'error.list',
            'errors': [
                {
                    'type': 'token_unauthorized',
                    'message': 'The PAT is not authorized for this action.'
                }
            ]
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.TokenUnauthorizedError):
                self.client.get('/users', {})

    @istest
    def it_handles_no_error_type(self):
        payload = {
            'errors': [
                {
                    'code': 'unique_user_constraint',
                    'message': 'User already exists.'
                }
            ],
            'request_id': '00000000-0000-0000-0000-000000000000',
            'type': 'error.list'
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.MultipleMatchingUsersError):
                self.client.get('/users', {})

        payload = {
            'errors': [
                {
                    'code': 'parameter_not_found',
                    'message': 'missing data parameter'
                }
            ],
            'request_id': None,
            'type': 'error.list'
        }
        content = json.dumps(payload).encode('utf-8')
        resp = mock_response(content)
        with patch('requests.sessions.Session.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(intercom.BadRequestError):
                self.client.get('/users', {})

    @istest
    def it_handles_empty_responses(self):
        resp = mock_response('', status_code=202)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            request = Request('GET', 'events')
            request.send_request_to_path('', ('x', 'y'), resp)

        resp = mock_response(' ', status_code=202)
        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            request = Request('GET', 'events')
            request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_handles_no_encoding(self):
        resp = mock_response(
            ' ', status_code=200, encoding=None, headers=None)
        resp.apparent_encoding = 'utf-8'

        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            request = Request('GET', 'events')
            request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_needs_encoding_or_apparent_encoding(self):
        payload = '{}'

        if not hasattr(payload, 'decode'):
            # python 3
            payload = payload.encode('utf-8')

        resp = mock_response(
            payload, status_code=200, encoding=None, headers=None)

        with patch('requests.request') as mock_method:
            mock_method.return_value = resp
            with assert_raises(TypeError):
                request = Request('GET', 'events')
                request.send_request_to_path('', ('x', 'y'), resp)

    @istest
    def it_allows_the_timeout_to_be_changed(self):
        from intercom.request import Request
        try:
            eq_(90, Request.timeout)
            Request.timeout = 3
            eq_(3, Request.timeout)
        finally:
            Request.timeout = 90

    @istest
    def it_allows_the_timeout_to_be_configured(self):
        import os
        from intercom.request import configure_timeout

        # check the default
        eq_(90, configure_timeout())

        # override the default
        os.environ['INTERCOM_REQUEST_TIMEOUT'] = '20'
        eq_(20, configure_timeout())

        # ignore bad timeouts, reset to default 90
        os.environ['INTERCOM_REQUEST_TIMEOUT'] = 'abc'
        eq_(90, configure_timeout())