From 6ac44d14700681e9e8cfd52f0b87e3b28d2a117a Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Wed, 7 Apr 2021 15:19:31 -0700 Subject: [PATCH 1/4] PYTHON-2635 Resync transactions spec tests --- test/transactions/{ => legacy}/abort.json | 0 test/transactions/{ => legacy}/bulk.json | 0 .../{ => legacy}/causal-consistency.json | 0 test/transactions/{ => legacy}/commit.json | 0 test/transactions/{ => legacy}/count.json | 0 .../{ => legacy}/create-collection.json | 0 .../{ => legacy}/create-index.json | 0 test/transactions/{ => legacy}/delete.json | 0 .../{ => legacy}/error-labels.json | 0 test/transactions/{ => legacy}/errors.json | 0 .../{ => legacy}/findOneAndDelete.json | 0 .../{ => legacy}/findOneAndReplace.json | 0 .../{ => legacy}/findOneAndUpdate.json | 0 test/transactions/{ => legacy}/insert.json | 0 test/transactions/{ => legacy}/isolation.json | 0 .../{ => legacy}/mongos-pin-auto.json | 0 .../{ => legacy}/mongos-recovery-token.json | 0 .../transactions/{ => legacy}/pin-mongos.json | 0 .../{ => legacy}/read-concern.json | 0 test/transactions/{ => legacy}/read-pref.json | 0 test/transactions/{ => legacy}/reads.json | 0 .../retryable-abort-errorLabels.json | 0 .../{ => legacy}/retryable-abort.json | 0 .../retryable-commit-errorLabels.json | 0 .../{ => legacy}/retryable-commit.json | 0 .../{ => legacy}/retryable-writes.json | 0 .../{ => legacy}/run-command.json | 0 .../transaction-options-repl.json | 0 .../{ => legacy}/transaction-options.json | 0 test/transactions/{ => legacy}/update.json | 0 .../{ => legacy}/write-concern.json | 0 test/transactions/unified/mongos-unpin.json | 373 ++++++++++++++++++ 32 files changed, 373 insertions(+) rename test/transactions/{ => legacy}/abort.json (100%) rename test/transactions/{ => legacy}/bulk.json (100%) rename test/transactions/{ => legacy}/causal-consistency.json (100%) rename test/transactions/{ => legacy}/commit.json (100%) rename test/transactions/{ => legacy}/count.json (100%) rename test/transactions/{ => legacy}/create-collection.json (100%) rename test/transactions/{ => legacy}/create-index.json (100%) rename test/transactions/{ => legacy}/delete.json (100%) rename test/transactions/{ => legacy}/error-labels.json (100%) rename test/transactions/{ => legacy}/errors.json (100%) rename test/transactions/{ => legacy}/findOneAndDelete.json (100%) rename test/transactions/{ => legacy}/findOneAndReplace.json (100%) rename test/transactions/{ => legacy}/findOneAndUpdate.json (100%) rename test/transactions/{ => legacy}/insert.json (100%) rename test/transactions/{ => legacy}/isolation.json (100%) rename test/transactions/{ => legacy}/mongos-pin-auto.json (100%) rename test/transactions/{ => legacy}/mongos-recovery-token.json (100%) rename test/transactions/{ => legacy}/pin-mongos.json (100%) rename test/transactions/{ => legacy}/read-concern.json (100%) rename test/transactions/{ => legacy}/read-pref.json (100%) rename test/transactions/{ => legacy}/reads.json (100%) rename test/transactions/{ => legacy}/retryable-abort-errorLabels.json (100%) rename test/transactions/{ => legacy}/retryable-abort.json (100%) rename test/transactions/{ => legacy}/retryable-commit-errorLabels.json (100%) rename test/transactions/{ => legacy}/retryable-commit.json (100%) rename test/transactions/{ => legacy}/retryable-writes.json (100%) rename test/transactions/{ => legacy}/run-command.json (100%) rename test/transactions/{ => legacy}/transaction-options-repl.json (100%) rename test/transactions/{ => legacy}/transaction-options.json (100%) rename test/transactions/{ => legacy}/update.json (100%) rename test/transactions/{ => legacy}/write-concern.json (100%) create mode 100644 test/transactions/unified/mongos-unpin.json diff --git a/test/transactions/abort.json b/test/transactions/legacy/abort.json similarity index 100% rename from test/transactions/abort.json rename to test/transactions/legacy/abort.json diff --git a/test/transactions/bulk.json b/test/transactions/legacy/bulk.json similarity index 100% rename from test/transactions/bulk.json rename to test/transactions/legacy/bulk.json diff --git a/test/transactions/causal-consistency.json b/test/transactions/legacy/causal-consistency.json similarity index 100% rename from test/transactions/causal-consistency.json rename to test/transactions/legacy/causal-consistency.json diff --git a/test/transactions/commit.json b/test/transactions/legacy/commit.json similarity index 100% rename from test/transactions/commit.json rename to test/transactions/legacy/commit.json diff --git a/test/transactions/count.json b/test/transactions/legacy/count.json similarity index 100% rename from test/transactions/count.json rename to test/transactions/legacy/count.json diff --git a/test/transactions/create-collection.json b/test/transactions/legacy/create-collection.json similarity index 100% rename from test/transactions/create-collection.json rename to test/transactions/legacy/create-collection.json diff --git a/test/transactions/create-index.json b/test/transactions/legacy/create-index.json similarity index 100% rename from test/transactions/create-index.json rename to test/transactions/legacy/create-index.json diff --git a/test/transactions/delete.json b/test/transactions/legacy/delete.json similarity index 100% rename from test/transactions/delete.json rename to test/transactions/legacy/delete.json diff --git a/test/transactions/error-labels.json b/test/transactions/legacy/error-labels.json similarity index 100% rename from test/transactions/error-labels.json rename to test/transactions/legacy/error-labels.json diff --git a/test/transactions/errors.json b/test/transactions/legacy/errors.json similarity index 100% rename from test/transactions/errors.json rename to test/transactions/legacy/errors.json diff --git a/test/transactions/findOneAndDelete.json b/test/transactions/legacy/findOneAndDelete.json similarity index 100% rename from test/transactions/findOneAndDelete.json rename to test/transactions/legacy/findOneAndDelete.json diff --git a/test/transactions/findOneAndReplace.json b/test/transactions/legacy/findOneAndReplace.json similarity index 100% rename from test/transactions/findOneAndReplace.json rename to test/transactions/legacy/findOneAndReplace.json diff --git a/test/transactions/findOneAndUpdate.json b/test/transactions/legacy/findOneAndUpdate.json similarity index 100% rename from test/transactions/findOneAndUpdate.json rename to test/transactions/legacy/findOneAndUpdate.json diff --git a/test/transactions/insert.json b/test/transactions/legacy/insert.json similarity index 100% rename from test/transactions/insert.json rename to test/transactions/legacy/insert.json diff --git a/test/transactions/isolation.json b/test/transactions/legacy/isolation.json similarity index 100% rename from test/transactions/isolation.json rename to test/transactions/legacy/isolation.json diff --git a/test/transactions/mongos-pin-auto.json b/test/transactions/legacy/mongos-pin-auto.json similarity index 100% rename from test/transactions/mongos-pin-auto.json rename to test/transactions/legacy/mongos-pin-auto.json diff --git a/test/transactions/mongos-recovery-token.json b/test/transactions/legacy/mongos-recovery-token.json similarity index 100% rename from test/transactions/mongos-recovery-token.json rename to test/transactions/legacy/mongos-recovery-token.json diff --git a/test/transactions/pin-mongos.json b/test/transactions/legacy/pin-mongos.json similarity index 100% rename from test/transactions/pin-mongos.json rename to test/transactions/legacy/pin-mongos.json diff --git a/test/transactions/read-concern.json b/test/transactions/legacy/read-concern.json similarity index 100% rename from test/transactions/read-concern.json rename to test/transactions/legacy/read-concern.json diff --git a/test/transactions/read-pref.json b/test/transactions/legacy/read-pref.json similarity index 100% rename from test/transactions/read-pref.json rename to test/transactions/legacy/read-pref.json diff --git a/test/transactions/reads.json b/test/transactions/legacy/reads.json similarity index 100% rename from test/transactions/reads.json rename to test/transactions/legacy/reads.json diff --git a/test/transactions/retryable-abort-errorLabels.json b/test/transactions/legacy/retryable-abort-errorLabels.json similarity index 100% rename from test/transactions/retryable-abort-errorLabels.json rename to test/transactions/legacy/retryable-abort-errorLabels.json diff --git a/test/transactions/retryable-abort.json b/test/transactions/legacy/retryable-abort.json similarity index 100% rename from test/transactions/retryable-abort.json rename to test/transactions/legacy/retryable-abort.json diff --git a/test/transactions/retryable-commit-errorLabels.json b/test/transactions/legacy/retryable-commit-errorLabels.json similarity index 100% rename from test/transactions/retryable-commit-errorLabels.json rename to test/transactions/legacy/retryable-commit-errorLabels.json diff --git a/test/transactions/retryable-commit.json b/test/transactions/legacy/retryable-commit.json similarity index 100% rename from test/transactions/retryable-commit.json rename to test/transactions/legacy/retryable-commit.json diff --git a/test/transactions/retryable-writes.json b/test/transactions/legacy/retryable-writes.json similarity index 100% rename from test/transactions/retryable-writes.json rename to test/transactions/legacy/retryable-writes.json diff --git a/test/transactions/run-command.json b/test/transactions/legacy/run-command.json similarity index 100% rename from test/transactions/run-command.json rename to test/transactions/legacy/run-command.json diff --git a/test/transactions/transaction-options-repl.json b/test/transactions/legacy/transaction-options-repl.json similarity index 100% rename from test/transactions/transaction-options-repl.json rename to test/transactions/legacy/transaction-options-repl.json diff --git a/test/transactions/transaction-options.json b/test/transactions/legacy/transaction-options.json similarity index 100% rename from test/transactions/transaction-options.json rename to test/transactions/legacy/transaction-options.json diff --git a/test/transactions/update.json b/test/transactions/legacy/update.json similarity index 100% rename from test/transactions/update.json rename to test/transactions/legacy/update.json diff --git a/test/transactions/write-concern.json b/test/transactions/legacy/write-concern.json similarity index 100% rename from test/transactions/write-concern.json rename to test/transactions/legacy/write-concern.json diff --git a/test/transactions/unified/mongos-unpin.json b/test/transactions/unified/mongos-unpin.json new file mode 100644 index 0000000000..33127198a8 --- /dev/null +++ b/test/transactions/unified/mongos-unpin.json @@ -0,0 +1,373 @@ +{ + "description": "mongos-unpin", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "topologies": [ + "sharded-replicaset" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "mongos-unpin-db" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "mongos-unpin-db", + "documents": [] + } + ], + "_yamlAnchors": { + "anchors": 24 + }, + "tests": [ + { + "description": "unpin after TransientTransctionError error on commit", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "targetedFailPoint", + "object": "testRunner", + "arguments": { + "session": "session0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "commitTransaction", + "object": "session0", + "expectError": { + "errorCode": 24, + "errorLabelsContain": [ + "TransientTransactionError" + ], + "errorLabelsOmit": [ + "UnknownTransactionCommitResult" + ] + } + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin on successful abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin after TransientTransctionError error on abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "targetedFailPoint", + "object": "testRunner", + "arguments": { + "session": "session0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin after non-transient error on abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "targetedFailPoint", + "object": "testRunner", + "arguments": { + "session": "session0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 91 + } + } + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin when a new transaction is started", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertSessionPinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin when a non-transaction write operation uses a session", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertSessionPinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin when a non-transaction read operation uses a session", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertSessionPinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + } + ] +} From c7a99c56f22c1c9b33665b0e37de4982866758a7 Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Wed, 7 Apr 2021 15:42:06 -0700 Subject: [PATCH 2/4] PYTHON-2635 Add unified test runner for txns --- test/test_transactions.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/test_transactions.py b/test/test_transactions.py index 859c8f3e25..09746ec28a 100644 --- a/test/test_transactions.py +++ b/test/test_transactions.py @@ -39,10 +39,13 @@ wait_until, OvertCommandListener, TestCreator) from test.utils_spec_runner import SpecRunner +from test.unified_format import generate_test_classes # Location of JSON test specifications. _TEST_PATH = os.path.join( - os.path.dirname(os.path.realpath(__file__)), 'transactions') + os.path.dirname(os.path.realpath(__file__)), 'transactions', 'legacy') +_UNIFIED_TEST_PATH = os.path.join( + os.path.dirname(os.path.realpath(__file__)), 'transactions', 'unified') _TXN_TESTS_DEBUG = os.environ.get('TRANSACTION_TESTS_DEBUG') @@ -474,5 +477,12 @@ def run_scenario(self): TestTransactionsConvenientAPI.TEST_PATH).create_tests() +UNIFIED_TEST_PATH = os.path.join( + os.path.dirname(os.path.realpath(__file__)), 'versioned-api') + +# Generate unified tests. +globals().update(generate_test_classes(_UNIFIED_TEST_PATH, module=__name__)) + + if __name__ == "__main__": unittest.main() From e50bd5898e594f475ba5e3044fe3ffe964a8edcd Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Thu, 8 Apr 2021 10:32:20 -0700 Subject: [PATCH 3/4] PYTHON-2635 Unpin on abortTransaction --- pymongo/client_session.py | 1 + test/unified_format.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pymongo/client_session.py b/pymongo/client_session.py index 5e3f081940..950fe0dc13 100644 --- a/pymongo/client_session.py +++ b/pymongo/client_session.py @@ -660,6 +660,7 @@ def abort_transaction(self): pass finally: self._transaction.state = _TxnState.ABORTED + self._unpin_mongos() def _finish_transaction_with_retry(self, command_name): """Run commit or abort with one retry after any retryable error. diff --git a/test/unified_format.py b/test/unified_format.py index fc23a193b1..3a5e5782c0 100644 --- a/test/unified_format.py +++ b/test/unified_format.py @@ -820,11 +820,12 @@ def _testOperation_assertSessionTransactionState(self, spec): def _testOperation_assertSessionPinned(self, spec): session = self.entity_map[spec['session']] - self.assertIsNotNone(session._pinned_address) + self.assertIsNotNone(session._transaction.pinned_address) def _testOperation_assertSessionUnpinned(self, spec): session = self.entity_map[spec['session']] self.assertIsNone(session._pinned_address) + self.assertIsNone(session._transaction.pinned_address) def __get_last_two_command_lsids(self, listener): cmd_started_events = [] From 13c6431da2f0ac4ba3a6fed64fc10054ea689193 Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Wed, 28 Apr 2021 12:36:42 -0700 Subject: [PATCH 4/4] PYTHON-2635 Remove cruft --- test/test_transactions.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/test_transactions.py b/test/test_transactions.py index 09746ec28a..2e154d4bc5 100644 --- a/test/test_transactions.py +++ b/test/test_transactions.py @@ -42,9 +42,9 @@ from test.unified_format import generate_test_classes # Location of JSON test specifications. -_TEST_PATH = os.path.join( +TEST_PATH = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'transactions', 'legacy') -_UNIFIED_TEST_PATH = os.path.join( +UNIFIED_TEST_PATH = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'transactions', 'unified') _TXN_TESTS_DEBUG = os.environ.get('TRANSACTION_TESTS_DEBUG') @@ -469,7 +469,7 @@ def run_scenario(self): return run_scenario -test_creator = TestCreator(create_test, TestTransactions, _TEST_PATH) +test_creator = TestCreator(create_test, TestTransactions, TEST_PATH) test_creator.create_tests() @@ -477,11 +477,8 @@ def run_scenario(self): TestTransactionsConvenientAPI.TEST_PATH).create_tests() -UNIFIED_TEST_PATH = os.path.join( - os.path.dirname(os.path.realpath(__file__)), 'versioned-api') - # Generate unified tests. -globals().update(generate_test_classes(_UNIFIED_TEST_PATH, module=__name__)) +globals().update(generate_test_classes(UNIFIED_TEST_PATH, module=__name__)) if __name__ == "__main__":