Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2a2c20e

Browse files
authoredSep 14, 2020
Merge pull request #31 from tannewt/http11
Add HTTP1.1 support and socket reuse
2 parents e49a815 + 51d9f09 commit 2a2c20e

17 files changed

+951
-216
lines changed
 

‎.github/workflows/test.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ jobs:
66
test:
77
runs-on: ubuntu-latest
88
steps:
9-
- name: Dump GitHub context
10-
env:
11-
GITHUB_CONTEXT: ${{ toJson(github) }}
12-
run: echo "$GITHUB_CONTEXT"
139
- name: Set up Python 3.6
1410
uses: actions/setup-python@v1
1511
with:

‎adafruit_requests.py

Lines changed: 453 additions & 161 deletions
Large diffs are not rendered by default.

‎examples/requests_advanced.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
from adafruit_esp32spi import adafruit_esp32spi
66
import adafruit_requests as requests
77

8+
# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
9+
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
10+
# source control.
11+
# pylint: disable=no-name-in-module,wrong-import-order
12+
try:
13+
from secrets import secrets
14+
except ImportError:
15+
print("WiFi secrets are kept in secrets.py, please add them there!")
16+
raise
17+
818
# If you are using a board with pre-defined ESP32 Pins:
919
esp32_cs = DigitalInOut(board.ESP_CS)
1020
esp32_ready = DigitalInOut(board.ESP_BUSY)
@@ -21,14 +31,15 @@
2131
print("Connecting to AP...")
2232
while not esp.is_connected:
2333
try:
24-
esp.connect_AP(b"MY_SSID_NAME", b"MY_SSID_PASSWORD")
34+
esp.connect_AP(secrets["ssid"], secrets["password"])
2535
except RuntimeError as e:
2636
print("could not connect to AP, retrying: ", e)
2737
continue
2838
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
2939

3040
# Initialize a requests object with a socket and esp32spi interface
31-
requests.set_socket(socket, esp)
41+
socket.set_interface(esp)
42+
requests.set_socket(socket)
3243

3344
JSON_GET_URL = "http://httpbin.org/get"
3445

‎examples/requests_advanced_cpython.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import socket
2+
import adafruit_requests
3+
4+
http = adafruit_requests.Session(socket)
5+
6+
JSON_GET_URL = "http://httpbin.org/get"
7+
8+
# Define a custom header as a dict.
9+
headers = {"user-agent": "blinka/1.0.0"}
10+
11+
print("Fetching JSON data from %s..." % JSON_GET_URL)
12+
response = http.get(JSON_GET_URL, headers=headers)
13+
print("-" * 60)
14+
15+
json_data = response.json()
16+
headers = json_data["headers"]
17+
print("Response's Custom User-Agent Header: {0}".format(headers["User-Agent"]))
18+
print("-" * 60)
19+
20+
# Read Response's HTTP status code
21+
print("Response HTTP Status Code: ", response.status_code)
22+
print("-" * 60)
23+
24+
# Read Response, as raw bytes instead of pretty text
25+
print("Raw Response: ", response.content)
26+
27+
# Close, delete and collect the response data
28+
response.close()

‎examples/requests_github_cpython.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# adafruit_requests usage with a CPython socket
2+
import socket
3+
import ssl
4+
import adafruit_requests
5+
6+
http = adafruit_requests.Session(socket, ssl.create_default_context())
7+
8+
print("Getting CircuitPython star count")
9+
headers = {"Transfer-Encoding": "chunked"}
10+
response = http.get(
11+
"https://api.github.com/repos/adafruit/circuitpython", headers=headers
12+
)
13+
print("circuitpython stars", response.json()["stargazers_count"])

