Merge branch 'master' of github.com:mongodb/mongo-python-driver

This commit is contained in:
Steven Silvester 2024-04-12 13:32:48 -05:00
commit 48ddb1fe76
No known key found for this signature in database
GPG Key ID: B1BF5EC3A8B32F91
45 changed files with 948 additions and 101 deletions

View File

@ -32,6 +32,9 @@ AUTH=${AUTH:-noauth}
SSL=${SSL:-nossl}
TEST_ARGS="${*:1}"
PYTHON=$(which python)
# TODO: Remove when we drop PyPy 3.8 support.
OLD_PYPY=$(python -c "import sys; print(sys.implementation.name.lower() == 'pypy' and sys.implementation.version < (7, 3, 12))")
export PIP_QUIET=1 # Quiet by default
export PIP_PREFER_BINARY=1 # Prefer binary dists by default
@ -110,6 +113,9 @@ fi
if [ "$COMPRESSORS" = "snappy" ]; then
python -m pip install '.[snappy]'
if [ "$OLD_PYPY" == "True" ]; then
pip install "python-snappy<0.7.0"
fi
PYTHON=python
elif [ "$COMPRESSORS" = "zstd" ]; then
python -m pip install zstandard
@ -250,6 +256,9 @@ fi
if [ -n "$GREEN_FRAMEWORK" ]; then
# Install all optional deps to ensure lazy imports are getting patched.
python -m pip install -q ".[aws,encryption,gssapi,ocsp,snappy,zstd]"
if [ "$OLD_PYPY" == "True" ]; then
pip install "python-snappy<0.7.0"
fi
python -m pip install $GREEN_FRAMEWORK
fi

View File

@ -71,7 +71,7 @@ ocsp = [
"service_identity>=18.1.0",
]
snappy = [
"python-snappy",
"python-snappy"
]
# PYTHON-3423 Removed in 4.3 but kept here to avoid pip warnings.
srv = []

View File

