@@ -394,11 +394,15 @@ async def test_checkout_more_than_max_pool_size(self):
394394 await asyncio .sleep (0.05 )
395395 await pool .close ()
396396
397- async def test_maxConnecting (self ):
398- client = await self .async_rs_or_single_client ()
399- await self .client .test .test .insert_one ({})
400- self .addAsyncCleanup (self .client .test .test .delete_many , {})
397+ async def _check_maxConnecting (
398+ self , client : AsyncMongoClient , backoff = False
399+ ) -> tuple [int , int ]:
400+ await client .test .test .insert_one ({})
401+
402+ self .addAsyncCleanup (client .test .test .delete_many , {})
401403 pool = await async_get_pool (client )
404+ if backoff :
405+ pool ._backoff = 1
402406 docs = []
403407
404408 # Run 50 short running operations
@@ -411,23 +415,29 @@ async def find_one():
411415 for task in tasks :
412416 await task .join (10 )
413417
414- self .assertEqual (len (docs ), 50 )
415- self .assertLessEqual (len (pool .conns ), 50 )
418+ return len (docs ), len (pool .conns )
419+
420+ async def test_maxConnecting (self ):
421+ client = await self .async_rs_or_single_client ()
422+ num_docs , num_conns = await self ._check_maxConnecting (client )
423+
424+ self .assertEqual (num_docs , 50 )
425+ self .assertLessEqual (num_conns , 50 )
416426 # TLS and auth make connection establishment more expensive than
417427 # the query which leads to more threads hitting maxConnecting.
418428 # The end result is fewer total connections and better latency.
419429 if async_client_context .tls and async_client_context .auth_enabled :
420- self .assertLessEqual (len ( pool . conns ) , 30 )
430+ self .assertLessEqual (num_conns , 30 )
421431 else :
422- self .assertLessEqual (len ( pool . conns ) , 50 )
432+ self .assertLessEqual (num_conns , 50 )
423433 # MongoDB 4.4.1 with auth + ssl:
424434 # maxConnecting = 2: 6 connections in ~0.231+ seconds
425435 # maxConnecting = unbounded: 50 connections in ~0.642+ seconds
426436 #
427437 # MongoDB 4.4.1 with no-auth no-ssl Python 3.8:
428438 # maxConnecting = 2: 15-22 connections in ~0.108+ seconds
429439 # maxConnecting = unbounded: 30+ connections in ~0.140+ seconds
430- print (len ( pool . conns ) )
440+ print (num_conns )
431441
432442 @async_client_context .require_failCommand_appName
433443 async def test_csot_timeout_message (self ):
@@ -513,8 +523,33 @@ async def test_connection_timeout_message(self):
513523 str (error .exception ),
514524 )
515525
526+ async def test_pool_check_backoff (self ):
527+ # Test that Pool recovers from two connection failures in a row.
528+ # This exercises code at the end of Pool._check().
529+ cx_pool = await self .create_pool (max_pool_size = 1 , connect_timeout = 1 , wait_queue_timeout = 1 )
530+ self .addAsyncCleanup (cx_pool .close )
531+
532+ async with cx_pool .checkout () as conn :
533+ # Simulate a closed socket without telling the Connection it's
534+ # closed.
535+ await conn .conn .close ()
536+
537+ # Enable backoff.
538+ cx_pool ._backoff = 1
539+
540+ # Swap pool's address with a bad one.
541+ address , cx_pool .address = cx_pool .address , ("foo.com" , 1234 )
542+ with self .assertRaises (AutoReconnect ):
543+ async with cx_pool .checkout ():
544+ pass
545+
546+ # Back to normal, semaphore was correctly released.
547+ cx_pool .address = address
548+ async with cx_pool .checkout ():
549+ pass
550+
516551 @async_client_context .require_failCommand_appName
517- async def test_pool_backoff_preserves_existing_collections (self ):
552+ async def test_pool_backoff_preserves_existing_connections (self ):
518553 client = await self .async_rs_or_single_client ()
519554 coll = self .db .t
520555 pool = await async_get_pool (client )
@@ -549,30 +584,17 @@ async def test_pool_backoff_preserves_existing_collections(self):
549584 await t .join ()
550585 await pool .close ()
551586
552- async def test_pool_check_backoff (self ):
553- # Test that Pool recovers from two connection failures in a row.
554- # This exercises code at the end of Pool._check().
555- cx_pool = await self .create_pool (max_pool_size = 1 , connect_timeout = 1 , wait_queue_timeout = 1 )
556- self .addAsyncCleanup (cx_pool .close )
557-
558- async with cx_pool .checkout () as conn :
559- # Simulate a closed socket without telling the Connection it's
560- # closed.
561- await conn .conn .close ()
562-
563- # Enable backoff.
564- cx_pool ._backoff = 1
587+ async def test_pool_backoff_limits_maxConnecting (self ):
588+ client = await self .async_rs_or_single_client ()
589+ _ , baseline_conns = await self ._check_maxConnecting (client )
590+ client .close ()
565591
566- # Swap pool's address with a bad one.
567- address , cx_pool .address = cx_pool .address , ("foo.com" , 1234 )
568- with self .assertRaises (AutoReconnect ):
569- async with cx_pool .checkout ():
570- pass
592+ client = await self .async_rs_or_single_client ()
593+ _ , backoff_conns = await self ._check_maxConnecting (client , backoff = True )
594+ client .close ()
571595
572- # Back to normal, semaphore was correctly released.
573- cx_pool .address = address
574- async with cx_pool .checkout ():
575- pass
596+ # We should have created less conns due to limiting maxConnecting.
597+ self .assertLess (backoff_conns , baseline_conns )
576598
577599
578600class TestPoolMaxSize (_TestPoolingBase ):
0 commit comments