‎examples/requests_https_cpython.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# adafruit_requests usage with a CPython socket
2+
import socket
3+
import ssl
4+
import adafruit_requests as requests
5+
6+
https = requests.Session(socket, ssl.create_default_context())
7+
8+
TEXT_URL = "https://wifitest.adafruit.com/testwifi/index.html"
9+
JSON_GET_URL = "https://httpbin.org/get"
10+
JSON_POST_URL = "https://httpbin.org/post"
11+
12+
# print("Fetching text from %s" % TEXT_URL)
13+
# response = requests.get(TEXT_URL)
14+
# print("-" * 40)
15+
16+
# print("Text Response: ", response.text)
17+
# print("-" * 40)
18+
# response.close()
19+
20+
print("Fetching JSON data from %s" % JSON_GET_URL)
21+
response = https.get(JSON_GET_URL)
22+
print("-" * 40)
23+
24+
print("JSON Response: ", response.json())
25+
print("-" * 40)
26+
27+
data = "31F"
28+
print("POSTing data to {0}: {1}".format(JSON_POST_URL, data))
29+
response = https.post(JSON_POST_URL, data=data)
30+
print("-" * 40)
31+
32+
json_resp = response.json()
33+
# Parse out the 'data' key from json_resp dict.
34+
print("Data received from server:", json_resp["data"])
35+
print("-" * 40)
36+
37+
json_data = {"Date": "July 25, 2019"}
38+
print("POSTing data to {0}: {1}".format(JSON_POST_URL, json_data))
39+
response = https.post(JSON_POST_URL, json=json_data)
40+
print("-" * 40)
41+
42+
json_resp = response.json()
43+
# Parse out the 'json' key from json_resp dict.
44+
print("JSON Data received from server:", json_resp["json"])
45+
print("-" * 40)

‎examples/requests_simpletest.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
from adafruit_esp32spi import adafruit_esp32spi
77
import adafruit_requests as requests
88

9+
# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
10+
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
11+
# source control.
12+
# pylint: disable=no-name-in-module,wrong-import-order
13+
try:
14+
from secrets import secrets
15+
except ImportError:
16+
print("WiFi secrets are kept in secrets.py, please add them there!")
17+
raise
18+
919
# If you are using a board with pre-defined ESP32 Pins:
1020
esp32_cs = DigitalInOut(board.ESP_CS)
1121
esp32_ready = DigitalInOut(board.ESP_BUSY)
@@ -22,14 +32,15 @@
2232
print("Connecting to AP...")
2333
while not esp.is_connected:
2434
try:
25-
esp.connect_AP(b"MY_SSID_NAME", b"MY_SSID_PASSWORD")
35+
esp.connect_AP(secrets["ssid"], secrets["password"])
2636
except RuntimeError as e:
2737
print("could not connect to AP, retrying: ", e)
2838
continue
2939
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
3040

3141
# Initialize a requests object with a socket and esp32spi interface
32-
requests.set_socket(socket, esp)
42+
socket.set_interface(esp)
43+
requests.set_socket(socket)
3344

3445
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"
3546
JSON_GET_URL = "http://httpbin.org/get"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# adafruit_requests usage with a CPython socket
2+
import socket
3+
import adafruit_requests
4+
5+
http = adafruit_requests.Session(socket)
6+
7+
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"
8+
JSON_GET_URL = "http://httpbin.org/get"
9+
JSON_POST_URL = "http://httpbin.org/post"
10+
11+
print("Fetching text from %s" % TEXT_URL)
12+
response = http.get(TEXT_URL)
13+
print("-" * 40)
14+
15+
print("Text Response: ", response.text)
16+
print("-" * 40)
17+
18+
print("Fetching JSON data from %s" % JSON_GET_URL)
19+
response = http.get(JSON_GET_URL)
20+
print("-" * 40)
21+
22+
print("JSON Response: ", response.json())
23+
print("-" * 40)
24+
response.close()
25+
26+
data = "31F"
27+
print("POSTing data to {0}: {1}".format(JSON_POST_URL, data))
28+
response = http.post(JSON_POST_URL, data=data)
29+
print("-" * 40)
30+
31+
json_resp = response.json()
32+
# Parse out the 'data' key from json_resp dict.
33+
print("Data received from server:", json_resp["data"])
34+
print("-" * 40)
35+
36+
json_data = {"Date": "July 25, 2019"}
37+
print("POSTing data to {0}: {1}".format(JSON_POST_URL, json_data))
38+
response = http.post(JSON_POST_URL, json=json_data)
39+
print("-" * 40)
40+
41+
json_resp = response.json()
42+
# Parse out the 'json' key from json_resp dict.
43+
print("JSON Data received from server:", json_resp["json"])
44+
print("-" * 40)