@ -1,6 +1,6 @@
{
"description": "unacknowledged-write",
"schemaVersion": "1.13",
"schemaVersion": "1.16",
"createEntities": [
{
"client": {
@ -53,11 +53,27 @@
"_id": 2
}
}
},
{
"name": "find",
"object": "collection",
"arguments": {
"filter": {}
},
"expectResult": [
{
"_id": 1
},
{
"_id": 2
}
]
}
],
"expectLogMessages": [
{
"client": "client",
"ignoreExtraMessages": true,
"messages": [
{
"level": "debug",

View File

@ -1,6 +1,6 @@
{
"description": "unacknowledgedBulkWrite",
"schemaVersion": "1.0",
"schemaVersion": "1.7",
"createEntities": [
{
"client": {
@ -64,11 +64,29 @@
],
"ordered": false
}
},
{
"name": "find",
"object": "collection",
"arguments": {
"filter": {}
},
"expectResult": [
{
"_id": 1,
"x": 11
},
{
"_id": "unorderedBulkWriteInsertW0",
"x": 44
}
]
}
],
"expectEvents": [
{
"client": "client",
"ignoreExtraEvents": true,
"events": [
{
"commandStartedEvent": {

View File

@ -43,6 +43,7 @@ import multiprocessing as mp
import os
import sys
import tempfile
import threading
import time
import warnings
from typing import Any, List, Optional
@ -101,10 +102,19 @@ class Timer:
self.interval = self.end - self.start
def threaded(n_threads, func):
threads = [threading.Thread(target=func) for _ in range(n_threads)]
for t in threads:
t.start()
for t in threads:
t.join()
class PerformanceTest:
dataset: str
data_size: int
fail: Any
n_threads: int = 1
@classmethod
def setUpClass(cls):
@ -118,7 +128,7 @@ class PerformanceTest:
# Remove "Test" so that TestFlatEncoding is reported as "FlatEncoding".
name = self.__class__.__name__[4:]
median = self.percentile(50)
megabytes_per_sec = self.data_size / median / 1000000
megabytes_per_sec = (self.data_size * self.n_threads) / median / 1000000
print(
f"Completed {self.__class__.__name__} {megabytes_per_sec:.3f} MB/s, MEDIAN={self.percentile(50):.3f}s, "
f"total time={duration:.3f}s, iterations={len(self.results)}"
@ -128,7 +138,7 @@ class PerformanceTest:
"info": {
"test_name": name,
"args": {
"threads": 1,
"threads": self.n_threads,
},
},
"metrics": [
@ -163,7 +173,10 @@ class PerformanceTest:
i += 1
self.before()
with Timer() as timer:
self.do_task()
if self.n_threads == 1:
self.do_task()
else:
threaded(self.n_threads, self.do_task)
self.after()
results.append(timer.interval)
duration = time.monotonic() - start
@ -308,6 +321,10 @@ class TestRunCommand(PerformanceTest, unittest.TestCase):
command("hello", True)
class TestRunCommand8Threads(TestRunCommand):
n_threads = 8
class TestDocument(PerformanceTest):
def setUp(self):
super().setUp()
@ -356,6 +373,10 @@ class TestFindOneByID(FindTest, unittest.TestCase):
find_one({"_id": _id})
class TestFindOneByID8Threads(TestFindOneByID):
n_threads = 8
class SmallDocInsertTest(TestDocument):
dataset = "small_doc.json"
@ -395,6 +416,10 @@ class TestFindManyAndEmptyCursor(FindTest, unittest.TestCase):
list(self.corpus.find())
class TestFindManyAndEmptyCursor8Threads(TestFindManyAndEmptyCursor):
n_threads = 8
class TestSmallDocBulkInsert(SmallDocInsertTest, unittest.TestCase):
def do_task(self):
self.corpus.insert_many(self.documents, ordered=True)

View File

@ -0,0 +1,18 @@
{
"description": "entity-client-observeLogMessages-minProperties",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0",
"observeLogMessages": {}
}
}
],
"tests": [
{
"description": "foo",
"operations": []
}
]
}

View File

@ -0,0 +1,20 @@
{
"description": "entity-client-observeLogMessages-property-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0",
"observeLogMessages": {
"command": {}
}
}
}
],
"tests": [
{
"description": "foo",
"operations": []
}
]
}

View File

@ -0,0 +1,20 @@
{
"description": "entity-client-observeLogMessages-property-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0",
"observeLogMessages": {
"command": "notALogLevel"
}
}
}
],
"tests": [
{
"description": "foo",
"operations": []
}
]
}

View File

@ -0,0 +1,18 @@
{
"description": "entity-client-observeLogMessages-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0",
"observeLogMessages": 0
}
}
],
"tests": [
{
"description": "foo",
"operations": []
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedCommandEvent-commandFailedEvent-databaseName-type",
"schemaVersion": "1.15",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandFailedEvent": {
"databaseName": 0
}
}
]
}
]
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedCommandEvent-commandSucceededEvent-databaseName-type",
"schemaVersion": "1.15",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandSucceededEvent": {
"databaseName": 0
}
}
]
}
]
}
]
}

View File

@ -0,0 +1,24 @@
{
"description": "expectedLogMessage-additionalProperties",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [],
"foo": 0
}
]
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedLogMessage-component-enum",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "debug",
"component": "foo",
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,28 @@
{
"description": "expectedLogMessage-component-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "debug",
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedLogMessage-component-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "debug",
"component": 0,
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,28 @@
{
"description": "expectedLogMessage-data-required",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "debug",
"component": "command"
}
]
}
]
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedLogMessage-data-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "debug",
"component": "command",
"data": 0
}
]
}
]
}
]
}

View File

@ -0,0 +1,30 @@
{
"description": "expectedLogMessage-failureIsRedacted-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "debug",
"component": "command",
"failureIsRedacted": 0,
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedLogMessage-level-enum",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": "foo",
"component": "command",
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,28 @@
{
"description": "expectedLogMessage-level-required",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"component": "command",
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,29 @@
{
"description": "expectedLogMessage-level-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
{
"level": 0,
"component": "command",
"data": {}
}
]
}
]
}
]
}

