Skip to content

Commit 6902362

Browse files
committed
tests/net_hosted: Improve and simplify non-block-xfer test.
CPython changed its non-blocking socket behaviour recently and this test would not run under CPython anymore. So the following steps were taken to get the test working again and then simplify it: - Run the test against CPython 3.10.10 and capture the output into the .exp file for the test. - Run this test on unix port of MicroPython and verify that the output matches the CPython 3.10.10 output in the new .exp file (it did). From now on take unix MicroPython as the source of truth for this test when modifying it. - Remove all code that was there for CPython compatibility. - Make it print out more useful information during the test run, including names of the OSError errno values. - Add polling of the socket before the send/write/recv/read to verify that the poll gives the correct result in non-blocking mode. Tested on unix MicroPython, ESP32_GENERIC, PYBD_SF2 and RPI_PICO_W boards. Signed-off-by: Damien George <[email protected]>
1 parent eab2869 commit 6902362

File tree

2 files changed

+94
-80
lines changed

2 files changed

+94
-80
lines changed
Lines changed: 50 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
# test that socket.connect() on a non-blocking socket raises EINPROGRESS
22
# and that an immediate write/send/read/recv does the right thing
33

4-
import sys, time, socket, errno, ssl
4+
import errno
5+
import select
6+
import socket
7+
import ssl
58

6-
isMP = sys.implementation.name == "micropython"
9+
# only mbedTLS supports non-blocking mode
10+
if not hasattr(ssl, "MBEDTLS_VERSION"):
11+
print("SKIP")
12+
raise SystemExit
713

814

9-
def dp(e):
10-
# uncomment next line for development and testing, to print the actual exceptions
11-
# print(repr(e))
12-
pass
15+
# get the name of an errno error code
16+
def errno_name(er):
17+
if er == errno.EAGAIN:
18+
return "EAGAIN"
19+
if er == errno.EINPROGRESS:
20+
return "EINPROGRESS"
21+
return er
1322

1423

1524
# do_connect establishes the socket and wraps it if tls is True.
@@ -22,112 +31,75 @@ def do_connect(peer_addr, tls, handshake):
2231
# print("Connecting to", peer_addr)
2332
s.connect(peer_addr)
2433
except OSError as er:
25-
print("connect:", er.errno == errno.EINPROGRESS)
26-
if er.errno != errno.EINPROGRESS:
27-
print(" got", er.errno)
34+
print("connect:", errno_name(er.errno))
2835
# wrap with ssl/tls if desired
2936
if tls:
3037
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
31-
if hasattr(ssl_context, "check_hostname"):
32-
ssl_context.check_hostname = False
33-
3438
try:
3539
s = ssl_context.wrap_socket(s, do_handshake_on_connect=handshake)
36-
print("wrap: True")
40+
print("wrap ok: True")
3741
except Exception as e:
38-
dp(e)
39-
print("wrap:", e)
40-
elif handshake:
41-
# just sleep a little bit, this allows any connect() errors to happen
42-
time.sleep(0.2)
42+
print("wrap er:", e)
4343
return s
4444

4545

46+
# poll a socket and print out the result
47+
def poll(s):
48+
poller = select.poll()
49+
poller.register(s)
50+
print("poll: ", poller.poll(0))
51+
52+
4653
# test runs the test against a specific peer address.
47-
def test(peer_addr, tls=False, handshake=False):
48-
# MicroPython plain sockets have read/write, but CPython's don't
49-
# MicroPython TLS sockets and CPython's have read/write
50-
# hasRW captures this wonderful state of affairs
51-
hasRW = isMP or tls
54+
def test(peer_addr, tls, handshake):
55+
# MicroPython plain and TLS sockets have read/write
56+
hasRW = True
5257

53-
# MicroPython plain sockets and CPython's have send/recv
54-
# MicroPython TLS sockets don't have send/recv, but CPython's do
55-
# hasSR captures this wonderful state of affairs
56-
hasSR = not (isMP and tls)
58+
# MicroPython plain sockets have send/recv
59+
# MicroPython TLS sockets don't have send/recv
60+
hasSR = not tls
5761

5862
# connect + send
63+
# non-blocking send should raise EAGAIN
5964
if hasSR:
6065
s = do_connect(peer_addr, tls, handshake)
61-
# send -> 4 or EAGAIN
66+
poll(s)
6267
try:
6368
ret = s.send(b"1234")
64-
print("send:", handshake and ret == 4)
69+
print("send ok:", ret) # shouldn't get here
6570
except OSError as er:
66-
#
67-
dp(er)
68-
print("send:", er.errno in (errno.EAGAIN, errno.EINPROGRESS))
71+
print("send er:", errno_name(er.errno))
6972
s.close()
70-
else: # fake it...
71-
print("connect:", True)
72-
if tls:
73-
print("wrap:", True)
74-
print("send:", True)
7573

