From 5c498db51f272ab47101ba261a7cfaf1c0b8b6c4 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Fri, 26 Aug 2011 11:54:21 -0400 Subject: [PATCH 1/2] updated client library to properly json serialize parameters when posting. --- .gitignore | 1 + aweber_api/oauth.py | 4 ++++ tests/data/any_collection/1.json | 1 + tests/data/any_collection/page1.json | 1 + tests/data/error.json | 2 +- tests/mock_adapter.py | 35 +++++++++++++++------------ tests/test_aweber_collection.py | 36 +++++++++++++++++++++------- 7 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 tests/data/any_collection/1.json create mode 100644 tests/data/any_collection/page1.json diff --git a/.gitignore b/.gitignore index 8dbcb5a..75fca04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.svn *.egg-info *.swp +build/ diff --git a/aweber_api/oauth.py b/aweber_api/oauth.py index c34835f..8817957 100644 --- a/aweber_api/oauth.py +++ b/aweber_api/oauth.py @@ -84,6 +84,10 @@ def _prepare_request_body(self, method, url, data): if method not in ['POST', 'GET', 'PATCH'] or len(data.keys()) == 0: return '' if method in ['POST', 'GET']: + # WARNING: non-primative items in data must be json serialized. + for key in data: + if type(data[key]) in [dict, list]: + data[key] = json.dumps(data[key]) return urlencode(data) if method == 'PATCH': return json.dumps(data) diff --git a/tests/data/any_collection/1.json b/tests/data/any_collection/1.json new file mode 100644 index 0000000..edd92fd --- /dev/null +++ b/tests/data/any_collection/1.json @@ -0,0 +1 @@ +{"name": "Favorite Color", "is_subscriber_updateable": true, "https_etag": "\"356a192b7913b04c54574d18c28d46e6395428ab-cf46a99b7a9ec9059c21044110a3528be7b0a5de\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/1", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 1} \ No newline at end of file diff --git a/tests/data/any_collection/page1.json b/tests/data/any_collection/page1.json new file mode 100644 index 0000000..dfeb2ea --- /dev/null +++ b/tests/data/any_collection/page1.json @@ -0,0 +1 @@ +{"start": 0, "total_size": 0, "entries": [], "resource_type_link": "https://api.aweber.com/1.0/#any_collection"} diff --git a/tests/data/error.json b/tests/data/error.json index 623bc5f..3291931 100644 --- a/tests/data/error.json +++ b/tests/data/error.json @@ -1 +1 @@ -{"error": {"message": "Simulated Exception", "type": "BadRequestError"}} +{"error": {"status": 400, "message": "Simulated Exception", "type": "BadRequestError", "documentation_url": "https://labs.aweber.com/docs/troubleshooting#BadRequestError"}} diff --git a/tests/mock_adapter.py b/tests/mock_adapter.py index 81c0cd2..d9b1826 100644 --- a/tests/mock_adapter.py +++ b/tests/mock_adapter.py @@ -18,21 +18,23 @@ '/accounts/1?ws.op=findSubscribers&' \ 'email=joe%40example.com&' \ 'ws.show=total_size': ({}, 'accounts/findSubscribers_ts'), - '/accounts/1?ws.op=getWebForms': ({}, 'accounts/webForms'), - '/accounts/1?ws.op=getWebFormSplitTests': ({}, 'accounts/webFormSplitTests'), - '/accounts/1/lists': ({}, 'lists/page1'), - '/accounts/1/lists?ws.start=20&ws.size=20': ({}, 'lists/page2'), - '/accounts/1/lists/303449': ({}, 'lists/303449'), - '/accounts/1/lists/505454': ({}, 'lists/505454'), - '/accounts/1/lists/303449/campaigns': ({}, 'campaigns/303449'), - '/accounts/1/lists/303449/custom_fields': ({}, 'custom_fields/303449'), - '/accounts/1/lists/505454/custom_fields': ({}, 'custom_fields/505454'), - '/accounts/1/lists/303449/custom_fields/1': ({}, 'custom_fields/1'), - '/accounts/1/lists/303449/custom_fields/2': ({}, 'custom_fields/2'), - '/accounts/1/lists/303449/subscribers': ({}, 'subscribers/page1'), - '/accounts/1/lists/303449/subscribers/1': ({}, 'subscribers/1'), - '/accounts/1/lists/303449/subscribers/2': ({}, 'subscribers/2'), - '/accounts/1/lists/505454/subscribers/3': ({}, 'subscribers/3'), + '/accounts/1?ws.op=getWebForms': ({}, 'accounts/webForms'), + '/accounts/1?ws.op=getWebFormSplitTests': ({}, 'accounts/webFormSplitTests'), + '/accounts/1/lists': ({}, 'lists/page1'), + '/accounts/1/lists?ws.start=20&ws.size=20': ({}, 'lists/page2'), + '/accounts/1/lists/303449': ({}, 'lists/303449'), + '/accounts/1/lists/505454': ({}, 'lists/505454'), + '/accounts/1/lists/303449/any_collection': ({}, 'any_collection/page1'), + '/accounts/1/lists/303449/any_collection/1': ({}, 'any_collection/1'), + '/accounts/1/lists/303449/campaigns': ({}, 'campaigns/303449'), + '/accounts/1/lists/303449/custom_fields': ({}, 'custom_fields/303449'), + '/accounts/1/lists/505454/custom_fields': ({}, 'custom_fields/505454'), + '/accounts/1/lists/303449/custom_fields/1': ({}, 'custom_fields/1'), + '/accounts/1/lists/303449/custom_fields/2': ({}, 'custom_fields/2'), + '/accounts/1/lists/303449/subscribers': ({}, 'subscribers/page1'), + '/accounts/1/lists/303449/subscribers/1': ({}, 'subscribers/1'), + '/accounts/1/lists/303449/subscribers/2': ({}, 'subscribers/2'), + '/accounts/1/lists/505454/subscribers/3': ({}, 'subscribers/3'), '/accounts/1/lists/303449/subscribers/1?ws.op=getActivity': ( {}, 'subscribers/get_activity'), '/accounts/1/lists/303449/subscribers/1?ws.op=getActivity&ws.show=total_size': ( @@ -48,6 +50,9 @@ 'ws.show=total_size': ({}, 'subscribers/find_ts'), }, 'POST' : { + '/accounts/1/lists/303449/any_collection': ({ + 'status': '201', + 'location': '/accounts/1/lists/303449/any_collection/1'}, None), '/accounts/1/lists/303449/custom_fields': ({ 'status': '201', 'location': '/accounts/1/lists/303449/custom_fields/2'}, None), diff --git a/tests/test_aweber_collection.py b/tests/test_aweber_collection.py index 2fdd767..c5601fd 100644 --- a/tests/test_aweber_collection.py +++ b/tests/test_aweber_collection.py @@ -1,4 +1,6 @@ +import json from unittest import TestCase + from aweber_api import AWeberAPI, AWeberCollection, AWeberEntry from aweber_api.base import API_BASE, APIException from mock_adapter import MockAdapter @@ -99,23 +101,41 @@ def test_should_return_new_resource_entry_object(self): assert self.resp.id == 2 assert self.resp.url == '/accounts/1/lists/303449/custom_fields/2' - def test_should_have_requested_create_with_post(self): - self.assertEqual(self.create_req['method'], 'POST') - def test_should_have_requested_create_on_cf(self): - self.assertEqual(self.create_req['url'] , self.cf.url) +class TestCreateMethod(TestCase): + + def setUp(self): + self.aweber = AWeberAPI('1', '2') + self.aweber.adapter = MockAdapter() + url = '/accounts/1/lists/303449/any_collection' + self.any_collection = self.aweber.load_from_url(url) + + self.aweber.adapter.requests = [] + self.resp = self.any_collection.create( + a_string='Bob', a_dict={'Color': 'blue'}, a_list=['apple']) + self.create_req = self.aweber.adapter.requests[0] + self.get_req = self.aweber.adapter.requests[1] + + def test_should_make_request_with_correct_parameters(self): + expected_params = {'ws.op': 'create', 'a_string': 'Bob', + 'a_dict': json.dumps({'Color': 'blue'}), + 'a_list': json.dumps(['apple'])} - def test_should_have_requested_move_with_correct_parameters(self): - expected_params = {'ws.op': 'create', 'name': 'Wedding Song'} self.assertEqual(self.create_req['data'], expected_params) def test_should_make_two_requests(self): self.assertEqual(len(self.aweber.adapter.requests), 2) - def test_should_refresh_cf_resource(self): + def test_should_have_requested_create_on_cf(self): + self.assertEqual(self.create_req['url'] , self.any_collection.url) + + def test_should_have_requested_create_with_post(self): + self.assertEqual(self.create_req['method'], 'POST') + + def test_should_refresh_created_resource(self): self.assertEqual(self.get_req['method'], 'GET') self.assertEqual(self.get_req['url'] , - '/accounts/1/lists/303449/custom_fields/2') + '/accounts/1/lists/303449/any_collection/1') class TestGettingParentEntry(TestCase): From 52a1bf57eeca08d3265a65dcce144085f2d9b78f Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Fri, 26 Aug 2011 11:58:12 -0400 Subject: [PATCH 2/2] bump changelog --- CHANGELOG.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d76d62..977c30c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,10 @@ Changelog --------- - 2011-08-25: v1.1.0 + 2011-08-26: v1.1.0 * Modified OAuthAdapter to raise an APIException when any API errors occur. * Added get_activity() method to return subscriber analytics activity. * Modified create() method to return the instance of the newly created Resource instead of true. - * Fixed bugs in find and findSubscribers methods when no matches are found. + * Modified create() method tests to be more generic. + * Fixed bug in POST and GET where dictionaries and lists were not properly json serialized. + * Fixed bug in find and findSubscribers methods when no matches are found by the api.