Skip to content

Commit 5ce53dc

Browse files
blink1073NoahStapp
andauthored
PYTHON-5374 Assert unset BulkWriteException.partialResult in CRUD prose tests (#2425)
Co-authored-by: Noah Stapp <[email protected]>
1 parent e07a6b7 commit 5ce53dc

File tree

4 files changed

+50
-30
lines changed

4 files changed

+50
-30
lines changed

test/asynchronous/test_client_bulk_write.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ async def test_formats_write_error_correctly(self):
8484

8585

8686
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
87+
# Note: tests 1 and 2 are in test_read_write_concern_spec.py
8788
class TestClientBulkWriteCRUD(AsyncIntegrationTest):
8889
async def asyncSetUp(self):
8990
await super().asyncSetUp()
@@ -92,7 +93,7 @@ async def asyncSetUp(self):
9293
self.max_message_size_bytes = await async_client_context.max_message_size_bytes
9394

9495
@async_client_context.require_version_min(8, 0, 0, -24)
95-
async def test_batch_splits_if_num_operations_too_large(self):
96+
async def test_3_batch_splits_if_num_operations_too_large(self):
9697
listener = OvertCommandListener()
9798
client = await self.async_rs_or_single_client(event_listeners=[listener])
9899

@@ -116,7 +117,7 @@ async def test_batch_splits_if_num_operations_too_large(self):
116117
self.assertEqual(first_event.operation_id, second_event.operation_id)
117118

118119
@async_client_context.require_version_min(8, 0, 0, -24)
119-
async def test_batch_splits_if_ops_payload_too_large(self):
120+
async def test_4_batch_splits_if_ops_payload_too_large(self):
120121
listener = OvertCommandListener()
121122
client = await self.async_rs_or_single_client(event_listeners=[listener])
122123

@@ -148,7 +149,7 @@ async def test_batch_splits_if_ops_payload_too_large(self):
148149

149150
@async_client_context.require_version_min(8, 0, 0, -24)
150151
@async_client_context.require_failCommand_fail_point
151-
async def test_collects_write_concern_errors_across_batches(self):
152+
async def test_5_collects_write_concern_errors_across_batches(self):
152153
listener = OvertCommandListener()
153154
client = await self.async_rs_or_single_client(
154155
event_listeners=[listener],
@@ -189,7 +190,7 @@ async def test_collects_write_concern_errors_across_batches(self):
189190
self.assertEqual(len(bulk_write_events), 2)
190191

191192
@async_client_context.require_version_min(8, 0, 0, -24)
192-
async def test_collects_write_errors_across_batches_unordered(self):
193+
async def test_6_collects_write_errors_across_batches_unordered(self):
193194
listener = OvertCommandListener()
194195
client = await self.async_rs_or_single_client(event_listeners=[listener])
195196

@@ -218,7 +219,7 @@ async def test_collects_write_errors_across_batches_unordered(self):
218219
self.assertEqual(len(bulk_write_events), 2)
219220

220221
@async_client_context.require_version_min(8, 0, 0, -24)
221-
async def test_collects_write_errors_across_batches_ordered(self):
222+
async def test_6_collects_write_errors_across_batches_ordered(self):
222223
listener = OvertCommandListener()
223224
client = await self.async_rs_or_single_client(event_listeners=[listener])
224225

@@ -247,7 +248,7 @@ async def test_collects_write_errors_across_batches_ordered(self):
247248
self.assertEqual(len(bulk_write_events), 1)
248249

249250
@async_client_context.require_version_min(8, 0, 0, -24)
250-
async def test_handles_cursor_requiring_getMore(self):
251+
async def test_7_handles_cursor_requiring_getMore(self):
251252
listener = OvertCommandListener()
252253
client = await self.async_rs_or_single_client(event_listeners=[listener])
253254

@@ -287,7 +288,7 @@ async def test_handles_cursor_requiring_getMore(self):
287288

288289
@async_client_context.require_version_min(8, 0, 0, -24)
289290
@async_client_context.require_no_standalone
290-
async def test_handles_cursor_requiring_getMore_within_transaction(self):
291+
async def test_8_handles_cursor_requiring_getMore_within_transaction(self):
291292
listener = OvertCommandListener()
292293
client = await self.async_rs_or_single_client(event_listeners=[listener])
293294

@@ -329,7 +330,7 @@ async def test_handles_cursor_requiring_getMore_within_transaction(self):
329330

330331
@async_client_context.require_version_min(8, 0, 0, -24)
331332
@async_client_context.require_failCommand_fail_point
332-
async def test_handles_getMore_error(self):
333+
async def test_9_handles_getMore_error(self):
333334
listener = OvertCommandListener()
334335
client = await self.async_rs_or_single_client(event_listeners=[listener])
335336

@@ -382,7 +383,7 @@ async def test_handles_getMore_error(self):
382383
self.assertTrue(kill_cursors_event)
383384

384385
@async_client_context.require_version_min(8, 0, 0, -24)
385-
async def test_returns_error_if_unacknowledged_too_large_insert(self):
386+
async def test_10_returns_error_if_unacknowledged_too_large_insert(self):
386387
listener = OvertCommandListener()
387388
client = await self.async_rs_or_single_client(event_listeners=[listener])
388389

@@ -441,7 +442,7 @@ async def _setup_namespace_test_models(self):
441442
return num_models, models
442443

443444
@async_client_context.require_version_min(8, 0, 0, -24)
444-
async def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
445+
async def test_11_no_batch_splits_if_new_namespace_is_not_too_large(self):
445446
listener = OvertCommandListener()
446447
client = await self.async_rs_or_single_client(event_listeners=[listener])
447448

@@ -471,7 +472,7 @@ async def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
471472
self.assertEqual(event.command["nsInfo"][0]["ns"], "db.coll")
472473

473474
@async_client_context.require_version_min(8, 0, 0, -24)
474-
async def test_batch_splits_if_new_namespace_is_too_large(self):
475+
async def test_11_batch_splits_if_new_namespace_is_too_large(self):
475476
listener = OvertCommandListener()
476477
client = await self.async_rs_or_single_client(event_listeners=[listener])
477478

@@ -508,25 +509,27 @@ async def test_batch_splits_if_new_namespace_is_too_large(self):
508509
self.assertEqual(second_event.command["nsInfo"][0]["ns"], namespace)
509510

510511
@async_client_context.require_version_min(8, 0, 0, -24)
511-
async def test_returns_error_if_no_writes_can_be_added_to_ops(self):
512+
async def test_12_returns_error_if_no_writes_can_be_added_to_ops(self):
512513
client = await self.async_rs_or_single_client()
513514

514515
# Document too large.
515516
b_repeated = "b" * self.max_message_size_bytes
516517
models = [InsertOne(namespace="db.coll", document={"a": b_repeated})]
517-
with self.assertRaises(DocumentTooLarge):
518+
with self.assertRaises(DocumentTooLarge) as context:
518519
await client.bulk_write(models=models)
520+
self.assertIsNone(context.exception.partial_result)
519521

520522
# Namespace too large.
521523
c_repeated = "c" * self.max_message_size_bytes
522524
namespace = f"db.{c_repeated}"
523525
models = [InsertOne(namespace=namespace, document={"a": "b"})]
524-
with self.assertRaises(DocumentTooLarge):
526+
with self.assertRaises(DocumentTooLarge) as context:
525527
await client.bulk_write(models=models)
528+
self.assertIsNone(context.exception.partial_result)
526529

527530
@async_client_context.require_version_min(8, 0, 0, -24)
528531
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
529-
async def test_returns_error_if_auto_encryption_configured(self):
532+
async def test_13_returns_error_if_auto_encryption_configured(self):
530533
opts = AutoEncryptionOpts(
531534
key_vault_namespace="db.coll",
532535
kms_providers={"aws": {"accessKeyId": "foo", "secretAccessKey": "bar"}},
@@ -536,6 +539,7 @@ async def test_returns_error_if_auto_encryption_configured(self):
536539
models = [InsertOne(namespace="db.coll", document={"a": "b"})]
537540
with self.assertRaises(InvalidOperation) as context:
538541
await client.bulk_write(models=models)
542+
self.assertIsNone(context.exception.partial_result)
539543
self.assertIn(
540544
"bulk_write does not currently support automatic encryption", context.exception._message
541545
)
@@ -579,6 +583,8 @@ async def test_upserted_result(self):
579583
self.assertEqual(result.update_results[1].did_upsert, True)
580584
self.assertEqual(result.update_results[2].did_upsert, False)
581585

586+
# Note: test 14 is optional and intentionally not implemented because we provide multiple APIs to specify explain.
587+
582588
@async_client_context.require_version_min(8, 0, 0, -24)
583589
async def test_15_unacknowledged_write_across_batches(self):
584590
listener = OvertCommandListener()

test/asynchronous/test_read_write_concern_spec.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ async def test_raise_wtimeout(self):
180180
WriteConcern(w=async_client_context.w, wtimeout=1), WTimeoutError
181181
)
182182

183+
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
184+
# Test 1 (included here instead of test_client_bulk_write.py)
183185
@async_client_context.require_failCommand_fail_point
184186
async def test_error_includes_errInfo(self):
185187
expected_wce = {
@@ -214,6 +216,8 @@ async def test_error_includes_errInfo(self):
214216
}
215217
self.assertEqual(ctx.exception.details, expected_details)
216218

219+
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
220+
# Test 2 (included here instead of test_client_bulk_write.py)
217221
@async_client_context.require_version_min(4, 9)
218222
async def test_write_error_details_exposes_errinfo(self):
219223
listener = OvertCommandListener()

test/test_client_bulk_write.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def test_formats_write_error_correctly(self):
8484

8585

8686
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
87+
# Note: tests 1 and 2 are in test_read_write_concern_spec.py
8788
class TestClientBulkWriteCRUD(IntegrationTest):
8889
def setUp(self):
8990
super().setUp()
@@ -92,7 +93,7 @@ def setUp(self):
9293
self.max_message_size_bytes = client_context.max_message_size_bytes
9394

9495
@client_context.require_version_min(8, 0, 0, -24)
95-
def test_batch_splits_if_num_operations_too_large(self):
96+
def test_3_batch_splits_if_num_operations_too_large(self):
9697
listener = OvertCommandListener()
9798
client = self.rs_or_single_client(event_listeners=[listener])
9899

@@ -116,7 +117,7 @@ def test_batch_splits_if_num_operations_too_large(self):
116117
self.assertEqual(first_event.operation_id, second_event.operation_id)
117118

118119
@client_context.require_version_min(8, 0, 0, -24)
119-
def test_batch_splits_if_ops_payload_too_large(self):
120+
def test_4_batch_splits_if_ops_payload_too_large(self):
120121
listener = OvertCommandListener()
121122
client = self.rs_or_single_client(event_listeners=[listener])
122123

@@ -148,7 +149,7 @@ def test_batch_splits_if_ops_payload_too_large(self):
148149

149150
@client_context.require_version_min(8, 0, 0, -24)
150151
@client_context.require_failCommand_fail_point
151-
def test_collects_write_concern_errors_across_batches(self):
152+
def test_5_collects_write_concern_errors_across_batches(self):
152153
listener = OvertCommandListener()
153154
client = self.rs_or_single_client(
154155
event_listeners=[listener],
@@ -189,7 +190,7 @@ def test_collects_write_concern_errors_across_batches(self):
189190
self.assertEqual(len(bulk_write_events), 2)
190191

191192
@client_context.require_version_min(8, 0, 0, -24)
192-
def test_collects_write_errors_across_batches_unordered(self):
193+
def test_6_collects_write_errors_across_batches_unordered(self):
193194
listener = OvertCommandListener()
194195
client = self.rs_or_single_client(event_listeners=[listener])
195196

@@ -218,7 +219,7 @@ def test_collects_write_errors_across_batches_unordered(self):
218219
self.assertEqual(len(bulk_write_events), 2)
219220

220221
@client_context.require_version_min(8, 0, 0, -24)
221-
def test_collects_write_errors_across_batches_ordered(self):
222+
def test_6_collects_write_errors_across_batches_ordered(self):
222223
listener = OvertCommandListener()
223224
client = self.rs_or_single_client(event_listeners=[listener])
224225

@@ -247,7 +248,7 @@ def test_collects_write_errors_across_batches_ordered(self):
247248
self.assertEqual(len(bulk_write_events), 1)
248249

249250
@client_context.require_version_min(8, 0, 0, -24)
250-
def test_handles_cursor_requiring_getMore(self):
251+
def test_7_handles_cursor_requiring_getMore(self):
251252
listener = OvertCommandListener()
252253
client = self.rs_or_single_client(event_listeners=[listener])
253254

@@ -287,7 +288,7 @@ def test_handles_cursor_requiring_getMore(self):
287288

288289
@client_context.require_version_min(8, 0, 0, -24)
289290
@client_context.require_no_standalone
290-
def test_handles_cursor_requiring_getMore_within_transaction(self):
291+
def test_8_handles_cursor_requiring_getMore_within_transaction(self):
291292
listener = OvertCommandListener()
292293
client = self.rs_or_single_client(event_listeners=[listener])
293294

@@ -329,7 +330,7 @@ def test_handles_cursor_requiring_getMore_within_transaction(self):
329330

330331
@client_context.require_version_min(8, 0, 0, -24)
331332
@client_context.require_failCommand_fail_point
332-
def test_handles_getMore_error(self):
333+
def test_9_handles_getMore_error(self):
333334
listener = OvertCommandListener()
334335
client = self.rs_or_single_client(event_listeners=[listener])
335336

@@ -382,7 +383,7 @@ def test_handles_getMore_error(self):
382383
self.assertTrue(kill_cursors_event)
383384

384385
@client_context.require_version_min(8, 0, 0, -24)
385-
def test_returns_error_if_unacknowledged_too_large_insert(self):
386+
def test_10_returns_error_if_unacknowledged_too_large_insert(self):
386387
listener = OvertCommandListener()
387388
client = self.rs_or_single_client(event_listeners=[listener])
388389

@@ -437,7 +438,7 @@ def _setup_namespace_test_models(self):
437438
return num_models, models
438439

439440
@client_context.require_version_min(8, 0, 0, -24)
440-
def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
441+
def test_11_no_batch_splits_if_new_namespace_is_not_too_large(self):
441442
listener = OvertCommandListener()
442443
client = self.rs_or_single_client(event_listeners=[listener])
443444

@@ -467,7 +468,7 @@ def test_no_batch_splits_if_new_namespace_is_not_too_large(self):
467468
self.assertEqual(event.command["nsInfo"][0]["ns"], "db.coll")
468469

469470
@client_context.require_version_min(8, 0, 0, -24)
470-
def test_batch_splits_if_new_namespace_is_too_large(self):
471+
def test_11_batch_splits_if_new_namespace_is_too_large(self):
471472
listener = OvertCommandListener()
472473
client = self.rs_or_single_client(event_listeners=[listener])
473474

@@ -504,25 +505,27 @@ def test_batch_splits_if_new_namespace_is_too_large(self):
504505
self.assertEqual(second_event.command["nsInfo"][0]["ns"], namespace)
505506

506507
@client_context.require_version_min(8, 0, 0, -24)
507-
def test_returns_error_if_no_writes_can_be_added_to_ops(self):
508+
def test_12_returns_error_if_no_writes_can_be_added_to_ops(self):
508509
client = self.rs_or_single_client()
509510

510511
# Document too large.
511512
b_repeated = "b" * self.max_message_size_bytes
512513
models = [InsertOne(namespace="db.coll", document={"a": b_repeated})]
513-
with self.assertRaises(DocumentTooLarge):
514+
with self.assertRaises(DocumentTooLarge) as context:
514515
client.bulk_write(models=models)
516+
self.assertIsNone(context.exception.partial_result)
515517

516518
# Namespace too large.
517519
c_repeated = "c" * self.max_message_size_bytes
518520
namespace = f"db.{c_repeated}"
519521
models = [InsertOne(namespace=namespace, document={"a": "b"})]
520-
with self.assertRaises(DocumentTooLarge):
522+
with self.assertRaises(DocumentTooLarge) as context:
521523
client.bulk_write(models=models)
524+
self.assertIsNone(context.exception.partial_result)
522525

523526
@client_context.require_version_min(8, 0, 0, -24)
524527
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
525-
def test_returns_error_if_auto_encryption_configured(self):
528+
def test_13_returns_error_if_auto_encryption_configured(self):
526529
opts = AutoEncryptionOpts(
527530
key_vault_namespace="db.coll",
528531
kms_providers={"aws": {"accessKeyId": "foo", "secretAccessKey": "bar"}},
@@ -532,6 +535,7 @@ def test_returns_error_if_auto_encryption_configured(self):
532535
models = [InsertOne(namespace="db.coll", document={"a": "b"})]
533536
with self.assertRaises(InvalidOperation) as context:
534537
client.bulk_write(models=models)
538+
self.assertIsNone(context.exception.partial_result)
535539
self.assertIn(
536540
"bulk_write does not currently support automatic encryption", context.exception._message
537541
)
@@ -575,6 +579,8 @@ def test_upserted_result(self):
575579
self.assertEqual(result.update_results[1].did_upsert, True)
576580
self.assertEqual(result.update_results[2].did_upsert, False)
577581

582+
# Note: test 14 is optional and intentionally not implemented because we provide multiple APIs to specify explain.
583+
578584
@client_context.require_version_min(8, 0, 0, -24)
579585
def test_15_unacknowledged_write_across_batches(self):
580586
listener = OvertCommandListener()

test/test_read_write_concern_spec.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ def test_raise_wtimeout(self):
178178
self.disable_replication(client_context.client)
179179
self.assertWriteOpsRaise(WriteConcern(w=client_context.w, wtimeout=1), WTimeoutError)
180180

181+
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
182+
# Test 1 (included here instead of test_client_bulk_write.py)
181183
@client_context.require_failCommand_fail_point
182184
def test_error_includes_errInfo(self):
183185
expected_wce = {
@@ -212,6 +214,8 @@ def test_error_includes_errInfo(self):
212214
}
213215
self.assertEqual(ctx.exception.details, expected_details)
214216

217+
# https://github.com/mongodb/specifications/tree/master/source/crud/tests
218+
# Test 2 (included here instead of test_client_bulk_write.py)
215219
@client_context.require_version_min(4, 9)
216220
def test_write_error_details_exposes_errinfo(self):
217221
listener = OvertCommandListener()

0 commit comments

Comments
 (0)