Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #1 from matt-livefyre/master

replace httplib2 with requests to avoid SSL certificate validation error
  • Loading branch information...
commit 39b77acd3e0531b11cbc8a76f9ec9a4ed6183d3e 2 parents ad9f24d + 69b8516
@geokat geokat authored
Showing with 79 additions and 55 deletions.
  1. +12 −8 backplane/__init__.py
  2. +1 −1  setup.py
  3. +66 −46 tests/test_backplane.py
View
20 backplane/__init__.py
@@ -7,7 +7,7 @@
import base64
import urllib
import json
-import httplib2
+import requests
__version__ = '0.1'
__author__ = 'George Katsitadze'
@@ -18,7 +18,6 @@
def debug(enable = True, level = 1):
"""Turn on debug output for the module."""
- httplib2.debuglevel = level
logging.basicConfig(level=logging.DEBUG)
def channel_from_scope(scope):
@@ -293,7 +292,7 @@ def _get_token(creds, scope = None, grant_type = 'client_credentials'):
if grant_type == 'refresh_token':
data['refresh_token'] = creds.token.refresh_token
- content = _call_backplane(url, 'POST', urllib.urlencode(data), headers)
+ content = _call_backplane(url, 'POST', data, headers)
return _json_to_token(content)
def _get_regular_token(server_url, bus):
@@ -307,11 +306,16 @@ def _get_regular_token(server_url, bus):
return _json_to_token(jsn)
-def _call_backplane(url, method, body = None, headers = None, extra = 0):
- #h = httplib2.Http(timeout = TIMEOUT + extra, disable_ssl_certificate_validation=True)
- h = httplib2.Http(timeout = TIMEOUT + extra)
+
+def _call_backplane(url, method, data = None, headers = None, extra = 0):
+ # map request methods to instance methods of requests module
+ # included inline in order to use with mock
+ REQUEST_METHOD_TO_INSTANCE_METHOD = dict(GET=requests.get,
+ POST=requests.post)
+ instance_method = REQUEST_METHOD_TO_INSTANCE_METHOD[method]
try:
- resp, content = h.request(url, method, body, headers)
+ resp = instance_method(url, data=data, headers=headers, timeout=TIMEOUT + extra)
+ content = resp.text
except:
msg = str(sys.exc_info()[1])
logger.error('call to %s failed: ' % url + msg)
@@ -320,7 +324,7 @@ def _call_backplane(url, method, body = None, headers = None, extra = 0):
if content:
logger.debug('server response: ' + content)
- if not resp['status'] in ['200', '201']:
+ if not resp.status_code in [200, 201]:
logger.warn('server returned error: ' + content)
if 'unauthorized scope' in content:
raise UnauthorizedScopeError(content)
View
2  setup.py
@@ -9,7 +9,7 @@
author_email='george@janrain.com',
url='http://github.com/geokat/backplane2-pyclient',
packages = find_packages(),
- install_requires = ['httplib2'],
+ install_requires = ['requests'],
keywords= 'backplane library',
zip_safe = True,
test_suite='tests',
View
112 tests/test_backplane.py
@@ -1,7 +1,7 @@
import unittest
import logging
import mock
-import httplib2
+import requests
import backplane as bp
logging.disable(logging.CRITICAL)
@@ -81,22 +81,46 @@ def test_client_creds(self):
self.assertEquals(c.client_secret, 'secret')
self.assertEquals(c.token, 'token')
+class MockHttpResponse(object):
+ def __init__(self, data, status_code):
+ self.data_ = data
+ self.status_code_ = status_code
+ @property
+ def text(self):
+ return self.data_
+ @property
+ def status_code(self):
+ return self.status_code_
class TestClient(unittest.TestCase):
creds = bp.ClientCredentials('url', 'id', 'secret')
- client = bp.Client(creds, False)
+ token = bp.Token('AAblVpGm8g4llDLdqnM4y0',
+ 'Bearer',
+ 'ARpIAYznoB4QenmLQIkbgH',
+ 604799,
+ 'bus:bus1 channel:I5sRIdzNdDxwcKnPPDB10oB1hwMfJYUb')
+
+ def tearDown(self):
+ self.creds.token = None
+
+ def add_token_to_creds(self):
+ self.creds.token = self.token
+
+ def get_client(self, initialize=False):
+ return bp.Client(self.creds, initialize=initialize)
# Scope should be passed when initializing only
def test_init_req_when_scope(self):
self.assertRaises(AssertionError, bp.Client, self.creds, False, 'scope')
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.get')
def test_get_regular_token(self, mockHttpRequest):
# Test with successful response
body = 'f({"token_type":"Bearer","access_token":"AAblVpGm8g4llDLdqnM4y0","expires_in":604799,"scope":"bus:bus1 channel:I5sRIdzNdDxwcKnPPDB10oB1hwMfJYUb","refresh_token":"ARpIAYznoB4QenmLQIkbgH"});'
- mockHttpRequest.side_effect = [({'status': '200'}, body)]
- t = self.client.get_regular_token('bus')
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 200)]
+ client = self.get_client()
+ t = client.get_regular_token('bus')
self.assertTrue(isinstance(t, bp.Token))
self.assertEquals(t.type, 'Bearer')
self.assertEquals(t.access_token, 'AAblVpGm8g4llDLdqnM4y0')
@@ -108,16 +132,17 @@ def test_get_regular_token(self, mockHttpRequest):
# Test with error response
body = 'f({"error":"invalid_request","error_description":"Invalid bus: invalid_bus"});'
# Since the API returns JSONP, status is 200 even on errors
- mockHttpRequest.side_effect = [({'status': '200'}, body)]
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 200)]
self.assertRaises(
- bp.BackplaneError, self.client.get_regular_token, 'bus')
+ bp.BackplaneError, client.get_regular_token, 'bus')
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.post')
def test_get_token(self, mockHttpRequest):
# Test with successful response
body = '{"token_type":"Bearer","access_token":"PCxNCDPos1kmsiTAZ7U08v","expires_in":31535999,"scope":"bus:bus2","refresh_token":"PRLX8EZdc1tI1E4nSvAGky"}'
- mockHttpRequest.side_effect = [({'status': '200'}, body)]
- t = self.client.get_token('bus')
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 200)]
+ client = self.get_client()
+ t = client.get_token('bus')
self.assertTrue(isinstance(t, bp.Token))
self.assertEquals(t.type, 'Bearer')
self.assertEquals(t.access_token, 'PCxNCDPos1kmsiTAZ7U08v')
@@ -127,11 +152,11 @@ def test_get_token(self, mockHttpRequest):
# Test with error response
body = '{"error":"invalid_scope","error_description":"unauthorized scope: bus:bus1"}'
- mockHttpRequest.side_effect = [({'status': '400'}, body)]
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 400)]
self.assertRaises(
- bp.UnauthorizedScopeError, self.client.get_token, 'bus')
+ bp.UnauthorizedScopeError, client.get_token, 'bus')
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.post')
def test_refresh_token(self, mockHttpRequest):
# Test with successful response
#
@@ -140,9 +165,9 @@ def test_refresh_token(self, mockHttpRequest):
# This is to refresh the token
body2 = '{"token_type":"Bearer","access_token":"PC3Rm17rJUM3jmbtB34JEJ","expires_in":31535999,"scope":"bus:bus2","refresh_token":"PR5LoqnbxvF93SOGWqGnrs"}'
mockHttpRequest.side_effect = [
- ({'status': '200'}, body1),
- ({'status': '200'}, body2)]
- client = bp.Client(self.creds, True)
+ MockHttpResponse(body1, 200),
+ MockHttpResponse(body2, 200)]
+ client = self.get_client(True)
client.refresh_token()
t = client.credentials.token
self.assertTrue(isinstance(t, bp.Token))
@@ -154,51 +179,46 @@ def test_refresh_token(self, mockHttpRequest):
# Test with error response
body = '{"error":"invalid_request","error_description":"invalid token"}'
- mockHttpRequest.side_effect = [({'status': '403'}, body)]
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 403)]
self.assertRaises(
- bp.InvalidTokenError, self.client.refresh_token)
+ bp.InvalidTokenError, client.refresh_token)
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.post')
def test_post_message(self, mockHttpRequest):
msg = bp.Message('bus', 'channel', 'type', {'hehe': 'haha'}, True)
- body = '{"token_type":"Bearer","access_token":"PC3Rm17rJUM3jmbtB34JEJ","expires_in":31535999,"scope":"bus:bus2","refresh_token":"PR5LoqnbxvF93SOGWqGnrs"}'
# Test with successful response
- mockHttpRequest.side_effect = [
- ({'status': '200'}, body),
- ({'status': '201'}, None)]
- client = bp.Client(self.creds, True)
+ mockHttpRequest.side_effect = [MockHttpResponse(None, 201)]
+ self.add_token_to_creds()
+ client = self.get_client()
client.post_message(msg)
# Test with error response
body = '{"error":"Invalid bus - channel binding "}'
- mockHttpRequest.side_effect = [({'status': '403'}, body)]
- self.assertRaises(bp.BackplaneError, self.client.post_message, msg)
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 403)]
+ self.assertRaises(bp.BackplaneError, client.post_message, msg)
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.get')
def test_get_single_message(self, mockHttpRequest):
- body1 = '{"token_type":"Bearer","access_token":"PC3Rm17rJUM3jmbtB34JEJ","expires_in":31535999,"scope":"bus:bus2","refresh_token":"PR5LoqnbxvF93SOGWqGnrs"}'
- body2 = '{"messageURL":"https://url/v2/message/mid","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"asxLPUhCFd7u7RLwJLAeoLm2DOeMbSdM","sticky":"true","expire":"2012-11-10T08:07:11Z","payload":{"hehe":"haha"}}'
- mockHttpRequest.side_effect = [
- ({'status': '200'}, body1),
- ({'status': '200'}, body2)]
- client = bp.Client(self.creds, True)
+ body = '{"messageURL":"https://url/v2/message/mid","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"asxLPUhCFd7u7RLwJLAeoLm2DOeMbSdM","sticky":"true","expire":"2012-11-10T08:07:11Z","payload":{"hehe":"haha"}}'
+ mockHttpRequest.side_effect = [MockHttpResponse(body, 200)]
+ self.add_token_to_creds()
+ client = self.get_client()
m = client.get_single_message('mid')
self.assertEquals(m.bus, 'bus1')
self.assertEquals(m.expire, '2012-11-10T08:07:11Z')
# The method should have constructed URL from a message ID
self.assertTrue('/v2/message/mid' in str(mockHttpRequest.mock_calls))
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.get')
def test_get_messages(self, mockHttpRequest):
- body1 = '{"token_type":"Bearer","access_token":"PC3Rm17rJUM3jmbtB34JEJ","expires_in":31535999,"scope":"bus:bus2","refresh_token":"PR5LoqnbxvF93SOGWqGnrs"}'
- body2 = '{"nextURL":"https://localhost/v2/messages?since=2012-11-10T01:30:28.037Z-CPbqzW16zA","messages":[{"messageURL":"https://localhost/v2/message/2012-11-10T00:07:11.512Z-dnveTh0M86","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"asxLPUhCFd7u7RLwJLAeoLm2DOeMbSdM","sticky":"true","expire":"2012-11-10T08:07:11Z","payload":{"hehe":"haha"}},{"messageURL":"https://localhost/v2/message/2012-11-10T00:26:57.184Z-vQeFesXKud","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"20Vh6Iwar7FNwH8v3AyXZUehQKaU22Bu","sticky":"true","expire":"2012-11-10T08:26:57Z","payload":{"context":"http://thinkwork/backplane2/token.html","identities":{"startIndex":0,"itemsPerPage":1,"totalResults":1,"entry":[{"id":"http://twitter.com/account/profile?user_id=144800941","displayName":"disp","photos":[{"type":"other","value":"http://a0.twimg.com/profile_images/1.jpg"}],"accountUri":"http://twitter.com/account/profile?user_id=14448848322","domain":"twitter.com","name":{"formatted":"disp"},"preferredUsername":"pref","urls":[{"type":"profile","value":"http://twitter.com/pref"}],"accessCredentials":{"access_credential_type":"oauth1","oauth_token":"1rrBrimru","oauth_token_secret":"JmUdxKoi"},"engage":{"following":["http://twitter.com/account/profile?user_id=172264980","http://twitter.com/account/profile?user_id=167336804","http://twitter.com/account/profile?user_id=145843434"],"followers":["http://twitter.com/account/profile?user_id=85736","http://twitter.com/account/profile?user_id=9857376","http://twitter.com/account/profile?user_id=433474458"],"friendships":["http://twitter.com/account/profile?user_id=172264980","http://twitter.com/account/profile?user_id=1475934"],"url":"http://twitter.com/pref","photo":"http://a0.twimg.com/profile_images/1","identifier":"http://twitter.com/account/profile?user_id=4598569","providerName":"Twitter"}}]}}},{"messageURL":"https://localhost/v2/message/2012-11-10T01:30:28.037Z-CPbqzW16zA","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"asxLPUhCFd7u7RLwJLAeoLm2DOeMbSdM","sticky":"true","expire":"2012-11-10T09:30:28Z","payload":{"hehe":"haha"}}],"moreMessages":false}'
- body3 = '{"nextURL":"https://localhost/v2/messages?since=2012-11-10T01:30:28.037Z-CPbqzW16zA","messages":[],"moreMessages":false}'
+ body1 = '{"nextURL":"https://localhost/v2/messages?since=2012-11-10T01:30:28.037Z-CPbqzW16zA","messages":[{"messageURL":"https://localhost/v2/message/2012-11-10T00:07:11.512Z-dnveTh0M86","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"asxLPUhCFd7u7RLwJLAeoLm2DOeMbSdM","sticky":"true","expire":"2012-11-10T08:07:11Z","payload":{"hehe":"haha"}},{"messageURL":"https://localhost/v2/message/2012-11-10T00:26:57.184Z-vQeFesXKud","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"20Vh6Iwar7FNwH8v3AyXZUehQKaU22Bu","sticky":"true","expire":"2012-11-10T08:26:57Z","payload":{"context":"http://thinkwork/backplane2/token.html","identities":{"startIndex":0,"itemsPerPage":1,"totalResults":1,"entry":[{"id":"http://twitter.com/account/profile?user_id=144800941","displayName":"disp","photos":[{"type":"other","value":"http://a0.twimg.com/profile_images/1.jpg"}],"accountUri":"http://twitter.com/account/profile?user_id=14448848322","domain":"twitter.com","name":{"formatted":"disp"},"preferredUsername":"pref","urls":[{"type":"profile","value":"http://twitter.com/pref"}],"accessCredentials":{"access_credential_type":"oauth1","oauth_token":"1rrBrimru","oauth_token_secret":"JmUdxKoi"},"engage":{"following":["http://twitter.com/account/profile?user_id=172264980","http://twitter.com/account/profile?user_id=167336804","http://twitter.com/account/profile?user_id=145843434"],"followers":["http://twitter.com/account/profile?user_id=85736","http://twitter.com/account/profile?user_id=9857376","http://twitter.com/account/profile?user_id=433474458"],"friendships":["http://twitter.com/account/profile?user_id=172264980","http://twitter.com/account/profile?user_id=1475934"],"url":"http://twitter.com/pref","photo":"http://a0.twimg.com/profile_images/1","identifier":"http://twitter.com/account/profile?user_id=4598569","providerName":"Twitter"}}]}}},{"messageURL":"https://localhost/v2/message/2012-11-10T01:30:28.037Z-CPbqzW16zA","source":"http://localhost","type":"identity/login","bus":"bus1","channel":"asxLPUhCFd7u7RLwJLAeoLm2DOeMbSdM","sticky":"true","expire":"2012-11-10T09:30:28Z","payload":{"hehe":"haha"}}],"moreMessages":false}'
+ body2 = '{"nextURL":"https://localhost/v2/messages?since=2012-11-10T01:30:28.037Z-CPbqzW16zA","messages":[],"moreMessages":false}'
mockHttpRequest.side_effect = [
- ({'status': '200'}, body1),
- ({'status': '200'}, body2),
- ({'status': '200'}, body3)]
- client = bp.Client(self.creds, True)
+ MockHttpResponse(body1, 200),
+ MockHttpResponse(body2, 200)]
+ self.add_token_to_creds()
+ client = self.get_client()
w = client.get_messages()
self.assertEquals(
w.messages[1].payload['identities']['entry'][0]['displayName'],
@@ -208,15 +228,15 @@ def test_get_messages(self, mockHttpRequest):
class TestFunctions(unittest.TestCase):
- @mock.patch('httplib2.Http.request')
+ @mock.patch('requests.get')
def test_call_backplane(self, mockHttpRequest):
body = 'Not found'
mockHttpRequest.side_effect = (
- lambda *args: ({'status': '404'}, body))
+ lambda *args, **kwargs: MockHttpResponse(body, 404))
self.assertRaises(
- bp.BackplaneError, bp._call_backplane, 'url', 'method')
+ bp.BackplaneError, bp._call_backplane, 'url', 'GET')
try:
- bp._call_backplane('url', 'method')
+ bp._call_backplane('url', 'GET')
except bp.BackplaneError, e:
self.assertEqual(e.response, body)
self.assertEqual(str(e), body)
@@ -224,7 +244,7 @@ def test_call_backplane(self, mockHttpRequest):
def raise_hell(*args):
raise Exception('bogus error')
mockHttpRequest.side_effect = raise_hell
- self.assertRaises(bp.BackplaneCallError, bp._call_backplane, 'u', 'm')
+ self.assertRaises(bp.BackplaneCallError, bp._call_backplane, 'u', 'GET')
if __name__ == "__main__":
Please sign in to comment.
Something went wrong with that request. Please try again.