‎tests/chunk_test.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from unittest import mock
2+
import mocket
3+
import adafruit_requests
4+
5+
ip = "1.2.3.4"
6+
host = "wifitest.adafruit.com"
7+
path = "/testwifi/index.html"
8+
text = b"This is a test of Adafruit WiFi!\r\nIf you can read this, its working :)"
9+
headers = b"HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
10+
11+
12+
def _chunk(response, split):
13+
i = 0
14+
chunked = b""
15+
while i < len(response):
16+
remaining = len(response) - i
17+
chunk_size = split
18+
if remaining < chunk_size:
19+
chunk_size = remaining
20+
new_i = i + chunk_size
21+
chunked += (
22+
hex(chunk_size)[2:].encode("ascii") + b"\r\n" + response[i:new_i] + b"\r\n"
23+
)
24+
i = new_i
25+
# The final chunk is zero length.
26+
chunked += b"0\r\n\r\n"
27+
return chunked
28+
29+
30+
def test_get_text():
31+
pool = mocket.MocketPool()
32+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
33+
c = _chunk(text, 33)
34+
print(c)
35+
sock = mocket.Mocket(headers + c)
36+
pool.socket.return_value = sock
37+
38+
s = adafruit_requests.Session(pool)
39+
r = s.get("http://" + host + path)
40+
41+
sock.connect.assert_called_once_with((ip, 80))
42+
sock.send.assert_has_calls(
43+
[
44+
mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
45+
mock.call(b"Host: wifitest.adafruit.com\r\n"),
46+
]
47+
)
48+
assert r.text == str(text, "utf-8")

‎tests/header_test.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@
99

1010

1111
def test_json():
12-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
12+
pool = mocket.MocketPool()
13+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
1314
sock = mocket.Mocket(response_headers)
14-
mocket.socket.return_value = sock
15+
pool.socket.return_value = sock
1516
sent = []
1617
sock.send.side_effect = sent.append
1718

18-
adafruit_requests.set_socket(mocket, mocket.interface)
19+
s = adafruit_requests.Session(pool)
1920
headers = {"user-agent": "blinka/1.0.0"}
20-
r = adafruit_requests.get("http://" + host + "/get", headers=headers)
21+
r = s.get("http://" + host + "/get", headers=headers)
2122

22-
sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE)
23+
sock.connect.assert_called_once_with((ip, 80))
2324
sent = b"".join(sent).lower()
2425
assert b"user-agent: blinka/1.0.0\r\n" in sent
2526
# The current implementation sends two user agents. Fix it, and uncomment below.

‎tests/legacy_mocket.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from unittest import mock
2+
3+
SOCK_STREAM = 0
4+
5+
set_interface = mock.Mock()
6+
interface = mock.MagicMock()
7+
getaddrinfo = mock.Mock()
8+
socket = mock.Mock()
9+
10+
11+
class Mocket:
12+
def __init__(self, response):
13+
self.settimeout = mock.Mock()
14+
self.close = mock.Mock()
15+
self.connect = mock.Mock()
16+
self.send = mock.Mock()
17+
self.readline = mock.Mock(side_effect=self._readline)
18+
self.recv = mock.Mock(side_effect=self._recv)
19+
self._response = response
20+
self._position = 0
21+
22+
def _readline(self):
23+
i = self._response.find(b"\r\n", self._position)
24+
r = self._response[self._position : i + 2]
25+
self._position = i + 2
26+
return r
27+
28+
def _recv(self, count):
29+
end = self._position + count
30+
r = self._response[self._position : end]
31+
self._position = end
32+
return r

‎tests/legacy_test.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from unittest import mock
2+
import legacy_mocket as mocket
3+
import json
4+
import adafruit_requests
5+
6+
ip = "1.2.3.4"
7+
host = "httpbin.org"
8+
response = {"Date": "July 25, 2019"}
9+
encoded = json.dumps(response).encode("utf-8")
10+
headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode(
11+
"utf-8"
12+
)
13+
14+
15+
def test_get_json():
16+
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
17+
sock = mocket.Mocket(headers + encoded)
18+
mocket.socket.return_value = sock
19+
20+
adafruit_requests.set_socket(mocket, mocket.interface)
21+
r = adafruit_requests.get("http://" + host + "/get")
22+
23+
sock.connect.assert_called_once_with((ip, 80))
24+
assert r.json() == response
25+
r.close()
26+
27+
28+
def test_tls_mode():
29+
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
30+
sock = mocket.Mocket(headers + encoded)
31+
mocket.socket.return_value = sock
32+
33+
adafruit_requests.set_socket(mocket, mocket.interface)
34+
r = adafruit_requests.get("https://" + host + "/get")
35+
36+
sock.connect.assert_called_once_with((host, 443), mocket.interface.TLS_MODE)
37+
assert r.json() == response
38+
r.close()
39+
40+
41+
def test_post_string():
42+
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
43+
sock = mocket.Mocket(headers + encoded)
44+
mocket.socket.return_value = sock
45+
46+
adafruit_requests.set_socket(mocket, mocket.interface)
47+
data = "31F"
48+
r = adafruit_requests.post("http://" + host + "/post", data=data)
49+
sock.connect.assert_called_once_with((ip, 80))
50+
sock.send.assert_called_with(b"31F")
51+
r.close()

