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/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) diff --git a/tests/header_test.py b/tests/header_test.py new file mode 100644 index 0000000..d1d273e --- /dev/null +++ b/tests/header_test.py @@ -0,0 +1,26 @@ +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..684aece --- /dev/null +++ b/tests/mocket.py @@ -0,0 +1,33 @@ +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..477a128 --- /dev/null +++ b/tests/parse_test.py @@ -0,0 +1,23 @@ +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..a2f5977 --- /dev/null +++ b/tests/post_test.py @@ -0,0 +1,49 @@ +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..0eec002 --- /dev/null +++ b/tests/protocol_test.py @@ -0,0 +1,48 @@ +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