View File

@ -0,0 +1,24 @@
{
"description": "expectedLogMessagesForClient-additionalProperties",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [],
"foo": 0
}
]
}
]
}

View File

@ -0,0 +1,22 @@
{
"description": "expectedLogMessagesForClient-client-required",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"messages": []
}
]
}
]
}

View File

@ -0,0 +1,23 @@
{
"description": "expectedEventsForClient-client-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": 0,
"messages": []
}
]
}
]
}

View File

@ -0,0 +1,24 @@
{
"description": "expectedLogMessagesForClient-ignoreExtraMessages-type",
"schemaVersion": "1.16",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"ignoreExtraMessages": "true",
"messages": []
}
]
}
]
}

View File

@ -0,0 +1,26 @@
{
"description": "expectedLogMessagesForClient-ignoreMessages-items",
"schemaVersion": "1.16",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [],
"ignoreMessages": [
0
]
}
]
}
]
}

View File

@ -0,0 +1,24 @@
{
"description": "expectedLogMessagesForClient-ignoreMessages-type",
"schemaVersion": "1.16",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [],
"ignoreMessages": 0
}
]
}
]
}

View File

@ -0,0 +1,25 @@
{
"description": "expectedLogMessagesForClient-messages-items",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": [
0
]
}
]
}
]
}

View File

@ -0,0 +1,22 @@
{
"description": "expectedLogMessagesForClient-messages-required",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0"
}
]
}
]
}

View File

@ -0,0 +1,23 @@
{
"description": "expectedLogMessagesForClient-messages-type",
"schemaVersion": "1.13",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
{
"client": "client0",
"messages": 0
}
]
}
]
}

View File

@ -0,0 +1,23 @@
{
"description": "expectedSdamEvent-topologyDescriptionChangedEvent-additionalProperties",
"schemaVersion": "1.14",
"tests": [
{
"description": "foo",
"operations": [],
"expectEvents": [
{
"client": "client0",
"eventType": "sdam",
"events": [
{
"topologyDescriptionChangedEvent": {
"foo": "bar"
}
}
]
}
]
}
]
}

View File

@ -0,0 +1,17 @@
{
"description": "runOnRequirement-authMechanism-type",
"schemaVersion": "1.19",
"runOnRequirements": [
{
"authMechanism": 0
}
],
"tests": [
{
"description": "foo",
"operations": [
]
}
]
}

View File

@ -0,0 +1,13 @@
{
"description": "test-expectLogMessages-items",
"schemaVersion": "1.13",
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": [
0
]
}
]
}

View File

@ -0,0 +1,11 @@
{
"description": "test-expectLogMessages-minItems",
"schemaVersion": "1.11",
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": []
}
]
}

View File

@ -0,0 +1,11 @@
{
"description": "test-expectLogMessages-type",
"schemaVersion": "1.13",
"tests": [
{
"description": "foo",
"operations": [],
"expectLogMessages": 0
}
]
}

View File