7674
# connect + write
75+
# non-blocking write should return None
7776
if hasRW:
7877
s = do_connect(peer_addr, tls, handshake)
79-
# write -> None
80-
try:
81-
ret = s.write(b"1234")
82-
print("write:", ret in (4, None)) # SSL may accept 4 into buffer
83-
except OSError as er:
84-
dp(er)
85-
print("write:", False) # should not raise
86-
except ValueError as er: # CPython
87-
dp(er)
88-
print("write:", er.args[0] == "Write on closed or unwrapped SSL socket.")
78+
poll(s)
79+
ret = s.write(b"1234")
80+
print("write: ", ret)
8981
s.close()
90-
else: # fake it...
91-
print("connect:", True)
92-
if tls:
93-
print("wrap:", True)
94-
print("write:", True)
9582

83+
# connect + recv
84+
# non-blocking recv should raise EAGAIN
9685
if hasSR:
97-
# connect + recv
9886
s = do_connect(peer_addr, tls, handshake)
99-
# recv -> EAGAIN
87+
poll(s)
10088
try:
101-
print("recv:", s.recv(10))
89+
ret = s.recv(10)
90+
print("recv ok:", ret) # shouldn't get here
10291
except OSError as er:
103-
dp(er)
104-
print("recv:", er.errno == errno.EAGAIN)
92+
print("recv er:", errno_name(er.errno))
10593
s.close()
106-
else: # fake it...
107-
print("connect:", True)
108-
if tls:
109-
print("wrap:", True)
110-
print("recv:", True)
11194

11295
# connect + read
96+
# non-blocking read should return None
11397
if hasRW:
11498
s = do_connect(peer_addr, tls, handshake)
115-
# read -> None
116-
try:
117-
ret = s.read(10)
118-
print("read:", ret is None)
119-
except OSError as er:
120-
dp(er)
121-
print("read:", False) # should not raise
122-
except ValueError as er: # CPython
123-
dp(er)
124-
print("read:", er.args[0] == "Read on closed or unwrapped SSL socket.")
99+
poll(s)
100+
ret = s.read(10)
101+
print("read: ", ret)
125102
s.close()
126-
else: # fake it...
127-
print("connect:", True)
128-
if tls:
129-
print("wrap:", True)
130-
print("read:", True)
131103

132104

133105
if __name__ == "__main__":
@@ -136,10 +108,8 @@ def test(peer_addr, tls=False, handshake=False):
136108
print("--- Plain sockets to nowhere ---")
137109
test(socket.getaddrinfo("192.0.2.1", 80)[0][-1], False, False)
138110
print("--- SSL sockets to nowhere ---")
139-
# this test fails with AXTLS because do_handshake=False blocks on first read/write and
140-
# there it times out until the connect is aborted
141111
test(socket.getaddrinfo("192.0.2.1", 443)[0][-1], True, False)
142112
print("--- Plain sockets ---")
143-
test(socket.getaddrinfo("micropython.org", 80)[0][-1], False, True)
113+
test(socket.getaddrinfo("micropython.org", 80)[0][-1], False, False)
144114
print("--- SSL sockets ---")
145115
test(socket.getaddrinfo("micropython.org", 443)[0][-1], True, True)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--- Plain sockets to nowhere ---
2+
connect: EINPROGRESS
3+
poll: []
4+
send er: EAGAIN
5+
connect: EINPROGRESS
6+
poll: []
7+
write: None
8+
connect: EINPROGRESS
9+
poll: []
10+
recv er: EAGAIN
11+
connect: EINPROGRESS
12+
poll: []
13+
read: None
14+
--- SSL sockets to nowhere ---
15+
connect: EINPROGRESS
16+
wrap ok: True
17+
poll: []
18+
write: None
19+
connect: EINPROGRESS
20+
wrap ok: True
21+
poll: []
22+
read: None
23+
--- Plain sockets ---
24+
connect: EINPROGRESS
25+
poll: []
26+
send er: EAGAIN
27+
connect: EINPROGRESS
28+
poll: []
29+
write: None
30+
connect: EINPROGRESS
31+
poll: []
32+
recv er: EAGAIN
33+
connect: EINPROGRESS
34+
poll: []
35+
read: None
36+
--- SSL sockets ---
37+
connect: EINPROGRESS
38+
wrap ok: True
39+
poll: [(<SSLSocket>, 4)]
40+
write: 4
41+
connect: EINPROGRESS
42+
wrap ok: True
43+
poll: [(<SSLSocket>, 4)]
44+
read: None

0 commit comments

Comments
 (0)