Skip to content

Commit 6f38a9b

Browse files
committed
add test for limiting maxConnecting
1 parent 6890c73 commit 6f38a9b

File tree

2 files changed

+106
-64
lines changed

2 files changed

+106
-64
lines changed

test/asynchronous/test_pooling.py

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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

578600
class TestPoolMaxSize(_TestPoolingBase):

test/test_pooling.py

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,13 @@ def test_checkout_more_than_max_pool_size(self):
394394
time.sleep(0.05)
395395
pool.close()
396396

397-
def test_maxConnecting(self):
398-
client = self.rs_or_single_client()
399-
self.client.test.test.insert_one({})
400-
self.addCleanup(self.client.test.test.delete_many, {})
397+
def _check_maxConnecting(self, client: MongoClient, backoff=False) -> tuple[int, int]:
398+
client.test.test.insert_one({})
399+
400+
self.addCleanup(client.test.test.delete_many, {})
401401
pool = get_pool(client)
402+
if backoff:
403+
pool._backoff = 1
402404
docs = []
403405

404406
# Run 50 short running operations
@@ -411,23 +413,29 @@ def find_one():
411413
for task in tasks:
412414
task.join(10)
413415

414-
self.assertEqual(len(docs), 50)
415-
self.assertLessEqual(len(pool.conns), 50)
416+
return len(docs), len(pool.conns)
417+
418+
def test_maxConnecting(self):
419+
client = self.rs_or_single_client()
420+
num_docs, num_conns = self._check_maxConnecting(client)
421+
422+
self.assertEqual(num_docs, 50)
423+
self.assertLessEqual(num_conns, 50)
416424
# TLS and auth make connection establishment more expensive than
417425
# the query which leads to more threads hitting maxConnecting.
418426
# The end result is fewer total connections and better latency.
419427
if client_context.tls and client_context.auth_enabled:
420-
self.assertLessEqual(len(pool.conns), 30)
428+
self.assertLessEqual(num_conns, 30)
421429
else:
422-
self.assertLessEqual(len(pool.conns), 50)
430+
self.assertLessEqual(num_conns, 50)
423431
# MongoDB 4.4.1 with auth + ssl:
424432
# maxConnecting = 2: 6 connections in ~0.231+ seconds
425433
# maxConnecting = unbounded: 50 connections in ~0.642+ seconds
426434
#
427435
# MongoDB 4.4.1 with no-auth no-ssl Python 3.8:
428436
# maxConnecting = 2: 15-22 connections in ~0.108+ seconds
429437
# maxConnecting = unbounded: 30+ connections in ~0.140+ seconds
430-
print(len(pool.conns))
438+
print(num_conns)
431439

432440
@client_context.require_failCommand_appName
433441
def test_csot_timeout_message(self):
@@ -511,8 +519,33 @@ def test_connection_timeout_message(self):
511519
str(error.exception),
512520
)
513521

522+
def test_pool_check_backoff(self):
523+
# Test that Pool recovers from two connection failures in a row.
524+
# This exercises code at the end of Pool._check().
525+
cx_pool = self.create_pool(max_pool_size=1, connect_timeout=1, wait_queue_timeout=1)
526+
self.addCleanup(cx_pool.close)
527+
528+
with cx_pool.checkout() as conn:
529+
# Simulate a closed socket without telling the Connection it's
530+
# closed.
531+
conn.conn.close()
532+
533+
# Enable backoff.
534+
cx_pool._backoff = 1
535+
536+
# Swap pool's address with a bad one.
537+
address, cx_pool.address = cx_pool.address, ("foo.com", 1234)
538+
with self.assertRaises(AutoReconnect):
539+
with cx_pool.checkout():
540+
pass
541+
542+
# Back to normal, semaphore was correctly released.
543+
cx_pool.address = address
544+
with cx_pool.checkout():
545+
pass
546+
514547
@client_context.require_failCommand_appName
515-
def test_pool_backoff_preserves_existing_collections(self):
548+
def test_pool_backoff_preserves_existing_connections(self):
516549
client = self.rs_or_single_client()
517550
coll = self.db.t
518551
pool = get_pool(client)
@@ -547,30 +580,17 @@ def test_pool_backoff_preserves_existing_collections(self):
547580
t.join()
548581
pool.close()
549582

550-
def test_pool_check_backoff(self):
551-
# Test that Pool recovers from two connection failures in a row.
552-
# This exercises code at the end of Pool._check().
553-
cx_pool = self.create_pool(max_pool_size=1, connect_timeout=1, wait_queue_timeout=1)
554-
self.addCleanup(cx_pool.close)
555-
556-
with cx_pool.checkout() as conn:
557-
# Simulate a closed socket without telling the Connection it's
558-
# closed.
559-
conn.conn.close()
560-
561-
# Enable backoff.
562-
cx_pool._backoff = 1
583+
def test_pool_backoff_limits_maxConnecting(self):
584+
client = self.rs_or_single_client()
585+
_, baseline_conns = self._check_maxConnecting(client)
586+
client.close()
563587

564-
# Swap pool's address with a bad one.
565-
address, cx_pool.address = cx_pool.address, ("foo.com", 1234)
566-
with self.assertRaises(AutoReconnect):
567-
with cx_pool.checkout():
568-
pass
588+
client = self.rs_or_single_client()
589+
_, backoff_conns = self._check_maxConnecting(client, backoff=True)
590+
client.close()
569591

570-
# Back to normal, semaphore was correctly released.
571-
cx_pool.address = address
572-
with cx_pool.checkout():
573-
pass
592+
# We should have created less conns due to limiting maxConnecting.
593+
self.assertLess(backoff_conns, baseline_conns)
574594

575595

576596
class TestPoolMaxSize(_TestPoolingBase):

0 commit comments

Comments
 (0)