‎tests/mocket.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from unittest import mock
22

3-
SOCK_STREAM = 0
43

5-
getaddrinfo = mock.Mock()
6-
socket = mock.Mock()
7-
set_interface = mock.Mock()
4+
class MocketPool:
5+
SOCK_STREAM = 0
86

9-
interface = mock.MagicMock()
7+
def __init__(self):
8+
self.getaddrinfo = mock.Mock()
9+
self.socket = mock.Mock()
1010

1111

1212
class Mocket:
@@ -17,6 +17,7 @@ def __init__(self, response):
1717
self.send = mock.Mock()
1818
self.readline = mock.Mock(side_effect=self._readline)
1919
self.recv = mock.Mock(side_effect=self._recv)
20+
self.recv_into = mock.Mock(side_effect=self._recv_into)
2021
self._response = response
2122
self._position = 0
2223

@@ -31,3 +32,22 @@ def _recv(self, count):
3132
r = self._response[self._position : end]
3233
self._position = end
3334
return r
35+
36+
def _recv_into(self, buf, nbytes=0):
37+
assert isinstance(nbytes, int) and nbytes >= 0
38+
read = nbytes if nbytes > 0 else len(buf)
39+
remaining = len(self._response) - self._position
40+
if read > remaining:
41+
read = remaining
42+
end = self._position + read
43+
buf[:read] = self._response[self._position : end]
44+
self._position = end
45+
return read
46+
47+
48+
class SSLContext:
49+
def __init__(self):
50+
self.wrap_socket = mock.Mock(side_effect=self._wrap_socket)
51+
52+
def _wrap_socket(self, sock, server_hostname=None):
53+
return sock

‎tests/parse_test.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@
77
host = "httpbin.org"
88
response = {"Date": "July 25, 2019"}
99
encoded = json.dumps(response).encode("utf-8")
10-
headers = "HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n".format(len(encoded)).encode(
10+
# Padding here tests the case where a header line is exactly 32 bytes buffered by
11+
# aligning the Content-Type header after it.
12+
headers = "HTTP/1.0 200 OK\r\npadding: 000\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n".format(
13+
len(encoded)
14+
).encode(
1115
"utf-8"
1216
)
1317

1418

1519
def test_json():
16-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
20+
pool = mocket.MocketPool()
21+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
1722
sock = mocket.Mocket(headers + encoded)
18-
mocket.socket.return_value = sock
23+
pool.socket.return_value = sock
1924

20-
adafruit_requests.set_socket(mocket, mocket.interface)
21-
r = adafruit_requests.get("http://" + host + "/get")
22-
sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE)
25+
s = adafruit_requests.Session(pool)
26+
r = s.get("http://" + host + "/get")
27+
sock.connect.assert_called_once_with((ip, 80))
2328
assert r.json() == response

‎tests/post_test.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,53 @@
1313

1414

1515
def test_method():
16-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
16+
pool = mocket.MocketPool()
17+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
1718
sock = mocket.Mocket(headers + encoded)
18-
mocket.socket.return_value = sock
19+
pool.socket.return_value = sock
1920

20-
adafruit_requests.set_socket(mocket, mocket.interface)
21-
r = adafruit_requests.post("http://" + host + "/post")
22-
sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE)
21+
s = adafruit_requests.Session(pool)
22+
r = s.post("http://" + host + "/post")
23+
sock.connect.assert_called_once_with((ip, 80))
2324
sock.send.assert_has_calls(
24-
[mock.call(b"POST /post HTTP/1.0\r\n"), mock.call(b"Host: httpbin.org\r\n")]
25+
[mock.call(b"POST /post HTTP/1.1\r\n"), mock.call(b"Host: httpbin.org\r\n")]
2526
)
2627

2728

