summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLena (zansorgova) <zuzana.ansorgova@nic.cz>2018-02-25 00:01:16 +0100
committerVlastimil Zíma <vlastimil.zima@nic.cz>2018-03-16 12:23:42 +0100
commit9138fb8b4af26f6d985d6c0d1d0b668fc39a49a6 (patch)
tree37fe314c01eb547a37b85a9a6c145358c8ff635a
parentdfbb723d218eeb779b6932bef16253c20a4f8235 (diff)
downloadopenid-9138fb8b4af26f6d985d6c0d1d0b668fc39a49a6.tar.gz
Add ResponseFetcher implementation
-rw-r--r--openid/fetchers.py24
-rw-r--r--openid/test/test_fetchers.py65
-rw-r--r--setup.py3
-rw-r--r--tox.ini5
4 files changed, 94 insertions, 3 deletions
diff --git a/openid/fetchers.py b/openid/fetchers.py
index 750b5f5..fa25184 100644
--- a/openid/fetchers.py
+++ b/openid/fetchers.py
@@ -29,6 +29,12 @@ try:
except ImportError:
pycurl = None
+# try to import requests
+try:
+ import requests
+except ImportError:
+ requests = None
+
USER_AGENT = "python-openid/%s (%s)" % (openid.__version__, sys.platform)
MAX_RESPONSE_KB = 1024
@@ -438,3 +444,21 @@ class HTTPLib2Fetcher(HTTPFetcher):
headers=dict(httplib2_response.items()),
status=httplib2_response.status,
)
+
+
+class RequestsFetcher(HTTPFetcher):
+ """A fetcher that uses C{requests} for performing HTTP requests."""
+
+ def fetch(self, url, body=None, headers=None):
+ """Perform an HTTP request
+
+ @raises Exception: Any exception that can be raised by 'requests'
+
+ @see: C{L{HTTPFetcher.fetch}}
+ """
+ if body:
+ method = 'POST'
+ else:
+ method = 'GET'
+ response = requests.request(method, url, data=body, headers=headers)
+ return HTTPResponse(response.url, response.status_code, response.headers, response.content)
diff --git a/openid/test/test_fetchers.py b/openid/test/test_fetchers.py
index 16f615a..36698ba 100644
--- a/openid/test/test_fetchers.py
+++ b/openid/test/test_fetchers.py
@@ -6,10 +6,18 @@ from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from cStringIO import StringIO
from urllib import addinfourl
+import responses
from mock import Mock
from openid import fetchers
+try:
+ import requests
+except ImportError:
+ requests = None
+else:
+ from requests.exceptions import ConnectionError, InvalidSchema
+
# XXX: make these separate test cases
@@ -336,3 +344,60 @@ class TestSilencedUrllib2Fetcher(TestUrllib2Fetcher):
fetcher = fetchers.ExceptionWrappingFetcher(fetchers.Urllib2Fetcher())
invalid_url_error = fetchers.HTTPFetchingError
+
+
+@unittest.skipUnless(requests, "Requests are not installed")
+class TestRequestsFetcher(unittest.TestCase):
+ """Test `RequestsFetcher` class."""
+
+ fetcher = fetchers.RequestsFetcher()
+
+ def test_get(self):
+ # Test GET response
+ with responses.RequestsMock() as rsps:
+ rsps.add(responses.GET, 'http://example.cz/', status=200, body='BODY',
+ headers={'Content-Type': 'text/plain'})
+ response = self.fetcher.fetch('http://example.cz/')
+ expected = fetchers.HTTPResponse('http://example.cz/', 200, {'Content-Type': 'text/plain'}, 'BODY')
+ assertResponse(expected, response)
+
+ def test_post(self):
+ # Test POST response
+ with responses.RequestsMock() as rsps:
+ rsps.add(responses.POST, 'http://example.cz/', status=200, body='BODY',
+ headers={'Content-Type': 'text/plain'})
+ response = self.fetcher.fetch('http://example.cz/', body='key=value')
+ expected = fetchers.HTTPResponse('http://example.cz/', 200, {'Content-Type': 'text/plain'}, 'BODY')
+ assertResponse(expected, response)
+
+ def test_redirect(self):
+ # Test redirect response - a final response comes from another URL.
+ with responses.RequestsMock() as rsps:
+ rsps.add(responses.GET, 'http://example.cz/redirect/', status=302,
+ headers={'Location': 'http://example.cz/target/'})
+ rsps.add(responses.GET, 'http://example.cz/target/', status=200, body='BODY',
+ headers={'Content-Type': 'text/plain'})
+ response = self.fetcher.fetch('http://example.cz/redirect/')
+ expected = fetchers.HTTPResponse('http://example.cz/target/', 200, {'Content-Type': 'text/plain'}, 'BODY')
+ assertResponse(expected, response)
+
+ def test_error(self):
+ # Test error responses - returned as obtained
+ with responses.RequestsMock() as rsps:
+ rsps.add(responses.GET, 'http://example.cz/error/', status=500, body='BODY',
+ headers={'Content-Type': 'text/plain'})
+ response = self.fetcher.fetch('http://example.cz/error/')
+ expected = fetchers.HTTPResponse('http://example.cz/error/', 500, {'Content-Type': 'text/plain'}, 'BODY')
+ assertResponse(expected, response)
+
+ def test_invalid_url(self):
+ invalid_url = 'invalid://example.cz/'
+ with self.assertRaisesRegexp(InvalidSchema, "No connection adapters were found for '" + invalid_url + "'"):
+ self.fetcher.fetch(invalid_url)
+
+ def test_connection_error(self):
+ # Test connection error
+ with responses.RequestsMock() as rsps:
+ rsps.add(responses.GET, 'http://example.cz/', body=ConnectionError('Name or service not known'))
+ with self.assertRaisesRegexp(ConnectionError, 'Name or service not known'):
+ self.fetcher.fetch('http://example.cz/')
diff --git a/setup.py b/setup.py
index d6de0ea..6b2e672 100644
--- a/setup.py
+++ b/setup.py
@@ -13,10 +13,11 @@ INSTALL_REQUIRES = [
]
EXTRAS_REQUIRE = {
'quality': ('flake8', 'isort'),
- 'tests': ('mock', 'testfixtures', 'coverage'),
+ 'tests': ('mock', 'testfixtures', 'responses', 'coverage'),
# Optional dependencies for fetchers
'httplib2': ('httplib2', ),
'pycurl': ('pycurl', ),
+ 'requests': ('requests', ),
# Dependencies for Django example
'djopenid': ('django<1.11.99', ),
}
diff --git a/tox.ini b/tox.ini
index ab9ef23..d75be23 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,8 @@
[tox]
envlist =
quality
- py27-{openid,djopenid,httplib2,pycurl}
- pypy-{openid,djopenid,httplib2,pycurl}
+ py27-{openid,djopenid,httplib2,pycurl,requests}
+ pypy-{openid,djopenid,httplib2,pycurl,requests}
# tox-travis specials
[travis]
@@ -18,6 +18,7 @@ extras =
djopenid: djopenid
httplib2: httplib2
pycurl: pycurl
+ requests: requests
passenv = CI TRAVIS TRAVIS_*
setenv =
DJANGO_SETTINGS_MODULE = djopenid.settings