From 176a94f5664a54ecc5addde54141583f9ab912ce Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 28 Aug 2020 11:42:26 -0700 Subject: [PATCH 1/3] Add basic tests --- .github/workflows/test.yml | 29 +++++++++++++++++++++++++ tests/header_test.py | 25 ++++++++++++++++++++++ tests/mocket.py | 32 ++++++++++++++++++++++++++++ tests/parse_test.py | 20 ++++++++++++++++++ tests/post_test.py | 43 ++++++++++++++++++++++++++++++++++++++ tests/protocol_test.py | 37 ++++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+) create mode 100644 .github/workflows/test.yml create mode 100644 tests/header_test.py create mode 100644 tests/mocket.py create mode 100644 tests/parse_test.py create mode 100644 tests/post_test.py create mode 100644 tests/protocol_test.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..d4888ef --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,29 @@ +name: Run Tests + +on: [pull_request, push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + - name: Set up Python 3.6 + uses: actions/setup-python@v1 + with: + python-version: 3.6 + - name: Versions + run: | + python3 --version + - name: Checkout Current Repo + uses: actions/checkout@v1 + with: + submodules: true + - name: Install pytest + run: pip install pytest + - name: Install locally + run: pip install . + - name: Run tests + run: pytest diff --git a/tests/header_test.py b/tests/header_test.py new file mode 100644 index 0000000..b13c833 --- /dev/null +++ b/tests/header_test.py @@ -0,0 +1,25 @@ +from unittest import mock +import mocket +import json +import adafruit_requests + +ip = "1.2.3.4" +host = "httpbin.org" +response_headers = b"HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n" + +def test_json(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) + sock = mocket.Mocket(response_headers) + mocket.socket.return_value = sock + sent = [] + sock.send.side_effect = sent.append + + adafruit_requests.set_socket(mocket, mocket.interface) + headers = {"user-agent": "blinka/1.0.0"} + r = adafruit_requests.get("http://" + host + "/get", headers=headers) + + sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) + sent = b"".join(sent).lower() + assert b"user-agent: blinka/1.0.0\r\n" in sent + # The current implementation sends two user agents. Fix it, and uncomment below. + # assert sent.count(b"user-agent:") == 1 diff --git a/tests/mocket.py b/tests/mocket.py new file mode 100644 index 0000000..75dff2c --- /dev/null +++ b/tests/mocket.py @@ -0,0 +1,32 @@ +from unittest import mock + +SOCK_STREAM = 0 + +getaddrinfo = mock.Mock() +socket = mock.Mock() +set_interface = mock.Mock() + +interface = mock.MagicMock() + +class Mocket: + def __init__(self, response): + self.settimeout = mock.Mock() + self.close = mock.Mock() + self.connect = mock.Mock() + self.send = mock.Mock() + self.readline = mock.Mock(side_effect=self._readline) + self.recv = mock.Mock(side_effect=self._recv) + self._response = response + self._position = 0 + + def _readline(self): + i = self._response.find(b"\r\n", self._position) + r = self._response[self._position:i+2] + self._position = i + 2 + return r + + def _recv(self, count): + end = self._position + count + r = self._response[self._position:end] + self._position = end + return r diff --git a/tests/parse_test.py b/tests/parse_test.py new file mode 100644 index 0000000..92a2a92 --- /dev/null +++ b/tests/parse_test.py @@ -0,0 +1,20 @@ +from unittest import mock +import mocket +import json +import adafruit_requests + +ip = "1.2.3.4" +host = "httpbin.org" +response = {"Date": "July 25, 2019"} +encoded = json.dumps(response).encode("utf-8") +headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode("utf-8") + +def test_json(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) + sock = mocket.Mocket(headers + encoded) + mocket.socket.return_value = sock + + adafruit_requests.set_socket(mocket, mocket.interface) + r = adafruit_requests.get("http://" + host + "/get") + sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) + assert r.json() == response diff --git a/tests/post_test.py b/tests/post_test.py new file mode 100644 index 0000000..25a541a --- /dev/null +++ b/tests/post_test.py @@ -0,0 +1,43 @@ +from unittest import mock +import mocket +import json +import adafruit_requests + +ip = "1.2.3.4" +host = "httpbin.org" +response = {} +encoded = json.dumps(response).encode("utf-8") +headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode("utf-8") + +def test_method(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) + sock = mocket.Mocket(headers + encoded) + mocket.socket.return_value = sock + + adafruit_requests.set_socket(mocket, mocket.interface) + r = adafruit_requests.post("http://" + host + "/post") + sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) + sock.send.assert_has_calls([mock.call(b'POST /post HTTP/1.0\r\n'), + mock.call(b'Host: httpbin.org\r\n')]) + +def test_string(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) + sock = mocket.Mocket(headers + encoded) + mocket.socket.return_value = sock + + adafruit_requests.set_socket(mocket, mocket.interface) + data = "31F" + r = adafruit_requests.post("http://" + host + "/post", data=data) + sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) + sock.send.assert_called_with(b'31F') + +def test_json(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) + sock = mocket.Mocket(headers + encoded) + mocket.socket.return_value = sock + + adafruit_requests.set_socket(mocket, mocket.interface) + json_data = {"Date": "July 25, 2019"} + r = adafruit_requests.post("http://" + host + "/post", json=json_data) + sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) + sock.send.assert_called_with(b'{"Date": "July 25, 2019"}') diff --git a/tests/protocol_test.py b/tests/protocol_test.py new file mode 100644 index 0000000..6e96b32 --- /dev/null +++ b/tests/protocol_test.py @@ -0,0 +1,37 @@ +from unittest import mock +import mocket +import adafruit_requests + +ip = "1.2.3.4" +host = "wifitest.adafruit.com" +path = "/testwifi/index.html" +text = b"This is a test of Adafruit WiFi!\r\nIf you can read this, its working :)" +response = b"HTTP/1.0 200 OK\r\nContent-Length: 70\r\n\r\n" + text + +def test_get_https_text(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip,80)),) + sock = mocket.Mocket(response) + mocket.socket.return_value = sock + + adafruit_requests.set_socket(mocket, mocket.interface) + r = adafruit_requests.get("https://" + host + path) + + sock.connect.assert_called_once_with((host, 443), mocket.interface.TLS_MODE) + sock.send.assert_has_calls([mock.call(b'GET /testwifi/index.html HTTP/1.0\r\n'), + mock.call(b'Host: wifitest.adafruit.com\r\n')]) + assert r.text == str(text, "utf-8") + +def test_get_http_text(): + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip,80)),) + sock = mocket.Mocket(response) + mocket.socket.return_value = sock + + adafruit_requests.set_socket(mocket, mocket.interface) + r = adafruit_requests.get("http://" + host + path) + + sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) + sock.send.assert_has_calls([mock.call(b'GET /testwifi/index.html HTTP/1.0\r\n'), + mock.call(b'Host: wifitest.adafruit.com\r\n')]) + assert r.text == str(text, "utf-8") + +# Add a chunked response test when we support HTTP 1.1 From b300c9c509b97f216377a2eebe436c52b3b7c1fb Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 28 Aug 2020 11:49:07 -0700 Subject: [PATCH 2/3] black --- tests/header_test.py | 1 + tests/mocket.py | 5 +++-- tests/parse_test.py | 5 ++++- tests/post_test.py | 14 ++++++++++---- tests/protocol_test.py | 25 ++++++++++++++++++------- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/tests/header_test.py b/tests/header_test.py index b13c833..d1d273e 100644 --- a/tests/header_test.py +++ b/tests/header_test.py @@ -7,6 +7,7 @@ host = "httpbin.org" response_headers = b"HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n" + def test_json(): mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) sock = mocket.Mocket(response_headers) diff --git a/tests/mocket.py b/tests/mocket.py index 75dff2c..684aece 100644 --- a/tests/mocket.py +++ b/tests/mocket.py @@ -8,6 +8,7 @@ interface = mock.MagicMock() + class Mocket: def __init__(self, response): self.settimeout = mock.Mock() @@ -21,12 +22,12 @@ def __init__(self, response): def _readline(self): i = self._response.find(b"\r\n", self._position) - r = self._response[self._position:i+2] + r = self._response[self._position : i + 2] self._position = i + 2 return r def _recv(self, count): end = self._position + count - r = self._response[self._position:end] + r = self._response[self._position : end] self._position = end return r diff --git a/tests/parse_test.py b/tests/parse_test.py index 92a2a92..477a128 100644 --- a/tests/parse_test.py +++ b/tests/parse_test.py @@ -7,7 +7,10 @@ host = "httpbin.org" response = {"Date": "July 25, 2019"} encoded = json.dumps(response).encode("utf-8") -headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode("utf-8") +headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode( + "utf-8" +) + def test_json(): mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) diff --git a/tests/post_test.py b/tests/post_test.py index 25a541a..a2f5977 100644 --- a/tests/post_test.py +++ b/tests/post_test.py @@ -7,7 +7,10 @@ host = "httpbin.org" response = {} encoded = json.dumps(response).encode("utf-8") -headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode("utf-8") +headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode( + "utf-8" +) + def test_method(): mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) @@ -17,8 +20,10 @@ def test_method(): adafruit_requests.set_socket(mocket, mocket.interface) r = adafruit_requests.post("http://" + host + "/post") sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) - sock.send.assert_has_calls([mock.call(b'POST /post HTTP/1.0\r\n'), - mock.call(b'Host: httpbin.org\r\n')]) + sock.send.assert_has_calls( + [mock.call(b"POST /post HTTP/1.0\r\n"), mock.call(b"Host: httpbin.org\r\n")] + ) + def test_string(): mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) @@ -29,7 +34,8 @@ def test_string(): data = "31F" r = adafruit_requests.post("http://" + host + "/post", data=data) sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) - sock.send.assert_called_with(b'31F') + sock.send.assert_called_with(b"31F") + def test_json(): mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) diff --git a/tests/protocol_test.py b/tests/protocol_test.py index 6e96b32..0eec002 100644 --- a/tests/protocol_test.py +++ b/tests/protocol_test.py @@ -8,21 +8,27 @@ text = b"This is a test of Adafruit WiFi!\r\nIf you can read this, its working :)" response = b"HTTP/1.0 200 OK\r\nContent-Length: 70\r\n\r\n" + text + def test_get_https_text(): - mocket.getaddrinfo.return_value = ((None, None, None, None, (ip,80)),) + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) sock = mocket.Mocket(response) mocket.socket.return_value = sock adafruit_requests.set_socket(mocket, mocket.interface) r = adafruit_requests.get("https://" + host + path) - + sock.connect.assert_called_once_with((host, 443), mocket.interface.TLS_MODE) - sock.send.assert_has_calls([mock.call(b'GET /testwifi/index.html HTTP/1.0\r\n'), - mock.call(b'Host: wifitest.adafruit.com\r\n')]) + sock.send.assert_has_calls( + [ + mock.call(b"GET /testwifi/index.html HTTP/1.0\r\n"), + mock.call(b"Host: wifitest.adafruit.com\r\n"), + ] + ) assert r.text == str(text, "utf-8") + def test_get_http_text(): - mocket.getaddrinfo.return_value = ((None, None, None, None, (ip,80)),) + mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),) sock = mocket.Mocket(response) mocket.socket.return_value = sock @@ -30,8 +36,13 @@ def test_get_http_text(): r = adafruit_requests.get("http://" + host + path) sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE) - sock.send.assert_has_calls([mock.call(b'GET /testwifi/index.html HTTP/1.0\r\n'), - mock.call(b'Host: wifitest.adafruit.com\r\n')]) + sock.send.assert_has_calls( + [ + mock.call(b"GET /testwifi/index.html HTTP/1.0\r\n"), + mock.call(b"Host: wifitest.adafruit.com\r\n"), + ] + ) assert r.text == str(text, "utf-8") + # Add a chunked response test when we support HTTP 1.1 From d426ea6fdab8940a41b6ed22aa80d47cec344511 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 28 Aug 2020 11:57:24 -0700 Subject: [PATCH 3/3] lint --- examples/requests_advanced_ethernet.py | 2 +- examples/requests_simpletest_ethernet.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/requests_advanced_ethernet.py b/examples/requests_advanced_ethernet.py index 8eedb50..2a0e7df 100644 --- a/examples/requests_advanced_ethernet.py +++ b/examples/requests_advanced_ethernet.py @@ -35,7 +35,7 @@ raise AssertionError( "Failed to resolve hostname, \ please check your router's DNS configuration." - ) + ) from error continue print("-" * 60) diff --git a/examples/requests_simpletest_ethernet.py b/examples/requests_simpletest_ethernet.py index 432bc42..865d777 100644 --- a/examples/requests_simpletest_ethernet.py +++ b/examples/requests_simpletest_ethernet.py @@ -34,7 +34,7 @@ raise AssertionError( "Failed to resolve hostname, \ please check your router's DNS configuration." - ) + ) from error continue print("-" * 40) @@ -55,7 +55,7 @@ raise AssertionError( "Failed to resolve hostname, \ please check your router's DNS configuration." - ) + ) from error continue print("-" * 40) @@ -77,7 +77,7 @@ raise AssertionError( "Failed to resolve hostname, \ please check your router's DNS configuration." - ) + ) from error continue print("-" * 40) @@ -101,7 +101,7 @@ raise AssertionError( "Failed to resolve hostname, \ please check your router's DNS configuration." - ) + ) from error continue print("-" * 40)