@ -93,7 +93,10 @@
"commandStartedEvent": {
"command": {
"getMore": {
"$$type": "long"
"$$type": [
"int",
"long"
]
},
"collection": "coll0"
},

View File

@ -109,7 +109,10 @@
"reply": {
"cursor": {
"id": {
"$$type": "long"
"$$type": [
"int",
"long"
]
},
"ns": {
"$$type": "string"
@ -126,7 +129,10 @@
"commandStartedEvent": {
"command": {
"getMore": {
"$$type": "long"
"$$type": [
"int",
"long"
]
},
"collection": "coll0"
},
@ -138,7 +144,10 @@
"reply": {
"cursor": {
"id": {
"$$type": "long"
"$$type": [
"int",
"long"
]
},
"ns": {
"$$type": "string"

View File

@ -0,0 +1,68 @@
{
"description": "expectedEventsForClient-topologyDescriptionChangedEvent",
"schemaVersion": "1.20",
"runOnRequirements": [
{
"topologies": [
"replicaset"
],
"minServerVersion": "4.4"
}
],
"tests": [
{
"description": "can assert on values of newDescription and previousDescription fields",
"operations": [
{
"name": "createEntities",
"object": "testRunner",
"arguments": {
"entities": [
{
"client": {
"id": "client",
"uriOptions": {
"directConnection": true
},
"observeEvents": [
"topologyDescriptionChangedEvent"
]
}
}
]
}
},
{
"name": "waitForEvent",
"object": "testRunner",
"arguments": {
"client": "client",
"event": {
"topologyDescriptionChangedEvent": {}
},
"count": 1
}
}
],
"expectEvents": [
{
"client": "client",
"eventType": "sdam",
"ignoreExtraEvents": true,
"events": [
{
"topologyDescriptionChangedEvent": {
"previousDescription": {
"type": "Unknown"
},
"newDescription": {
"type": "Single"
}
}
}
]
}
]
}
]
}

View File

@ -322,7 +322,7 @@
"minServerVersion": "4.1.0",
"topologies": [
"replicaset",
"sharded-replicaset"
"sharded"
],
"serverless": "forbid"
}

View File

@ -264,7 +264,7 @@
{
"minServerVersion": "4.1.8",
"topologies": [
"sharded-replicaset"
"sharded"
]
}
],

View File

@ -11,7 +11,7 @@
{
"minServerVersion": "4.1.8",
"topologies": [
"sharded-replicaset"
"sharded"
]
}
],

View File

@ -5,7 +5,7 @@
{
"minServerVersion": "4.1.8",
"topologies": [
"sharded-replicaset"
"sharded"
]
}
],

View File

@ -11,7 +11,7 @@
{
"minServerVersion": "4.1.8",
"topologies": [
"sharded-replicaset"
"sharded"
]
}
],
@ -93,7 +93,7 @@
"minServerVersion": "4.3.4",
"topologies": [
"replicaset",
"sharded-replicaset"
"sharded"
]
}
],
@ -203,7 +203,7 @@
"minServerVersion": "4.3.4",
"topologies": [
"replicaset",
"sharded-replicaset"
"sharded"
]
}
],

View File

