PYTHON-5248 - Drop support for MongoDB 4.0 (#2353)
This commit is contained in:
parent
4ea0288eaa
commit
e2bfa9a590
File diff suppressed because it is too large
Load Diff
@ -146,7 +146,7 @@ buildvariants:
|
||||
COMPRESSOR: zlib
|
||||
- name: compression-zstd-rhel8
|
||||
tasks:
|
||||
- name: .test-standard !.server-4.0
|
||||
- name: .test-standard !.server-4.2
|
||||
display_name: Compression zstd RHEL8
|
||||
run_on:
|
||||
- rhel87-small
|
||||
@ -522,13 +522,6 @@ buildvariants:
|
||||
PYTHON_BINARY: /opt/python/3.9/bin/python3
|
||||
|
||||
# Server version tests
|
||||
- name: mongodb-v4.0
|
||||
tasks:
|
||||
- name: .server-version
|
||||
display_name: "* MongoDB v4.0"
|
||||
run_on:
|
||||
- rhel87-small
|
||||
tags: [coverage_tag]
|
||||
- name: mongodb-v4.2
|
||||
tasks:
|
||||
- name: .server-version
|
||||
@ -664,11 +657,3 @@ buildvariants:
|
||||
- rhel87-small
|
||||
expansions:
|
||||
STORAGE_ENGINE: inmemory
|
||||
- name: storage-mmapv1-rhel8
|
||||
tasks:
|
||||
- name: .test-standard !.sharded_cluster-auth-ssl .server-4.0
|
||||
display_name: Storage MMAPv1 RHEL8
|
||||
run_on:
|
||||
- rhel87-small
|
||||
expansions:
|
||||
STORAGE_ENGINE: mmapv1
|
||||
|
||||
@ -25,7 +25,6 @@ from generate_config_utils import (
|
||||
get_task_name,
|
||||
get_variant_name,
|
||||
get_versions_from,
|
||||
get_versions_until,
|
||||
handle_c_ext,
|
||||
write_functions_to_file,
|
||||
write_tasks_to_file,
|
||||
@ -196,7 +195,7 @@ def create_compression_variants():
|
||||
for compressor in "snappy", "zlib", "zstd":
|
||||
expansions = dict(COMPRESSOR=compressor)
|
||||
if compressor == "zstd":
|
||||
tasks = [".test-standard !.server-4.0"]
|
||||
tasks = [".test-standard !.server-4.2"]
|
||||
else:
|
||||
tasks = [".test-standard"]
|
||||
display_name = get_variant_name(f"Compression {compressor}", host)
|
||||
@ -249,16 +248,11 @@ def create_pyopenssl_variants():
|
||||
|
||||
def create_storage_engine_variants():
|
||||
host = DEFAULT_HOST
|
||||
engines = ["InMemory", "MMAPv1"]
|
||||
engines = ["InMemory"]
|
||||
variants = []
|
||||
for engine in engines:
|
||||
expansions = dict(STORAGE_ENGINE=engine.lower())
|
||||
if engine == engines[0]:
|
||||
tasks = [".test-standard .standalone-noauth-nossl"]
|
||||
else:
|
||||
# MongoDB 4.2 drops support for MMAPv1
|
||||
versions = get_versions_until("4.0")
|
||||
tasks = [f".test-standard !.sharded_cluster-auth-ssl .server-{v}" for v in versions]
|
||||
tasks = [".test-standard .standalone-noauth-nossl"]
|
||||
display_name = get_variant_name(f"Storage {engine}", host)
|
||||
variant = create_variant(tasks, display_name, host=host, expansions=expansions)
|
||||
variants.append(variant)
|
||||
|
||||
@ -21,7 +21,7 @@ from shrub.v3.shrub_service import ShrubService
|
||||
# Globals
|
||||
##############
|
||||
|
||||
ALL_VERSIONS = ["4.0", "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "rapid", "latest"]
|
||||
ALL_VERSIONS = ["4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "rapid", "latest"]
|
||||
CPYTHONS = ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
PYPYS = ["pypy3.10"]
|
||||
ALL_PYTHONS = CPYTHONS + PYPYS
|
||||
|
||||
@ -66,8 +66,8 @@ MAX_WIRE_VERSION = 0
|
||||
MAX_WRITE_BATCH_SIZE = 100000
|
||||
|
||||
# What this version of PyMongo supports.
|
||||
MIN_SUPPORTED_SERVER_VERSION = "4.0"
|
||||
MIN_SUPPORTED_WIRE_VERSION = 7
|
||||
MIN_SUPPORTED_SERVER_VERSION = "4.2"
|
||||
MIN_SUPPORTED_WIRE_VERSION = 8
|
||||
# MongoDB 8.0
|
||||
MAX_SUPPORTED_WIRE_VERSION = 25
|
||||
|
||||
|
||||
@ -508,19 +508,6 @@ class ClientContext:
|
||||
func=func,
|
||||
)
|
||||
|
||||
def require_no_mmap(self, func):
|
||||
"""Run a test only if the server is not using the MMAPv1 storage
|
||||
engine. Only works for standalone and replica sets; tests are
|
||||
run regardless of storage engine on sharded clusters.
|
||||
"""
|
||||
|
||||
def is_not_mmap():
|
||||
if self.is_mongos:
|
||||
return True
|
||||
return self.storage_engine != "mmapv1"
|
||||
|
||||
return self._require(is_not_mmap, "Storage engine must not be MMAPv1", func=func)
|
||||
|
||||
def require_version_min(self, *ver):
|
||||
"""Run a test only if the server version is at least ``version``."""
|
||||
other_version = Version(*ver)
|
||||
@ -651,7 +638,7 @@ class ClientContext:
|
||||
|
||||
def require_change_streams(self, func):
|
||||
"""Run a test only if the server supports change streams."""
|
||||
return self.require_no_mmap(self.require_no_standalone(func))
|
||||
return self.require_no_standalone(func)
|
||||
|
||||
def is_topology_type(self, topologies):
|
||||
unknown = set(topologies) - {
|
||||
@ -754,8 +741,6 @@ class ClientContext:
|
||||
return self._require(lambda: self.sessions_enabled, "Sessions not supported", func=func)
|
||||
|
||||
def supports_retryable_writes(self):
|
||||
if self.storage_engine == "mmapv1":
|
||||
return False
|
||||
if not self.sessions_enabled:
|
||||
return False
|
||||
return self.is_mongos or self.is_rs
|
||||
@ -769,9 +754,6 @@ class ClientContext:
|
||||
)
|
||||
|
||||
def supports_transactions(self):
|
||||
if self.storage_engine == "mmapv1":
|
||||
return False
|
||||
|
||||
if self.version.at_least(4, 1, 8):
|
||||
return self.is_mongos or self.is_rs
|
||||
|
||||
|
||||
@ -508,19 +508,6 @@ class AsyncClientContext:
|
||||
func=func,
|
||||
)
|
||||
|
||||
def require_no_mmap(self, func):
|
||||
"""Run a test only if the server is not using the MMAPv1 storage
|
||||
engine. Only works for standalone and replica sets; tests are
|
||||
run regardless of storage engine on sharded clusters.
|
||||
"""
|
||||
|
||||
def is_not_mmap():
|
||||
if self.is_mongos:
|
||||
return True
|
||||
return self.storage_engine != "mmapv1"
|
||||
|
||||
return self._require(is_not_mmap, "Storage engine must not be MMAPv1", func=func)
|
||||
|
||||
def require_version_min(self, *ver):
|
||||
"""Run a test only if the server version is at least ``version``."""
|
||||
other_version = Version(*ver)
|
||||
@ -651,7 +638,7 @@ class AsyncClientContext:
|
||||
|
||||
def require_change_streams(self, func):
|
||||
"""Run a test only if the server supports change streams."""
|
||||
return self.require_no_mmap(self.require_no_standalone(func))
|
||||
return self.require_no_standalone(func)
|
||||
|
||||
async def is_topology_type(self, topologies):
|
||||
unknown = set(topologies) - {
|
||||
@ -754,8 +741,6 @@ class AsyncClientContext:
|
||||
return self._require(lambda: self.sessions_enabled, "Sessions not supported", func=func)
|
||||
|
||||
def supports_retryable_writes(self):
|
||||
if self.storage_engine == "mmapv1":
|
||||
return False
|
||||
if not self.sessions_enabled:
|
||||
return False
|
||||
return self.is_mongos or self.is_rs
|
||||
@ -769,9 +754,6 @@ class AsyncClientContext:
|
||||
)
|
||||
|
||||
def supports_transactions(self):
|
||||
if self.storage_engine == "mmapv1":
|
||||
return False
|
||||
|
||||
if self.version.at_least(4, 1, 8):
|
||||
return self.is_mongos or self.is_rs
|
||||
|
||||
|
||||
@ -165,7 +165,7 @@ class AsyncTestBulk(AsyncBulkTestBase):
|
||||
async def test_update_many(self):
|
||||
await self._test_update_many({"$set": {"foo": "bar"}})
|
||||
|
||||
@async_client_context.require_version_min(4, 1, 11)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_update_many_pipeline(self):
|
||||
await self._test_update_many([{"$set": {"foo": "bar"}}])
|
||||
|
||||
@ -206,7 +206,7 @@ class AsyncTestBulk(AsyncBulkTestBase):
|
||||
async def test_update_one(self):
|
||||
await self._test_update_one({"$set": {"foo": "bar"}})
|
||||
|
||||
@async_client_context.require_version_min(4, 1, 11)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_update_one_pipeline(self):
|
||||
await self._test_update_one([{"$set": {"foo": "bar"}}])
|
||||
|
||||
|
||||
@ -267,7 +267,7 @@ class APITestsMixin:
|
||||
|
||||
# $changeStream.startAtOperationTime was added in 4.0.0.
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_start_at_operation_time(self):
|
||||
optime = await self.get_start_at_operation_time()
|
||||
|
||||
@ -436,7 +436,7 @@ class APITestsMixin:
|
||||
await self._test_get_invalidate_event(change_stream)
|
||||
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 1, 1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_start_after(self):
|
||||
resume_token = await self.get_resume_token(invalidate=True)
|
||||
|
||||
@ -452,7 +452,7 @@ class APITestsMixin:
|
||||
self.assertEqual(change["fullDocument"], {"_id": 2})
|
||||
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 1, 1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_start_after_resume_process_with_changes(self):
|
||||
resume_token = await self.get_resume_token(invalidate=True)
|
||||
|
||||
@ -563,27 +563,16 @@ class ProseSpecTestsMixin:
|
||||
)
|
||||
|
||||
# Prose test no. 1
|
||||
@async_client_context.require_version_min(4, 0, 7)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_update_resume_token(self):
|
||||
await self._test_update_resume_token(self._get_expected_resume_token)
|
||||
|
||||
# Prose test no. 1
|
||||
@async_client_context.require_version_max(4, 0, 7)
|
||||
async def test_update_resume_token_legacy(self):
|
||||
await self._test_update_resume_token(self._get_expected_resume_token_legacy)
|
||||
|
||||
# Prose test no. 2
|
||||
@async_client_context.require_version_min(4, 1, 8)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_raises_error_on_missing_id_418plus(self):
|
||||
# Server returns an error on 4.1.8+
|
||||
await self._test_raises_error_on_missing_id(OperationFailure)
|
||||
|
||||
# Prose test no. 2
|
||||
@async_client_context.require_version_max(4, 1, 8)
|
||||
async def test_raises_error_on_missing_id_418minus(self):
|
||||
# PyMongo raises an error
|
||||
await self._test_raises_error_on_missing_id(InvalidOperation)
|
||||
|
||||
# Prose test no. 3
|
||||
@no_type_check
|
||||
async def test_resume_on_error(self):
|
||||
@ -642,40 +631,12 @@ class ProseSpecTestsMixin:
|
||||
cursor.close = raise_error
|
||||
await self.insert_one_and_check(change_stream, {"_id": 2})
|
||||
|
||||
# Prose test no. 9
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_max(4, 0, 7)
|
||||
async def test_start_at_operation_time_caching(self):
|
||||
# Case 1: change stream not started with startAtOperationTime
|
||||
client, listener = self.client_with_listener("aggregate")
|
||||
async with await self.change_stream_with_client(client) as cs:
|
||||
await self.kill_change_stream_cursor(cs)
|
||||
await cs.try_next()
|
||||
cmd = listener.started_events[-1].command
|
||||
self.assertIsNotNone(cmd["pipeline"][0]["$changeStream"].get("startAtOperationTime"))
|
||||
|
||||
# Case 2: change stream started with startAtOperationTime
|
||||
listener.reset()
|
||||
optime = await self.get_start_at_operation_time()
|
||||
async with await self.change_stream_with_client(
|
||||
client, start_at_operation_time=optime
|
||||
) as cs:
|
||||
await self.kill_change_stream_cursor(cs)
|
||||
await cs.try_next()
|
||||
cmd = listener.started_events[-1].command
|
||||
self.assertEqual(
|
||||
cmd["pipeline"][0]["$changeStream"].get("startAtOperationTime"),
|
||||
optime,
|
||||
str([k.command for k in listener.started_events]),
|
||||
)
|
||||
|
||||
# Prose test no. 10 - SKIPPED
|
||||
# This test is identical to prose test no. 3.
|
||||
|
||||
# Prose test no. 11
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 0, 7)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_resumetoken_empty_batch(self):
|
||||
client, listener = await self._client_with_listener("getMore")
|
||||
async with await self.change_stream_with_client(client) as change_stream:
|
||||
@ -687,7 +648,7 @@ class ProseSpecTestsMixin:
|
||||
|
||||
# Prose test no. 11
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 0, 7)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_resumetoken_exhausted_batch(self):
|
||||
client, listener = await self._client_with_listener("getMore")
|
||||
async with await self.change_stream_with_client(client) as change_stream:
|
||||
@ -697,38 +658,6 @@ class ProseSpecTestsMixin:
|
||||
response = listener.succeeded_events[-1].reply
|
||||
self.assertEqual(resume_token, response["cursor"]["postBatchResumeToken"])
|
||||
|
||||
# Prose test no. 12
|
||||
@no_type_check
|
||||
@async_client_context.require_version_max(4, 0, 7)
|
||||
async def test_resumetoken_empty_batch_legacy(self):
|
||||
resume_point = await self.get_resume_token()
|
||||
|
||||
# Empty resume token when neither resumeAfter or startAfter specified.
|
||||
async with await self.change_stream() as change_stream:
|
||||
await change_stream.try_next()
|
||||
self.assertIsNone(change_stream.resume_token)
|
||||
|
||||
# Resume token value is same as resumeAfter.
|
||||
async with await self.change_stream(resume_after=resume_point) as change_stream:
|
||||
await change_stream.try_next()
|
||||
resume_token = change_stream.resume_token
|
||||
self.assertEqual(resume_token, resume_point)
|
||||
|
||||
# Prose test no. 12
|
||||
@no_type_check
|
||||
@async_client_context.require_version_max(4, 0, 7)
|
||||
async def test_resumetoken_exhausted_batch_legacy(self):
|
||||
# Resume token is _id of last change.
|
||||
async with await self.change_stream() as change_stream:
|
||||
change = await self._populate_and_exhaust_change_stream(change_stream)
|
||||
self.assertEqual(change_stream.resume_token, change["_id"])
|
||||
resume_point = change["_id"]
|
||||
|
||||
# Resume token is _id of last change even if resumeAfter is specified.
|
||||
async with await self.change_stream(resume_after=resume_point) as change_stream:
|
||||
change = await self._populate_and_exhaust_change_stream(change_stream)
|
||||
self.assertEqual(change_stream.resume_token, change["_id"])
|
||||
|
||||
# Prose test no. 13
|
||||
@no_type_check
|
||||
async def test_resumetoken_partially_iterated_batch(self):
|
||||
@ -770,13 +699,13 @@ class ProseSpecTestsMixin:
|
||||
# Prose test no. 14
|
||||
@no_type_check
|
||||
@async_client_context.require_no_mongos
|
||||
@async_client_context.require_version_min(4, 1, 1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_resumetoken_uniterated_nonempty_batch_startafter(self):
|
||||
await self._test_resumetoken_uniterated_nonempty_batch("start_after")
|
||||
|
||||
# Prose test no. 17
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 1, 1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_startafter_resume_uses_startafter_after_empty_getMore(self):
|
||||
# Resume should use startAfter after no changes have been returned.
|
||||
resume_point = await self.get_resume_token()
|
||||
@ -796,7 +725,7 @@ class ProseSpecTestsMixin:
|
||||
|
||||
# Prose test no. 18
|
||||
@no_type_check
|
||||
@async_client_context.require_version_min(4, 1, 1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
async def test_startafter_resume_uses_resumeafter_after_nonempty_getMore(self):
|
||||
# Resume should use resumeAfter after some changes have been returned.
|
||||
resume_point = await self.get_resume_token()
|
||||
@ -843,7 +772,7 @@ class ProseSpecTestsMixin:
|
||||
class TestClusterAsyncChangeStream(TestAsyncChangeStreamBase, APITestsMixin):
|
||||
dbs: list
|
||||
|
||||
@async_client_context.require_version_min(4, 0, 0, -1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
@async_client_context.require_change_streams
|
||||
async def asyncSetUp(self) -> None:
|
||||
await super().asyncSetUp()
|
||||
@ -903,7 +832,7 @@ class TestClusterAsyncChangeStream(TestAsyncChangeStreamBase, APITestsMixin):
|
||||
|
||||
|
||||
class TestAsyncDatabaseAsyncChangeStream(TestAsyncChangeStreamBase, APITestsMixin):
|
||||
@async_client_context.require_version_min(4, 0, 0, -1)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
@async_client_context.require_change_streams
|
||||
async def asyncSetUp(self) -> None:
|
||||
await super().asyncSetUp()
|
||||
|
||||
@ -122,18 +122,12 @@ class TestAsyncConnectionsSurvivePrimaryStepDown(AsyncIntegrationTest):
|
||||
async def test_not_primary_keep_connection_pool(self):
|
||||
await self.run_scenario(10107, True, self.verify_pool_not_cleared)
|
||||
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_max(4, 1, 0, -1)
|
||||
@async_client_context.require_test_commands
|
||||
async def test_not_primary_reset_connection_pool(self):
|
||||
await self.run_scenario(10107, False, self.verify_pool_cleared)
|
||||
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
@async_client_context.require_test_commands
|
||||
async def test_shutdown_in_progress(self):
|
||||
await self.run_scenario(91, False, self.verify_pool_cleared)
|
||||
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
@async_client_context.require_test_commands
|
||||
async def test_interrupted_at_shutdown(self):
|
||||
await self.run_scenario(11600, False, self.verify_pool_cleared)
|
||||
|
||||
@ -1190,15 +1190,6 @@ class TestCursor(AsyncIntegrationTest):
|
||||
|
||||
self.assertEqual(["b", "c"], distinct)
|
||||
|
||||
@async_client_context.require_version_max(4, 1, 0, -1)
|
||||
async def test_max_scan(self):
|
||||
await self.db.drop_collection("test")
|
||||
await self.db.test.insert_many([{} for _ in range(100)])
|
||||
|
||||
self.assertEqual(100, len(await self.db.test.find().to_list()))
|
||||
self.assertEqual(50, len(await self.db.test.find().max_scan(50).to_list()))
|
||||
self.assertEqual(50, len(await self.db.test.find().max_scan(90).max_scan(50).to_list()))
|
||||
|
||||
async def test_with_statement(self):
|
||||
await self.db.drop_collection("test")
|
||||
await self.db.test.insert_many([{} for _ in range(100)])
|
||||
@ -1600,7 +1591,6 @@ class TestRawBatchCursor(AsyncIntegrationTest):
|
||||
async def test_collation(self):
|
||||
await anext(self.db.test.find_raw_batches(collation=Collation("en_US")))
|
||||
|
||||
@async_client_context.require_no_mmap # MMAPv1 does not support read concern
|
||||
async def test_read_concern(self):
|
||||
await self.db.get_collection("test", write_concern=WriteConcern(w="majority")).insert_one(
|
||||
{}
|
||||
|
||||
@ -953,7 +953,7 @@ class TestCollectionChangeStreamsWCustomTypes(
|
||||
class TestDatabaseChangeStreamsWCustomTypes(
|
||||
AsyncIntegrationTest, ChangeStreamsWCustomTypesTestMixin
|
||||
):
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
@async_client_context.require_change_streams
|
||||
async def asyncSetUp(self):
|
||||
await super().asyncSetUp()
|
||||
@ -973,7 +973,7 @@ class TestDatabaseChangeStreamsWCustomTypes(
|
||||
class TestClusterChangeStreamsWCustomTypes(
|
||||
AsyncIntegrationTest, ChangeStreamsWCustomTypesTestMixin
|
||||
):
|
||||
@async_client_context.require_version_min(4, 0, 0)
|
||||
@async_client_context.require_version_min(4, 2, 0)
|
||||
@async_client_context.require_change_streams
|
||||
async def asyncSetUp(self):
|
||||
await super().asyncSetUp()
|
||||
|
||||
@ -451,20 +451,6 @@ class TestClientMaxWireVersion(AsyncIntegrationTest):
|
||||
async def asyncSetUp(self):
|
||||
await super().asyncSetUp()
|
||||
|
||||
@async_client_context.require_version_max(4, 0, 99)
|
||||
async def test_raise_max_wire_version_error(self):
|
||||
opts = AutoEncryptionOpts(KMS_PROVIDERS, "keyvault.datakeys")
|
||||
client = await self.async_rs_or_single_client(auto_encryption_opts=opts)
|
||||
msg = "Auto-encryption requires a minimum MongoDB version of 4.2"
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
await client.test.test.insert_one({})
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
await client.admin.command("ping")
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
await client.test.test.find_one({})
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
await client.test.test.bulk_write([InsertOne({})])
|
||||
|
||||
async def test_raise_unsupported_error(self):
|
||||
opts = AutoEncryptionOpts(KMS_PROVIDERS, "keyvault.datakeys")
|
||||
client = await self.async_rs_or_single_client(auto_encryption_opts=opts)
|
||||
|
||||
@ -1162,7 +1162,6 @@ class TestTransactionExamples(AsyncIntegrationTest):
|
||||
|
||||
class TestCausalConsistencyExamples(AsyncIntegrationTest):
|
||||
@async_client_context.require_secondaries_count(1)
|
||||
@async_client_context.require_no_mmap
|
||||
async def test_causal_consistency(self):
|
||||
# Causal consistency examples
|
||||
client = self.client
|
||||
|
||||
@ -140,40 +140,10 @@ class IgnoreDeprecationsTest(AsyncIntegrationTest):
|
||||
self.deprecation_filter.stop()
|
||||
|
||||
|
||||
class TestRetryableWritesMMAPv1(IgnoreDeprecationsTest):
|
||||
knobs: client_knobs
|
||||
|
||||
async def asyncSetUp(self) -> None:
|
||||
await super().asyncSetUp()
|
||||
# Speed up the tests by decreasing the heartbeat frequency.
|
||||
self.knobs = client_knobs(heartbeat_frequency=0.1, min_heartbeat_interval=0.1)
|
||||
self.knobs.enable()
|
||||
self.client = await self.async_rs_or_single_client(retryWrites=True)
|
||||
self.db = self.client.pymongo_test
|
||||
|
||||
async def asyncTearDown(self) -> None:
|
||||
self.knobs.disable()
|
||||
|
||||
@async_client_context.require_no_standalone
|
||||
async def test_actionable_error_message(self):
|
||||
if async_client_context.storage_engine != "mmapv1":
|
||||
raise SkipTest("This cluster is not running MMAPv1")
|
||||
|
||||
expected_msg = (
|
||||
"This MongoDB deployment does not support retryable "
|
||||
"writes. Please add retryWrites=false to your "
|
||||
"connection string."
|
||||
)
|
||||
for method, args, kwargs in retryable_single_statement_ops(self.db.retryable_write_test):
|
||||
with self.assertRaisesRegex(OperationFailure, expected_msg):
|
||||
await method(*args, **kwargs)
|
||||
|
||||
|
||||
class TestRetryableWrites(IgnoreDeprecationsTest):
|
||||
listener: OvertCommandListener
|
||||
knobs: client_knobs
|
||||
|
||||
@async_client_context.require_no_mmap
|
||||
async def asyncSetUp(self) -> None:
|
||||
await super().asyncSetUp()
|
||||
# Speed up the tests by decreasing the heartbeat frequency.
|
||||
@ -425,7 +395,6 @@ class TestWriteConcernError(AsyncIntegrationTest):
|
||||
fail_insert: dict
|
||||
|
||||
@async_client_context.require_replica_set
|
||||
@async_client_context.require_no_mmap
|
||||
@async_client_context.require_failCommand_fail_point
|
||||
async def asyncSetUp(self) -> None:
|
||||
await super().asyncSetUp()
|
||||
@ -596,7 +565,6 @@ class TestPoolPausedError(AsyncIntegrationTest):
|
||||
# TODO: Make this a real integration test where we stepdown the primary.
|
||||
class TestRetryableWritesTxnNumber(IgnoreDeprecationsTest):
|
||||
@async_client_context.require_replica_set
|
||||
@async_client_context.require_no_mmap
|
||||
async def test_increment_transaction_id_without_sending_command(self):
|
||||
"""Test that the txnNumber field is properly incremented, even when
|
||||
the first attempt fails before sending the command.
|
||||
|
||||
@ -1045,14 +1045,6 @@ class TestCausalConsistency(AsyncUnitTest):
|
||||
lambda coll, session: coll.find({}, session=session).explain()
|
||||
)
|
||||
|
||||
@async_client_context.require_no_standalone
|
||||
@async_client_context.require_version_max(4, 1, 0)
|
||||
async def test_aggregate_out_does_not_include_read_concern(self):
|
||||
async def alambda(coll, session):
|
||||
await (await coll.aggregate([{"$out": "aggout"}], session=session)).to_list()
|
||||
|
||||
await self._test_no_read_concern(alambda)
|
||||
|
||||
@async_client_context.require_no_standalone
|
||||
async def test_get_more_does_not_include_read_concern(self):
|
||||
coll = self.client.pymongo_test.test
|
||||
@ -1095,7 +1087,6 @@ class TestCausalConsistency(AsyncUnitTest):
|
||||
self.assertIsNone(act)
|
||||
|
||||
@async_client_context.require_no_standalone
|
||||
@async_client_context.require_no_mmap
|
||||
async def test_read_concern(self):
|
||||
async with self.client.start_session(causal_consistency=True) as s:
|
||||
coll = self.client.pymongo_test.test
|
||||
|
||||
@ -27,7 +27,6 @@ from test.asynchronous.unified_format import generate_test_classes
|
||||
_IS_SYNC = False
|
||||
|
||||
|
||||
@client_context.require_no_mmap
|
||||
def setUpModule():
|
||||
pass
|
||||
|
||||
|
||||
@ -493,11 +493,6 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
|
||||
raise unittest.SkipTest(f"{self.__class__.__name__} runOnRequirements not satisfied")
|
||||
|
||||
# add any special-casing for skipping tests here
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
if "retryable-writes" in self.TEST_SPEC["description"] or "retryable_writes" in str(
|
||||
self.TEST_PATH
|
||||
):
|
||||
raise unittest.SkipTest("MMAPv1 does not support retryWrites=True")
|
||||
|
||||
# Handle mongos_clients for transactions tests.
|
||||
self.mongos_clients = []
|
||||
@ -519,13 +514,6 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
|
||||
|
||||
def maybe_skip_test(self, spec):
|
||||
# add any special-casing for skipping tests here
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
if (
|
||||
"Dirty explicit session is discarded" in spec["description"]
|
||||
or "Dirty implicit session is discarded" in spec["description"]
|
||||
or "Cancel server check" in spec["description"]
|
||||
):
|
||||
self.skipTest("MMAPv1 does not support retryWrites=True")
|
||||
if "Client side error in command starting transaction" in spec["description"]:
|
||||
self.skipTest("Implement PYTHON-1894")
|
||||
if "timeoutMS applied to entire download" in spec["description"]:
|
||||
@ -544,10 +532,6 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
|
||||
if "csot" in class_name:
|
||||
if "gridfs" in class_name and sys.platform == "win32":
|
||||
self.skipTest("PYTHON-3522 CSOT GridFS tests are flaky on Windows")
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
self.skipTest(
|
||||
"MMAPv1 does not support retryable writes which is required for CSOT tests"
|
||||
)
|
||||
if "change" in description or "change" in class_name:
|
||||
self.skipTest("CSOT not implemented for watch()")
|
||||
if "cursors" in class_name:
|
||||
@ -572,11 +556,6 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
|
||||
self.skipTest("PyMongo does not support count()")
|
||||
if name == "listIndexNames":
|
||||
self.skipTest("PyMongo does not support list_index_names()")
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
if name == "createChangeStream":
|
||||
self.skipTest("MMAPv1 does not support change streams")
|
||||
if name == "withTransaction" or name == "startTransaction":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
if not async_client_context.test_commands_enabled:
|
||||
if name == "failPoint" or name == "targetedFailPoint":
|
||||
self.skipTest("Test commands must be enabled to use fail points")
|
||||
@ -682,8 +661,6 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
|
||||
self.fail(f"Operation {opname} not supported for entity of type {type(target)}")
|
||||
|
||||
async def __entityOperation_createChangeStream(self, target, *args, **kwargs):
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support change streams")
|
||||
self.__raise_if_unsupported(
|
||||
"createChangeStream", target, AsyncMongoClient, AsyncDatabase, AsyncCollection
|
||||
)
|
||||
@ -810,14 +787,10 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
|
||||
return await (await target.list_search_indexes(name, **agg_kwargs)).to_list()
|
||||
|
||||
async def _sessionOperation_withTransaction(self, target, *args, **kwargs):
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
self.__raise_if_unsupported("withTransaction", target, AsyncClientSession)
|
||||
return await target.with_transaction(*args, **kwargs)
|
||||
|
||||
async def _sessionOperation_startTransaction(self, target, *args, **kwargs):
|
||||
if async_client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
self.__raise_if_unsupported("startTransaction", target, AsyncClientSession)
|
||||
return await target.start_transaction(*args, **kwargs)
|
||||
|
||||
|
||||
@ -648,12 +648,6 @@ class AsyncSpecRunner(AsyncIntegrationTest):
|
||||
server_listener = ServerAndTopologyEventListener()
|
||||
# Create a new client, to avoid interference from pooled sessions.
|
||||
client_options = self.parse_client_options(test["clientOptions"])
|
||||
# MMAPv1 does not support retryable writes.
|
||||
if (
|
||||
client_options.get("retryWrites") is True
|
||||
and async_client_context.storage_engine == "mmapv1"
|
||||
):
|
||||
self.skipTest("MMAPv1 does not support retryWrites=True")
|
||||
use_multi_mongos = test["useMultipleMongoses"]
|
||||
host = None
|
||||
if use_multi_mongos:
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 InterruptedAtShutdown error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 InterruptedAtShutdown error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "InterruptedAtShutdown",
|
||||
"code": 11600
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 InterruptedDueToReplStateChange error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 InterruptedDueToReplStateChange error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "InterruptedDueToReplStateChange",
|
||||
"code": 11602
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 LegacyNotPrimary error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 LegacyNotPrimary error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "LegacyNotPrimary",
|
||||
"code": 10058
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 NotPrimaryNoSecondaryOk error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 NotPrimaryNoSecondaryOk error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "NotPrimaryNoSecondaryOk",
|
||||
"code": 13435
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 NotPrimaryOrSecondary error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 NotPrimaryOrSecondary error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "NotPrimaryOrSecondary",
|
||||
"code": 13436
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 NotWritablePrimary error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 NotWritablePrimary error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "NotWritablePrimary",
|
||||
"code": 10107
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 PrimarySteppedDown error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 PrimarySteppedDown error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "PrimarySteppedDown",
|
||||
"code": 189
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"description": "Pre-4.2 ShutdownInProgress error",
|
||||
"uri": "mongodb://a/?replicaSet=rs",
|
||||
"phases": [
|
||||
{
|
||||
"description": "Primary A is discovered",
|
||||
"responses": [
|
||||
[
|
||||
"a:27017",
|
||||
{
|
||||
"ok": 1,
|
||||
"helloOk": true,
|
||||
"isWritablePrimary": true,
|
||||
"hosts": [
|
||||
"a:27017"
|
||||
],
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
}
|
||||
]
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "RSPrimary",
|
||||
"setName": "rs",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetWithPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Pre-4.2 ShutdownInProgress error marks server Unknown and clears the pool",
|
||||
"applicationErrors": [
|
||||
{
|
||||
"address": "a:27017",
|
||||
"when": "afterHandshakeCompletes",
|
||||
"maxWireVersion": 7,
|
||||
"type": "command",
|
||||
"response": {
|
||||
"ok": 0,
|
||||
"errmsg": "ShutdownInProgress",
|
||||
"code": 91
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"servers": {
|
||||
"a:27017": {
|
||||
"type": "Unknown",
|
||||
"topologyVersion": null,
|
||||
"pool": {
|
||||
"generation": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"topologyType": "ReplicaSetNoPrimary",
|
||||
"logicalSessionTimeoutMinutes": null,
|
||||
"setName": "rs"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -18,7 +18,7 @@
|
||||
"setVersion": 1,
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -66,7 +66,7 @@
|
||||
"$oid": "000000000000000000000002"
|
||||
},
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -116,7 +116,7 @@
|
||||
"setVersion": 1,
|
||||
"setName": "rs",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -167,7 +167,7 @@
|
||||
"$oid": "000000000000000000000001"
|
||||
},
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
"primary": "localhost:27017",
|
||||
"me": "a:27017",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 25
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -55,7 +55,7 @@
|
||||
"primary": "localhost:27017",
|
||||
"me": "localhost:27018",
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 25
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
"setName": "rs",
|
||||
"setVersion": 2,
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -56,7 +56,7 @@
|
||||
"setName": "rs",
|
||||
"setVersion": 1,
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
"$oid": "000000000000000000000001"
|
||||
},
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -64,7 +64,7 @@
|
||||
"setName": "rs",
|
||||
"setVersion": 2,
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -109,7 +109,7 @@
|
||||
"$oid": "000000000000000000000002"
|
||||
},
|
||||
"minWireVersion": 0,
|
||||
"maxWireVersion": 7
|
||||
"maxWireVersion": 16
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
@ -40,7 +40,7 @@ class TestCursorNamespace(PyMongoTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.server = MockupDB(auto_ismaster={"maxWireVersion": 7})
|
||||
cls.server = MockupDB(auto_ismaster={"maxWireVersion": 8})
|
||||
cls.server.run()
|
||||
cls.client = cls.unmanaged_simple_client(cls.server.uri)
|
||||
|
||||
|
||||
@ -165,7 +165,7 @@ class TestBulk(BulkTestBase):
|
||||
def test_update_many(self):
|
||||
self._test_update_many({"$set": {"foo": "bar"}})
|
||||
|
||||
@client_context.require_version_min(4, 1, 11)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_update_many_pipeline(self):
|
||||
self._test_update_many([{"$set": {"foo": "bar"}}])
|
||||
|
||||
@ -206,7 +206,7 @@ class TestBulk(BulkTestBase):
|
||||
def test_update_one(self):
|
||||
self._test_update_one({"$set": {"foo": "bar"}})
|
||||
|
||||
@client_context.require_version_min(4, 1, 11)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_update_one_pipeline(self):
|
||||
self._test_update_one([{"$set": {"foo": "bar"}}])
|
||||
|
||||
|
||||
@ -263,7 +263,7 @@ class APITestsMixin:
|
||||
|
||||
# $changeStream.startAtOperationTime was added in 4.0.0.
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_start_at_operation_time(self):
|
||||
optime = self.get_start_at_operation_time()
|
||||
|
||||
@ -432,7 +432,7 @@ class APITestsMixin:
|
||||
self._test_get_invalidate_event(change_stream)
|
||||
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 1, 1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_start_after(self):
|
||||
resume_token = self.get_resume_token(invalidate=True)
|
||||
|
||||
@ -448,7 +448,7 @@ class APITestsMixin:
|
||||
self.assertEqual(change["fullDocument"], {"_id": 2})
|
||||
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 1, 1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_start_after_resume_process_with_changes(self):
|
||||
resume_token = self.get_resume_token(invalidate=True)
|
||||
|
||||
@ -553,27 +553,16 @@ class ProseSpecTestsMixin:
|
||||
)
|
||||
|
||||
# Prose test no. 1
|
||||
@client_context.require_version_min(4, 0, 7)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_update_resume_token(self):
|
||||
self._test_update_resume_token(self._get_expected_resume_token)
|
||||
|
||||
# Prose test no. 1
|
||||
@client_context.require_version_max(4, 0, 7)
|
||||
def test_update_resume_token_legacy(self):
|
||||
self._test_update_resume_token(self._get_expected_resume_token_legacy)
|
||||
|
||||
# Prose test no. 2
|
||||
@client_context.require_version_min(4, 1, 8)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_raises_error_on_missing_id_418plus(self):
|
||||
# Server returns an error on 4.1.8+
|
||||
self._test_raises_error_on_missing_id(OperationFailure)
|
||||
|
||||
# Prose test no. 2
|
||||
@client_context.require_version_max(4, 1, 8)
|
||||
def test_raises_error_on_missing_id_418minus(self):
|
||||
# PyMongo raises an error
|
||||
self._test_raises_error_on_missing_id(InvalidOperation)
|
||||
|
||||
# Prose test no. 3
|
||||
@no_type_check
|
||||
def test_resume_on_error(self):
|
||||
@ -632,38 +621,12 @@ class ProseSpecTestsMixin:
|
||||
cursor.close = raise_error
|
||||
self.insert_one_and_check(change_stream, {"_id": 2})
|
||||
|
||||
# Prose test no. 9
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_max(4, 0, 7)
|
||||
def test_start_at_operation_time_caching(self):
|
||||
# Case 1: change stream not started with startAtOperationTime
|
||||
client, listener = self.client_with_listener("aggregate")
|
||||
with self.change_stream_with_client(client) as cs:
|
||||
self.kill_change_stream_cursor(cs)
|
||||
cs.try_next()
|
||||
cmd = listener.started_events[-1].command
|
||||
self.assertIsNotNone(cmd["pipeline"][0]["$changeStream"].get("startAtOperationTime"))
|
||||
|
||||
# Case 2: change stream started with startAtOperationTime
|
||||
listener.reset()
|
||||
optime = self.get_start_at_operation_time()
|
||||
with self.change_stream_with_client(client, start_at_operation_time=optime) as cs:
|
||||
self.kill_change_stream_cursor(cs)
|
||||
cs.try_next()
|
||||
cmd = listener.started_events[-1].command
|
||||
self.assertEqual(
|
||||
cmd["pipeline"][0]["$changeStream"].get("startAtOperationTime"),
|
||||
optime,
|
||||
str([k.command for k in listener.started_events]),
|
||||
)
|
||||
|
||||
# Prose test no. 10 - SKIPPED
|
||||
# This test is identical to prose test no. 3.
|
||||
|
||||
# Prose test no. 11
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 0, 7)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_resumetoken_empty_batch(self):
|
||||
client, listener = self._client_with_listener("getMore")
|
||||
with self.change_stream_with_client(client) as change_stream:
|
||||
@ -675,7 +638,7 @@ class ProseSpecTestsMixin:
|
||||
|
||||
# Prose test no. 11
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 0, 7)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_resumetoken_exhausted_batch(self):
|
||||
client, listener = self._client_with_listener("getMore")
|
||||
with self.change_stream_with_client(client) as change_stream:
|
||||
@ -685,38 +648,6 @@ class ProseSpecTestsMixin:
|
||||
response = listener.succeeded_events[-1].reply
|
||||
self.assertEqual(resume_token, response["cursor"]["postBatchResumeToken"])
|
||||
|
||||
# Prose test no. 12
|
||||
@no_type_check
|
||||
@client_context.require_version_max(4, 0, 7)
|
||||
def test_resumetoken_empty_batch_legacy(self):
|
||||
resume_point = self.get_resume_token()
|
||||
|
||||
# Empty resume token when neither resumeAfter or startAfter specified.
|
||||
with self.change_stream() as change_stream:
|
||||
change_stream.try_next()
|
||||
self.assertIsNone(change_stream.resume_token)
|
||||
|
||||
# Resume token value is same as resumeAfter.
|
||||
with self.change_stream(resume_after=resume_point) as change_stream:
|
||||
change_stream.try_next()
|
||||
resume_token = change_stream.resume_token
|
||||
self.assertEqual(resume_token, resume_point)
|
||||
|
||||
# Prose test no. 12
|
||||
@no_type_check
|
||||
@client_context.require_version_max(4, 0, 7)
|
||||
def test_resumetoken_exhausted_batch_legacy(self):
|
||||
# Resume token is _id of last change.
|
||||
with self.change_stream() as change_stream:
|
||||
change = self._populate_and_exhaust_change_stream(change_stream)
|
||||
self.assertEqual(change_stream.resume_token, change["_id"])
|
||||
resume_point = change["_id"]
|
||||
|
||||
# Resume token is _id of last change even if resumeAfter is specified.
|
||||
with self.change_stream(resume_after=resume_point) as change_stream:
|
||||
change = self._populate_and_exhaust_change_stream(change_stream)
|
||||
self.assertEqual(change_stream.resume_token, change["_id"])
|
||||
|
||||
# Prose test no. 13
|
||||
@no_type_check
|
||||
def test_resumetoken_partially_iterated_batch(self):
|
||||
@ -758,13 +689,13 @@ class ProseSpecTestsMixin:
|
||||
# Prose test no. 14
|
||||
@no_type_check
|
||||
@client_context.require_no_mongos
|
||||
@client_context.require_version_min(4, 1, 1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_resumetoken_uniterated_nonempty_batch_startafter(self):
|
||||
self._test_resumetoken_uniterated_nonempty_batch("start_after")
|
||||
|
||||
# Prose test no. 17
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 1, 1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_startafter_resume_uses_startafter_after_empty_getMore(self):
|
||||
# Resume should use startAfter after no changes have been returned.
|
||||
resume_point = self.get_resume_token()
|
||||
@ -782,7 +713,7 @@ class ProseSpecTestsMixin:
|
||||
|
||||
# Prose test no. 18
|
||||
@no_type_check
|
||||
@client_context.require_version_min(4, 1, 1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
def test_startafter_resume_uses_resumeafter_after_nonempty_getMore(self):
|
||||
# Resume should use resumeAfter after some changes have been returned.
|
||||
resume_point = self.get_resume_token()
|
||||
@ -827,7 +758,7 @@ class ProseSpecTestsMixin:
|
||||
class TestClusterChangeStream(TestChangeStreamBase, APITestsMixin):
|
||||
dbs: list
|
||||
|
||||
@client_context.require_version_min(4, 0, 0, -1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
@client_context.require_change_streams
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
@ -887,7 +818,7 @@ class TestClusterChangeStream(TestChangeStreamBase, APITestsMixin):
|
||||
|
||||
|
||||
class TestDatabaseChangeStream(TestChangeStreamBase, APITestsMixin):
|
||||
@client_context.require_version_min(4, 0, 0, -1)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
@client_context.require_change_streams
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
|
||||
@ -122,18 +122,12 @@ class TestConnectionsSurvivePrimaryStepDown(IntegrationTest):
|
||||
def test_not_primary_keep_connection_pool(self):
|
||||
self.run_scenario(10107, True, self.verify_pool_not_cleared)
|
||||
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_max(4, 1, 0, -1)
|
||||
@client_context.require_test_commands
|
||||
def test_not_primary_reset_connection_pool(self):
|
||||
self.run_scenario(10107, False, self.verify_pool_cleared)
|
||||
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
@client_context.require_test_commands
|
||||
def test_shutdown_in_progress(self):
|
||||
self.run_scenario(91, False, self.verify_pool_cleared)
|
||||
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
@client_context.require_test_commands
|
||||
def test_interrupted_at_shutdown(self):
|
||||
self.run_scenario(11600, False, self.verify_pool_cleared)
|
||||
|
||||
@ -1181,15 +1181,6 @@ class TestCursor(IntegrationTest):
|
||||
|
||||
self.assertEqual(["b", "c"], distinct)
|
||||
|
||||
@client_context.require_version_max(4, 1, 0, -1)
|
||||
def test_max_scan(self):
|
||||
self.db.drop_collection("test")
|
||||
self.db.test.insert_many([{} for _ in range(100)])
|
||||
|
||||
self.assertEqual(100, len(self.db.test.find().to_list()))
|
||||
self.assertEqual(50, len(self.db.test.find().max_scan(50).to_list()))
|
||||
self.assertEqual(50, len(self.db.test.find().max_scan(90).max_scan(50).to_list()))
|
||||
|
||||
def test_with_statement(self):
|
||||
self.db.drop_collection("test")
|
||||
self.db.test.insert_many([{} for _ in range(100)])
|
||||
@ -1591,7 +1582,6 @@ class TestRawBatchCursor(IntegrationTest):
|
||||
def test_collation(self):
|
||||
next(self.db.test.find_raw_batches(collation=Collation("en_US")))
|
||||
|
||||
@client_context.require_no_mmap # MMAPv1 does not support read concern
|
||||
def test_read_concern(self):
|
||||
self.db.get_collection("test", write_concern=WriteConcern(w="majority")).insert_one({})
|
||||
c = self.db.get_collection("test", read_concern=ReadConcern("majority"))
|
||||
|
||||
@ -949,7 +949,7 @@ class TestCollectionChangeStreamsWCustomTypes(IntegrationTest, ChangeStreamsWCus
|
||||
|
||||
|
||||
class TestDatabaseChangeStreamsWCustomTypes(IntegrationTest, ChangeStreamsWCustomTypesTestMixin):
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
@client_context.require_change_streams
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@ -967,7 +967,7 @@ class TestDatabaseChangeStreamsWCustomTypes(IntegrationTest, ChangeStreamsWCusto
|
||||
|
||||
|
||||
class TestClusterChangeStreamsWCustomTypes(IntegrationTest, ChangeStreamsWCustomTypesTestMixin):
|
||||
@client_context.require_version_min(4, 0, 0)
|
||||
@client_context.require_version_min(4, 2, 0)
|
||||
@client_context.require_change_streams
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
@ -451,20 +451,6 @@ class TestClientMaxWireVersion(IntegrationTest):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
@client_context.require_version_max(4, 0, 99)
|
||||
def test_raise_max_wire_version_error(self):
|
||||
opts = AutoEncryptionOpts(KMS_PROVIDERS, "keyvault.datakeys")
|
||||
client = self.rs_or_single_client(auto_encryption_opts=opts)
|
||||
msg = "Auto-encryption requires a minimum MongoDB version of 4.2"
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
client.test.test.insert_one({})
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
client.admin.command("ping")
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
client.test.test.find_one({})
|
||||
with self.assertRaisesRegex(ConfigurationError, msg):
|
||||
client.test.test.bulk_write([InsertOne({})])
|
||||
|
||||
def test_raise_unsupported_error(self):
|
||||
opts = AutoEncryptionOpts(KMS_PROVIDERS, "keyvault.datakeys")
|
||||
client = self.rs_or_single_client(auto_encryption_opts=opts)
|
||||
|
||||
@ -1160,7 +1160,6 @@ class TestTransactionExamples(IntegrationTest):
|
||||
|
||||
class TestCausalConsistencyExamples(IntegrationTest):
|
||||
@client_context.require_secondaries_count(1)
|
||||
@client_context.require_no_mmap
|
||||
def test_causal_consistency(self):
|
||||
# Causal consistency examples
|
||||
client = self.client
|
||||
|
||||
@ -140,40 +140,10 @@ class IgnoreDeprecationsTest(IntegrationTest):
|
||||
self.deprecation_filter.stop()
|
||||
|
||||
|
||||
class TestRetryableWritesMMAPv1(IgnoreDeprecationsTest):
|
||||
knobs: client_knobs
|
||||
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
# Speed up the tests by decreasing the heartbeat frequency.
|
||||
self.knobs = client_knobs(heartbeat_frequency=0.1, min_heartbeat_interval=0.1)
|
||||
self.knobs.enable()
|
||||
self.client = self.rs_or_single_client(retryWrites=True)
|
||||
self.db = self.client.pymongo_test
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.knobs.disable()
|
||||
|
||||
@client_context.require_no_standalone
|
||||
def test_actionable_error_message(self):
|
||||
if client_context.storage_engine != "mmapv1":
|
||||
raise SkipTest("This cluster is not running MMAPv1")
|
||||
|
||||
expected_msg = (
|
||||
"This MongoDB deployment does not support retryable "
|
||||
"writes. Please add retryWrites=false to your "
|
||||
"connection string."
|
||||
)
|
||||
for method, args, kwargs in retryable_single_statement_ops(self.db.retryable_write_test):
|
||||
with self.assertRaisesRegex(OperationFailure, expected_msg):
|
||||
method(*args, **kwargs)
|
||||
|
||||
|
||||
class TestRetryableWrites(IgnoreDeprecationsTest):
|
||||
listener: OvertCommandListener
|
||||
knobs: client_knobs
|
||||
|
||||
@client_context.require_no_mmap
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
# Speed up the tests by decreasing the heartbeat frequency.
|
||||
@ -423,7 +393,6 @@ class TestWriteConcernError(IntegrationTest):
|
||||
fail_insert: dict
|
||||
|
||||
@client_context.require_replica_set
|
||||
@client_context.require_no_mmap
|
||||
@client_context.require_failCommand_fail_point
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
@ -592,7 +561,6 @@ class TestPoolPausedError(IntegrationTest):
|
||||
# TODO: Make this a real integration test where we stepdown the primary.
|
||||
class TestRetryableWritesTxnNumber(IgnoreDeprecationsTest):
|
||||
@client_context.require_replica_set
|
||||
@client_context.require_no_mmap
|
||||
def test_increment_transaction_id_without_sending_command(self):
|
||||
"""Test that the txnNumber field is properly incremented, even when
|
||||
the first attempt fails before sending the command.
|
||||
|
||||
@ -1031,14 +1031,6 @@ class TestCausalConsistency(UnitTest):
|
||||
# Not a write, but explain also doesn't support readConcern.
|
||||
self._test_no_read_concern(lambda coll, session: coll.find({}, session=session).explain())
|
||||
|
||||
@client_context.require_no_standalone
|
||||
@client_context.require_version_max(4, 1, 0)
|
||||
def test_aggregate_out_does_not_include_read_concern(self):
|
||||
def alambda(coll, session):
|
||||
(coll.aggregate([{"$out": "aggout"}], session=session)).to_list()
|
||||
|
||||
self._test_no_read_concern(alambda)
|
||||
|
||||
@client_context.require_no_standalone
|
||||
def test_get_more_does_not_include_read_concern(self):
|
||||
coll = self.client.pymongo_test.test
|
||||
@ -1081,7 +1073,6 @@ class TestCausalConsistency(UnitTest):
|
||||
self.assertIsNone(act)
|
||||
|
||||
@client_context.require_no_standalone
|
||||
@client_context.require_no_mmap
|
||||
def test_read_concern(self):
|
||||
with self.client.start_session(causal_consistency=True) as s:
|
||||
coll = self.client.pymongo_test.test
|
||||
|
||||
@ -559,7 +559,7 @@ class TestMultiServerTopology(TopologyTest):
|
||||
)
|
||||
|
||||
self.assertEqual(server.description.min_wire_version, 1)
|
||||
self.assertEqual(server.description.max_wire_version, 7)
|
||||
self.assertEqual(server.description.max_wire_version, 8)
|
||||
t.select_servers(any_server_selector, _Op.TEST)
|
||||
|
||||
# Incompatible.
|
||||
|
||||
@ -27,7 +27,6 @@ from test.unified_format import generate_test_classes
|
||||
_IS_SYNC = True
|
||||
|
||||
|
||||
@client_context.require_no_mmap
|
||||
def setUpModule():
|
||||
pass
|
||||
|
||||
|
||||
@ -492,11 +492,6 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
raise unittest.SkipTest(f"{self.__class__.__name__} runOnRequirements not satisfied")
|
||||
|
||||
# add any special-casing for skipping tests here
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
if "retryable-writes" in self.TEST_SPEC["description"] or "retryable_writes" in str(
|
||||
self.TEST_PATH
|
||||
):
|
||||
raise unittest.SkipTest("MMAPv1 does not support retryWrites=True")
|
||||
|
||||
# Handle mongos_clients for transactions tests.
|
||||
self.mongos_clients = []
|
||||
@ -518,13 +513,6 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
|
||||
def maybe_skip_test(self, spec):
|
||||
# add any special-casing for skipping tests here
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
if (
|
||||
"Dirty explicit session is discarded" in spec["description"]
|
||||
or "Dirty implicit session is discarded" in spec["description"]
|
||||
or "Cancel server check" in spec["description"]
|
||||
):
|
||||
self.skipTest("MMAPv1 does not support retryWrites=True")
|
||||
if "Client side error in command starting transaction" in spec["description"]:
|
||||
self.skipTest("Implement PYTHON-1894")
|
||||
if "timeoutMS applied to entire download" in spec["description"]:
|
||||
@ -543,10 +531,6 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
if "csot" in class_name:
|
||||
if "gridfs" in class_name and sys.platform == "win32":
|
||||
self.skipTest("PYTHON-3522 CSOT GridFS tests are flaky on Windows")
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
self.skipTest(
|
||||
"MMAPv1 does not support retryable writes which is required for CSOT tests"
|
||||
)
|
||||
if "change" in description or "change" in class_name:
|
||||
self.skipTest("CSOT not implemented for watch()")
|
||||
if "cursors" in class_name:
|
||||
@ -571,11 +555,6 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
self.skipTest("PyMongo does not support count()")
|
||||
if name == "listIndexNames":
|
||||
self.skipTest("PyMongo does not support list_index_names()")
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
if name == "createChangeStream":
|
||||
self.skipTest("MMAPv1 does not support change streams")
|
||||
if name == "withTransaction" or name == "startTransaction":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
if not client_context.test_commands_enabled:
|
||||
if name == "failPoint" or name == "targetedFailPoint":
|
||||
self.skipTest("Test commands must be enabled to use fail points")
|
||||
@ -681,8 +660,6 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
self.fail(f"Operation {opname} not supported for entity of type {type(target)}")
|
||||
|
||||
def __entityOperation_createChangeStream(self, target, *args, **kwargs):
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support change streams")
|
||||
self.__raise_if_unsupported("createChangeStream", target, MongoClient, Database, Collection)
|
||||
stream = target.watch(*args, **kwargs)
|
||||
self.addCleanup(stream.close)
|
||||
@ -807,14 +784,10 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
return (target.list_search_indexes(name, **agg_kwargs)).to_list()
|
||||
|
||||
def _sessionOperation_withTransaction(self, target, *args, **kwargs):
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
self.__raise_if_unsupported("withTransaction", target, ClientSession)
|
||||
return target.with_transaction(*args, **kwargs)
|
||||
|
||||
def _sessionOperation_startTransaction(self, target, *args, **kwargs):
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
self.__raise_if_unsupported("startTransaction", target, ClientSession)
|
||||
return target.start_transaction(*args, **kwargs)
|
||||
|
||||
|
||||
@ -648,9 +648,6 @@ class SpecRunner(IntegrationTest):
|
||||
server_listener = ServerAndTopologyEventListener()
|
||||
# Create a new client, to avoid interference from pooled sessions.
|
||||
client_options = self.parse_client_options(test["clientOptions"])
|
||||
# MMAPv1 does not support retryable writes.
|
||||
if client_options.get("retryWrites") is True and client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support retryWrites=True")
|
||||
use_multi_mongos = test["useMultipleMongoses"]
|
||||
host = None
|
||||
if use_multi_mongos:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user