53
53
54
54
HOST = '127.0.0.1'
55
55
RESOURCE = '/resource'
56
+ DEFAULT_TEST_MAX_DURATION = 1
56
57
57
58
# Timeout tests follow a general pattern: one side waits TIMEOUT seconds for an
58
59
# event. The other side delays for FORCE_TIMEOUT seconds to force the timeout
59
60
# to trigger. Each test also has maximum runtime (measure by Trio's clock) to
60
61
# prevent a faulty test from hanging the entire suite.
61
62
TIMEOUT = 1
62
63
FORCE_TIMEOUT = 2
63
- MAX_TIMEOUT_TEST_DURATION = 3
64
+ TIMEOUT_TEST_MAX_DURATION = 3
64
65
65
66
66
67
@pytest .fixture
@@ -89,12 +90,6 @@ async def echo_request_handler(request):
89
90
Accept incoming request and then pass off to echo connection handler.
90
91
'''
91
92
conn = await request .accept ()
92
- await echo_conn_handler (conn )
93
-
94
-
95
- async def echo_conn_handler (conn ):
96
- ''' A connection handler that reads one message, sends back the same
97
- message, then exits. '''
98
93
try :
99
94
msg = await conn .get_message ()
100
95
await conn .send_message (msg )
@@ -391,7 +386,7 @@ async def handler(stream):
391
386
await client .send_message ('Hello from client!' )
392
387
393
388
394
- @fail_after (MAX_TIMEOUT_TEST_DURATION )
389
+ @fail_after (TIMEOUT_TEST_MAX_DURATION )
395
390
async def test_client_open_timeout (nursery , autojump_clock ):
396
391
'''
397
392
The client times out waiting for the server to complete the opening
@@ -411,7 +406,7 @@ async def handler(request):
411
406
pass
412
407
413
408
414
- @fail_after (MAX_TIMEOUT_TEST_DURATION )
409
+ @fail_after (TIMEOUT_TEST_MAX_DURATION )
415
410
async def test_client_close_timeout (nursery , autojump_clock ):
416
411
'''
417
412
This client times out waiting for the server to complete the closing
@@ -430,15 +425,16 @@ async def handler(request):
430
425
pytest .fail ('Should not reach this line.' )
431
426
432
427
server = await nursery .start (
433
- partial (serve_websocket , handler , HOST , 0 , ssl_context = None ))
428
+ partial (serve_websocket , handler , HOST , 0 , ssl_context = None ,
429
+ message_queue_size = 0 ))
434
430
435
431
with pytest .raises (trio .TooSlowError ):
436
432
async with open_websocket (HOST , server .port , RESOURCE , use_ssl = False ,
437
433
disconnect_timeout = TIMEOUT ) as client_ws :
438
434
await client_ws .send_message ('test' )
439
435
440
436
441
- @fail_after (MAX_TIMEOUT_TEST_DURATION )
437
+ @fail_after (TIMEOUT_TEST_MAX_DURATION )
442
438
async def test_server_open_timeout (autojump_clock ):
443
439
'''
444
440
The server times out waiting for the client to complete the opening
@@ -470,7 +466,7 @@ async def handler(request):
470
466
nursery .cancel_scope .cancel ()
471
467
472
468
473
- @fail_after (MAX_TIMEOUT_TEST_DURATION )
469
+ @fail_after (TIMEOUT_TEST_MAX_DURATION )
474
470
async def test_server_close_timeout (autojump_clock ):
475
471
'''
476
472
The server times out waiting for the client to complete the closing
@@ -488,7 +484,7 @@ async def handler(request):
488
484
ws = await request .accept ()
489
485
# Send one message to block the client's reader task:
490
486
await ws .send_message ('test' )
491
- import logging
487
+
492
488
async with trio .open_nursery () as outer :
493
489
server = await outer .start (partial (serve_websocket , handler , HOST , 0 ,
494
490
ssl_context = None , handler_nursery = outer ,
@@ -523,7 +519,6 @@ async def handler(request):
523
519
with pytest .raises (ConnectionClosed ):
524
520
await server_ws .get_message ()
525
521
server = await nursery .start (serve_websocket , handler , HOST , 0 , None )
526
- port = server .port
527
522
stream = await trio .open_tcp_stream (HOST , server .port )
528
523
client_ws = await wrap_client_stream (nursery , stream , HOST , RESOURCE )
529
524
async with client_ws :
@@ -566,12 +561,14 @@ async def handler(request):
566
561
assert exc .reason .name == 'NORMAL_CLOSURE'
567
562
568
563
569
- @pytest . mark . skip ( reason = 'Hangs because channel size is hard coded to 0' )
564
+ @fail_after ( DEFAULT_TEST_MAX_DURATION )
570
565
async def test_read_messages_after_remote_close (nursery ):
571
566
'''
572
567
When the remote endpoint closes, the local endpoint can still read all
573
568
of the messages sent prior to closing. Any attempt to read beyond that will
574
569
raise ConnectionClosed.
570
+
571
+ This test also exercises the configuration of the queue size.
575
572
'''
576
573
server_closed = trio .Event ()
577
574
@@ -585,7 +582,10 @@ async def handler(request):
585
582
server = await nursery .start (
586
583
partial (serve_websocket , handler , HOST , 0 , ssl_context = None ))
587
584
588
- async with open_websocket (HOST , server .port , '/' , use_ssl = False ) as client :
585
+ # The client needs a message queue of size 2 so that it can buffer both
586
+ # incoming messages without blocking the reader task.
587
+ async with open_websocket (HOST , server .port , '/' , use_ssl = False ,
588
+ message_queue_size = 2 ) as client :
589
589
await server_closed .wait ()
590
590
assert await client .get_message () == '1'
591
591
assert await client .get_message () == '2'
@@ -618,12 +618,49 @@ async def handler(request):
618
618
client_closed .set ()
619
619
620
620
621
- async def test_client_cm_exit_with_pending_messages (echo_server , autojump_clock ):
621
+ async def test_cm_exit_with_pending_messages (echo_server , autojump_clock ):
622
+ '''
623
+ Regression test for #74, where a context manager was not able to exit when
624
+ there were pending messages in the receive queue.
625
+ '''
622
626
with trio .fail_after (1 ):
623
627
async with open_websocket (HOST , echo_server .port , RESOURCE ,
624
628
use_ssl = False ) as ws :
625
629
await ws .send_message ('hello' )
626
630
# allow time for the server to respond
627
631
await trio .sleep (.1 )
628
- # bug: context manager exit is blocked on unconsumed message
629
- #await ws.get_message()
632
+
633
+
634
+ @fail_after (DEFAULT_TEST_MAX_DURATION )
635
+ async def test_max_message_size (nursery ):
636
+ '''
637
+ Set the client's max message size to 100 bytes. The client can send a
638
+ message larger than 100 bytes, but when it receives a message larger than
639
+ 100 bytes, it closes the connection with code 1009.
640
+ '''
641
+ async def handler (request ):
642
+ ''' Similar to the echo_request_handler fixture except it runs in a
643
+ loop. '''
644
+ conn = await request .accept ()
645
+ while True :
646
+ try :
647
+ msg = await conn .get_message ()
648
+ await conn .send_message (msg )
649
+ except ConnectionClosed :
650
+ break
651
+
652
+ server = await nursery .start (
653
+ partial (serve_websocket , handler , HOST , 0 , ssl_context = None ))
654
+
655
+ async with open_websocket (HOST , server .port , RESOURCE , use_ssl = False ,
656
+ max_message_size = 100 ) as client :
657
+ # We can send and receive 100 bytes:
658
+ await client .send_message (b'A' * 100 )
659
+ msg = await client .get_message ()
660
+ assert len (msg ) == 100
661
+ # We can send 101 bytes but cannot receive 101 bytes:
662
+ await client .send_message (b'B' * 101 )
663
+ with pytest .raises (ConnectionClosed ):
664
+ await client .get_message ()
665
+ assert client .closed
666
+ assert client .closed .code == 1009
0 commit comments