From ee5b16415e1856a976ca78fadf8a56dc5b5db4e3 Mon Sep 17 00:00:00 2001 From: Jason Robinson Date: Mon, 5 Sep 2016 22:57:01 +0300 Subject: [PATCH] Add send_document network utility It's a wrapper around requests.post that adds the correct user agent and silently captures common requests exceptions and returns them instead. --- CHANGELOG.md | 1 + federation/tests/utils/test_network.py | 21 ++++++++++++++++++++- federation/utils/network.py | 25 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0517fe..37da5c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ## Added - `Post.provider_display_name` is now supported in the entity outbound/inbound mappers. [#44](https://github.com/jaywink/social-federation/pull/44) +- Add utility method `federation.utils.network.send_document` which is just a wrapper around `requests.post`. User agent will be added to the headers and exceptions will be silently captured and returned instead. [#45](https://github.com/jaywink/social-federation/pull/45) ## [0.4.1] - 2016-09-04 diff --git a/federation/tests/utils/test_network.py b/federation/tests/utils/test_network.py index 82902de..8e19577 100644 --- a/federation/tests/utils/test_network.py +++ b/federation/tests/utils/test_network.py @@ -5,7 +5,7 @@ import pytest from requests import HTTPError from requests.exceptions import SSLError, RequestException -from federation.utils.network import fetch_document, USER_AGENT +from federation.utils.network import fetch_document, USER_AGENT, send_document class TestFetchDocument(object): @@ -86,3 +86,22 @@ class TestFetchDocument(object): assert doc == None assert code == None assert exc.__class__ == RequestException + + +class TestSendDocument(object): + call_args = {"timeout": 10, "headers": {'user-agent': USER_AGENT}} + + @patch("federation.utils.network.requests.post", return_value=Mock(status_code=200)) + def test_post_is_called(self, mock_post): + code, exc = send_document("http://localhost", {"foo": "bar"}) + mock_post.assert_called_once_with( + "http://localhost", data={"foo": "bar"}, **self.call_args + ) + assert code == 200 + assert exc == None + + @patch("federation.utils.network.requests.post", side_effect=RequestException) + def test_post_raises_and_returns_exception(self, mock_post): + code, exc = send_document("http://localhost", {"foo": "bar"}) + assert code == None + assert exc.__class__ == RequestException diff --git a/federation/utils/network.py b/federation/utils/network.py index 149414b..4f27e02 100644 --- a/federation/utils/network.py +++ b/federation/utils/network.py @@ -74,3 +74,28 @@ def fetch_document(url=None, host=None, path="/", timeout=10, raise_ssl_errors=T except RequestException as ex: logger.debug("fetch_document: exception %s", ex) return None, None, ex + + +def send_document(url, data, timeout=10, *args, **kwargs): + """Helper method to send a document via POST. + + Args: + url (str) - Full url to send to, including protocol + data (dict) - POST data to send + timeout (int) - Seconds to wait for response (defaults to 10) + + Additional *args and **kwargs will be passed on to `requests.post`. + + Returns: + status_code (int) - Status code returned or None + error (obj) - Exception raised, if any + """ + logger.debug("send_document: url=%s, data=%s, timeout=%s", url, data, timeout) + headers = {'user-agent': USER_AGENT} + try: + response = requests.post(url, data=data, timeout=timeout, headers=headers, *args, **kwargs) + logger.debug("send_document: response status code %s", response.status_code) + return response.status_code, None + except RequestException as ex: + logger.debug("send_document: exception %s", ex) + return None, ex