diff --git a/.travis.yml b/.travis.yml index 226af0dd..d3bb8afd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: python python: - 2.7 + - 3.4 install: - pip install -r requirements.txt --use-mirrors - pip install -r dev-requirements.txt --use-mirrors diff --git a/dev-requirements.txt b/dev-requirements.txt index 216b3b8b..0930a260 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,5 @@ # # Development dependencies. # -https://github.com/jeffh/describe/tarball/dev#egg=describe-dev httpretty==0.8.8 mock==1.0.1 diff --git a/intercom/__init__.py b/intercom/__init__.py index 1f65c9eb..c05c1dee 100644 --- a/intercom/__init__.py +++ b/intercom/__init__.py @@ -22,6 +22,7 @@ import copy import random import re +import six import time __version__ = '2.0.alpha' @@ -47,7 +48,7 @@ class IntercomType(type): # noqa _endpoints = None _current_endpoint = None _target_base_url = None - _endpoint_randomized_at = None + _endpoint_randomized_at = 0 @property def _auth(self): @@ -134,9 +135,9 @@ def endpoint(self, value): self.endpoints = [value] +@six.add_metaclass(IntercomType) class Intercom(object): _class_register = {} - __metaclass__ = IntercomType @classmethod def get_url(cls, path): diff --git a/intercom/api_operations/save.py b/intercom/api_operations/save.py index 561f84e0..ba00181a 100644 --- a/intercom/api_operations/save.py +++ b/intercom/api_operations/save.py @@ -13,13 +13,13 @@ def create(cls, **params): return cls(**response) def from_dict(self, pdict): - for key, value in pdict.items(): + for key, value in list(pdict.items()): setattr(self, key, value) @property def to_dict(self): a_dict = {} - for name in self.__dict__.keys(): + for name in list(self.__dict__.keys()): if name == "changed_attributes": continue a_dict[name] = self.__dict__[name] # direct access diff --git a/intercom/collection_proxy.py b/intercom/collection_proxy.py index a7053b79..b86e0d20 100644 --- a/intercom/collection_proxy.py +++ b/intercom/collection_proxy.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- +import six from intercom import HttpError -class CollectionProxy(object): +class CollectionProxy(six.Iterator): def __init__(self, cls, collection, finder_url, finder_params={}): # needed to create class instances of the resource @@ -27,7 +28,7 @@ def __init__(self, cls, collection, finder_url, finder_params={}): def __iter__(self): return self - def next(self): + def __next__(self): if self.resources is None: # get the first page of results self.get_first_page() @@ -36,18 +37,18 @@ def next(self): # current resource iterator (StopIteration is raised) # try to get the next page of results first try: - resource = self.resources.next() + resource = six.next(self.resources) except StopIteration: self.get_next_page() - resource = self.resources.next() + resource = six.next(self.resources) instance = self.collection_cls(**resource) return instance def __getitem__(self, index): for i in range(index): - self.next() - return self.next() + six.next(self) + return six.next(self) def get_first_page(self): # get the first page of results diff --git a/intercom/errors.py b/intercom/errors.py index f08fc432..0bf64908 100644 --- a/intercom/errors.py +++ b/intercom/errors.py @@ -13,6 +13,7 @@ class IntercomError(Exception): def __init__(self, message=None, context=None): super(IntercomError, self).__init__(message) + self.message = message self.context = context diff --git a/intercom/lib/flat_store.py b/intercom/lib/flat_store.py index 44b590cc..1c330436 100644 --- a/intercom/lib/flat_store.py +++ b/intercom/lib/flat_store.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import numbers +import six class FlatStore(dict): @@ -11,11 +12,11 @@ def __init__(self, *args, **kwargs): def __setitem__(self, key, value): if not ( isinstance(value, numbers.Real) or - isinstance(value, basestring) + isinstance(value, six.string_types) ): raise ValueError( "custom data only allows string and real number values") - if not isinstance(key, basestring): + if not isinstance(key, six.string_types): raise ValueError("custom data only allows string keys") super(FlatStore, self).__setitem__(key, value) diff --git a/intercom/request.py b/intercom/request.py index 632fc108..8b3d5696 100644 --- a/intercom/request.py +++ b/intercom/request.py @@ -40,7 +40,7 @@ def send_request_to_path(cls, method, url, auth, params=None): @classmethod def parse_body(cls, resp): try: - body = json.loads(resp.content) + body = json.loads(resp.content.decode()) except ValueError: cls.raise_errors_on_failure(resp) if body.get('type') == 'error.list': diff --git a/intercom/traits/api_resource.py b/intercom/traits/api_resource.py index 6b7f3814..04930558 100644 --- a/intercom/traits/api_resource.py +++ b/intercom/traits/api_resource.py @@ -63,7 +63,7 @@ def from_response(self, response): return self def from_dict(self, dict): - for attribute, value in dict.items(): + for attribute, value in list(dict.items()): if type_field(attribute): continue setattr(self, attribute, value) @@ -71,7 +71,7 @@ def from_dict(self, dict): @property def attributes(self): res = {} - for name, value in self.__dict__.items(): + for name, value in list(self.__dict__.items()): if self.submittable_attribute(name, value): res[name] = value return res diff --git a/intercom/utils.py b/intercom/utils.py index c4e68d57..4319339b 100644 --- a/intercom/utils.py +++ b/intercom/utils.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import inflection +import six def pluralize(str): @@ -46,8 +47,9 @@ def __new__(cls, name, bases, attributes): return super(Meta, cls).__new__( cls, str(class_name), bases, attributes) + @six.add_metaclass(Meta) class DynamicClass(Resource, Load): - __metaclass__ = Meta + pass dyncls = DynamicClass() CLASS_REGISTRY[class_name] = dyncls diff --git a/requirements.txt b/requirements.txt index 29a8f068..571df20b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ certifi inflection==0.3.0 requests==2.6.0 -urllib3==1.10.2 \ No newline at end of file +urllib3==1.10.2 +six==1.9.0 diff --git a/tests/integration/test_user.py b/tests/integration/test_user.py index e61b11b6..73fcd9f2 100644 --- a/tests/integration/test_user.py +++ b/tests/integration/test_user.py @@ -27,7 +27,6 @@ def teardown_class(cls): def test_find_by_email(self): # Find user by email user = User.find(email=self.email) - print user self.assertEqual(self.email, user.email) def test_find_by_user_id(self): diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index 3c968c97..1093b163 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -24,9 +24,9 @@ def local_response(**params): def _call(*args, **kwargs): response = Mock() reply = {} - for name, value in kwargs.items(): + for name, value in list(kwargs.items()): reply[name] = value - for name, value in params.items(): + for name, value in list(params.items()): reply[name] = value response.content = json.dumps(reply) response.status_code = 200 @@ -34,7 +34,7 @@ def _call(*args, **kwargs): return _call -def test_user(email="bob@example.com"): +def a_test_user(email="bob@example.com"): return { "type": "user", "id": "aaaaaaaaaaaaaaaaaaaaaaaa", @@ -136,7 +136,10 @@ def page_of_users(include_next_link=False): "per_page": 50, "total_pages": 7 }, - "users": [test_user("user1@example.com"), test_user("user2@example.com"), test_user("user3@example.com")], + "users": [ + a_test_user("user1@example.com"), + a_test_user("user2@example.com"), + a_test_user("user3@example.com")], "total_count": 314 } if include_next_link: diff --git a/tests/unit/admin_spec.py b/tests/unit/admin_spec.py deleted file mode 100644 index 66cd5aa6..00000000 --- a/tests/unit/admin_spec.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -from describe import expect -from describe import patch -from intercom import Request -from intercom import Admin -from intercom.collection_proxy import CollectionProxy - - -class DescribeIntercomAdmin: - - @patch.object(Request, 'send_request_to_path') - def it_returns_a_collection_proxy_for_all_without_making_any_requests(send_request, self): # noqa - send_request.expects().and_raises(AssertionError) - all = Admin.all() - expect(all).to.be_instance_of(CollectionProxy) diff --git a/tests/unit/intercom_spec.py b/tests/unit/intercom_spec.py deleted file mode 100644 index 9b87c484..00000000 --- a/tests/unit/intercom_spec.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- - -from describe import expect -import intercom -import mock -import time -from datetime import datetime - - -class DescribeIntercom: - - # def it_has_a_version_number(self): - # expect(intercom).to.have_attr('__version__') - - class DescribeExpectingArguments: - - def before_each(self, context): - logfile = open('log.txt', 'w') - logfile.write('%s\n' % (context)) - logfile.close() - context['intercom'] = intercom.Intercom - self.intercom = context['intercom'] - self.intercom.app_id = 'abc123' - self.intercom.app_api_key = 'super-secret-key' - - def it_raises_argumenterror_if_no_app_id_or_app_api_key_specified(self): # noqa - self.intercom.app_id = None - self.intercom.app_api_key = None - with expect.to_raise_error(intercom.ArgumentError): - self.intercom.target_base_url - - def it_returns_the_app_id_and_app_api_key_previously_set(self): - expect(self.intercom.app_id) == 'abc123' - expect(self.intercom.app_api_key) == 'super-secret-key' - - def it_defaults_to_https_to_api_intercom_io(self): - expect(self.intercom.target_base_url) == \ - 'https://abc123:super-secret-key@api.intercom.io' - - class DescribeOverridingProtocolHostname: - def before_each(self, context): - self.intercom = context['intercom'] - self.protocol = self.intercom.protocol - self.hostname = self.intercom.hostname - self.intercom.endpoints = None - - def after_each(self, context): - self.intercom.protocol = self.protocol - self.intercom.hostname = self.hostname - self.intercom.endpoints = ["https://api.intercom.io"] - - def it_allows_overriding_of_the_endpoint_and_protocol(self): - self.intercom.protocol = "http" - self.intercom.hostname = "localhost:3000" - expect( - self.intercom._target_base_url, - "http://abc123:super-secret-key@localhost:3000") - - def it_prefers_endpoints(self): - self.intercom.endpoint = "https://localhost:7654" - expect(self.intercom.target_base_url) == "https://abc123:super-secret-key@localhost:7654" # noqa - - # turn off the shuffle - with mock.patch("random.shuffle") as mock_shuffle: - mock_shuffle.return_value = ["http://example.com", "https://localhost:7654"] # noqa - self.intercom.endpoints = ["http://example.com", "https://localhost:7654"] # noqa - expect(self.intercom.target_base_url) == \ - 'http://abc123:super-secret-key@example.com' - - def it_has_endpoints(self): - expect(self.intercom.endpoints) == ["https://api.intercom.io"] - self.intercom.endpoints = ["http://example.com", "https://localhost:7654"] # noqa - expect(self.intercom.endpoints) == ["http://example.com", "https://localhost:7654"] # noqa - - def it_should_randomize_endpoints_if_last_checked_endpoint_is_gt_5_minutes_ago(self): # noqa - now = time.mktime(datetime.utcnow().timetuple()) - self.intercom._endpoint_randomized_at = now - self.intercom.endpoints = ["http://alternative"] - self.intercom.current_endpoint = "http://start" - - self.intercom._endpoint_randomized_at = now - 120 - expect(self.intercom.current_endpoint) == "http://start" - self.intercom._endpoint_randomized_at = now - 360 - expect(self.intercom.current_endpoint) == "http://alternative" diff --git a/tests/unit/lib/flat_store_spec.py b/tests/unit/lib/test_flat_store.py similarity index 55% rename from tests/unit/lib/flat_store_spec.py rename to tests/unit/lib/test_flat_store.py index f503662a..aa52a742 100644 --- a/tests/unit/lib/flat_store_spec.py +++ b/tests/unit/lib/test_flat_store.py @@ -1,31 +1,37 @@ # -*- coding: utf-8 -*- -from describe import expect +import unittest from intercom.lib.flat_store import FlatStore +from nose.tools import assert_raises +from nose.tools import eq_ +from nose.tools import istest -class DescribeIntercomFlatStore: +class IntercomFlatStore(unittest.TestCase): + @istest def it_raises_if_you_try_to_set_or_merge_in_nested_hash_structures(self): data = FlatStore() - with expect.raise_error(ValueError): + with assert_raises(ValueError): data["thing"] = [1] - with expect.raise_error(ValueError): + with assert_raises(ValueError): data["thing"] = {1: 2} - with expect.raise_error(ValueError): + with assert_raises(ValueError): FlatStore(**{"1": {2: 3}}) + @istest def it_raises_if_you_try_to_use_a_non_string_key(self): data = FlatStore() - with expect.raise_error(ValueError): + with assert_raises(ValueError): data[1] = "something" + @istest def it_sets_and_merges_valid_entries(self): data = FlatStore() data["a"] = 1 data["b"] = 2 - expect(data["a"]) == 1 - expect(data["b"]) == 2 + eq_(data["a"], 1) + eq_(data["b"], 2) data = FlatStore(a=1, b=2) - expect(data["a"]) == 1 - expect(data["b"]) == 2 + eq_(data["a"], 1) + eq_(data["b"], 2) diff --git a/tests/unit/test_admin.py b/tests/unit/test_admin.py new file mode 100644 index 00000000..a22e550b --- /dev/null +++ b/tests/unit/test_admin.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +import unittest + +from intercom import Request +from intercom import Admin +from intercom.collection_proxy import CollectionProxy +from mock import patch +from nose.tools import assert_raises +from nose.tools import istest + + +def send_request(*args, **kwargs): + # empty impl + raise (AssertionError) + + +class AdminTest(unittest.TestCase): + + @istest + @patch.object(Request, 'send_request_to_path', send_request) + def it_returns_a_collection_proxy_for_all_without_making_any_requests(self): # noqa + # prove a call to send_request_to_path will raise an error + with assert_raises(AssertionError): + send_request() + all = Admin.all() + self.assertIsInstance(all, CollectionProxy) diff --git a/tests/unit/collection_proxy_spec.py b/tests/unit/test_collection_proxy.py similarity index 63% rename from tests/unit/collection_proxy_spec.py rename to tests/unit/test_collection_proxy.py index e858475d..c35f9e09 100644 --- a/tests/unit/collection_proxy_spec.py +++ b/tests/unit/test_collection_proxy.py @@ -3,43 +3,50 @@ import httpretty import json import re -from describe import expect +import unittest + from intercom import User +from nose.tools import eq_ +from nose.tools import istest from tests.unit import page_of_users get = httpretty.GET r = re.compile -class DescribeIntercomCollectionProxy: +class CollectionProxyTest(unittest.TestCase): + @istest @httpretty.activate def it_stops_iterating_if_no_next_link(self): body = json.dumps(page_of_users(include_next_link=False)) httpretty.register_uri(get, r(r"/users"), body=body) emails = [user.email for user in User.all()] - expect(emails) == ['user1@example.com', 'user2@example.com', 'user3@example.com'] # noqa + eq_(emails, ['user1@example.com', 'user2@example.com', 'user3@example.com']) # noqa + @istest @httpretty.activate def it_keeps_iterating_if_next_link(self): page1 = json.dumps(page_of_users(include_next_link=True)) page2 = json.dumps(page_of_users(include_next_link=False)) httpretty.register_uri(get, r(r"/users$"), body=page1) httpretty.register_uri( - get, r(r'https://api.intercom.io/users\?per_page=50&page=2'), + get, r(r'/users\?per_page=50&page=2$'), body=page2, match_querystring=True) emails = [user.email for user in User.all()] - expect(emails) == ['user1@example.com', 'user2@example.com', 'user3@example.com'] * 2 # noqa + eq_(emails, ['user1@example.com', 'user2@example.com', 'user3@example.com'] * 2) # noqa + @istest @httpretty.activate def it_supports_indexed_array_access(self): body = json.dumps(page_of_users(include_next_link=False)) - httpretty.register_uri(get, r(r"/users"), body=body) - expect(User.all()[0].email) == 'user1@example.com' + httpretty.register_uri(get, r(r"/users$"), body=body) + eq_(User.all()[0].email, 'user1@example.com') + @istest @httpretty.activate def it_supports_querying(self): body = json.dumps(page_of_users(include_next_link=False)) - httpretty.register_uri(get, r(r"/users"), body=body) + httpretty.register_uri(get, r(r"/users$"), body=body) emails = [user.email for user in User.find_all(tag_name='Taggart J')] - expect(emails) == ['user1@example.com', 'user2@example.com', 'user3@example.com'] # noqa + eq_(emails, ['user1@example.com', 'user2@example.com', 'user3@example.com']) # noqa diff --git a/tests/unit/company_spec.py b/tests/unit/test_company.py similarity index 78% rename from tests/unit/company_spec.py rename to tests/unit/test_company.py index 706c7fe4..633d078d 100644 --- a/tests/unit/company_spec.py +++ b/tests/unit/test_company.py @@ -3,30 +3,36 @@ import httpretty import json import re -from describe import expect import intercom +import unittest + from intercom import Company +from nose.tools import assert_raises +from nose.tools import istest get = httpretty.GET r = re.compile -class DescribeIntercomCompany: +class CompanyTest(unittest.TestCase): + @istest @httpretty.activate def it_raises_error_if_no_response_on_find(self): httpretty.register_uri( get, r(r'/companies$'), body=None, status=200) - with expect.to_raise_error(intercom.HttpError): + with assert_raises(intercom.HttpError): Company.find(company_id='4') + @istest @httpretty.activate def it_raises_error_if_no_response_on_find_all(self): httpretty.register_uri( get, r(r'/companies$'), body=None, status=200) - with expect.to_raise_error(intercom.HttpError): + with assert_raises(intercom.HttpError): [x for x in Company.all()] + @istest @httpretty.activate def it_raises_error_on_load(self): data = { @@ -40,5 +46,5 @@ def it_raises_error_on_load(self): company = Company.find(company_id='4') httpretty.register_uri( get, r(r'/companies/aaaaaaaaaaaaaaaaaaaaaaaa$'), body=None, status=200) # noqa - with expect.to_raise_error(intercom.HttpError): + with assert_raises(intercom.HttpError): company.load() diff --git a/tests/unit/event_spec.py b/tests/unit/test_event.py similarity index 75% rename from tests/unit/event_spec.py rename to tests/unit/test_event.py index d9989122..60046bb7 100644 --- a/tests/unit/event_spec.py +++ b/tests/unit/test_event.py @@ -4,18 +4,22 @@ import json import re import time +import unittest + from datetime import datetime -from describe import expect from intercom import User from intercom import Event +from nose.tools import eq_ +from nose.tools import ok_ +from nose.tools import istest post = httpretty.POST r = re.compile -class DescribeIntercomEvent: +class EventTest(unittest.TestCase): - def before_each(self, context): + def setUp(self): # noqa now = time.mktime(datetime.utcnow().timetuple()) self.user = User( email="jim@example.com", @@ -24,6 +28,7 @@ def before_each(self, context): name="Jim Bob") self.created_time = now - 300 + @istest @httpretty.activate def it_creates_an_event_with_metadata(self): data = { @@ -40,10 +45,11 @@ def it_creates_an_event_with_metadata(self): post, r(r'/events/$'), body=json.dumps(data), status=202) event = Event.create(**data) - expect('Eventful 1') == event.event_name - expect(event).to.have_attr('metadata') - expect('pi@example.com') == event.metadata['invitee_email'] + eq_('Eventful 1', event.event_name) + ok_(hasattr(event, 'metadata')) + eq_('pi@example.com', event.metadata['invitee_email']) + @istest @httpretty.activate def it_creates_an_event_without_metadata(self): data = { @@ -54,5 +60,5 @@ def it_creates_an_event_without_metadata(self): post, r(r'/events/$'), body=json.dumps(data), status=202) event = Event.create(**data) - expect('sale of item') == event.event_name - expect(event).to_not.have_attr('metadata') + eq_('sale of item', event.event_name) + ok_(not hasattr(event, 'metadata')) diff --git a/tests/unit/test_intercom.py b/tests/unit/test_intercom.py new file mode 100644 index 00000000..b6534d82 --- /dev/null +++ b/tests/unit/test_intercom.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +import intercom +import mock +import time +import unittest + +from datetime import datetime +from nose.tools import assert_raises +from nose.tools import eq_ +from nose.tools import istest + + +class ExpectingArgumentsTest(unittest.TestCase): + + def setUp(self): # noqa + self.intercom = intercom.Intercom + self.intercom.app_id = 'abc123' + self.intercom.app_api_key = 'super-secret-key' + + @istest + def it_raises_argumenterror_if_no_app_id_or_app_api_key_specified(self): # noqa + self.intercom.app_id = None + self.intercom.app_api_key = None + with assert_raises(intercom.ArgumentError): + self.intercom.target_base_url + + @istest + def it_returns_the_app_id_and_app_api_key_previously_set(self): + eq_(self.intercom.app_id, 'abc123') + eq_(self.intercom.app_api_key, 'super-secret-key') + + @istest + def it_defaults_to_https_to_api_intercom_io(self): + eq_(self.intercom.target_base_url, + 'https://abc123:super-secret-key@api.intercom.io') + + +class OverridingProtocolHostnameTest(unittest.TestCase): + def setUp(self): # noqa + self.intercom = intercom.Intercom + self.protocol = self.intercom.protocol + self.hostname = self.intercom.hostname + self.intercom.endpoints = None + + def tearDown(self): # noqa + self.intercom.protocol = self.protocol + self.intercom.hostname = self.hostname + self.intercom.endpoints = ["https://api.intercom.io"] + + @istest + def it_allows_overriding_of_the_endpoint_and_protocol(self): + self.intercom.protocol = "http" + self.intercom.hostname = "localhost:3000" + eq_( + self.intercom.target_base_url, + "http://abc123:super-secret-key@localhost:3000") + + @istest + def it_prefers_endpoints(self): + self.intercom.endpoint = "https://localhost:7654" + eq_(self.intercom.target_base_url, + "https://abc123:super-secret-key@localhost:7654") + + # turn off the shuffle + with mock.patch("random.shuffle") as mock_shuffle: + mock_shuffle.return_value = ["http://example.com", "https://localhost:7654"] # noqa + self.intercom.endpoints = ["http://example.com", "https://localhost:7654"] # noqa + eq_(self.intercom.target_base_url, + 'http://abc123:super-secret-key@example.com') + + @istest + def it_has_endpoints(self): + eq_(self.intercom.endpoints, ["https://api.intercom.io"]) + self.intercom.endpoints = ["http://example.com", "https://localhost:7654"] # noqa + eq_(self.intercom.endpoints, ["http://example.com", "https://localhost:7654"]) # noqa + + @istest + def it_should_randomize_endpoints_if_last_checked_endpoint_is_gt_5_minutes_ago(self): # noqa + now = time.mktime(datetime.utcnow().timetuple()) + self.intercom._endpoint_randomized_at = now + self.intercom.endpoints = ["http://alternative"] + self.intercom.current_endpoint = "http://start" + + self.intercom._endpoint_randomized_at = now - 120 + eq_(self.intercom.current_endpoint, "http://start") + self.intercom._endpoint_randomized_at = now - 360 + eq_(self.intercom.current_endpoint, "http://alternative") diff --git a/tests/unit/message_spec.py b/tests/unit/test_message.py similarity index 82% rename from tests/unit/message_spec.py rename to tests/unit/test_message.py index f737addb..10a1b58a 100644 --- a/tests/unit/message_spec.py +++ b/tests/unit/test_message.py @@ -4,17 +4,21 @@ import json import re import time +import unittest + from datetime import datetime -from describe import expect from intercom import User from intercom import Message +from nose.tools import eq_ +from nose.tools import istest post = httpretty.POST r = re.compile -class DescribeIntercomEvent: - def before_each(self, context): +class MessageTest(unittest.TestCase): + + def setUp(self): # noqa now = time.mktime(datetime.utcnow().timetuple()) self.user = User( email="jim@example.com", @@ -23,6 +27,7 @@ def before_each(self, context): name="Jim Bob") self.created_time = now - 300 + @istest @httpretty.activate def it_creates_a_user_message_with_string_keys(self): data = { @@ -35,8 +40,9 @@ def it_creates_a_user_message_with_string_keys(self): httpretty.register_uri( post, r(r'/messages/$'), body=json.dumps(data), status=200) message = Message.create(**data) - expect('halp') == message.body + eq_('halp', message.body) + @istest @httpretty.activate def it_creates_an_admin_message(self): data = { @@ -54,5 +60,5 @@ def it_creates_an_admin_message(self): httpretty.register_uri( post, r(r'/messages/$'), body=json.dumps(data), status=200) message = Message.create(**data) - expect('halp') == message.body - expect('inapp') == message.message_type + eq_('halp', message.body) + eq_('inapp', message.message_type) diff --git a/tests/unit/note_spec.py b/tests/unit/test_note.py similarity index 69% rename from tests/unit/note_spec.py rename to tests/unit/test_note.py index ee658885..020a80a8 100644 --- a/tests/unit/note_spec.py +++ b/tests/unit/test_note.py @@ -3,15 +3,19 @@ import httpretty import json import re -from describe import expect +import unittest + from intercom import Note +from nose.tools import eq_ +from nose.tools import istest post = httpretty.POST r = re.compile -class DescribeIntercomNote: +class NoteTest(unittest.TestCase): + @istest @httpretty.activate def it_creates_a_note(self): data = { @@ -21,8 +25,9 @@ def it_creates_a_note(self): httpretty.register_uri( post, r(r'/notes/$'), body=json.dumps(data)) note = Note.create(body="Note to leave on user") - expect(note.body) == "
Note to leave on user
" + eq_(note.body, "Note to leave on user
") + @istest @httpretty.activate def it_sets_gets_allowed_keys(self): params = { @@ -30,14 +35,14 @@ def it_sets_gets_allowed_keys(self): 'email': 'me@example.com', 'user_id': 'abc123' } - params_keys = params.keys() + params_keys = list(params.keys()) params_keys.sort() note = Note(**params) note_dict = note.to_dict - note_keys = note_dict.keys() + note_keys = list(note_dict.keys()) note_keys.sort() - expect(params_keys) == note_keys + eq_(params_keys, note_keys) for key in params_keys: - expect(getattr(note, key)) == params[key] + eq_(getattr(note, key), params[key]) diff --git a/tests/unit/notification_spec.py b/tests/unit/test_notification.py similarity index 73% rename from tests/unit/notification_spec.py rename to tests/unit/test_notification.py index babfd9b7..537205ca 100644 --- a/tests/unit/notification_spec.py +++ b/tests/unit/test_notification.py @@ -1,53 +1,65 @@ # -*- coding: utf-8 -*- -from describe import expect +import unittest + from intercom import Notification from intercom.utils import create_class_instance +from nose.tools import eq_ +from nose.tools import istest from tests.unit import test_conversation_notification from tests.unit import test_user_notification -class DescribeIntercomNotification: +class NotificationTest(unittest.TestCase): + @istest def it_converts_notification_hash_to_object(self): payload = Notification(**test_user_notification) - expect(payload).to.be_instance_of(Notification) + self.assertIsInstance(payload, Notification) + @istest def it_returns_correct_model_type_for_user(self): payload = Notification(**test_user_notification) User = create_class_instance('User') # noqa - expect(payload.model).to.be_instance_of(User.__class__) - expect(payload.model_type) == User.__class__ + self.assertIsInstance(payload.model, User.__class__) + eq_(payload.model_type, User.__class__) + @istest def it_returns_correct_user_notification_topic(self): payload = Notification(**test_user_notification) - expect(payload.topic) == "user.created" + eq_(payload.topic, "user.created") + @istest def it_returns_instance_of_user(self): User = create_class_instance('User') # noqa payload = Notification(**test_user_notification) - expect(payload.model).to.be_instance_of(User.__class__) + self.assertIsInstance(payload.model, User.__class__) + @istest def it_returns_instance_of_conversation(self): Conversation = create_class_instance('Conversation') # noqa payload = Notification(**test_conversation_notification) - expect(payload.model).to.be_instance_of(Conversation.__class__) + self.assertIsInstance(payload.model, Conversation.__class__) + @istest def it_returns_correct_model_type_for_conversation(self): Conversation = create_class_instance('Conversation') # noqa payload = Notification(**test_conversation_notification) - expect(payload.model_type) == Conversation.__class__ + eq_(payload.model_type, Conversation.__class__) + @istest def it_returns_correct_conversation_notification_topic(self): payload = Notification(**test_conversation_notification) - expect(payload.topic) == "conversation.user.created" + eq_(payload.topic, "conversation.user.created") + @istest def it_returns_inner_user_object_for_conversation(self): User = create_class_instance('User') # noqa payload = Notification(**test_conversation_notification) - expect(payload.model.user).to.be_instance_of(User.__class__) + self.assertIsInstance(payload.model.user, User.__class__) + @istest def it_returns_inner_user_object_with_nil_tags(self): user_notification = { "type": "notification_event", @@ -68,4 +80,4 @@ def it_returns_inner_user_object_with_nil_tags(self): } } payload = Notification(**user_notification) - expect(payload.model.tags) == [] + eq_(payload.model.tags, []) diff --git a/tests/unit/request_spec.py b/tests/unit/test_request.py similarity index 78% rename from tests/unit/request_spec.py rename to tests/unit/test_request.py index 34017099..f51e3ced 100644 --- a/tests/unit/request_spec.py +++ b/tests/unit/test_request.py @@ -4,59 +4,71 @@ import intercom import json import re -from describe import expect +import unittest + from intercom import Intercom from intercom import UnexpectedError +from nose.tools import assert_raises +from nose.tools import eq_ +from nose.tools import ok_ +from nose.tools import istest get = httpretty.GET post = httpretty.POST r = re.compile -class DescribeRequest: +class RequestTest(unittest.TestCase): + @istest @httpretty.activate def it_raises_resource_not_found(self): httpretty.register_uri( get, r(r'/notes$'), body='', status=404) - with expect.to_raise_error(intercom.ResourceNotFound): + with assert_raises(intercom.ResourceNotFound): Intercom.get('/notes') + @istest @httpretty.activate def it_raises_authentication_error_unauthorized(self): httpretty.register_uri( get, r(r'/notes$'), body='', status=401) - with expect.to_raise_error(intercom.AuthenticationError): + with assert_raises(intercom.AuthenticationError): Intercom.get('/notes') + @istest @httpretty.activate def it_raises_authentication_error_forbidden(self): httpretty.register_uri( get, r(r'/notes$'), body='', status=403) - with expect.to_raise_error(intercom.AuthenticationError): + with assert_raises(intercom.AuthenticationError): Intercom.get('/notes') + @istest @httpretty.activate def it_raises_server_error(self): httpretty.register_uri( get, r(r'/notes$'), body='', status=500) - with expect.to_raise_error(intercom.ServerError): + with assert_raises(intercom.ServerError): Intercom.get('/notes') + @istest @httpretty.activate def it_raises_bad_gateway_error(self): httpretty.register_uri( get, r(r'/notes$'), body='', status=502) - with expect.to_raise_error(intercom.BadGatewayError): + with assert_raises(intercom.BadGatewayError): Intercom.get('/notes') + @istest @httpretty.activate def it_raises_service_unavailable_error(self): httpretty.register_uri( get, r(r'/notes$'), body='', status=503) - with expect.to_raise_error(intercom.ServiceUnavailableError): + with assert_raises(intercom.ServiceUnavailableError): Intercom.get('/notes') + @istest @httpretty.activate def it_raises_an_unexpected_typed_error(self): payload = { @@ -72,10 +84,11 @@ def it_raises_an_unexpected_typed_error(self): try: Intercom.get('/users') except (UnexpectedError) as err: - assert "The error of type 'hopper' is not recognized" in err.message # noqa - expect(err.context['http_code']) == 200 - expect(err.context['application_error_code']) == 'hopper' + 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 @httpretty.activate def it_raises_an_unexpected_untyped_error(self): payload = { @@ -90,9 +103,10 @@ def it_raises_an_unexpected_untyped_error(self): try: Intercom.get('/users') except (UnexpectedError) as err: - assert "An unexpected error occured." in err.message - expect(err.context['application_error_code']) is None + ok_("An unexpected error occured." in err.message) + eq_(err.context['application_error_code'], None) + @istest @httpretty.activate def it_raises_a_bad_request_error(self): payload = { @@ -108,9 +122,10 @@ def it_raises_a_bad_request_error(self): for code in ['missing_parameter', 'parameter_invalid', 'bad_request']: payload['errors'][0]['type'] = code httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(intercom.BadRequestError): + with assert_raises(intercom.BadRequestError): Intercom.get('/users') + @istest @httpretty.activate def it_raises_an_authentication_error(self): payload = { @@ -125,9 +140,10 @@ def it_raises_an_authentication_error(self): for code in ['unauthorized', 'forbidden']: payload['errors'][0]['type'] = code httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(intercom.AuthenticationError): + with assert_raises(intercom.AuthenticationError): Intercom.get('/users') + @istest @httpretty.activate def it_raises_resource_not_found_by_type(self): payload = { @@ -140,9 +156,10 @@ def it_raises_resource_not_found_by_type(self): ] } httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(intercom.ResourceNotFound): + with assert_raises(intercom.ResourceNotFound): Intercom.get('/users') + @istest @httpretty.activate def it_raises_rate_limit_exceeded(self): payload = { @@ -155,9 +172,10 @@ def it_raises_rate_limit_exceeded(self): ] } httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(intercom.RateLimitExceeded): + with assert_raises(intercom.RateLimitExceeded): Intercom.get('/users') + @istest @httpretty.activate def it_raises_a_service_unavailable_error(self): payload = { @@ -170,9 +188,10 @@ def it_raises_a_service_unavailable_error(self): ] } httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(intercom.ServiceUnavailableError): + with assert_raises(intercom.ServiceUnavailableError): Intercom.get('/users') + @istest @httpretty.activate def it_raises_a_multiple_matching_users_error(self): payload = { @@ -185,5 +204,5 @@ def it_raises_a_multiple_matching_users_error(self): ] } httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(intercom.MultipleMatchingUsersError): + with assert_raises(intercom.MultipleMatchingUsersError): Intercom.get('/users') diff --git a/tests/unit/subscription_spec.py b/tests/unit/test_subscription.py similarity index 69% rename from tests/unit/subscription_spec.py rename to tests/unit/test_subscription.py index 88a0209c..b91c046a 100644 --- a/tests/unit/subscription_spec.py +++ b/tests/unit/test_subscription.py @@ -3,20 +3,22 @@ import httpretty import json import re +import unittest -from describe import expect from intercom import Subscription +from nose.tools import eq_ +from nose.tools import istest from tests.unit import test_subscription - get = httpretty.GET post = httpretty.POST r = re.compile -class DescribeIntercomSubscription: +class SubscriptionTest(unittest.TestCase): + @istest @httpretty.activate def it_gets_a_subscription(self): body = json.dumps(test_subscription) @@ -26,11 +28,12 @@ def it_gets_a_subscription(self): body=body) subscription = Subscription.find(id="nsub_123456789") - expect(subscription.topics[0]) == "user.created" - expect(subscription.topics[1]) == "conversation.user.replied" - expect(subscription.self) == \ - "https://api.intercom.io/subscriptions/nsub_123456789" + eq_(subscription.topics[0], "user.created") + eq_(subscription.topics[1], "conversation.user.replied") + eq_(subscription.self, + "https://api.intercom.io/subscriptions/nsub_123456789") + @istest @httpretty.activate def it_creates_a_subscription(self): body = json.dumps(test_subscription) @@ -42,5 +45,5 @@ def it_creates_a_subscription(self): url="http://example.com", topics=["user.created"] ) - expect(subscription.topics[0]) == "user.created" - expect(subscription.url) == "http://example.com" + eq_(subscription.topics[0], "user.created") + eq_(subscription.url, "http://example.com") diff --git a/tests/unit/tag_spec.py b/tests/unit/test_tag.py similarity index 75% rename from tests/unit/tag_spec.py rename to tests/unit/test_tag.py index b0aeeae9..92f3c63d 100644 --- a/tests/unit/tag_spec.py +++ b/tests/unit/test_tag.py @@ -3,8 +3,11 @@ import httpretty import json import re -from describe import expect +import unittest + from intercom import Tag +from nose.tools import eq_ +from nose.tools import istest from tests.unit import test_tag get = httpretty.GET @@ -12,22 +15,25 @@ r = re.compile -class DescribeIntercomTag: +class TagTest(unittest.TestCase): + @istest @httpretty.activate def it_gets_a_tag(self): httpretty.register_uri( get, r(r'/tags'), body=json.dumps(test_tag)) tag = Tag.find(name="Test Tag") - expect(tag.name) == "Test Tag" + eq_(tag.name, "Test Tag") + @istest @httpretty.activate def it_creates_a_tag(self): httpretty.register_uri( post, r(r'/tags'), body=json.dumps(test_tag)) tag = Tag.create(name="Test Tag") - expect(tag.name) == "Test Tag" + eq_(tag.name, "Test Tag") + @istest @httpretty.activate def it_tags_users(self): params = { @@ -38,5 +44,5 @@ def it_tags_users(self): httpretty.register_uri( post, r(r'/tags'), body=json.dumps(test_tag)) tag = Tag.create(**params) - expect(tag.name) == "Test Tag" - expect(tag.tagged_user_count) == 2 + eq_(tag.name, "Test Tag") + eq_(tag.tagged_user_count, 2) diff --git a/tests/unit/user_spec.py b/tests/unit/test_user.py similarity index 56% rename from tests/unit/user_spec.py rename to tests/unit/test_user.py index b389f2d4..80cff544 100644 --- a/tests/unit/user_spec.py +++ b/tests/unit/test_user.py @@ -5,16 +5,20 @@ import mock import re import time +import unittest from datetime import datetime -from describe import expect from intercom.collection_proxy import CollectionProxy from intercom.lib.flat_store import FlatStore from intercom import Intercom from intercom import User from intercom import MultipleMatchingUsersError from intercom.utils import create_class_instance -from tests.unit import test_user +from nose.tools import assert_raises +from nose.tools import eq_ +from nose.tools import ok_ +from nose.tools import istest +from tests.unit import a_test_user get = httpretty.GET @@ -24,95 +28,100 @@ r = re.compile -class DescribeIntercomUser: +class UserTest(unittest.TestCase): + @istest def it_to_dict_itself(self): created_at = datetime.utcnow() user = User( email="jim@example.com", user_id="12345", created_at=created_at, name="Jim Bob") as_dict = user.to_dict - expect(as_dict["email"]) == "jim@example.com" - expect(as_dict["user_id"]) == "12345" - expect(as_dict["created_at"]) == time.mktime(created_at.timetuple()) - expect(as_dict["name"]) == "Jim Bob" + eq_(as_dict["email"], "jim@example.com") + eq_(as_dict["user_id"], "12345") + eq_(as_dict["created_at"], time.mktime(created_at.timetuple())) + eq_(as_dict["name"], "Jim Bob") + @istest def it_presents_created_at_and_last_impression_at_as_datetime(self): now = datetime.utcnow() now_ts = time.mktime(now.timetuple()) user = User.from_api( {'created_at': now_ts, 'last_impression_at': now_ts}) - expect(user.created_at).to.be_instance_of(datetime) - expect(now.strftime('%c')) == user.created_at.strftime('%c') - expect(user.last_impression_at).to.be_instance_of(datetime) - expect(now.strftime('%c')) == user.last_impression_at.strftime('%c') + 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 expect.to_raise_error(AttributeError): + with assert_raises(AttributeError): user = User() user.foo_property + @istest def it_presents_a_complete_user_record_correctly(self): - user = User.from_api(test_user()) - expect('id-from-customers-app') == user.user_id - expect('bob@example.com') == user.email - expect('Joe Schmoe') == user.name - expect('the-app-id') == user.app_id - expect(123) == user.session_count - expect(1401970114) == time.mktime(user.created_at.timetuple()) - expect(1393613864) == time.mktime(user.remote_created_at.timetuple()) - expect(1401970114) == time.mktime(user.updated_at.timetuple()) + user = User.from_api(a_test_user()) + eq_('id-from-customers-app', user.user_id) + eq_('bob@example.com', user.email) + eq_('Joe Schmoe', user.name) + eq_('the-app-id', user.app_id) + eq_(123, user.session_count) + eq_(1401970114, time.mktime(user.created_at.timetuple())) + eq_(1393613864, time.mktime(user.remote_created_at.timetuple())) + eq_(1401970114, time.mktime(user.updated_at.timetuple())) Avatar = create_class_instance('Avatar') # noqa Company = create_class_instance('Company') # noqa SocialProfile = create_class_instance('SocialProfile') # noqa LocationData = create_class_instance('LocationData') # noqa - expect(user.avatar).to.be_instance_of(Avatar.__class__) + self.assertIsInstance(user.avatar, Avatar.__class__) img_url = 'https://graph.facebook.com/1/picture?width=24&height=24' - expect(img_url) == user.avatar.image_url - - expect(user.companies).to.be_instance_of(list) - expect(1) == len(user.companies) - expect(user.companies[0]).to.be_instance_of(Company.__class__) - expect('123') == user.companies[0].company_id - expect('bbbbbbbbbbbbbbbbbbbbbbbb') == user.companies[0].id - expect('the-app-id') == user.companies[0].app_id - expect('Company 1') == user.companies[0].name - expect(1390936440) == time.mktime( - user.companies[0].remote_created_at.timetuple()) - expect(1401970114) == time.mktime( - user.companies[0].created_at.timetuple()) - expect(1401970114) == time.mktime( - user.companies[0].updated_at.timetuple()) - expect(1401970113) == time.mktime( - user.companies[0].last_request_at.timetuple()) - expect(0) == user.companies[0].monthly_spend - expect(0) == user.companies[0].session_count - expect(1) == user.companies[0].user_count - expect([]) == user.companies[0].tag_ids - - expect(user.custom_attributes).to.be_instance_of(FlatStore) - expect('b') == user.custom_attributes["a"] - expect(2) == user.custom_attributes["b"] - - expect(4) == len(user.social_profiles) + eq_(img_url, user.avatar.image_url) + + self.assertIsInstance(user.companies, list) + eq_(1, len(user.companies)) + self.assertIsInstance(user.companies[0], 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, time.mktime( + user.companies[0].remote_created_at.timetuple())) + eq_(1401970114, time.mktime( + user.companies[0].created_at.timetuple())) + eq_(1401970114, time.mktime( + user.companies[0].updated_at.timetuple())) + eq_(1401970113, time.mktime( + user.companies[0].last_request_at.timetuple())) + 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] - expect(twitter_account).to.be_instance_of(SocialProfile.__class__) - expect('twitter') == twitter_account.name - expect('abc') == twitter_account.username - expect('http://twitter.com/abc') == twitter_account.url - - expect(user.location_data).to.be_instance_of(LocationData.__class__) - expect('Dublin') == user.location_data.city_name - expect('EU') == user.location_data.continent_code - expect('Ireland') == user.location_data.country_name - expect('90') == user.location_data.latitude - expect('10') == user.location_data.longitude - expect('IRL') == user.location_data.country_code - - expect(user.unsubscribed_from_emails) - expect("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 - + self.assertIsInstance(twitter_account, 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, 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', @@ -122,6 +131,7 @@ def it_allows_update_last_request_at(self): httpretty.register_uri(post, r("/users"), body=json.dumps(payload)) User(user_id='1224242', update_last_request_at=True) + @istest def it_allows_easy_setting_of_custom_data(self): now = datetime.utcnow() now_ts = time.mktime(now.timetuple()) @@ -131,8 +141,9 @@ def it_allows_easy_setting_of_custom_data(self): user.custom_attributes["other"] = now_ts user.custom_attributes["thing"] = "yay" attrs = {"mad": 123, "other": now_ts, "thing": "yay"} - expect(user.to_dict["custom_attributes"]) == attrs + eq_(user.to_dict["custom_attributes"], attrs) + @istest def it_allows_easy_setting_of_multiple_companies(self): user = User() companies = [ @@ -140,34 +151,37 @@ def it_allows_easy_setting_of_multiple_companies(self): {"name": "Test", "company_id": "9"}, ] user.companies = companies - expect(user.to_dict["companies"]) == companies + eq_(user.to_dict["companies"], companies) + @istest def it_rejects_nested_data_structures_in_custom_attributes(self): user = User() - with expect.to_raise_error(ValueError): + with assert_raises(ValueError): user.custom_attributes["thing"] = [1] - with expect.to_raise_error(ValueError): + with assert_raises(ValueError): user.custom_attributes["thing"] = {1: 2} - with expect.to_raise_error(ValueError): + with assert_raises(ValueError): user.custom_attributes = {1: {2: 3}} - user = User.from_api(test_user()) - with expect.to_raise_error(ValueError): + user = User.from_api(a_test_user()) + with assert_raises(ValueError): user.custom_attributes["thing"] = [1] + @istest @httpretty.activate def it_fetches_a_user(self): - body = json.dumps(test_user()) + body = json.dumps(a_test_user()) httpretty.register_uri( get, r(r"https://api.intercom.io/users\?email="), body=body, match_querystring=True) user = User.find(email='somebody@example.com') - expect(user.email) == 'bob@example.com' - expect(user.name) == 'Joe Schmoe' + eq_(user.email, 'bob@example.com') + eq_(user.name, 'Joe Schmoe') + @istest @httpretty.activate def it_saves_a_user_always_sends_custom_attributes(self): user = User(email="jo@example.com", user_id="i-1224242") @@ -180,9 +194,10 @@ def it_saves_a_user_always_sends_custom_attributes(self): httpretty.register_uri( post, r(r"/users"), body=body) user.save() - expect(user.email) == 'jo@example.com' - expect(user.custom_attributes) == {} + eq_(user.email, 'jo@example.com') + eq_(user.custom_attributes, {}) + @istest @httpretty.activate def it_saves_a_user_with_a_company(self): user = User( @@ -200,9 +215,10 @@ def it_saves_a_user_with_a_company(self): httpretty.register_uri( post, r(r"/users"), body=body) user.save() - expect(user.email) == 'jo@example.com' - expect(len(user.companies)) == 1 + eq_(user.email, 'jo@example.com') + eq_(len(user.companies), 1) + @istest @httpretty.activate def it_saves_a_user_with_companies(self): user = User( @@ -219,9 +235,10 @@ def it_saves_a_user_with_companies(self): httpretty.register_uri( post, r(r"/users"), body=body) user.save() - expect(user.email) == 'jo@example.com' - expect(len(user.companies)) == 1 + eq_(user.email, 'jo@example.com') + eq_(len(user.companies), 1) + @istest @httpretty.activate def it_can_save_a_user_with_a_none_email(self): user = User( @@ -239,17 +256,19 @@ def it_can_save_a_user_with_a_none_email(self): httpretty.register_uri( post, r(r"/users"), body=body) user.save() - expect(user.email) is None - expect(user.user_id) is 'i-1224242' + ok_(user.email is None) + eq_(user.user_id, 'i-1224242') + @istest @httpretty.activate def it_deletes_a_user(self): user = User(id="1") httpretty.register_uri( delete, r(r"https://api.intercom.io/users/1"), body='{}') user = user.delete() - expect(user.id) == "1" + eq_(user.id, "1") + @istest @httpretty.activate def it_can_use_user_create_for_convenience(self): payload = { @@ -259,8 +278,9 @@ def it_can_use_user_create_for_convenience(self): } httpretty.register_uri(post, r(r"/users"), body=json.dumps(payload)) user = User.create(email="jo@example.com", user_id="i-1224242") - expect(payload) == user.to_dict + eq_(payload, user.to_dict) + @istest @httpretty.activate def it_updates_the_user_with_attributes_set_by_the_server(self): payload = { @@ -272,8 +292,9 @@ def it_updates_the_user_with_attributes_set_by_the_server(self): httpretty.register_uri(post, r(r"/users"), body=json.dumps(payload)) user = User.create(email="jo@example.com", user_id="i-1224242") - expect(payload) == user.to_dict + eq_(payload, user.to_dict) + @istest @httpretty.activate def it_allows_setting_dates_to_none_without_converting_them_to_0(self): payload = { @@ -283,8 +304,9 @@ def it_allows_setting_dates_to_none_without_converting_them_to_0(self): } httpretty.register_uri(post, r("/users"), body=json.dumps(payload)) user = User.create(email="jo@example.com", remote_created_at=None) - expect(user.remote_created_at) is None + ok_(user.remote_created_at is None) + @istest @httpretty.activate def it_gets_sets_rw_keys(self): created_at = datetime.utcnow() @@ -299,26 +321,30 @@ def it_gets_sets_rw_keys(self): httpretty.register_uri(post, r("/users"), body=json.dumps(payload)) user = User(**payload) expected_keys = ['custom_attributes'] - expected_keys.extend(payload.keys()) - expect(sorted(expected_keys)) == sorted(user.to_dict.keys()) - for key in payload.keys(): - expect(payload[key]) == user.to_dict[key] + 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 @httpretty.activate def it_will_allow_extra_attributes_in_response_from_api(self): user = User.from_api({'new_param': 'some value'}) - expect('some value') == user.new_param + eq_('some value', user.new_param) + @istest def it_returns_a_collectionproxy_for_all_without_making_any_requests(self): with mock.patch('intercom.Request.send_request_to_path', new_callable=mock.NonCallableMock): # noqa res = User.all() - expect(res).to.be_instance_of(CollectionProxy) + self.assertIsInstance(res, CollectionProxy) + @istest def it_returns_the_total_number_of_users(self): with mock.patch.object(User, 'count') as mock_count: mock_count.return_value = 100 - expect(100) == User.count() + eq_(100, User.count()) + @istest @httpretty.activate def it_raises_a_multiple_matching_users_error_when_receiving_a_conflict(self): # noqa payload = { @@ -331,42 +357,48 @@ def it_raises_a_multiple_matching_users_error_when_receiving_a_conflict(self): ] } httpretty.register_uri(get, r("/users"), body=json.dumps(payload)) - with expect.to_raise_error(MultipleMatchingUsersError): + with assert_raises(MultipleMatchingUsersError): Intercom.get('/users') - class DescribeIncrementingCustomAttributeFields: - - def before_each(self, context): - created_at = datetime.utcnow() - params = { - 'email': 'jo@example.com', - 'user_id': 'i-1224242', - 'custom_attributes': { - 'mad': 123, - 'another': 432, - 'other': time.mktime(created_at.timetuple()), - 'thing': 'yay' - } - } - self.user = User(**params) - - def it_increments_up_by_1_with_no_args(self): - self.user.increment('mad') - expect(self.user.to_dict['custom_attributes']['mad']) == 124 - - def it_increments_up_by_given_value(self): - self.user.increment('mad', 4) - expect(self.user.to_dict['custom_attributes']['mad']) == 127 - - def it_increments_down_by_given_value(self): - self.user.increment('mad', -1) - expect(self.user.to_dict['custom_attributes']['mad']) == 122 - def it_can_increment_new_custom_data_fields(self): - self.user.increment('new_field', 3) - expect(self.user.to_dict['custom_attributes']['new_field']) == 3 +class DescribeIncrementingCustomAttributeFields(unittest.TestCase): - def it_can_call_increment_on_the_same_key_twice_and_increment_by_2(self): # noqa - self.user.increment('mad') - self.user.increment('mad') - expect(self.user.to_dict['custom_attributes']['mad']) == 125 + def setUp(self): # noqa + created_at = datetime.utcnow() + params = { + 'email': 'jo@example.com', + 'user_id': 'i-1224242', + 'custom_attributes': { + 'mad': 123, + 'another': 432, + 'other': time.mktime(created_at.timetuple()), + 'thing': 'yay' + } + } + self.user = User(**params) + + @istest + def it_increments_up_by_1_with_no_args(self): + self.user.increment('mad') + eq_(self.user.to_dict['custom_attributes']['mad'], 124) + + @istest + def it_increments_up_by_given_value(self): + self.user.increment('mad', 4) + eq_(self.user.to_dict['custom_attributes']['mad'], 127) + + @istest + def it_increments_down_by_given_value(self): + self.user.increment('mad', -1) + eq_(self.user.to_dict['custom_attributes']['mad'], 122) + + @istest + def it_can_increment_new_custom_data_fields(self): + self.user.increment('new_field', 3) + eq_(self.user.to_dict['custom_attributes']['new_field'], 3) + + @istest + def it_can_call_increment_on_the_same_key_twice_and_increment_by_2(self): # noqa + self.user.increment('mad') + self.user.increment('mad') + eq_(self.user.to_dict['custom_attributes']['mad'], 125) diff --git a/tests/unit/traits/api_resource_spec.py b/tests/unit/traits/test_api_resource.py similarity index 64% rename from tests/unit/traits/api_resource_spec.py rename to tests/unit/traits/test_api_resource.py index 9c25b0b5..92a73ee5 100644 --- a/tests/unit/traits/api_resource_spec.py +++ b/tests/unit/traits/test_api_resource.py @@ -1,13 +1,18 @@ # -*- coding: utf-8 -*- +import unittest + from datetime import datetime -from describe import expect from intercom.traits.api_resource import Resource +from nose.tools import assert_raises +from nose.tools import eq_ +from nose.tools import ok_ +from nose.tools import istest -class DescribeIntercomTraitsApiResource: +class IntercomTraitsApiResource(unittest.TestCase): - def before_each(self, context): + def setUp(self): # noqa self.object_json = { "type": "company", "id": "aaaaaaaaaaaaaaaaaaaaaaaa", @@ -23,48 +28,59 @@ def before_each(self, context): self.api_resource = Resource().from_response(self.object_json) self.api_resource_obj = super(Resource, self.api_resource) + @istest def it_does_not_set_type_on_parsing_json(self): - expect(self.api_resource).to_not.have_attr('type') + ok_(not hasattr(self.api_resource, 'type')) + @istest def it_coerces_time_on_parsing_json(self): - expect(datetime.fromtimestamp(1374056196)) == self.api_resource.created_at # noqa + eq_(datetime.fromtimestamp(1374056196), self.api_resource.created_at) + @istest def it_dynamically_defines_accessors_for_non_existent_properties(self): - expect(self.api_resource).to_not.have_attr('spiders') + ok_(not hasattr(self.api_resource, 'spiders')) self.api_resource.spiders = 4 - expect(self.api_resource).to.have_attr('spiders') + ok_(hasattr(self.api_resource, 'spiders')) + @istest def it_calls_dynamically_defined_getter_when_asked(self): self.api_resource.foo = 4 - expect(4) == self.api_resource.foo + eq_(4, self.api_resource.foo) + @istest def it_accepts_unix_timestamps_into_dynamically_defined_date_setters(self): self.api_resource.foo_at = 1401200468 - expect(1401200468) == self.api_resource_obj.__getattribute__('foo_at') + eq_(1401200468, self.api_resource_obj.__getattribute__('foo_at')) + @istest def it_exposes_dates_correctly_for_dynamically_defined_getters(self): self.api_resource.foo_at = 1401200468 - expect(datetime.fromtimestamp(1401200468)) == self.api_resource.foo_at + eq_(datetime.fromtimestamp(1401200468), self.api_resource.foo_at) + # @istest # def it_throws_regular_error_when_non_existant_getter_is_called_that_is_backed_by_an_instance_variable(self): # noqa # super(Resource, self.api_resource).__setattr__('bar', 'you cant see me') # noqa - # print self.api_resource.bar + # print (self.api_resource.bar) + @istest def it_throws_attribute_error_when_non_existent_attribute_is_called(self): - with expect.to_raise_error(AttributeError): + with assert_raises(AttributeError): self.api_resource.flubber + @istest def it_throws_attribute_error_when_non_existent_method_is_called(self): - with expect.to_raise_error(AttributeError): + with assert_raises(AttributeError): self.api_resource.flubber() + @istest def it_throws_attribute_error_when_non_existent_setter_is_called(self): - with expect.to_raise_error(AttributeError): + with assert_raises(AttributeError): self.api_resource.flubber('a', 'b') + @istest def it_create_an_initialized_resource_equal_to_a_from_response_resource(self): # noqa initialized_api_resource = Resource(**self.object_json) - for key in self.object_json.keys(): + for key in list(self.object_json.keys()): if key == "type": continue - expect(getattr(initialized_api_resource, key)) == getattr(self.api_resource, key) # noqa + eq_(getattr(initialized_api_resource, key), getattr(self.api_resource, key)) # noqa