2829
def test_string():
29-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
30+
pool = mocket.MocketPool()
31+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
3032
sock = mocket.Mocket(headers + encoded)
31-
mocket.socket.return_value = sock
33+
pool.socket.return_value = sock
3234

33-
adafruit_requests.set_socket(mocket, mocket.interface)
35+
s = adafruit_requests.Session(pool)
3436
data = "31F"
35-
r = adafruit_requests.post("http://" + host + "/post", data=data)
36-
sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE)
37+
r = s.post("http://" + host + "/post", data=data)
38+
sock.connect.assert_called_once_with((ip, 80))
3739
sock.send.assert_called_with(b"31F")
3840

3941

42+
def test_form():
43+
pool = mocket.MocketPool()
44+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
45+
sock = mocket.Mocket(headers + encoded)
46+
pool.socket.return_value = sock
47+
48+
s = adafruit_requests.Session(pool)
49+
data = {"Date": "July 25, 2019"}
50+
r = s.post("http://" + host + "/post", data=data)
51+
sock.connect.assert_called_once_with((ip, 80))
52+
sock.send.assert_called_with(b"Date=July 25, 2019")
53+
54+
4055
def test_json():
41-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
56+
pool = mocket.MocketPool()
57+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
4258
sock = mocket.Mocket(headers + encoded)
43-
mocket.socket.return_value = sock
59+
pool.socket.return_value = sock
4460

45-
adafruit_requests.set_socket(mocket, mocket.interface)
61+
s = adafruit_requests.Session(pool)
4662
json_data = {"Date": "July 25, 2019"}
47-
r = adafruit_requests.post("http://" + host + "/post", json=json_data)
48-
sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE)
63+
r = s.post("http://" + host + "/post", json=json_data)
64+
sock.connect.assert_called_once_with((ip, 80))
4965
sock.send.assert_called_with(b'{"Date": "July 25, 2019"}')

‎tests/protocol_test.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from unittest import mock
22
import mocket
3+
import pytest
34
import adafruit_requests
45

56
ip = "1.2.3.4"
@@ -9,40 +10,54 @@
910
response = b"HTTP/1.0 200 OK\r\nContent-Length: 70\r\n\r\n" + text
1011

1112

13+
def test_get_https_no_ssl():
14+
pool = mocket.MocketPool()
15+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
16+
sock = mocket.Mocket(response)
17+
pool.socket.return_value = sock
18+
19+
s = adafruit_requests.Session(pool)
20+
with pytest.raises(RuntimeError):
21+
r = s.get("https://" + host + path)
22+
23+
1224
def test_get_https_text():
13-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
25+
pool = mocket.MocketPool()
26+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
1427
sock = mocket.Mocket(response)
15-
mocket.socket.return_value = sock
28+
pool.socket.return_value = sock
29+
ssl = mocket.SSLContext()
1630

17-
adafruit_requests.set_socket(mocket, mocket.interface)
18-
r = adafruit_requests.get("https://" + host + path)
31+
s = adafruit_requests.Session(pool, ssl)
32+
r = s.get("https://" + host + path)
1933

20-
sock.connect.assert_called_once_with((host, 443), mocket.interface.TLS_MODE)
34+
sock.connect.assert_called_once_with((host, 443))
2135
sock.send.assert_has_calls(
2236
[
23-
mock.call(b"GET /testwifi/index.html HTTP/1.0\r\n"),
37+
mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
2438
mock.call(b"Host: wifitest.adafruit.com\r\n"),
2539
]
2640
)
2741
assert r.text == str(text, "utf-8")
2842

43+
# Close isn't needed but can be called to release the socket early.
44+
r.close()
45+
2946

3047
def test_get_http_text():
31-
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
48+
pool = mocket.MocketPool()
49+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
3250
sock = mocket.Mocket(response)
33-
mocket.socket.return_value = sock
51+
pool.socket.return_value = sock
3452

35-
adafruit_requests.set_socket(mocket, mocket.interface)
36-
r = adafruit_requests.get("http://" + host + path)
53+
s = adafruit_requests.Session(pool)
54+
r = s.get("http://" + host + path)
3755

