Updated script that can be controled by Nodejs web app
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
import errno
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import trio
|
||||
from trio.testing._fake_net import FakeNet
|
||||
|
||||
# ENOTCONN gives different messages on different platforms
|
||||
if sys.platform == "linux":
|
||||
ENOTCONN_MSG = r"^\[Errno 107\] (Transport endpoint is|Socket) not connected$"
|
||||
elif sys.platform == "darwin":
|
||||
ENOTCONN_MSG = r"^\[Errno 57\] Socket is not connected$"
|
||||
else:
|
||||
ENOTCONN_MSG = r"^\[Errno 10057\] Unknown error$"
|
||||
|
||||
|
||||
def fn() -> FakeNet:
|
||||
fn = FakeNet()
|
||||
fn.enable()
|
||||
return fn
|
||||
|
||||
|
||||
async def test_basic_udp() -> None:
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
s2 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
|
||||
await s1.bind(("127.0.0.1", 0))
|
||||
ip, port = s1.getsockname()
|
||||
assert ip == "127.0.0.1"
|
||||
assert port != 0
|
||||
|
||||
with pytest.raises(
|
||||
OSError,
|
||||
match=r"^\[\w+ \d+\] Invalid argument$",
|
||||
) as exc: # Cannot rebind.
|
||||
await s1.bind(("192.0.2.1", 0))
|
||||
assert exc.value.errno == errno.EINVAL
|
||||
|
||||
# Cannot bind multiple sockets to the same address
|
||||
with pytest.raises(
|
||||
OSError,
|
||||
match=r"^\[\w+ \d+\] (Address (already )?in use|Unknown error)$",
|
||||
) as exc:
|
||||
await s2.bind(("127.0.0.1", port))
|
||||
assert exc.value.errno == errno.EADDRINUSE
|
||||
|
||||
await s2.sendto(b"xyz", s1.getsockname())
|
||||
data, addr = await s1.recvfrom(10)
|
||||
assert data == b"xyz"
|
||||
assert addr == s2.getsockname()
|
||||
await s1.sendto(b"abc", s2.getsockname())
|
||||
data, addr = await s2.recvfrom(10)
|
||||
assert data == b"abc"
|
||||
assert addr == s1.getsockname()
|
||||
|
||||
|
||||
async def test_msg_trunc() -> None:
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
s2 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
await s1.bind(("127.0.0.1", 0))
|
||||
await s2.sendto(b"xyz", s1.getsockname())
|
||||
data, addr = await s1.recvfrom(10)
|
||||
|
||||
|
||||
async def test_recv_methods() -> None:
|
||||
"""Test all recv methods for codecov"""
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
s2 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
|
||||
# receiving on an unbound socket is a bad idea (I think?)
|
||||
with pytest.raises(NotImplementedError, match="code will most likely hang"):
|
||||
await s2.recv(10)
|
||||
|
||||
await s1.bind(("127.0.0.1", 0))
|
||||
ip, port = s1.getsockname()
|
||||
assert ip == "127.0.0.1"
|
||||
assert port != 0
|
||||
|
||||
# recvfrom
|
||||
await s2.sendto(b"abc", s1.getsockname())
|
||||
data, addr = await s1.recvfrom(10)
|
||||
assert data == b"abc"
|
||||
assert addr == s2.getsockname()
|
||||
|
||||
# recv
|
||||
await s1.sendto(b"def", s2.getsockname())
|
||||
data = await s2.recv(10)
|
||||
assert data == b"def"
|
||||
|
||||
# recvfrom_into
|
||||
assert await s1.sendto(b"ghi", s2.getsockname()) == 3
|
||||
buf = bytearray(10)
|
||||
|
||||
with pytest.raises(NotImplementedError, match="^partial recvfrom_into$"):
|
||||
(nbytes, addr) = await s2.recvfrom_into(buf, nbytes=2)
|
||||
|
||||
(nbytes, addr) = await s2.recvfrom_into(buf)
|
||||
assert nbytes == 3
|
||||
assert buf == b"ghi" + b"\x00" * 7
|
||||
assert addr == s1.getsockname()
|
||||
|
||||
# recv_into
|
||||
assert await s1.sendto(b"jkl", s2.getsockname()) == 3
|
||||
buf2 = bytearray(10)
|
||||
nbytes = await s2.recv_into(buf2)
|
||||
assert nbytes == 3
|
||||
assert buf2 == b"jkl" + b"\x00" * 7
|
||||
|
||||
if sys.platform == "linux" and sys.implementation.name == "cpython":
|
||||
flags: int = socket.MSG_MORE
|
||||
else:
|
||||
flags = 1
|
||||
|
||||
# Send seems explicitly non-functional
|
||||
with pytest.raises(OSError, match=ENOTCONN_MSG) as exc:
|
||||
await s2.send(b"mno")
|
||||
assert exc.value.errno == errno.ENOTCONN
|
||||
with pytest.raises(NotImplementedError, match="^FakeNet send flags must be 0, not"):
|
||||
await s2.send(b"mno", flags)
|
||||
|
||||
# sendto errors
|
||||
# it's successfully used earlier
|
||||
with pytest.raises(NotImplementedError, match="^FakeNet send flags must be 0, not"):
|
||||
await s2.sendto(b"mno", flags, s1.getsockname())
|
||||
with pytest.raises(TypeError, match="wrong number of arguments$"):
|
||||
await s2.sendto(b"mno", flags, s1.getsockname(), "extra arg") # type: ignore[call-overload]
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32",
|
||||
reason="functions not in socket on windows",
|
||||
)
|
||||
async def test_nonwindows_functionality() -> None:
|
||||
# mypy doesn't support a good way of aborting typechecking on different platforms
|
||||
if sys.platform != "win32": # pragma: no branch
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
s2 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
await s2.bind(("127.0.0.1", 0))
|
||||
|
||||
# sendmsg
|
||||
with pytest.raises(OSError, match=ENOTCONN_MSG) as exc:
|
||||
await s2.sendmsg([b"mno"])
|
||||
assert exc.value.errno == errno.ENOTCONN
|
||||
|
||||
assert await s1.sendmsg([b"jkl"], (), 0, s2.getsockname()) == 3
|
||||
(data, ancdata, msg_flags, addr) = await s2.recvmsg(10)
|
||||
assert data == b"jkl"
|
||||
assert ancdata == []
|
||||
assert msg_flags == 0
|
||||
assert addr == s1.getsockname()
|
||||
|
||||
# TODO: recvmsg
|
||||
|
||||
# recvmsg_into
|
||||
assert await s1.sendto(b"xyzw", s2.getsockname()) == 4
|
||||
buf1 = bytearray(2)
|
||||
buf2 = bytearray(3)
|
||||
ret = await s2.recvmsg_into([buf1, buf2])
|
||||
(nbytes, ancdata, msg_flags, addr) = ret
|
||||
assert nbytes == 4
|
||||
assert buf1 == b"xy"
|
||||
assert buf2 == b"zw" + b"\x00"
|
||||
assert ancdata == []
|
||||
assert msg_flags == 0
|
||||
assert addr == s1.getsockname()
|
||||
|
||||
# recvmsg_into with MSG_TRUNC set
|
||||
assert await s1.sendto(b"xyzwv", s2.getsockname()) == 5
|
||||
buf1 = bytearray(2)
|
||||
ret = await s2.recvmsg_into([buf1])
|
||||
(nbytes, ancdata, msg_flags, addr) = ret
|
||||
assert nbytes == 2
|
||||
assert buf1 == b"xy"
|
||||
assert ancdata == []
|
||||
assert msg_flags == socket.MSG_TRUNC
|
||||
assert addr == s1.getsockname()
|
||||
|
||||
with pytest.raises(
|
||||
AttributeError,
|
||||
match="^'FakeSocket' object has no attribute 'share'$",
|
||||
):
|
||||
await s1.share(0) # type: ignore[attr-defined]
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform != "win32",
|
||||
reason="windows-specific fakesocket testing",
|
||||
)
|
||||
async def test_windows_functionality() -> None:
|
||||
# mypy doesn't support a good way of aborting typechecking on different platforms
|
||||
if sys.platform == "win32": # pragma: no branch
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
s2 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
await s1.bind(("127.0.0.1", 0))
|
||||
with pytest.raises(
|
||||
AttributeError,
|
||||
match="^'FakeSocket' object has no attribute 'sendmsg'$",
|
||||
):
|
||||
await s1.sendmsg([b"jkl"], (), 0, s2.getsockname()) # type: ignore[attr-defined]
|
||||
with pytest.raises(
|
||||
AttributeError,
|
||||
match="^'FakeSocket' object has no attribute 'recvmsg'$",
|
||||
):
|
||||
s2.recvmsg(0) # type: ignore[attr-defined]
|
||||
with pytest.raises(
|
||||
AttributeError,
|
||||
match="^'FakeSocket' object has no attribute 'recvmsg_into'$",
|
||||
):
|
||||
s2.recvmsg_into([]) # type: ignore[attr-defined]
|
||||
with pytest.raises(NotImplementedError):
|
||||
s1.share(0)
|
||||
|
||||
|
||||
async def test_basic_tcp() -> None:
|
||||
fn()
|
||||
with pytest.raises(NotImplementedError):
|
||||
trio.socket.socket()
|
||||
|
||||
|
||||
async def test_not_implemented_functions() -> None:
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
|
||||
# getsockopt
|
||||
with pytest.raises(
|
||||
OSError,
|
||||
match=r"^FakeNet doesn't implement getsockopt\(\d, \d\)$",
|
||||
):
|
||||
s1.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
|
||||
|
||||
# setsockopt
|
||||
with pytest.raises(
|
||||
NotImplementedError,
|
||||
match="^FakeNet always has IPV6_V6ONLY=True$",
|
||||
):
|
||||
s1.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
with pytest.raises(
|
||||
OSError,
|
||||
match=r"^FakeNet doesn't implement setsockopt\(\d+, \d+, \.\.\.\)$",
|
||||
):
|
||||
s1.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, True)
|
||||
with pytest.raises(
|
||||
OSError,
|
||||
match=r"^FakeNet doesn't implement setsockopt\(\d+, \d+, \.\.\.\)$",
|
||||
):
|
||||
s1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# set_inheritable
|
||||
s1.set_inheritable(False)
|
||||
with pytest.raises(
|
||||
NotImplementedError,
|
||||
match="^FakeNet can't make inheritable sockets$",
|
||||
):
|
||||
s1.set_inheritable(True)
|
||||
|
||||
# get_inheritable
|
||||
assert not s1.get_inheritable()
|
||||
|
||||
|
||||
async def test_getpeername() -> None:
|
||||
fn()
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
with pytest.raises(OSError, match=ENOTCONN_MSG) as exc:
|
||||
s1.getpeername()
|
||||
assert exc.value.errno == errno.ENOTCONN
|
||||
|
||||
await s1.bind(("127.0.0.1", 0))
|
||||
|
||||
with pytest.raises(
|
||||
AssertionError,
|
||||
match="^This method seems to assume that self._binding has a remote UDPEndpoint$",
|
||||
):
|
||||
s1.getpeername()
|
||||
|
||||
|
||||
async def test_init() -> None:
|
||||
fn()
|
||||
with pytest.raises(
|
||||
NotImplementedError,
|
||||
match=re.escape(
|
||||
f"FakeNet doesn't (yet) support type={trio.socket.SOCK_STREAM}",
|
||||
),
|
||||
):
|
||||
s1 = trio.socket.socket()
|
||||
|
||||
# getsockname on unbound ipv4 socket
|
||||
s1 = trio.socket.socket(type=trio.socket.SOCK_DGRAM)
|
||||
assert s1.getsockname() == ("0.0.0.0", 0)
|
||||
|
||||
# getsockname on bound ipv4 socket
|
||||
await s1.bind(("0.0.0.0", 0))
|
||||
ip, port = s1.getsockname()
|
||||
assert ip == "127.0.0.1"
|
||||
assert port != 0
|
||||
|
||||
# getsockname on unbound ipv6 socket
|
||||
s2 = trio.socket.socket(family=socket.AF_INET6, type=socket.SOCK_DGRAM)
|
||||
assert s2.getsockname() == ("::", 0)
|
||||
|
||||
# getsockname on bound ipv6 socket
|
||||
await s2.bind(("::", 0))
|
||||
ip, port, *_ = s2.getsockname()
|
||||
assert ip == "::1"
|
||||
assert port != 0
|
||||
assert _ == [0, 0]
|
||||
Reference in New Issue
Block a user