@ -814,84 +814,79 @@ class MatchEvaluatorUtil:
self.test.assertEqual(expectation, actual)
return None
def assertHasDatabaseName(self, spec, actual):
if "databaseName" in spec:
self.test.assertEqual(spec["databaseName"], actual.database_name)
def assertHasServiceId(self, spec, actual):
if "hasServiceId" in spec:
if spec.get("hasServiceId"):
self.test.assertIsNotNone(actual.service_id)
self.test.assertIsInstance(actual.service_id, ObjectId)
else:
self.test.assertIsNone(actual.service_id)
def assertHasInterruptInUseConnections(self, spec, actual):
if "interruptInUseConnections" in spec:
self.test.assertEqual(
spec.get("interruptInUseConnections"), actual.interrupt_connections
)
else:
self.test.assertIsInstance(actual.interrupt_connections, bool)
def assertHasServerConnectionId(self, spec, actual):
if "hasServerConnectionId" in spec:
if spec.get("hasServerConnectionId"):
self.test.assertIsNotNone(actual.server_connection_id)
self.test.assertIsInstance(actual.server_connection_id, int)
else:
self.test.assertIsNone(actual.server_connection_id)
def match_server_description(self, actual: ServerDescription, spec: dict) -> None:
if "type" in spec:
self.test.assertEqual(actual.server_type_name, spec["type"])
if "error" in spec:
self.test.process_error(actual.error, spec["error"])
if "minWireVersion" in spec:
self.test.assertEqual(actual.min_wire_version, spec["minWireVersion"])
if "maxWireVersion" in spec:
self.test.assertEqual(actual.max_wire_version, spec["maxWireVersion"])
if "topologyVersion" in spec:
self.test.assertEqual(actual.topology_version, spec["topologyVersion"])
for field, expected in spec.items():
field = camel_to_snake(field)
if field == "type":
field = "server_type_name"
self.test.assertEqual(getattr(actual, field), expected)
def match_event(self, event_type, expectation, actual):
def match_topology_description(self, actual: TopologyDescription, spec: dict) -> None:
for field, expected in spec.items():
field = camel_to_snake(field)
if field == "type":
field = "topology_type_name"
self.test.assertEqual(getattr(actual, field), expected)
def match_event_fields(self, actual: Any, spec: dict) -> None:
for field, expected in spec.items():
if field == "command" and isinstance(actual, CommandStartedEvent):
command = spec["command"]
if command:
self.match_result(command, actual.command)
continue
if field == "reply" and isinstance(actual, CommandSucceededEvent):
reply = spec["reply"]
if reply:
self.match_result(reply, actual.reply)
continue
if field == "hasServiceId":
if spec["hasServiceId"]:
self.test.assertIsNotNone(actual.service_id)
self.test.assertIsInstance(actual.service_id, ObjectId)
else:
self.test.assertIsNone(actual.service_id)
continue
if field == "hasServerConnectionId":
if spec["hasServerConnectionId"]:
self.test.assertIsNotNone(actual.server_connection_id)
self.test.assertIsInstance(actual.server_connection_id, int)
else:
self.test.assertIsNone(actual.server_connection_id)
continue
if field in ("previousDescription", "newDescription"):
if isinstance(actual, ServerDescriptionChangedEvent):
self.match_server_description(
getattr(actual, camel_to_snake(field)), spec[field]
)
continue
if isinstance(actual, TopologyDescriptionChangedEvent):
self.match_topology_description(
getattr(actual, camel_to_snake(field)), spec[field]
)
continue
if field == "interruptInUseConnections":
field = "interrupt_connections"
else:
field = camel_to_snake(field)
self.test.assertEqual(getattr(actual, field), expected)
def match_event(self, expectation, actual):
name, spec = next(iter(expectation.items()))
# every command event has the commandName field
if event_type == "command":
command_name = spec.get("commandName")
if command_name:
self.test.assertEqual(command_name, actual.command_name)
if name == "commandStartedEvent":
self.test.assertIsInstance(actual, CommandStartedEvent)
command = spec.get("command")
if command:
self.match_result(command, actual.command)
self.assertHasDatabaseName(spec, actual)
self.assertHasServiceId(spec, actual)
self.assertHasServerConnectionId(spec, actual)
elif name == "commandSucceededEvent":
self.test.assertIsInstance(actual, CommandSucceededEvent)
reply = spec.get("reply")
if reply:
self.match_result(reply, actual.reply)
self.assertHasDatabaseName(spec, actual)
self.assertHasServiceId(spec, actual)
self.assertHasServerConnectionId(spec, actual)
elif name == "commandFailedEvent":
self.test.assertIsInstance(actual, CommandFailedEvent)
self.assertHasServiceId(spec, actual)
self.assertHasDatabaseName(spec, actual)
self.assertHasServerConnectionId(spec, actual)
elif name == "poolCreatedEvent":
self.test.assertIsInstance(actual, PoolCreatedEvent)
elif name == "poolReadyEvent":
self.test.assertIsInstance(actual, PoolReadyEvent)
elif name == "poolClearedEvent":
self.test.assertIsInstance(actual, PoolClearedEvent)
self.assertHasServiceId(spec, actual)
self.assertHasInterruptInUseConnections(spec, actual)
self.test.assertIsInstance(actual.interrupt_connections, bool)
elif name == "poolClosedEvent":
self.test.assertIsInstance(actual, PoolClosedEvent)
elif name == "connectionCreatedEvent":
@ -900,43 +895,29 @@ class MatchEvaluatorUtil:
self.test.assertIsInstance(actual, ConnectionReadyEvent)
elif name == "connectionClosedEvent":
self.test.assertIsInstance(actual, ConnectionClosedEvent)
if "reason" in spec:
self.test.assertEqual(actual.reason, spec["reason"])
elif name == "connectionCheckOutStartedEvent":
self.test.assertIsInstance(actual, ConnectionCheckOutStartedEvent)
elif name == "connectionCheckOutFailedEvent":
self.test.assertIsInstance(actual, ConnectionCheckOutFailedEvent)
if "reason" in spec:
self.test.assertEqual(actual.reason, spec["reason"])
elif name == "connectionCheckedOutEvent":
self.test.assertIsInstance(actual, ConnectionCheckedOutEvent)
elif name == "connectionCheckedInEvent":
self.test.assertIsInstance(actual, ConnectionCheckedInEvent)
elif name == "serverDescriptionChangedEvent":
self.test.assertIsInstance(actual, ServerDescriptionChangedEvent)
if "previousDescription" in spec:
self.match_server_description(
actual.previous_description, spec["previousDescription"]
)
if "newDescription" in spec:
self.match_server_description(actual.new_description, spec["newDescription"])
elif name == "serverHeartbeatStartedEvent":
self.test.assertIsInstance(actual, ServerHeartbeatStartedEvent)
if "awaited" in spec:
self.test.assertEqual(actual.awaited, spec["awaited"])
elif name == "serverHeartbeatSucceededEvent":
self.test.assertIsInstance(actual, ServerHeartbeatSucceededEvent)
if "awaited" in spec:
self.test.assertEqual(actual.awaited, spec["awaited"])
elif name == "serverHeartbeatFailedEvent":
self.test.assertIsInstance(actual, ServerHeartbeatFailedEvent)
if "awaited" in spec:
self.test.assertEqual(actual.awaited, spec["awaited"])
elif name == "topologyDescriptionChangedEvent":
self.test.assertIsInstance(actual, TopologyDescriptionChangedEvent)
else:
raise Exception(f"Unsupported event type {name}")
self.match_event_fields(actual, spec)
def coerce_result(opname, result):
"""Convert a pymongo result into the spec's result format."""
@ -972,7 +953,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
a class attribute ``TEST_SPEC``.
"""
SCHEMA_VERSION = Version.from_string("1.19")
SCHEMA_VERSION = Version.from_string("1.20")
RUN_ON_LOAD_BALANCER = True
RUN_ON_SERVERLESS = True
TEST_SPEC: Any
@ -1068,6 +1049,10 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
if "unpin after TransientTransactionError error on" in spec["description"]:
self.skipTest("Skipping TransientTransactionError pending PYTHON-4227")
if "withTransaction commits after callback returns" in spec["description"]:
self.skipTest("Skipping TransientTransactionError pending PYTHON-4303")
if "unpin on successful abort" in spec["description"]:
self.skipTest("Skipping TransientTransactionError pending PYTHON-4227")
if "unpin after non-transient error on abort" in spec["description"]:
if client_context.version[0] == 8:
@ -1606,7 +1591,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
count = 0
for actual in actual_events:
try:
self.match_evaluator.match_event("all", event, actual)
self.match_evaluator.match_event(event, actual)
except AssertionError:
continue
else:
@ -1763,10 +1748,17 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
self.assertEqual(actual_events, [])
continue
self.assertEqual(len(actual_events), len(events), actual_events)
if len(actual_events) != len(events):
expected = "\n".join(str(e) for e in events)
actual = "\n".join(str(a) for a in actual_events)
self.assertEqual(
len(actual_events),
len(events),
f"expected events:\n{expected}\nactual events:\n{actual}",
)
for idx, expected_event in enumerate(events):
self.match_evaluator.match_event(event_type, expected_event, actual_events[idx])
self.match_evaluator.match_event(expected_event, actual_events[idx])
if has_server_connection_id:
assert server_connection_id is not None
@ -1800,6 +1792,8 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
clientid = self.entity_map[client["client"]]._topology_settings._topology_id
actual_logs = formatted_logs[clientid]
actual_logs = [log for log in actual_logs if log["component"] in components]
if client.get("ignoreExtraMessages", False):
actual_logs = actual_logs[: len(client["messages"])]
self.assertEqual(len(client["messages"]), len(actual_logs))
for expected_msg, actual_msg in zip(client["messages"], actual_logs):
expected_data, actual_data = expected_msg.pop("data"), actual_msg.pop("data")