38-
sock.connect.assert_called_once_with((ip, 80), mocket.interface.TCP_MODE)
56+
sock.connect.assert_called_once_with((ip, 80))
3957
sock.send.assert_has_calls(
4058
[
41-
mock.call(b"GET /testwifi/index.html HTTP/1.0\r\n"),
59+
mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
4260
mock.call(b"Host: wifitest.adafruit.com\r\n"),
4361
]
4462
)
4563
assert r.text == str(text, "utf-8")
46-
47-
48-
# Add a chunked response test when we support HTTP 1.1

‎tests/reuse_test.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from unittest import mock
2+
import mocket
3+
import pytest
4+
import adafruit_requests
5+
6+
ip = "1.2.3.4"
7+
host = "wifitest.adafruit.com"
8+
host2 = "wifitest2.adafruit.com"
9+
path = "/testwifi/index.html"
10+
text = b"This is a test of Adafruit WiFi!\r\nIf you can read this, its working :)"
11+
response = b"HTTP/1.0 200 OK\r\nContent-Length: 70\r\n\r\n" + text
12+
13+
# def test_get_twice():
14+
# pool = mocket.MocketPool()
15+
# pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
16+
# sock = mocket.Mocket(response + response)
17+
# pool.socket.return_value = sock
18+
# ssl = mocket.SSLContext()
19+
20+
# s = adafruit_requests.Session(pool, ssl)
21+
# r = s.get("https://" + host + path)
22+
23+
# sock.send.assert_has_calls(
24+
# [
25+
# mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
26+
# mock.call(b"Host: wifitest.adafruit.com\r\n"),
27+
# ]
28+
# )
29+
# assert r.text == str(text, "utf-8")
30+
31+
# r = s.get("https://" + host + path + "2")
32+
# sock.send.assert_has_calls(
33+
# [
34+
# mock.call(b"GET /testwifi/index.html2 HTTP/1.1\r\n"),
35+
# mock.call(b"Host: wifitest.adafruit.com\r\n"),
36+
# ]
37+
# )
38+
39+
# assert r.text == str(text, "utf-8")
40+
# sock.connect.assert_called_once_with((host, 443))
41+
# pool.socket.assert_called_once()
42+
43+
44+
def test_get_twice_after_second():
45+
pool = mocket.MocketPool()
46+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
47+
sock = mocket.Mocket(response + response)
48+
pool.socket.return_value = sock
49+
ssl = mocket.SSLContext()
50+
51+
s = adafruit_requests.Session(pool, ssl)
52+
r = s.get("https://" + host + path)
53+
54+
sock.send.assert_has_calls(
55+
[
56+
mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
57+
mock.call(b"Host: wifitest.adafruit.com\r\n"),
58+
]
59+
)
60+
61+
r2 = s.get("https://" + host + path + "2")
62+
sock.send.assert_has_calls(
63+
[
64+
mock.call(b"GET /testwifi/index.html2 HTTP/1.1\r\n"),
65+
mock.call(b"Host: wifitest.adafruit.com\r\n"),
66+
]
67+
)
68+
sock.connect.assert_called_once_with((host, 443))
69+
pool.socket.assert_called_once()
70+
71+
with pytest.raises(RuntimeError):
72+
r.text == str(text, "utf-8")
73+
74+
75+
def test_connect_out_of_memory():
76+
pool = mocket.MocketPool()
77+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
78+
sock = mocket.Mocket(response)
79+
sock2 = mocket.Mocket(response)
80+
sock3 = mocket.Mocket(response)
81+
pool.socket.side_effect = [sock, sock2, sock3]
82+
sock2.connect.side_effect = MemoryError()
83+
ssl = mocket.SSLContext()
84+
85+
s = adafruit_requests.Session(pool, ssl)
86+
r = s.get("https://" + host + path)
87+
88+
sock.send.assert_has_calls(
89+
[
90+
mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
91+
mock.call(b"Host: wifitest.adafruit.com\r\n"),
92+
]
93+
)
94+
assert r.text == str(text, "utf-8")
95+
96+
r = s.get("https://" + host2 + path)
97+
sock3.send.assert_has_calls(
98+
[
99+
mock.call(b"GET /testwifi/index.html HTTP/1.1\r\n"),
100+
mock.call(b"Host: wifitest2.adafruit.com\r\n"),
101+
]
102+
)
103+
104+
assert r.text == str(text, "utf-8")
105+
sock.close.assert_called_once()
106+
sock.connect.assert_called_once_with((host, 443))
107+
sock3.connect.assert_called_once_with((host2, 443))

0 commit comments

Comments
 (0)
Please sign in to comment.