Skip to content

Commit 650862f

Browse files
committed
add xfail test case for #175
1 parent ad40220 commit 650862f

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

tests/test_connection.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@
3737
import pytest
3838
import trio
3939
import trustme
40+
import wsproto
4041
from trio.testing import memory_stream_pair
4142
from wsproto.events import CloseConnection
43+
from wsproto.utilities import LocalProtocolError
4244

4345
try:
4446
from trio.lowlevel import current_task # pylint: disable=ungrouped-imports
@@ -63,6 +65,7 @@
6365
wrap_server_stream
6466
)
6567

68+
WS_PROTO_VERSION = tuple(map(int, wsproto.__version__.split('.')))
6669

6770
HOST = '127.0.0.1'
6871
RESOURCE = '/resource'
@@ -904,7 +907,7 @@ async def handler(request):
904907
assert client.closed.code == 1009
905908

906909

907-
async def test_close_race(nursery, autojump_clock):
910+
async def test_server_close_client_disconnect_race(nursery, autojump_clock):
908911
"""server attempts close just as client disconnects (issue #96)"""
909912

910913
async def handler(request: WebSocketRequest):
@@ -925,6 +928,40 @@ async def handler(request: WebSocketRequest):
925928
await trio.sleep(.1)
926929

927930

931+
@pytest.mark.xfail(
932+
reason='send_message() API oversight for closing-in-process case',
933+
raises=None if WS_PROTO_VERSION < (1, 2, 0) else LocalProtocolError,
934+
strict=True)
935+
async def test_remote_close_local_message_race(nursery, autojump_clock):
936+
"""as remote initiates close, local attempts message (issue #175)
937+
938+
This exposes multiple problems in the trio-websocket API and implementation:
939+
* send_message() silently fails if a close is in progress. This was
940+
likely an oversight in the API, since send_message() raises `ConnectionClosed`
941+
only in the already-closed case, yet `ConnectionClosed` is defined to cover
942+
"in the process of closing".
943+
* with wsproto >= 1.2.0, LocalProtocolError will be leaked
944+
"""
945+
946+
async def handler(request: WebSocketRequest):
947+
ws = await request.accept()
948+
await ws.get_message()
949+
await ws.aclose()
950+
951+
server = await nursery.start(
952+
partial(serve_websocket, handler, HOST, 0, ssl_context=None))
953+
954+
client = await connect_websocket(nursery, HOST, server.port,
955+
RESOURCE, use_ssl=False)
956+
client._for_testing_peer_closed_connection = trio.Event()
957+
await client.send_message('foo')
958+
await client._for_testing_peer_closed_connection.wait()
959+
with pytest.raises(ConnectionClosed):
960+
await client.send_message('bar') # wsproto < 1.2.0: silently ignored
961+
# wsproto >= 1.2.0: raises LocalProtocolError
962+
# desired: raises ConnectionClosed
963+
964+
928965
@fail_after(DEFAULT_TEST_MAX_DURATION)
929966
async def test_server_tcp_closed_on_close_connection_event(nursery):
930967
"""ensure server closes TCP immediately after receiving CloseConnection"""

0 commit comments

Comments
 (0)