Permalink
Browse files

Extracted make_request into an external dependency so it can be stubb…

…ed during tests.

Updated test cases so they demonstrate the natural client API.
  • Loading branch information...
1 parent 176283a commit e6078e16a298b593663618670515097de4149cfa @stevenwei committed Apr 20, 2010
Showing with 80 additions and 67 deletions.
  1. +0 −1 .gitignore
  2. +51 −43 chargify.py
  3. +29 −23 test_chargify.py
View
@@ -1,3 +1,2 @@
*.pyc
-artwork
.DS_Store
View
@@ -32,21 +32,69 @@ class ChargifyServerError(ChargifyError):pass
'handle':'handle'
}
+class ChargifyHttpClient(object):
+ """
+ Extracted from the main Chargify class so it can be stubbed out during testing.
+ """
+
+ def make_request(self, url, method, data, api_key):
+ """
+ Actually responsible for making the HTTP request.
+ :param url: The URL to load.
+ :param method: The HTTP method to use.
+ :param data: Any POST data that should be included with the request.
+ """
+ opener = urllib2.build_opener(urllib2.HTTPHandler)
+ request = urllib2.Request(url=url, data=data)
+
+ # Build header
+ request.get_method = lambda: method
+ request.add_header('Authorization', 'Basic %s' % base64.encodestring('%s:%s' % (api_key, 'x'))[:-1])
+ request.add_header('User-Agent', 'Chargify Python Client')
+ request.add_header('Accept', 'application/json')
+ request.add_header('Content-Type', 'application/json')
+
+ # Make request and trap for HTTP errors
+ try:
+ response = opener.open(request)
+ result = response.read()
+ except urllib2.HTTPError, e:
+ if e.code == 401:
+ raise ChargifyUnauthorizedError(e)
+ elif e.code == 403:
+ raise ChargifyForbiddenError(e)
+ elif e.code == 404:
+ raise ChargifyNotFoundError(e)
+ elif e.code == 422:
+ raise ChargifyUnprocessableEntityError(e)
+ elif e.code == 500:
+ raise ChargifyServerError(e)
+ else:
+ raise ChargifyError(e)
+ except urllib2.URLError, e:
+ raise ChargifyConnectionError(e)
+
+ # Parse and return JSON Result
+ return simplejson.loads(result)
+
class Chargify(object):
api_key = ''
sub_domain = ''
path = []
domain = 'https://%s.chargify.com/'
+ client = None
- def __init__(self, api_key, sub_domain, path=None):
+ def __init__(self, api_key, sub_domain, path=None, client=None):
"""
:param api_key: The API key for your Chargify account.
:param sub_domain: The sub domain of your Chargify account.
:param path: The current path constructed for this request.
+ :param client: The HTTP client to use to make the request.
"""
self.api_key = api_key
self.sub_domain = sub_domain
self.path = path or []
+ self.client = client or ChargifyHttpClient()
def __getattr__(self, attr):
"""
@@ -55,7 +103,7 @@ def __getattr__(self, attr):
try:
return object.__getattr__(self, attr)
except AttributeError:
- return Chargify(self.api_key, self.sub_domain, self.path + [attr])
+ return Chargify(self.api_key, self.sub_domain, self.path + [attr], self.client)
def construct_request(self, **kwargs):
"""
@@ -95,49 +143,9 @@ def construct_request(self, **kwargs):
url = url + '/'.join(path) + '.json' + args
return url, method, data
-
- def make_request(self, url, method, data):
- """
- Actually responsible for making the HTTP request.
- :param url: The URL to load.
- :param method: The HTTP method to use.
- :param data: Any POST data that should be included with the request.
- """
- opener = urllib2.build_opener(urllib2.HTTPHandler)
- request = urllib2.Request(url=url, data=data)
-
- # Build header
- request.get_method = lambda: method
- request.add_header('Authorization', 'Basic %s' % base64.encodestring('%s:%s' % (self.api_key, 'x'))[:-1])
- request.add_header('User-Agent', 'Chargify Python Client')
- request.add_header('Accept', 'application/json')
- request.add_header('Content-Type', 'application/json')
-
- # Make request and trap for HTTP errors
- try:
- response = opener.open(request)
- result = response.read()
- except urllib2.HTTPError, e:
- if e.code == 401:
- raise ChargifyUnauthorizedError(e)
- elif e.code == 403:
- raise ChargifyForbiddenError(e)
- elif e.code == 404:
- raise ChargifyNotFoundError(e)
- elif e.code == 422:
- raise ChargifyUnprocessableEntityError(e)
- elif e.code == 500:
- raise ChargifyServerError(e)
- else:
- raise ChargifyError(e)
- except urllib2.URLError, e:
- raise ChargifyConnectionError(e)
-
- # Parse and return JSON Result
- return simplejson.loads(result)
def __call__(self, **kwargs):
url, method, data = self.construct_request(**kwargs)
- return self.make_request(url, method, data)
+ return self.client.make_request(url, method, data, self.api_key)
View
@@ -1,8 +1,16 @@
import unittest
from chargify import Chargify, ChargifyError
+class ChargifyHttpClientStub(object):
+
+ def make_request(self, url, method, data, api_key):
+ return url, method, data
+
class ChargifyTestCase(unittest.TestCase):
+ def setUp(self):
+ self.chargify = Chargify('api_key','subdomain',client=ChargifyHttpClientStub())
+
def assertResult(self, result, expected_url, expected_method, expected_data):
"""
A little helper method to help verify that the correct URL, HTTP method, and POST data are
@@ -17,22 +25,20 @@ def assertResult(self, result, expected_url, expected_method, expected_data):
class TestCustomers(ChargifyTestCase):
def test_construct_request(self):
- chargify = Chargify('api_key','subdomain')
-
# List
- result = chargify.customers.construct_request()
+ result = self.chargify.customers()
self.assertResult(result,'https://subdomain.chargify.com/customers.json','GET',None)
# Read/show (via chargify id)
- result = chargify.customers.construct_request(customer_id=123)
+ result = self.chargify.customers(customer_id=123)
self.assertResult(result,'https://subdomain.chargify.com/customers/123.json','GET',None)
# Read/show (via reference value)
- result = chargify.customers.lookup.construct_request(reference=123)
+ result = self.chargify.customers.lookup(reference=123)
self.assertResult(result,'https://subdomain.chargify.com/customers/lookup.json?reference=123','GET',None)
# Create
- result = chargify.customers.create.construct_request(data={
+ result = self.chargify.customers.create(data={
'customer':{
'first_name':'Joe',
'last_name':'Blow',
@@ -43,7 +49,7 @@ def test_construct_request(self):
'{"customer": {"first_name": "Joe", "last_name": "Blow", "email": "joe@example.com"}}')
# Edit/update
- result = chargify.customers.update.construct_request(customer_id=123,data={
+ result = self.chargify.customers.update(customer_id=123,data={
'customer':{
'email':'joe@example.com'
}
@@ -52,7 +58,7 @@ def test_construct_request(self):
'{"customer": {"email": "joe@example.com"}}')
# Delete
- result = chargify.customers.delete.construct_request(customer_id=123)
+ result = self.chargify.customers.delete(customer_id=123)
self.assertResult(result,'https://subdomain.chargify.com/customers/123.json','DELETE',None)
class TestProducts(ChargifyTestCase):
@@ -61,15 +67,15 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# List
- result = chargify.products.construct_request()
+ result = self.chargify.products()
self.assertResult(result,'https://subdomain.chargify.com/products.json','GET',None)
# Read/show (via chargify id)
- result = chargify.products.construct_request(product_id=123)
+ result = self.chargify.products(product_id=123)
self.assertResult(result,'https://subdomain.chargify.com/products/123.json','GET',None)
# Read/show (via api handle)
- result = chargify.products.handle.construct_request(handle='myhandle')
+ result = self.chargify.products.handle(handle='myhandle')
self.assertResult(result,'https://subdomain.chargify.com/products/handle/myhandle.json','GET',None)
class TestSubscriptions(ChargifyTestCase):
@@ -78,15 +84,15 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# List
- result = chargify.customers.subscriptions.construct_request(customer_id=123)
+ result = self.chargify.customers.subscriptions(customer_id=123)
self.assertResult(result,'https://subdomain.chargify.com/customers/123/subscriptions.json','GET',None)
# Read
- result = chargify.subscriptions.construct_request(subscription_id=123)
+ result = self.chargify.subscriptions(subscription_id=123)
self.assertResult(result,'https://subdomain.chargify.com/subscriptions/123.json','GET',None)
# Create
- result = chargify.subscriptions.create.construct_request(data={
+ result = self.chargify.subscriptions.create(data={
'subscription':{
'product_handle':'my_product',
'customer_attributes':{
@@ -105,7 +111,7 @@ def test_construct_request(self):
'{"subscription": {"product_handle": "my_product", "credit_card_attributes": {"expiration_month": "10", "full_number": "1", "expiration_year": "2020"}, "customer_attributes": {"first_name": "Joe", "last_name": "Blow", "email": "joe@example.com"}}}')
# Update
- result = chargify.subscriptions.update.construct_request(data={
+ result = self.chargify.subscriptions.update(data={
'subscription':{
'credit_card_attributes':{
'full_number':'2',
@@ -118,7 +124,7 @@ def test_construct_request(self):
'{"subscription": {"credit_card_attributes": {"expiration_month": "10", "full_number": "2", "expiration_year": "2030"}}}')
# Delete
- result = chargify.subscriptions.delete.construct_request(subscription_id=123,data={
+ result = self.chargify.subscriptions.delete(subscription_id=123,data={
'subscription':{
'cancellation_message':'Goodbye!'
}
@@ -132,7 +138,7 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# Create
- result = chargify.subscriptions.charges.create.construct_request(subscription_id=123,data={
+ result = self.chargify.subscriptions.charges.create(subscription_id=123,data={
'charge':{
'amount':'1.00',
'memo':'This is the description of the one time charge.'
@@ -147,11 +153,11 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# List
- result = chargify.subscriptions.components.usages.construct_request(subscription_id=123,component_id=456)
+ result = self.chargify.subscriptions.components.usages(subscription_id=123,component_id=456)
self.assertResult(result,'https://subdomain.chargify.com/subscriptions/123/components/456/usages.json','GET',None)
# Create
- result = chargify.subscriptions.components.usages.create.construct_request(subscription_id=123,component_id=456,data={
+ result = self.chargify.subscriptions.components.usages.create(subscription_id=123,component_id=456,data={
'usage':{
'quantity':5,
'memo':'My memo'
@@ -166,7 +172,7 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# Create
- result = chargify.subscriptions.migrations.create.construct_request(subscription_id=123,data={
+ result = self.chargify.subscriptions.migrations.create(subscription_id=123,data={
'product_id':1234
})
self.assertResult(result,'https://subdomain.chargify.com/subscriptions/123/migrations.json','POST',
@@ -178,7 +184,7 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# Reactivate
- result = chargify.subscriptions.reactivate.update.construct_request(subscription_id=123)
+ result = self.chargify.subscriptions.reactivate.update(subscription_id=123)
self.assertResult(result,'https://subdomain.chargify.com/subscriptions/123/reactivate.json','PUT',None)
class TestTransactions(ChargifyTestCase):
@@ -187,11 +193,11 @@ def test_construct_request(self):
chargify = Chargify('api_key','subdomain')
# List transactions for a site
- result = chargify.transactions.construct_request()
+ result = self.chargify.transactions()
self.assertResult(result,'https://subdomain.chargify.com/transactions.json','GET',None)
# List transactions for a subscription
- result = chargify.subscriptions.transactions.construct_request(subscription_id=123)
+ result = self.chargify.subscriptions.transactions(subscription_id=123)
self.assertResult(result,'https://subdomain.chargify.com/subscriptions/123/transactions.json','GET',None)
if __name__ == "__main__":

0 comments on commit e6078e1

Please sign in to comment.