From 917173fe02b953ff60d566b56d459fdd3bab95c3 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 10 Jun 2026 14:13:18 -0700 Subject: [PATCH 01/15] initial generated tests Signed-off-by: Alina (Xi) Li --- .../commands/abortTransaction/__init__.py | 1 + .../test_abortTransaction_autocommit.py | 116 +++++ .../test_abortTransaction_comment.py | 161 +++++++ .../test_abortTransaction_core.py | 311 +++++++++++++ .../test_abortTransaction_field_types.py | 203 ++++++++ .../test_abortTransaction_txn_number.py | 129 ++++++ ...st_abortTransaction_unrecognized_fields.py | 106 +++++ .../test_abortTransaction_writeconcern.py | 432 ++++++++++++++++++ .../core/sessions/commands/utils/__init__.py | 1 + .../utils/session_command_test_case.py | 23 + .../commands/utils/session_test_case.py | 107 +++++ documentdb_tests/framework/error_codes.py | 1 + documentdb_tests/framework/executor.py | 130 ++++++ .../framework/test_format_validator.py | 2 + 14 files changed, 1723 insertions(+) create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/utils/__init__.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_command_test_case.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py new file mode 100644 index 000000000..8848fcb30 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py @@ -0,0 +1 @@ +"""Tests for abortTransaction command.""" diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py new file mode 100644 index 000000000..4a9c42997 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py @@ -0,0 +1,116 @@ +"""Tests for abortTransaction autocommit parameter validation. + +Validates type and value acceptance for the autocommit parameter. Per the +MongoDB documentation, autocommit must be literal boolean false. Boolean true +produces InvalidOptions, non-boolean types produce TypeMismatch, and null is +treated as omitted (falls through to NoSuchTransaction). +""" + +from __future__ import annotations + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import ( + INVALID_OPTIONS_ERROR, + NO_SUCH_TRANSACTION_ERROR, + TYPE_MISMATCH_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + + +# Property [autocommit Boolean Values]: autocommit accepts only boolean values. +AUTOCOMMIT_BOOLEAN_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "autocommit_bool_false", + command={"abortTransaction": 1, "autocommit": False}, + error_code=INVALID_OPTIONS_ERROR, + msg="abortTransaction should reject autocommit:false outside txn with InvalidOptions", + ), + SessionCommandTestCase( + "autocommit_bool_true", + command={"abortTransaction": 1, "autocommit": True}, + error_code=INVALID_OPTIONS_ERROR, + msg="abortTransaction should reject autocommit:true with InvalidOptions", + ), +] + +# Property [autocommit Type Strictness]: non-boolean types are rejected with TypeMismatch. +AUTOCOMMIT_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "autocommit_int32_zero", + command={"abortTransaction": 1, "autocommit": 0}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:0 (int32) as wrong type", + ), + SessionCommandTestCase( + "autocommit_int32_one", + command={"abortTransaction": 1, "autocommit": 1}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:1 (int32) as wrong type", + ), + SessionCommandTestCase( + "autocommit_int64_zero", + command={"abortTransaction": 1, "autocommit": Int64(0)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:Int64(0) as wrong type", + ), + SessionCommandTestCase( + "autocommit_double_zero", + command={"abortTransaction": 1, "autocommit": 0.0}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:0.0 as wrong type", + ), + SessionCommandTestCase( + "autocommit_decimal128_zero", + command={"abortTransaction": 1, "autocommit": Decimal128("0")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:Decimal128('0') as wrong type", + ), + SessionCommandTestCase( + "autocommit_string", + command={"abortTransaction": 1, "autocommit": "false"}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:'false' (string) as wrong type", + ), + SessionCommandTestCase( + "autocommit_object", + command={"abortTransaction": 1, "autocommit": {}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:{} (object) as wrong type", + ), + SessionCommandTestCase( + "autocommit_array", + command={"abortTransaction": 1, "autocommit": []}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject autocommit:[] (array) as wrong type", + ), +] + +# Property [autocommit Null Handling]: null autocommit is treated as omitted. +AUTOCOMMIT_NULL_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "autocommit_null", + command={"abortTransaction": 1, "autocommit": None}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should treat autocommit:null as omitted", + ), +] + +AUTOCOMMIT_TESTS: list[SessionCommandTestCase] = ( + AUTOCOMMIT_BOOLEAN_TESTS + AUTOCOMMIT_TYPE_REJECTION_TESTS + AUTOCOMMIT_NULL_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(AUTOCOMMIT_TESTS)) +def test_abortTransaction_autocommit(collection, test): + """Test abortTransaction autocommit parameter validation.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py new file mode 100644 index 000000000..135f76dfc --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py @@ -0,0 +1,161 @@ +"""Tests for abortTransaction comment parameter type acceptance. + +Validates that the comment parameter accepts any BSON type. All types produce +NoSuchTransaction because no transaction is active, confirming the comment +field itself is not type-checked. +""" + +from __future__ import annotations + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + + +# Property [comment Type Acceptance]: comment accepts any BSON type. +COMMENT_TYPE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "comment_string", + command={"abortTransaction": 1, "comment": "test comment"}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:string", + ), + SessionCommandTestCase( + "comment_string_empty", + command={"abortTransaction": 1, "comment": ""}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:empty string", + ), + SessionCommandTestCase( + "comment_int32", + command={"abortTransaction": 1, "comment": 42}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:int32", + ), + SessionCommandTestCase( + "comment_int64", + command={"abortTransaction": 1, "comment": Int64(42)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:Int64", + ), + SessionCommandTestCase( + "comment_double", + command={"abortTransaction": 1, "comment": 3.14}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:double", + ), + SessionCommandTestCase( + "comment_decimal128", + command={"abortTransaction": 1, "comment": Decimal128("1.5")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:Decimal128", + ), + SessionCommandTestCase( + "comment_bool_true", + command={"abortTransaction": 1, "comment": True}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:true", + ), + SessionCommandTestCase( + "comment_bool_false", + command={"abortTransaction": 1, "comment": False}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:false", + ), + SessionCommandTestCase( + "comment_null", + command={"abortTransaction": 1, "comment": None}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:null", + ), + SessionCommandTestCase( + "comment_object", + command={"abortTransaction": 1, "comment": {"key": "value"}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:object", + ), + SessionCommandTestCase( + "comment_object_empty", + command={"abortTransaction": 1, "comment": {}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:empty object", + ), + SessionCommandTestCase( + "comment_array", + command={"abortTransaction": 1, "comment": [1, 2, 3]}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:array", + ), + SessionCommandTestCase( + "comment_array_empty", + command={"abortTransaction": 1, "comment": []}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:empty array", + ), + SessionCommandTestCase( + "comment_objectid", + command={"abortTransaction": 1, "comment": ObjectId()}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:ObjectId", + ), + SessionCommandTestCase( + "comment_datetime", + command={"abortTransaction": 1, "comment": datetime(2024, 1, 1, tzinfo=timezone.utc)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:datetime", + ), + SessionCommandTestCase( + "comment_binary", + command={"abortTransaction": 1, "comment": Binary(b"\x00")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:Binary", + ), + SessionCommandTestCase( + "comment_regex", + command={"abortTransaction": 1, "comment": Regex(".*")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:Regex", + ), + SessionCommandTestCase( + "comment_timestamp", + command={"abortTransaction": 1, "comment": Timestamp(0, 0)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:Timestamp", + ), + SessionCommandTestCase( + "comment_minkey", + command={"abortTransaction": 1, "comment": MinKey()}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:MinKey", + ), + SessionCommandTestCase( + "comment_maxkey", + command={"abortTransaction": 1, "comment": MaxKey()}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:MaxKey", + ), + SessionCommandTestCase( + "comment_code", + command={"abortTransaction": 1, "comment": Code("function(){}")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept comment:Code", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(COMMENT_TYPE_TESTS)) +def test_abortTransaction_comment(collection, test): + """Test abortTransaction comment parameter type acceptance.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py new file mode 100644 index 000000000..0ad472bc6 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -0,0 +1,311 @@ +"""Tests for abortTransaction command core behavior and success cases. + +Validates fundamental command behavior including the no-transaction error, +admin database requirement, and parameter interactions. Also validates that +abortTransaction rolls back operations within a real transaction context, +including insert, update, delete, and multi-operation transactions, verifies +the response structure on success, and that pre-transaction data survives abort. +""" + +from __future__ import annotations + +import pytest +from bson import Binary, Int64 + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( + AbortSessionTestCase, + SessionOp, + SessionOperation, +) +from documentdb_tests.framework.assertions import ( + assertFailureCode, + assertNotError, + assertSuccess, + assertSuccessPartial, +) +from documentdb_tests.framework.error_codes import ( + ILLEGAL_OPERATION_ERROR, + INVALID_OPTIONS_ERROR, + NO_SUCH_TRANSACTION_ERROR, + UNAUTHORIZED_ERROR, +) +from documentdb_tests.framework.executor import ( + execute_abort_session_command, + execute_admin_command, + execute_command, +) +from documentdb_tests.framework.parametrize import pytest_params + +# =========================================================================== +# Outside-transaction error tests (admin db) +# =========================================================================== + +pytestmark = pytest.mark.admin + + +# Property [No-Transaction Error]: abortTransaction outside a transaction fails. +CORE_NO_TRANSACTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "no_transaction_basic", + command={"abortTransaction": 1}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should fail with NoSuchTransaction outside a transaction", + ), +] + +# Property [Parameter Acceptance]: all valid parameters combined are syntactically accepted. +CORE_PARAMETER_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "all_valid_params", + command={ + "abortTransaction": 1, + "autocommit": False, + "txnNumber": Int64(1), + "writeConcern": {"w": "majority", "j": True, "wtimeout": 10_000}, + "comment": "full abort", + }, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction with all valid params should not produce a parsing error", + ), +] + +# Property [Parameter Interactions]: combinations of valid parameters behave correctly. +CORE_PARAMETER_INTERACTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "interaction_autocommit_only", + command={"abortTransaction": 1, "autocommit": False}, + error_code=INVALID_OPTIONS_ERROR, + msg="abortTransaction with autocommit:false only should fail with InvalidOptions", + ), + SessionCommandTestCase( + "interaction_txn_number_only", + command={"abortTransaction": 1, "txnNumber": Int64(1)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction with txnNumber only should fail with IllegalOperation", + ), + SessionCommandTestCase( + "interaction_autocommit_txn_number", + command={"abortTransaction": 1, "autocommit": False, "txnNumber": Int64(1)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction with autocommit + txnNumber should fail with IllegalOperation", + ), + SessionCommandTestCase( + "interaction_lsid", + command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction with explicit lsid should accept the field", + ), +] + +CORE_TESTS: list[SessionCommandTestCase] = ( + CORE_NO_TRANSACTION_TESTS + CORE_PARAMETER_ACCEPTANCE_TESTS + CORE_PARAMETER_INTERACTION_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(CORE_TESTS)) +def test_abortTransaction_core(collection, test): + """Test abortTransaction core behavior.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) + + +# Property [Admin Database Requirement]: abortTransaction must run against the admin database. +ADMIN_DB_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "non_admin_database", + command={"abortTransaction": 1}, + error_code=UNAUTHORIZED_ERROR, + msg="abortTransaction on a non-admin database should fail with Unauthorized", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(ADMIN_DB_TESTS)) +def test_abortTransaction_admin_db_required(collection, test): + """Test abortTransaction requires admin database.""" + result = execute_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) + + +# =========================================================================== +# In-transaction success tests (replica_set) +# =========================================================================== + + +# --------------------------------------------------------------------------- +# Property [Abort Rollback]: aborted operations are rolled back. +# --------------------------------------------------------------------------- + +ABORT_ROLLBACK_TESTS: list[AbortSessionTestCase] = [ + AbortSessionTestCase( + "abort_insert", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1, "x": "inserted"})], + expected=[], + msg="abortTransaction should roll back the inserted document", + ), + AbortSessionTestCase( + "abort_update", + docs=[{"_id": 1, "x": "before"}], + ops=[ + SessionOperation( + op=SessionOp.UPDATE, + filter={"_id": 1}, + update={"$set": {"x": "after"}}, + ) + ], + expected=[{"_id": 1, "x": "before"}], + msg="abortTransaction should roll back the updated value", + ), + AbortSessionTestCase( + "abort_delete", + docs=[{"_id": 1, "x": "to_delete"}], + ops=[SessionOperation(op=SessionOp.DELETE, filter={"_id": 1})], + expected=[{"_id": 1, "x": "to_delete"}], + msg="abortTransaction should roll back the deletion", + ), + AbortSessionTestCase( + "abort_multi_operation", + docs=[{"_id": 1, "x": "original"}], + ops=[ + SessionOperation(op=SessionOp.INSERT, document={"_id": 2, "x": "new"}), + SessionOperation( + op=SessionOp.UPDATE, + filter={"_id": 1}, + update={"$set": {"x": "modified"}}, + ), + ], + expected=[{"_id": 1, "x": "original"}], + msg="abortTransaction should roll back all operations from a multi-op transaction", + ), + AbortSessionTestCase( + "abort_with_writeconcern", + docs=[{"_id": 1, "x": "before"}], + ops=[ + SessionOperation( + op=SessionOp.UPDATE, + filter={"_id": 1}, + update={"$set": {"x": "after"}}, + ) + ], + abort_command={"abortTransaction": 1, "writeConcern": {"w": 1}}, + expected=[{"_id": 1, "x": "before"}], + msg="abortTransaction with writeConcern should roll back changes", + ), + AbortSessionTestCase( + "abort_insert_delete_same_doc", + ops=[ + SessionOperation(op=SessionOp.INSERT, document={"_id": 1}), + SessionOperation(op=SessionOp.DELETE, filter={"_id": 1}), + ], + expected=[], + msg="abortTransaction should roll back insert+delete of the same document", + ), + AbortSessionTestCase( + "abort_multiple_inserts", + ops=[ + SessionOperation(op=SessionOp.INSERT, document={"_id": 1}), + SessionOperation(op=SessionOp.INSERT, document={"_id": 2}), + ], + expected=[], + msg="abortTransaction should roll back multiple inserts", + ), + AbortSessionTestCase( + "abort_update_insert_different_docs", + docs=[{"_id": 1, "x": "original"}], + ops=[ + SessionOperation( + op=SessionOp.UPDATE, + filter={"_id": 1}, + update={"$set": {"x": "modified"}}, + ), + SessionOperation(op=SessionOp.INSERT, document={"_id": 2, "x": "new"}), + ], + expected=[{"_id": 1, "x": "original"}], + msg="abortTransaction should roll back update+insert of different documents", + ), +] + + +@pytest.mark.replica_set +@pytest.mark.parametrize("test", pytest_params(ABORT_ROLLBACK_TESTS)) +def test_abortTransaction_core_rollback(collection, test): + """Test abortTransaction rolls back operations.""" + result = execute_abort_session_command(collection, test) + assertSuccess(result, test.expected, msg=test.msg) + + +# --------------------------------------------------------------------------- +# Property [Pre-Transaction Data Survival]: seed data survives abort. +# --------------------------------------------------------------------------- + +PRE_TRANSACTION_TESTS: list[AbortSessionTestCase] = [ + AbortSessionTestCase( + "pre_existing_data_survives", + docs=[{"_id": 1, "x": "seed"}], + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 2, "x": "txn"})], + expected=[{"_id": 1, "x": "seed"}], + msg="Pre-existing documents should survive abort", + ), +] + + +@pytest.mark.replica_set +@pytest.mark.parametrize("test", pytest_params(PRE_TRANSACTION_TESTS)) +def test_abortTransaction_core_pre_transaction_data(collection, test): + """Test pre-transaction data survives abort.""" + result = execute_abort_session_command(collection, test) + assertSuccess(result, test.expected, msg=test.msg) + + +# --------------------------------------------------------------------------- +# Property [Empty Transaction]: aborting a transaction with no ops succeeds. +# --------------------------------------------------------------------------- + +EMPTY_TRANSACTION_TESTS: list[AbortSessionTestCase] = [ + AbortSessionTestCase( + "abort_empty_transaction", + ops=[], + msg="abortTransaction on empty transaction should not error", + ), +] + + +@pytest.mark.replica_set +@pytest.mark.parametrize("test", pytest_params(EMPTY_TRANSACTION_TESTS)) +def test_abortTransaction_core_empty(collection, test): + """Test abortTransaction succeeds on an empty transaction.""" + result = execute_abort_session_command(collection, test) + assertNotError(result, msg=test.msg) + + +# --------------------------------------------------------------------------- +# Property [Response Structure]: abort response contains ok:1 on success. +# --------------------------------------------------------------------------- + +RESPONSE_STRUCTURE_TESTS: list[AbortSessionTestCase] = [ + AbortSessionTestCase( + "abort_response_ok", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + abort_command={"abortTransaction": 1}, + expected_response={"ok": 1.0}, + msg="abortTransaction response should have ok:1 on success", + ), + AbortSessionTestCase( + "abort_with_comment", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + abort_command={"abortTransaction": 1, "comment": "test abort"}, + expected_response={"ok": 1.0}, + msg="abortTransaction with comment should succeed", + ), +] + + +@pytest.mark.replica_set +@pytest.mark.parametrize("test", pytest_params(RESPONSE_STRUCTURE_TESTS)) +def test_abortTransaction_core_response(collection, test): + """Test abortTransaction returns expected response fields.""" + result = execute_abort_session_command(collection, test) + assertSuccessPartial(result, test.expected_response, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py new file mode 100644 index 000000000..a2522b3fd --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py @@ -0,0 +1,203 @@ +"""Tests for abortTransaction command field type acceptance. + +Validates that the abortTransaction command's primary field accepts all BSON +types. All types produce NoSuchTransaction because no transaction is active, +confirming the field value itself is not type-checked. +""" + +from __future__ import annotations + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + + +# Property [Field Type Acceptance]: the command field accepts any BSON type. +FIELD_TYPE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "field_int32_positive", + command={"abortTransaction": 1}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept int32 positive value", + ), + SessionCommandTestCase( + "field_int32_negative", + command={"abortTransaction": -1}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept int32 negative value", + ), + SessionCommandTestCase( + "field_int32_zero", + command={"abortTransaction": 0}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept int32 zero value", + ), + SessionCommandTestCase( + "field_int64", + command={"abortTransaction": Int64(1)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept int64 value", + ), + SessionCommandTestCase( + "field_int64_max", + command={"abortTransaction": Int64(9_223_372_036_854_775_807)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept int64 max value", + ), + SessionCommandTestCase( + "field_double", + command={"abortTransaction": 1.0}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept double value", + ), + SessionCommandTestCase( + "field_double_negative", + command={"abortTransaction": -1.0}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept negative double value", + ), + SessionCommandTestCase( + "field_double_zero", + command={"abortTransaction": 0.0}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept double zero value", + ), + SessionCommandTestCase( + "field_decimal128", + command={"abortTransaction": Decimal128("1")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept Decimal128 value", + ), + SessionCommandTestCase( + "field_bool_true", + command={"abortTransaction": True}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept bool true value", + ), + SessionCommandTestCase( + "field_bool_false", + command={"abortTransaction": False}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept bool false value", + ), + SessionCommandTestCase( + "field_nan", + command={"abortTransaction": float("nan")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept NaN value", + ), + SessionCommandTestCase( + "field_infinity", + command={"abortTransaction": float("inf")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept Infinity value", + ), + SessionCommandTestCase( + "field_string", + command={"abortTransaction": "abortTransaction"}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept string value", + ), + SessionCommandTestCase( + "field_string_empty", + command={"abortTransaction": ""}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept empty string value", + ), + SessionCommandTestCase( + "field_null", + command={"abortTransaction": None}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept null value", + ), + SessionCommandTestCase( + "field_object_empty", + command={"abortTransaction": {}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept empty object value", + ), + SessionCommandTestCase( + "field_object_nonempty", + command={"abortTransaction": {"key": "value"}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept non-empty object value", + ), + SessionCommandTestCase( + "field_array_empty", + command={"abortTransaction": []}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept empty array value", + ), + SessionCommandTestCase( + "field_array_nonempty", + command={"abortTransaction": [1, 2]}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept non-empty array value", + ), + SessionCommandTestCase( + "field_binary", + command={"abortTransaction": Binary(b"\x00")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept Binary value", + ), + SessionCommandTestCase( + "field_objectid", + command={"abortTransaction": ObjectId()}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept ObjectId value", + ), + SessionCommandTestCase( + "field_datetime", + command={"abortTransaction": datetime(2024, 1, 1, tzinfo=timezone.utc)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept datetime value", + ), + SessionCommandTestCase( + "field_regex", + command={"abortTransaction": Regex(".*")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept Regex value", + ), + SessionCommandTestCase( + "field_timestamp", + command={"abortTransaction": Timestamp(0, 0)}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept Timestamp value", + ), + SessionCommandTestCase( + "field_code", + command={"abortTransaction": Code("function(){}")}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept Code value", + ), + SessionCommandTestCase( + "field_minkey", + command={"abortTransaction": MinKey()}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept MinKey value", + ), + SessionCommandTestCase( + "field_maxkey", + command={"abortTransaction": MaxKey()}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept MaxKey value", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(FIELD_TYPE_TESTS)) +def test_abortTransaction_field_types(collection, test): + """Test abortTransaction command field type acceptance.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py new file mode 100644 index 000000000..3ba66cac3 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py @@ -0,0 +1,129 @@ +"""Tests for abortTransaction txnNumber parameter validation. + +Validates type acceptance for the txnNumber parameter. Per the MongoDB +documentation, txnNumber is typed as long (Int64). Int64 values produce +IllegalOperation because the session has no matching transaction. Non-Int64 +numeric types and non-numeric types produce TypeMismatch. Null is treated +as omitted (falls through to NoSuchTransaction). +""" + +from __future__ import annotations + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import ( + ILLEGAL_OPERATION_ERROR, + NO_SUCH_TRANSACTION_ERROR, + TYPE_MISMATCH_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + + +# Property [txnNumber Int64 Acceptance]: Int64 values are accepted for txnNumber. +TXN_NUMBER_INT64_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "txn_number_int64_positive", + command={"abortTransaction": 1, "txnNumber": Int64(1)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction should accept txnNumber:Int64(1) and fail with IllegalOperation", + ), + SessionCommandTestCase( + "txn_number_int64_zero", + command={"abortTransaction": 1, "txnNumber": Int64(0)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction should accept txnNumber:Int64(0) and fail with IllegalOperation", + ), + SessionCommandTestCase( + "txn_number_int64_max", + command={"abortTransaction": 1, "txnNumber": Int64(9_223_372_036_854_775_807)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction should accept txnNumber:Int64 max value", + ), + SessionCommandTestCase( + "txn_number_int64_negative", + command={"abortTransaction": 1, "txnNumber": Int64(-1)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction should reject negative txnNumber with IllegalOperation", + ), +] + +# Property [txnNumber Type Strictness]: non-Int64 types are rejected with TypeMismatch. +TXN_NUMBER_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "txn_number_int32", + command={"abortTransaction": 1, "txnNumber": 1}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:int32 as wrong type", + ), + SessionCommandTestCase( + "txn_number_double_whole", + command={"abortTransaction": 1, "txnNumber": 1.0}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:double (whole) as wrong type", + ), + SessionCommandTestCase( + "txn_number_double_fractional", + command={"abortTransaction": 1, "txnNumber": 1.5}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:double (fractional) as wrong type", + ), + SessionCommandTestCase( + "txn_number_decimal128", + command={"abortTransaction": 1, "txnNumber": Decimal128("1")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:Decimal128 as wrong type", + ), + SessionCommandTestCase( + "txn_number_string", + command={"abortTransaction": 1, "txnNumber": "1"}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:string as wrong type", + ), + SessionCommandTestCase( + "txn_number_bool", + command={"abortTransaction": 1, "txnNumber": True}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:bool as wrong type", + ), + SessionCommandTestCase( + "txn_number_object", + command={"abortTransaction": 1, "txnNumber": {}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:{} (object) as wrong type", + ), + SessionCommandTestCase( + "txn_number_array", + command={"abortTransaction": 1, "txnNumber": []}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject txnNumber:[] (array) as wrong type", + ), +] + +# Property [txnNumber Null Handling]: null txnNumber is treated as omitted. +TXN_NUMBER_NULL_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "txn_number_null", + command={"abortTransaction": 1, "txnNumber": None}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should treat txnNumber:null as omitted", + ), +] + +TXN_NUMBER_TESTS: list[SessionCommandTestCase] = ( + TXN_NUMBER_INT64_TESTS + TXN_NUMBER_TYPE_REJECTION_TESTS + TXN_NUMBER_NULL_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(TXN_NUMBER_TESTS)) +def test_abortTransaction_txn_number(collection, test): + """Test abortTransaction txnNumber parameter validation.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py new file mode 100644 index 000000000..a72c41cb4 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py @@ -0,0 +1,106 @@ +"""Tests for abortTransaction unrecognized field handling. + +Validates that the abortTransaction command rejects unknown fields. Covers +single unknown fields, multiple unknown fields, case-sensitive field names, +known fields from other commands, and dollar-prefixed fields. +""" + +from __future__ import annotations + +import pytest +from bson import Int64 + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import UNRECOGNIZED_COMMAND_FIELD_ERROR +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + + +# Property [Unrecognized Field Rejection]: unknown fields are rejected. +UNRECOGNIZED_FIELD_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "unknown_single_field", + command={"abortTransaction": 1, "unknownField": 1}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject single unknown field", + ), + SessionCommandTestCase( + "unknown_multiple_fields", + command={"abortTransaction": 1, "foo": 1, "bar": 2}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject multiple unknown fields", + ), +] + +# Property [Case Sensitivity]: field names are case-sensitive and wrong-case variants are rejected. +CASE_SENSITIVITY_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "case_WriteConcern", + command={"abortTransaction": 1, "WriteConcern": {"w": 1}}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject 'WriteConcern' (capital W) as unrecognized", + ), + SessionCommandTestCase( + "case_Autocommit", + command={"abortTransaction": 1, "Autocommit": False}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject 'Autocommit' (capital A) as unrecognized", + ), + SessionCommandTestCase( + "case_TxnNumber", + command={"abortTransaction": 1, "TxnNumber": Int64(1)}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject 'TxnNumber' (capital T) as unrecognized", + ), + SessionCommandTestCase( + "case_Comment", + command={"abortTransaction": 1, "Comment": "test"}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject 'Comment' (capital C) as unrecognized", + ), +] + +# Property [Foreign Field Rejection]: fields from other commands are rejected. +FOREIGN_FIELD_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "foreign_query", + command={"abortTransaction": 1, "query": {"x": 1}}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject 'query' field from other commands", + ), + SessionCommandTestCase( + "dollar_prefixed", + command={"abortTransaction": 1, "$unknown": 1}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject dollar-prefixed unknown field", + ), +] + +# Property [writeConcern Unknown Sub-Field]: unknown writeConcern sub-fields are rejected. +WRITECONCERN_UNKNOWN_SUBFIELD_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "wc_unknown_subfield", + command={"abortTransaction": 1, "writeConcern": {"w": 1, "unknownOption": True}}, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="abortTransaction should reject unknown writeConcern sub-field", + ), +] + +UNRECOGNIZED_TESTS: list[SessionCommandTestCase] = ( + UNRECOGNIZED_FIELD_TESTS + + CASE_SENSITIVITY_TESTS + + FOREIGN_FIELD_TESTS + + WRITECONCERN_UNKNOWN_SUBFIELD_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(UNRECOGNIZED_TESTS)) +def test_abortTransaction_unrecognized_fields(collection, test): + """Test abortTransaction unrecognized field handling.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py new file mode 100644 index 000000000..7780caa38 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py @@ -0,0 +1,432 @@ +"""Tests for abortTransaction writeConcern parameter validation. + +Validates type acceptance for writeConcern (must be a document), and type and +value acceptance for sub-fields w, j, and wtimeout. +""" + +from __future__ import annotations + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import ( + BAD_VALUE_ERROR, + FAILED_TO_PARSE_ERROR, + NO_SUCH_TRANSACTION_ERROR, + TYPE_MISMATCH_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + + +# Property [writeConcern Document Acceptance]: writeConcern accepts document values. +WRITECONCERN_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "writeconcern_doc_w1", + command={"abortTransaction": 1, "writeConcern": {"w": 1}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern document with w:1", + ), + SessionCommandTestCase( + "writeconcern_empty_doc", + command={"abortTransaction": 1, "writeConcern": {}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept empty writeConcern document", + ), + SessionCommandTestCase( + "writeconcern_null", + command={"abortTransaction": 1, "writeConcern": None}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern:null", + ), + SessionCommandTestCase( + "wc_combined_w_j_wtimeout", + command={ + "abortTransaction": 1, + "writeConcern": {"w": "majority", "j": True, "wtimeout": 10_000}, + }, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept combined w + j + wtimeout", + ), + SessionCommandTestCase( + "wc_w0_j_true", + command={"abortTransaction": 1, "writeConcern": {"w": 0, "j": True}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept conflicting w:0 with j:true", + ), + SessionCommandTestCase( + "wc_fsync_true", + command={"abortTransaction": 1, "writeConcern": {"fsync": True}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept legacy writeConcern.fsync:true", + ), +] + +# Property [writeConcern Type Rejection]: non-document types are rejected with TypeMismatch. +WRITECONCERN_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "writeconcern_string", + command={"abortTransaction": 1, "writeConcern": "majority"}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:string as wrong type", + ), + SessionCommandTestCase( + "writeconcern_int32", + command={"abortTransaction": 1, "writeConcern": 1}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:int32 as wrong type", + ), + SessionCommandTestCase( + "writeconcern_int64", + command={"abortTransaction": 1, "writeConcern": Int64(1)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Int64 as wrong type", + ), + SessionCommandTestCase( + "writeconcern_double", + command={"abortTransaction": 1, "writeConcern": 1.0}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:double as wrong type", + ), + SessionCommandTestCase( + "writeconcern_decimal128", + command={"abortTransaction": 1, "writeConcern": Decimal128("1")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Decimal128 as wrong type", + ), + SessionCommandTestCase( + "writeconcern_bool_true", + command={"abortTransaction": 1, "writeConcern": True}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:true as wrong type", + ), + SessionCommandTestCase( + "writeconcern_bool_false", + command={"abortTransaction": 1, "writeConcern": False}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:false as wrong type", + ), + SessionCommandTestCase( + "writeconcern_array_empty", + command={"abortTransaction": 1, "writeConcern": []}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:[] as wrong type", + ), + SessionCommandTestCase( + "writeconcern_array_nonempty", + command={"abortTransaction": 1, "writeConcern": [{"w": 1}]}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:[{w:1}] as wrong type", + ), + SessionCommandTestCase( + "writeconcern_binary", + command={"abortTransaction": 1, "writeConcern": Binary(b"\x00")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Binary as wrong type", + ), + SessionCommandTestCase( + "writeconcern_objectid", + command={"abortTransaction": 1, "writeConcern": ObjectId()}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:ObjectId as wrong type", + ), + SessionCommandTestCase( + "writeconcern_datetime", + command={"abortTransaction": 1, "writeConcern": datetime(2024, 1, 1, tzinfo=timezone.utc)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:datetime as wrong type", + ), + SessionCommandTestCase( + "writeconcern_regex", + command={"abortTransaction": 1, "writeConcern": Regex(".*")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Regex as wrong type", + ), + SessionCommandTestCase( + "writeconcern_timestamp", + command={"abortTransaction": 1, "writeConcern": Timestamp(0, 0)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Timestamp as wrong type", + ), + SessionCommandTestCase( + "writeconcern_code", + command={"abortTransaction": 1, "writeConcern": Code("function(){}")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Code as wrong type", + ), + SessionCommandTestCase( + "writeconcern_minkey", + command={"abortTransaction": 1, "writeConcern": MinKey()}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:MinKey as wrong type", + ), + SessionCommandTestCase( + "writeconcern_maxkey", + command={"abortTransaction": 1, "writeConcern": MaxKey()}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:MaxKey as wrong type", + ), +] + +# Property [w Accepted Values]: w accepts int and string "majority" values. +W_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "w_int32_one", + command={"abortTransaction": 1, "writeConcern": {"w": 1}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:1", + ), + SessionCommandTestCase( + "w_int32_zero", + command={"abortTransaction": 1, "writeConcern": {"w": 0}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:0 (unacknowledged)", + ), + SessionCommandTestCase( + "w_majority", + command={"abortTransaction": 1, "writeConcern": {"w": "majority"}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:'majority'", + ), + SessionCommandTestCase( + "w_int64", + command={"abortTransaction": 1, "writeConcern": {"w": Int64(1)}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:Int64(1)", + ), + SessionCommandTestCase( + "w_double_whole", + command={"abortTransaction": 1, "writeConcern": {"w": 1.0}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:1.0", + ), + SessionCommandTestCase( + "w_double_fractional", + command={"abortTransaction": 1, "writeConcern": {"w": 1.5}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:1.5", + ), + SessionCommandTestCase( + "w_decimal128", + command={"abortTransaction": 1, "writeConcern": {"w": Decimal128("1")}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.w:Decimal128('1')", + ), +] + +# Property [w Invalid Values]: invalid w values are rejected with BadValue or FailedToParse. +W_INVALID_VALUE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "w_custom_tag", + command={"abortTransaction": 1, "writeConcern": {"w": "myTag"}}, + error_code=BAD_VALUE_ERROR, + msg="abortTransaction should reject writeConcern.w:'myTag' with BadValue", + ), + SessionCommandTestCase( + "w_empty_string", + command={"abortTransaction": 1, "writeConcern": {"w": ""}}, + error_code=BAD_VALUE_ERROR, + msg="abortTransaction should reject writeConcern.w:'' with BadValue", + ), + SessionCommandTestCase( + "w_null", + command={"abortTransaction": 1, "writeConcern": {"w": None}}, + error_code=BAD_VALUE_ERROR, + msg="abortTransaction should reject writeConcern.w:null with BadValue", + ), + SessionCommandTestCase( + "w_negative_int", + command={"abortTransaction": 1, "writeConcern": {"w": -1}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:-1 with FailedToParse", + ), + SessionCommandTestCase( + "w_int32_max", + command={"abortTransaction": 1, "writeConcern": {"w": 2_147_483_647}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:INT32_MAX with FailedToParse", + ), + SessionCommandTestCase( + "w_bool_false", + command={"abortTransaction": 1, "writeConcern": {"w": False}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:false with FailedToParse", + ), + SessionCommandTestCase( + "w_bool_true", + command={"abortTransaction": 1, "writeConcern": {"w": True}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:true with FailedToParse", + ), + SessionCommandTestCase( + "w_object", + command={"abortTransaction": 1, "writeConcern": {"w": {}}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:{} with FailedToParse", + ), + SessionCommandTestCase( + "w_array", + command={"abortTransaction": 1, "writeConcern": {"w": []}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:[] with FailedToParse", + ), +] + +# Property [j Accepted Values]: j accepts boolean and numeric types. +J_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "j_bool_true", + command={"abortTransaction": 1, "writeConcern": {"j": True}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.j:true", + ), + SessionCommandTestCase( + "j_bool_false", + command={"abortTransaction": 1, "writeConcern": {"j": False}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.j:false", + ), + SessionCommandTestCase( + "j_int32_one", + command={"abortTransaction": 1, "writeConcern": {"j": 1}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.j:1 (coerced to true)", + ), + SessionCommandTestCase( + "j_int32_zero", + command={"abortTransaction": 1, "writeConcern": {"j": 0}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.j:0 (coerced to false)", + ), + SessionCommandTestCase( + "j_null", + command={"abortTransaction": 1, "writeConcern": {"j": None}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.j:null", + ), +] + +# Property [j Type Rejection]: non-boolean non-numeric types are rejected with TypeMismatch. +J_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "j_string", + command={"abortTransaction": 1, "writeConcern": {"j": "true"}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern.j:'true' as wrong type", + ), + SessionCommandTestCase( + "j_object", + command={"abortTransaction": 1, "writeConcern": {"j": {}}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern.j:{} as wrong type", + ), + SessionCommandTestCase( + "j_array", + command={"abortTransaction": 1, "writeConcern": {"j": []}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern.j:[] as wrong type", + ), +] + +# Property [wtimeout Accepted Values]: wtimeout accepts numeric types broadly. +WTIMEOUT_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "wtimeout_int32_positive", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:1000", + ), + SessionCommandTestCase( + "wtimeout_int32_zero", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": 0}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:0 (no timeout)", + ), + SessionCommandTestCase( + "wtimeout_int64", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": Int64(1000)}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:Int64(1000)", + ), + SessionCommandTestCase( + "wtimeout_double_whole", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000.0}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:1000.0", + ), + SessionCommandTestCase( + "wtimeout_negative", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": -1}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:-1", + ), + SessionCommandTestCase( + "wtimeout_string", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": "1000"}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:'1000'", + ), + SessionCommandTestCase( + "wtimeout_bool", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": True}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:true", + ), + SessionCommandTestCase( + "wtimeout_null", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": None}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:null", + ), + SessionCommandTestCase( + "wtimeout_object", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": {}}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:{}", + ), + SessionCommandTestCase( + "wtimeout_array", + command={"abortTransaction": 1, "writeConcern": {"wtimeout": []}}, + error_code=NO_SUCH_TRANSACTION_ERROR, + msg="abortTransaction should accept writeConcern.wtimeout:[]", + ), +] + +# Property [wtimeout Overflow]: Int64 max value overflows and produces FailedToParse. +WTIMEOUT_OVERFLOW_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "wtimeout_int64_max", + command={ + "abortTransaction": 1, + "writeConcern": {"wtimeout": Int64(9_223_372_036_854_775_807)}, + }, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.wtimeout:Int64 max with FailedToParse", + ), +] + +WRITECONCERN_TESTS: list[SessionCommandTestCase] = ( + WRITECONCERN_ACCEPTANCE_TESTS + + WRITECONCERN_TYPE_REJECTION_TESTS + + W_ACCEPTANCE_TESTS + + W_INVALID_VALUE_TESTS + + J_ACCEPTANCE_TESTS + + J_TYPE_REJECTION_TESTS + + WTIMEOUT_ACCEPTANCE_TESTS + + WTIMEOUT_OVERFLOW_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(WRITECONCERN_TESTS)) +def test_abortTransaction_writeconcern(collection, test): + """Test abortTransaction writeConcern parameter validation.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/__init__.py b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/__init__.py new file mode 100644 index 000000000..37acbb8e6 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/__init__.py @@ -0,0 +1 @@ +"""Shared utilities for session command tests.""" diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_command_test_case.py b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_command_test_case.py new file mode 100644 index 000000000..f44d1d30c --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_command_test_case.py @@ -0,0 +1,23 @@ +"""Shared test case for session command tests.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Dict, Optional + +from documentdb_tests.framework.test_case import BaseTestCase + + +@dataclass(frozen=True) +class SessionCommandTestCase(BaseTestCase): + """Test case for session command tests. + + Session commands (commitTransaction, abortTransaction, etc.) run against + the admin database and do not reference a specific collection. The command + is always a plain dict. + + Attributes: + command: The command document to execute against the admin database. + """ + + command: Optional[Dict[str, Any]] = None diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py new file mode 100644 index 000000000..f8d509496 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py @@ -0,0 +1,107 @@ +"""Shared test case for session command tests (e.g. commitTransaction, abortTransaction).""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import Any + +from pymongo.collection import Collection + +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, +) + + +class SessionOp(Enum): + """Operation types that can be executed inside a transaction.""" + + INSERT = "insert" + UPDATE = "update" + DELETE = "delete" + + +@dataclass(frozen=True) +class SessionOperation: + """A single operation to execute inside a transaction. + + Attributes: + op: The operation type. + document: For INSERT, the document to insert. + filter: For UPDATE/DELETE, the query filter. + update: For UPDATE, the update document. + """ + + op: SessionOp + document: dict[str, Any] | None = None + filter: dict[str, Any] | None = None + update: dict[str, Any] | None = None + + def execute(self, collection: Collection, session: Any) -> None: + """Execute this operation against the collection within the session.""" + if self.op == SessionOp.INSERT: + collection.insert_one(self.document, session=session) + elif self.op == SessionOp.UPDATE: + collection.update_one(self.filter, self.update, session=session) + elif self.op == SessionOp.DELETE: + collection.delete_one(self.filter, session=session) + + +@dataclass(frozen=True) +class SessionTestCase(CommandTestCase): + """Test case for session command success tests (e.g. commitTransaction). + + Extends CommandTestCase to model a multi-step transaction workflow: + seed documents, run operations inside a transaction, commit, and + verify the result via readback or commit response. + + Attributes: + ops: Operations to execute inside the transaction before committing. + commit_command: Optional raw command dict for committing (e.g. to + include writeConcern or comment). When None, uses + ``session.commit_transaction()``. + expected_response: Expected fields from the commit command response. + When set, the assertion targets the commit response instead of + a readback query. Defaults to ``None``. + Mutually exclusive with ``expected``. + readback_filter: Filter for the post-commit readback query. Defaults + to ``{}``. + readback_sort: Sort for the post-commit readback query. Defaults + to ``{"_id": 1}``. + """ + + ops: list[SessionOperation] = field(default_factory=list) + commit_command: dict[str, Any] | None = None + expected_response: dict[str, Any] | None = None + readback_filter: dict[str, Any] = field(default_factory=dict) + readback_sort: dict[str, Any] = field(default_factory=lambda: {"_id": 1}) + + +@dataclass(frozen=True) +class AbortSessionTestCase(CommandTestCase): + """Test case for abortTransaction success tests. + + Extends CommandTestCase to model a multi-step transaction workflow: + seed documents, run operations inside a transaction, abort, and + verify the result via readback (expecting rollback). + + Attributes: + ops: Operations to execute inside the transaction before aborting. + abort_command: Optional raw command dict for aborting (e.g. to + include writeConcern or comment). When None, uses + ``session.abort_transaction()``. + expected_response: Expected fields from the abort command response. + When set, the assertion targets the abort response instead of + a readback query. Defaults to ``None``. + Mutually exclusive with ``expected``. + readback_filter: Filter for the post-abort readback query. Defaults + to ``{}``. + readback_sort: Sort for the post-abort readback query. Defaults + to ``{"_id": 1}``. + """ + + ops: list[SessionOperation] = field(default_factory=list) + abort_command: dict[str, Any] | None = None + expected_response: dict[str, Any] | None = None + readback_filter: dict[str, Any] = field(default_factory=dict) + readback_sort: dict[str, Any] = field(default_factory=lambda: {"_id": 1}) diff --git a/documentdb_tests/framework/error_codes.py b/documentdb_tests/framework/error_codes.py index 2375b9dcd..ee90ca498 100644 --- a/documentdb_tests/framework/error_codes.py +++ b/documentdb_tests/framework/error_codes.py @@ -34,6 +34,7 @@ OPERATION_FAILED_ERROR = 96 DOCUMENT_VALIDATION_FAILURE_ERROR = 121 NOT_A_REPLICA_SET_ERROR = 123 +NO_SUCH_TRANSACTION_ERROR = 125 CAPPED_POSITION_LOST_ERROR = 136 INCOMPATIBLE_COLLATION_VERSION_ERROR = 161 VIEW_DEPTH_LIMIT_ERROR = 165 diff --git a/documentdb_tests/framework/executor.py b/documentdb_tests/framework/executor.py index 4df8464aa..ab3e1df51 100644 --- a/documentdb_tests/framework/executor.py +++ b/documentdb_tests/framework/executor.py @@ -2,6 +2,8 @@ Unified execution and assertion utilities for tests. """ +from __future__ import annotations + from datetime import timezone from typing import Any, Dict @@ -49,3 +51,131 @@ def execute_admin_command(collection, command: Dict) -> Any: return result except Exception as e: return e + + +def execute_session_command(collection, test_case) -> Any: + """Execute a SessionTestCase: seed, transact, commit, and return the result. + + Runs the full transaction lifecycle described by *test_case*: + + 1. Seed ``test_case.docs`` into *collection* (via ``prepare``). + 2. Open a client session and start a transaction. + 3. Execute each ``SessionOperation`` in ``test_case.ops``. + 4. Commit — either via ``session.commit_transaction()`` or by sending + ``test_case.commit_command`` as a raw admin command. + 5. Return the appropriate result for assertion: + - If ``test_case.expected_response`` is set, return the commit + command response (a dict). + - Otherwise, return the readback query result via + ``execute_command``. + + Args: + collection: The pytest ``collection`` fixture. + test_case: A ``SessionTestCase`` instance. + + Returns: + Result dict (commit response or readback) or Exception. + """ + from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( # noqa: E501 + SessionTestCase, + ) + + assert isinstance(test_case, SessionTestCase) + + # 1. Seed documents. + if test_case.docs is not None: + if test_case.docs: + collection.insert_many(test_case.docs) + + # 2-4. Transaction lifecycle. + client = collection.database.client + commit_result = None + with client.start_session() as session: + session.start_transaction() + for op in test_case.ops: + op.execute(collection, session) + if test_case.commit_command is not None: + try: + commit_result = client.admin.command(test_case.commit_command, session=session) + except Exception as e: + commit_result = e + else: + session.commit_transaction() + + # 5. Return commit response or readback. + if test_case.expected_response is not None: + execute_command(collection, {"find": collection.name, "filter": {}}) + return commit_result + + return execute_command( + collection, + { + "find": collection.name, + "filter": test_case.readback_filter, + "sort": test_case.readback_sort, + }, + ) + + +def execute_abort_session_command(collection, test_case) -> Any: + """Execute an AbortSessionTestCase: seed, transact, abort, and return the result. + + Runs the full transaction lifecycle described by *test_case*: + + 1. Seed ``test_case.docs`` into *collection* (via ``prepare``). + 2. Open a client session and start a transaction. + 3. Execute each ``SessionOperation`` in ``test_case.ops``. + 4. Abort — either via ``session.abort_transaction()`` or by sending + ``test_case.abort_command`` as a raw admin command. + 5. Return the appropriate result for assertion: + - If ``test_case.expected_response`` is set, return the abort + command response (a dict). + - Otherwise, return the readback query result via + ``execute_command``. + + Args: + collection: The pytest ``collection`` fixture. + test_case: An ``AbortSessionTestCase`` instance. + + Returns: + Result dict (abort response or readback) or Exception. + """ + from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( # noqa: E501 + AbortSessionTestCase, + ) + + assert isinstance(test_case, AbortSessionTestCase) + + # 1. Seed documents. + if test_case.docs is not None: + if test_case.docs: + collection.insert_many(test_case.docs) + + # 2-4. Transaction lifecycle. + client = collection.database.client + abort_result = None + with client.start_session() as session: + session.start_transaction() + for op in test_case.ops: + op.execute(collection, session) + if test_case.abort_command is not None: + try: + abort_result = client.admin.command(test_case.abort_command, session=session) + except Exception as e: + abort_result = e + else: + session.abort_transaction() + + # 5. Return abort response or readback. + if test_case.expected_response is not None: + execute_command(collection, {"find": collection.name, "filter": {}}) + return abort_result + + return execute_command( + collection, + { + "find": collection.name, + "filter": test_case.readback_filter, + "sort": test_case.readback_sort, + }, + ) diff --git a/documentdb_tests/framework/test_format_validator.py b/documentdb_tests/framework/test_format_validator.py index 295b1351d..2b06629c3 100644 --- a/documentdb_tests/framework/test_format_validator.py +++ b/documentdb_tests/framework/test_format_validator.py @@ -32,6 +32,8 @@ def validate_test_format(file_path: str) -> list[str]: "execute_project_with_insert", "execute_expression", "execute_expression_with_insert", + "execute_session_command", + "execute_abort_session_command", ] ) From 8638fc9ae3fbf131370d919e31566cab1c99d781 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 10 Jun 2026 14:29:16 -0700 Subject: [PATCH 02/15] apply style-guide.md Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_core.py | 22 -- .../test_abortTransaction_writeconcern.py | 228 +---------------- ...est_abortTransaction_writeconcern_error.py | 239 ++++++++++++++++++ 3 files changed, 248 insertions(+), 241 deletions(-) create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index 0ad472bc6..b59ea7af8 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -39,13 +39,8 @@ ) from documentdb_tests.framework.parametrize import pytest_params -# =========================================================================== -# Outside-transaction error tests (admin db) -# =========================================================================== - pytestmark = pytest.mark.admin - # Property [No-Transaction Error]: abortTransaction outside a transaction fails. CORE_NO_TRANSACTION_TESTS: list[SessionCommandTestCase] = [ SessionCommandTestCase( @@ -130,15 +125,7 @@ def test_abortTransaction_admin_db_required(collection, test): assertFailureCode(result, test.error_code, msg=test.msg) -# =========================================================================== -# In-transaction success tests (replica_set) -# =========================================================================== - - -# --------------------------------------------------------------------------- # Property [Abort Rollback]: aborted operations are rolled back. -# --------------------------------------------------------------------------- - ABORT_ROLLBACK_TESTS: list[AbortSessionTestCase] = [ AbortSessionTestCase( "abort_insert", @@ -237,10 +224,7 @@ def test_abortTransaction_core_rollback(collection, test): assertSuccess(result, test.expected, msg=test.msg) -# --------------------------------------------------------------------------- # Property [Pre-Transaction Data Survival]: seed data survives abort. -# --------------------------------------------------------------------------- - PRE_TRANSACTION_TESTS: list[AbortSessionTestCase] = [ AbortSessionTestCase( "pre_existing_data_survives", @@ -260,10 +244,7 @@ def test_abortTransaction_core_pre_transaction_data(collection, test): assertSuccess(result, test.expected, msg=test.msg) -# --------------------------------------------------------------------------- # Property [Empty Transaction]: aborting a transaction with no ops succeeds. -# --------------------------------------------------------------------------- - EMPTY_TRANSACTION_TESTS: list[AbortSessionTestCase] = [ AbortSessionTestCase( "abort_empty_transaction", @@ -281,10 +262,7 @@ def test_abortTransaction_core_empty(collection, test): assertNotError(result, msg=test.msg) -# --------------------------------------------------------------------------- # Property [Response Structure]: abort response contains ok:1 on success. -# --------------------------------------------------------------------------- - RESPONSE_STRUCTURE_TESTS: list[AbortSessionTestCase] = [ AbortSessionTestCase( "abort_response_ok", diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py index 7780caa38..e215bfe27 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py @@ -1,32 +1,25 @@ -"""Tests for abortTransaction writeConcern parameter validation. +"""Tests for abortTransaction writeConcern parameter acceptance. -Validates type acceptance for writeConcern (must be a document), and type and -value acceptance for sub-fields w, j, and wtimeout. +Validates that accepted writeConcern variants (document types, w sub-field +values, j sub-field values, wtimeout sub-field values, and combinations) +are syntactically accepted by abortTransaction outside a transaction. """ from __future__ import annotations -from datetime import datetime, timezone - import pytest -from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp +from bson import Decimal128, Int64 from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 SessionCommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import ( - BAD_VALUE_ERROR, - FAILED_TO_PARSE_ERROR, - NO_SUCH_TRANSACTION_ERROR, - TYPE_MISMATCH_ERROR, -) +from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params pytestmark = pytest.mark.admin - # Property [writeConcern Document Acceptance]: writeConcern accepts document values. WRITECONCERN_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ SessionCommandTestCase( @@ -70,112 +63,6 @@ ), ] -# Property [writeConcern Type Rejection]: non-document types are rejected with TypeMismatch. -WRITECONCERN_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( - "writeconcern_string", - command={"abortTransaction": 1, "writeConcern": "majority"}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:string as wrong type", - ), - SessionCommandTestCase( - "writeconcern_int32", - command={"abortTransaction": 1, "writeConcern": 1}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:int32 as wrong type", - ), - SessionCommandTestCase( - "writeconcern_int64", - command={"abortTransaction": 1, "writeConcern": Int64(1)}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:Int64 as wrong type", - ), - SessionCommandTestCase( - "writeconcern_double", - command={"abortTransaction": 1, "writeConcern": 1.0}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:double as wrong type", - ), - SessionCommandTestCase( - "writeconcern_decimal128", - command={"abortTransaction": 1, "writeConcern": Decimal128("1")}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:Decimal128 as wrong type", - ), - SessionCommandTestCase( - "writeconcern_bool_true", - command={"abortTransaction": 1, "writeConcern": True}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:true as wrong type", - ), - SessionCommandTestCase( - "writeconcern_bool_false", - command={"abortTransaction": 1, "writeConcern": False}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:false as wrong type", - ), - SessionCommandTestCase( - "writeconcern_array_empty", - command={"abortTransaction": 1, "writeConcern": []}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:[] as wrong type", - ), - SessionCommandTestCase( - "writeconcern_array_nonempty", - command={"abortTransaction": 1, "writeConcern": [{"w": 1}]}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:[{w:1}] as wrong type", - ), - SessionCommandTestCase( - "writeconcern_binary", - command={"abortTransaction": 1, "writeConcern": Binary(b"\x00")}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:Binary as wrong type", - ), - SessionCommandTestCase( - "writeconcern_objectid", - command={"abortTransaction": 1, "writeConcern": ObjectId()}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:ObjectId as wrong type", - ), - SessionCommandTestCase( - "writeconcern_datetime", - command={"abortTransaction": 1, "writeConcern": datetime(2024, 1, 1, tzinfo=timezone.utc)}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:datetime as wrong type", - ), - SessionCommandTestCase( - "writeconcern_regex", - command={"abortTransaction": 1, "writeConcern": Regex(".*")}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:Regex as wrong type", - ), - SessionCommandTestCase( - "writeconcern_timestamp", - command={"abortTransaction": 1, "writeConcern": Timestamp(0, 0)}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:Timestamp as wrong type", - ), - SessionCommandTestCase( - "writeconcern_code", - command={"abortTransaction": 1, "writeConcern": Code("function(){}")}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:Code as wrong type", - ), - SessionCommandTestCase( - "writeconcern_minkey", - command={"abortTransaction": 1, "writeConcern": MinKey()}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:MinKey as wrong type", - ), - SessionCommandTestCase( - "writeconcern_maxkey", - command={"abortTransaction": 1, "writeConcern": MaxKey()}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern:MaxKey as wrong type", - ), -] - # Property [w Accepted Values]: w accepts int and string "majority" values. W_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ SessionCommandTestCase( @@ -222,64 +109,6 @@ ), ] -# Property [w Invalid Values]: invalid w values are rejected with BadValue or FailedToParse. -W_INVALID_VALUE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( - "w_custom_tag", - command={"abortTransaction": 1, "writeConcern": {"w": "myTag"}}, - error_code=BAD_VALUE_ERROR, - msg="abortTransaction should reject writeConcern.w:'myTag' with BadValue", - ), - SessionCommandTestCase( - "w_empty_string", - command={"abortTransaction": 1, "writeConcern": {"w": ""}}, - error_code=BAD_VALUE_ERROR, - msg="abortTransaction should reject writeConcern.w:'' with BadValue", - ), - SessionCommandTestCase( - "w_null", - command={"abortTransaction": 1, "writeConcern": {"w": None}}, - error_code=BAD_VALUE_ERROR, - msg="abortTransaction should reject writeConcern.w:null with BadValue", - ), - SessionCommandTestCase( - "w_negative_int", - command={"abortTransaction": 1, "writeConcern": {"w": -1}}, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.w:-1 with FailedToParse", - ), - SessionCommandTestCase( - "w_int32_max", - command={"abortTransaction": 1, "writeConcern": {"w": 2_147_483_647}}, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.w:INT32_MAX with FailedToParse", - ), - SessionCommandTestCase( - "w_bool_false", - command={"abortTransaction": 1, "writeConcern": {"w": False}}, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.w:false with FailedToParse", - ), - SessionCommandTestCase( - "w_bool_true", - command={"abortTransaction": 1, "writeConcern": {"w": True}}, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.w:true with FailedToParse", - ), - SessionCommandTestCase( - "w_object", - command={"abortTransaction": 1, "writeConcern": {"w": {}}}, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.w:{} with FailedToParse", - ), - SessionCommandTestCase( - "w_array", - command={"abortTransaction": 1, "writeConcern": {"w": []}}, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.w:[] with FailedToParse", - ), -] - # Property [j Accepted Values]: j accepts boolean and numeric types. J_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ SessionCommandTestCase( @@ -314,28 +143,6 @@ ), ] -# Property [j Type Rejection]: non-boolean non-numeric types are rejected with TypeMismatch. -J_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( - "j_string", - command={"abortTransaction": 1, "writeConcern": {"j": "true"}}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern.j:'true' as wrong type", - ), - SessionCommandTestCase( - "j_object", - command={"abortTransaction": 1, "writeConcern": {"j": {}}}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern.j:{} as wrong type", - ), - SessionCommandTestCase( - "j_array", - command={"abortTransaction": 1, "writeConcern": {"j": []}}, - error_code=TYPE_MISMATCH_ERROR, - msg="abortTransaction should reject writeConcern.j:[] as wrong type", - ), -] - # Property [wtimeout Accepted Values]: wtimeout accepts numeric types broadly. WTIMEOUT_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ SessionCommandTestCase( @@ -400,33 +207,16 @@ ), ] -# Property [wtimeout Overflow]: Int64 max value overflows and produces FailedToParse. -WTIMEOUT_OVERFLOW_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( - "wtimeout_int64_max", - command={ - "abortTransaction": 1, - "writeConcern": {"wtimeout": Int64(9_223_372_036_854_775_807)}, - }, - error_code=FAILED_TO_PARSE_ERROR, - msg="abortTransaction should reject writeConcern.wtimeout:Int64 max with FailedToParse", - ), -] - -WRITECONCERN_TESTS: list[SessionCommandTestCase] = ( +WRITECONCERN_ACCEPTANCE_ALL_TESTS: list[SessionCommandTestCase] = ( WRITECONCERN_ACCEPTANCE_TESTS - + WRITECONCERN_TYPE_REJECTION_TESTS + W_ACCEPTANCE_TESTS - + W_INVALID_VALUE_TESTS + J_ACCEPTANCE_TESTS - + J_TYPE_REJECTION_TESTS + WTIMEOUT_ACCEPTANCE_TESTS - + WTIMEOUT_OVERFLOW_TESTS ) -@pytest.mark.parametrize("test", pytest_params(WRITECONCERN_TESTS)) +@pytest.mark.parametrize("test", pytest_params(WRITECONCERN_ACCEPTANCE_ALL_TESTS)) def test_abortTransaction_writeconcern(collection, test): - """Test abortTransaction writeConcern parameter validation.""" + """Test abortTransaction writeConcern parameter acceptance.""" result = execute_admin_command(collection, test.command) assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py new file mode 100644 index 000000000..72f70027a --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py @@ -0,0 +1,239 @@ +"""Tests for abortTransaction writeConcern parameter error cases. + +Validates that invalid writeConcern types and sub-field values are rejected +with the appropriate error codes. +""" + +from __future__ import annotations + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 + SessionCommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import ( + BAD_VALUE_ERROR, + FAILED_TO_PARSE_ERROR, + TYPE_MISMATCH_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + +# Property [writeConcern Type Rejection]: non-document types are rejected with TypeMismatch. +WRITECONCERN_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "writeconcern_string", + command={"abortTransaction": 1, "writeConcern": "majority"}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:string as wrong type", + ), + SessionCommandTestCase( + "writeconcern_int32", + command={"abortTransaction": 1, "writeConcern": 1}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:int32 as wrong type", + ), + SessionCommandTestCase( + "writeconcern_int64", + command={"abortTransaction": 1, "writeConcern": Int64(1)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Int64 as wrong type", + ), + SessionCommandTestCase( + "writeconcern_double", + command={"abortTransaction": 1, "writeConcern": 1.0}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:double as wrong type", + ), + SessionCommandTestCase( + "writeconcern_decimal128", + command={"abortTransaction": 1, "writeConcern": Decimal128("1")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Decimal128 as wrong type", + ), + SessionCommandTestCase( + "writeconcern_bool_true", + command={"abortTransaction": 1, "writeConcern": True}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:true as wrong type", + ), + SessionCommandTestCase( + "writeconcern_bool_false", + command={"abortTransaction": 1, "writeConcern": False}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:false as wrong type", + ), + SessionCommandTestCase( + "writeconcern_array_empty", + command={"abortTransaction": 1, "writeConcern": []}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:[] as wrong type", + ), + SessionCommandTestCase( + "writeconcern_array_nonempty", + command={"abortTransaction": 1, "writeConcern": [{"w": 1}]}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:[{w:1}] as wrong type", + ), + SessionCommandTestCase( + "writeconcern_binary", + command={"abortTransaction": 1, "writeConcern": Binary(b"\x00")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Binary as wrong type", + ), + SessionCommandTestCase( + "writeconcern_objectid", + command={"abortTransaction": 1, "writeConcern": ObjectId()}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:ObjectId as wrong type", + ), + SessionCommandTestCase( + "writeconcern_datetime", + command={"abortTransaction": 1, "writeConcern": datetime(2024, 1, 1, tzinfo=timezone.utc)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:datetime as wrong type", + ), + SessionCommandTestCase( + "writeconcern_regex", + command={"abortTransaction": 1, "writeConcern": Regex(".*")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Regex as wrong type", + ), + SessionCommandTestCase( + "writeconcern_timestamp", + command={"abortTransaction": 1, "writeConcern": Timestamp(0, 0)}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Timestamp as wrong type", + ), + SessionCommandTestCase( + "writeconcern_code", + command={"abortTransaction": 1, "writeConcern": Code("function(){}")}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:Code as wrong type", + ), + SessionCommandTestCase( + "writeconcern_minkey", + command={"abortTransaction": 1, "writeConcern": MinKey()}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:MinKey as wrong type", + ), + SessionCommandTestCase( + "writeconcern_maxkey", + command={"abortTransaction": 1, "writeConcern": MaxKey()}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern:MaxKey as wrong type", + ), +] + +# Property [w Invalid Values]: invalid w values are rejected with BadValue or FailedToParse. +W_INVALID_VALUE_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "w_custom_tag", + command={"abortTransaction": 1, "writeConcern": {"w": "myTag"}}, + error_code=BAD_VALUE_ERROR, + msg="abortTransaction should reject writeConcern.w:'myTag' with BadValue", + ), + SessionCommandTestCase( + "w_empty_string", + command={"abortTransaction": 1, "writeConcern": {"w": ""}}, + error_code=BAD_VALUE_ERROR, + msg="abortTransaction should reject writeConcern.w:'' with BadValue", + ), + SessionCommandTestCase( + "w_null", + command={"abortTransaction": 1, "writeConcern": {"w": None}}, + error_code=BAD_VALUE_ERROR, + msg="abortTransaction should reject writeConcern.w:null with BadValue", + ), + SessionCommandTestCase( + "w_negative_int", + command={"abortTransaction": 1, "writeConcern": {"w": -1}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:-1 with FailedToParse", + ), + SessionCommandTestCase( + "w_int32_max", + command={"abortTransaction": 1, "writeConcern": {"w": 2_147_483_647}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:INT32_MAX with FailedToParse", + ), + SessionCommandTestCase( + "w_bool_false", + command={"abortTransaction": 1, "writeConcern": {"w": False}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:false with FailedToParse", + ), + SessionCommandTestCase( + "w_bool_true", + command={"abortTransaction": 1, "writeConcern": {"w": True}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:true with FailedToParse", + ), + SessionCommandTestCase( + "w_object", + command={"abortTransaction": 1, "writeConcern": {"w": {}}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:{} with FailedToParse", + ), + SessionCommandTestCase( + "w_array", + command={"abortTransaction": 1, "writeConcern": {"w": []}}, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.w:[] with FailedToParse", + ), +] + +# Property [j Type Rejection]: non-boolean non-numeric types are rejected with TypeMismatch. +J_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "j_string", + command={"abortTransaction": 1, "writeConcern": {"j": "true"}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern.j:'true' as wrong type", + ), + SessionCommandTestCase( + "j_object", + command={"abortTransaction": 1, "writeConcern": {"j": {}}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern.j:{} as wrong type", + ), + SessionCommandTestCase( + "j_array", + command={"abortTransaction": 1, "writeConcern": {"j": []}}, + error_code=TYPE_MISMATCH_ERROR, + msg="abortTransaction should reject writeConcern.j:[] as wrong type", + ), +] + +# Property [wtimeout Overflow]: Int64 max value overflows and produces FailedToParse. +WTIMEOUT_OVERFLOW_TESTS: list[SessionCommandTestCase] = [ + SessionCommandTestCase( + "wtimeout_int64_max", + command={ + "abortTransaction": 1, + "writeConcern": {"wtimeout": Int64(9_223_372_036_854_775_807)}, + }, + error_code=FAILED_TO_PARSE_ERROR, + msg="abortTransaction should reject writeConcern.wtimeout:Int64 max with FailedToParse", + ), +] + +WRITECONCERN_ERROR_TESTS: list[SessionCommandTestCase] = ( + WRITECONCERN_TYPE_REJECTION_TESTS + + W_INVALID_VALUE_TESTS + + J_TYPE_REJECTION_TESTS + + WTIMEOUT_OVERFLOW_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(WRITECONCERN_ERROR_TESTS)) +def test_abortTransaction_writeconcern_error(collection, test): + """Test abortTransaction writeConcern parameter error cases.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) From e9e16e64671b2c26798c2e3206edd5688ca4c315 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 16:34:53 -0700 Subject: [PATCH 03/15] apply style guide change Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_autocommit.py | 34 ++++----- .../test_abortTransaction_comment.py | 48 ++++++------ .../test_abortTransaction_core.py | 46 +++++------- .../test_abortTransaction_field_types.py | 62 ++++++++-------- .../test_abortTransaction_txn_number.py | 38 +++++----- ...st_abortTransaction_unrecognized_fields.py | 32 ++++---- .../test_abortTransaction_writeconcern.py | 74 +++++++++---------- ...est_abortTransaction_writeconcern_error.py | 74 +++++++++---------- .../test_smoke_abortTransaction.py | 9 ++- 9 files changed, 201 insertions(+), 216 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py index 4a9c42997..880ba9bfd 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py @@ -11,8 +11,8 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import ( @@ -27,14 +27,14 @@ # Property [autocommit Boolean Values]: autocommit accepts only boolean values. -AUTOCOMMIT_BOOLEAN_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +AUTOCOMMIT_BOOLEAN_TESTS: list[CommandTestCase] = [ + CommandTestCase( "autocommit_bool_false", command={"abortTransaction": 1, "autocommit": False}, error_code=INVALID_OPTIONS_ERROR, msg="abortTransaction should reject autocommit:false outside txn with InvalidOptions", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_bool_true", command={"abortTransaction": 1, "autocommit": True}, error_code=INVALID_OPTIONS_ERROR, @@ -43,50 +43,50 @@ ] # Property [autocommit Type Strictness]: non-boolean types are rejected with TypeMismatch. -AUTOCOMMIT_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +AUTOCOMMIT_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( "autocommit_int32_zero", command={"abortTransaction": 1, "autocommit": 0}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:0 (int32) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_int32_one", command={"abortTransaction": 1, "autocommit": 1}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:1 (int32) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_int64_zero", command={"abortTransaction": 1, "autocommit": Int64(0)}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:Int64(0) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_double_zero", command={"abortTransaction": 1, "autocommit": 0.0}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:0.0 as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_decimal128_zero", command={"abortTransaction": 1, "autocommit": Decimal128("0")}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:Decimal128('0') as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_string", command={"abortTransaction": 1, "autocommit": "false"}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:'false' (string) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_object", command={"abortTransaction": 1, "autocommit": {}}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject autocommit:{} (object) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "autocommit_array", command={"abortTransaction": 1, "autocommit": []}, error_code=TYPE_MISMATCH_ERROR, @@ -95,8 +95,8 @@ ] # Property [autocommit Null Handling]: null autocommit is treated as omitted. -AUTOCOMMIT_NULL_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +AUTOCOMMIT_NULL_TESTS: list[CommandTestCase] = [ + CommandTestCase( "autocommit_null", command={"abortTransaction": 1, "autocommit": None}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -104,7 +104,7 @@ ), ] -AUTOCOMMIT_TESTS: list[SessionCommandTestCase] = ( +AUTOCOMMIT_TESTS: list[CommandTestCase] = ( AUTOCOMMIT_BOOLEAN_TESTS + AUTOCOMMIT_TYPE_REJECTION_TESTS + AUTOCOMMIT_NULL_TESTS ) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py index 135f76dfc..93490c074 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py @@ -12,8 +12,8 @@ import pytest from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR @@ -24,128 +24,128 @@ # Property [comment Type Acceptance]: comment accepts any BSON type. -COMMENT_TYPE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +COMMENT_TYPE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "comment_string", command={"abortTransaction": 1, "comment": "test comment"}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:string", ), - SessionCommandTestCase( + CommandTestCase( "comment_string_empty", command={"abortTransaction": 1, "comment": ""}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:empty string", ), - SessionCommandTestCase( + CommandTestCase( "comment_int32", command={"abortTransaction": 1, "comment": 42}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:int32", ), - SessionCommandTestCase( + CommandTestCase( "comment_int64", command={"abortTransaction": 1, "comment": Int64(42)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:Int64", ), - SessionCommandTestCase( + CommandTestCase( "comment_double", command={"abortTransaction": 1, "comment": 3.14}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:double", ), - SessionCommandTestCase( + CommandTestCase( "comment_decimal128", command={"abortTransaction": 1, "comment": Decimal128("1.5")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:Decimal128", ), - SessionCommandTestCase( + CommandTestCase( "comment_bool_true", command={"abortTransaction": 1, "comment": True}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:true", ), - SessionCommandTestCase( + CommandTestCase( "comment_bool_false", command={"abortTransaction": 1, "comment": False}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:false", ), - SessionCommandTestCase( + CommandTestCase( "comment_null", command={"abortTransaction": 1, "comment": None}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:null", ), - SessionCommandTestCase( + CommandTestCase( "comment_object", command={"abortTransaction": 1, "comment": {"key": "value"}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:object", ), - SessionCommandTestCase( + CommandTestCase( "comment_object_empty", command={"abortTransaction": 1, "comment": {}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:empty object", ), - SessionCommandTestCase( + CommandTestCase( "comment_array", command={"abortTransaction": 1, "comment": [1, 2, 3]}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:array", ), - SessionCommandTestCase( + CommandTestCase( "comment_array_empty", command={"abortTransaction": 1, "comment": []}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:empty array", ), - SessionCommandTestCase( + CommandTestCase( "comment_objectid", command={"abortTransaction": 1, "comment": ObjectId()}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:ObjectId", ), - SessionCommandTestCase( + CommandTestCase( "comment_datetime", command={"abortTransaction": 1, "comment": datetime(2024, 1, 1, tzinfo=timezone.utc)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:datetime", ), - SessionCommandTestCase( + CommandTestCase( "comment_binary", command={"abortTransaction": 1, "comment": Binary(b"\x00")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:Binary", ), - SessionCommandTestCase( + CommandTestCase( "comment_regex", command={"abortTransaction": 1, "comment": Regex(".*")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:Regex", ), - SessionCommandTestCase( + CommandTestCase( "comment_timestamp", command={"abortTransaction": 1, "comment": Timestamp(0, 0)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:Timestamp", ), - SessionCommandTestCase( + CommandTestCase( "comment_minkey", command={"abortTransaction": 1, "comment": MinKey()}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:MinKey", ), - SessionCommandTestCase( + CommandTestCase( "comment_maxkey", command={"abortTransaction": 1, "comment": MaxKey()}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept comment:MaxKey", ), - SessionCommandTestCase( + CommandTestCase( "comment_code", command={"abortTransaction": 1, "comment": Code("function(){}")}, error_code=NO_SUCH_TRANSACTION_ERROR, diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index b59ea7af8..76dabff2c 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -1,10 +1,10 @@ """Tests for abortTransaction command core behavior and success cases. -Validates fundamental command behavior including the no-transaction error, -admin database requirement, and parameter interactions. Also validates that -abortTransaction rolls back operations within a real transaction context, -including insert, update, delete, and multi-operation transactions, verifies -the response structure on success, and that pre-transaction data survives abort. +Validates fundamental command behavior including the admin database +requirement and parameter interactions. Also validates that abortTransaction +rolls back operations within a real transaction context, including insert, +update, delete, and multi-operation transactions, verifies the response +structure on success, and that pre-transaction data survives abort. """ from __future__ import annotations @@ -12,8 +12,8 @@ import pytest from bson import Binary, Int64 -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( AbortSessionTestCase, @@ -41,19 +41,9 @@ pytestmark = pytest.mark.admin -# Property [No-Transaction Error]: abortTransaction outside a transaction fails. -CORE_NO_TRANSACTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( - "no_transaction_basic", - command={"abortTransaction": 1}, - error_code=NO_SUCH_TRANSACTION_ERROR, - msg="abortTransaction should fail with NoSuchTransaction outside a transaction", - ), -] - # Property [Parameter Acceptance]: all valid parameters combined are syntactically accepted. -CORE_PARAMETER_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +CORE_PARAMETER_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "all_valid_params", command={ "abortTransaction": 1, @@ -68,26 +58,26 @@ ] # Property [Parameter Interactions]: combinations of valid parameters behave correctly. -CORE_PARAMETER_INTERACTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +CORE_PARAMETER_INTERACTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( "interaction_autocommit_only", command={"abortTransaction": 1, "autocommit": False}, error_code=INVALID_OPTIONS_ERROR, msg="abortTransaction with autocommit:false only should fail with InvalidOptions", ), - SessionCommandTestCase( + CommandTestCase( "interaction_txn_number_only", command={"abortTransaction": 1, "txnNumber": Int64(1)}, error_code=ILLEGAL_OPERATION_ERROR, msg="abortTransaction with txnNumber only should fail with IllegalOperation", ), - SessionCommandTestCase( + CommandTestCase( "interaction_autocommit_txn_number", command={"abortTransaction": 1, "autocommit": False, "txnNumber": Int64(1)}, error_code=ILLEGAL_OPERATION_ERROR, msg="abortTransaction with autocommit + txnNumber should fail with IllegalOperation", ), - SessionCommandTestCase( + CommandTestCase( "interaction_lsid", command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -95,8 +85,8 @@ ), ] -CORE_TESTS: list[SessionCommandTestCase] = ( - CORE_NO_TRANSACTION_TESTS + CORE_PARAMETER_ACCEPTANCE_TESTS + CORE_PARAMETER_INTERACTION_TESTS +CORE_TESTS: list[CommandTestCase] = ( + CORE_PARAMETER_ACCEPTANCE_TESTS + CORE_PARAMETER_INTERACTION_TESTS ) @@ -108,8 +98,8 @@ def test_abortTransaction_core(collection, test): # Property [Admin Database Requirement]: abortTransaction must run against the admin database. -ADMIN_DB_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +ADMIN_DB_TESTS: list[CommandTestCase] = [ + CommandTestCase( "non_admin_database", command={"abortTransaction": 1}, error_code=UNAUTHORIZED_ERROR, diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py index a2522b3fd..a894a1e0b 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py @@ -12,8 +12,8 @@ import pytest from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR @@ -24,170 +24,170 @@ # Property [Field Type Acceptance]: the command field accepts any BSON type. -FIELD_TYPE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +FIELD_TYPE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "field_int32_positive", command={"abortTransaction": 1}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept int32 positive value", ), - SessionCommandTestCase( + CommandTestCase( "field_int32_negative", command={"abortTransaction": -1}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept int32 negative value", ), - SessionCommandTestCase( + CommandTestCase( "field_int32_zero", command={"abortTransaction": 0}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept int32 zero value", ), - SessionCommandTestCase( + CommandTestCase( "field_int64", command={"abortTransaction": Int64(1)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept int64 value", ), - SessionCommandTestCase( + CommandTestCase( "field_int64_max", command={"abortTransaction": Int64(9_223_372_036_854_775_807)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept int64 max value", ), - SessionCommandTestCase( + CommandTestCase( "field_double", command={"abortTransaction": 1.0}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept double value", ), - SessionCommandTestCase( + CommandTestCase( "field_double_negative", command={"abortTransaction": -1.0}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept negative double value", ), - SessionCommandTestCase( + CommandTestCase( "field_double_zero", command={"abortTransaction": 0.0}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept double zero value", ), - SessionCommandTestCase( + CommandTestCase( "field_decimal128", command={"abortTransaction": Decimal128("1")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept Decimal128 value", ), - SessionCommandTestCase( + CommandTestCase( "field_bool_true", command={"abortTransaction": True}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept bool true value", ), - SessionCommandTestCase( + CommandTestCase( "field_bool_false", command={"abortTransaction": False}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept bool false value", ), - SessionCommandTestCase( + CommandTestCase( "field_nan", command={"abortTransaction": float("nan")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept NaN value", ), - SessionCommandTestCase( + CommandTestCase( "field_infinity", command={"abortTransaction": float("inf")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept Infinity value", ), - SessionCommandTestCase( + CommandTestCase( "field_string", command={"abortTransaction": "abortTransaction"}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept string value", ), - SessionCommandTestCase( + CommandTestCase( "field_string_empty", command={"abortTransaction": ""}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept empty string value", ), - SessionCommandTestCase( + CommandTestCase( "field_null", command={"abortTransaction": None}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept null value", ), - SessionCommandTestCase( + CommandTestCase( "field_object_empty", command={"abortTransaction": {}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept empty object value", ), - SessionCommandTestCase( + CommandTestCase( "field_object_nonempty", command={"abortTransaction": {"key": "value"}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept non-empty object value", ), - SessionCommandTestCase( + CommandTestCase( "field_array_empty", command={"abortTransaction": []}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept empty array value", ), - SessionCommandTestCase( + CommandTestCase( "field_array_nonempty", command={"abortTransaction": [1, 2]}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept non-empty array value", ), - SessionCommandTestCase( + CommandTestCase( "field_binary", command={"abortTransaction": Binary(b"\x00")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept Binary value", ), - SessionCommandTestCase( + CommandTestCase( "field_objectid", command={"abortTransaction": ObjectId()}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept ObjectId value", ), - SessionCommandTestCase( + CommandTestCase( "field_datetime", command={"abortTransaction": datetime(2024, 1, 1, tzinfo=timezone.utc)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept datetime value", ), - SessionCommandTestCase( + CommandTestCase( "field_regex", command={"abortTransaction": Regex(".*")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept Regex value", ), - SessionCommandTestCase( + CommandTestCase( "field_timestamp", command={"abortTransaction": Timestamp(0, 0)}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept Timestamp value", ), - SessionCommandTestCase( + CommandTestCase( "field_code", command={"abortTransaction": Code("function(){}")}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept Code value", ), - SessionCommandTestCase( + CommandTestCase( "field_minkey", command={"abortTransaction": MinKey()}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept MinKey value", ), - SessionCommandTestCase( + CommandTestCase( "field_maxkey", command={"abortTransaction": MaxKey()}, error_code=NO_SUCH_TRANSACTION_ERROR, diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py index 3ba66cac3..8618a7148 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py @@ -12,8 +12,8 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import ( @@ -28,26 +28,26 @@ # Property [txnNumber Int64 Acceptance]: Int64 values are accepted for txnNumber. -TXN_NUMBER_INT64_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +TXN_NUMBER_INT64_TESTS: list[CommandTestCase] = [ + CommandTestCase( "txn_number_int64_positive", command={"abortTransaction": 1, "txnNumber": Int64(1)}, error_code=ILLEGAL_OPERATION_ERROR, msg="abortTransaction should accept txnNumber:Int64(1) and fail with IllegalOperation", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_int64_zero", command={"abortTransaction": 1, "txnNumber": Int64(0)}, error_code=ILLEGAL_OPERATION_ERROR, msg="abortTransaction should accept txnNumber:Int64(0) and fail with IllegalOperation", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_int64_max", command={"abortTransaction": 1, "txnNumber": Int64(9_223_372_036_854_775_807)}, error_code=ILLEGAL_OPERATION_ERROR, msg="abortTransaction should accept txnNumber:Int64 max value", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_int64_negative", command={"abortTransaction": 1, "txnNumber": Int64(-1)}, error_code=ILLEGAL_OPERATION_ERROR, @@ -56,50 +56,50 @@ ] # Property [txnNumber Type Strictness]: non-Int64 types are rejected with TypeMismatch. -TXN_NUMBER_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +TXN_NUMBER_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( "txn_number_int32", command={"abortTransaction": 1, "txnNumber": 1}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:int32 as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_double_whole", command={"abortTransaction": 1, "txnNumber": 1.0}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:double (whole) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_double_fractional", command={"abortTransaction": 1, "txnNumber": 1.5}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:double (fractional) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_decimal128", command={"abortTransaction": 1, "txnNumber": Decimal128("1")}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:Decimal128 as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_string", command={"abortTransaction": 1, "txnNumber": "1"}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:string as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_bool", command={"abortTransaction": 1, "txnNumber": True}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:bool as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_object", command={"abortTransaction": 1, "txnNumber": {}}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject txnNumber:{} (object) as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "txn_number_array", command={"abortTransaction": 1, "txnNumber": []}, error_code=TYPE_MISMATCH_ERROR, @@ -108,8 +108,8 @@ ] # Property [txnNumber Null Handling]: null txnNumber is treated as omitted. -TXN_NUMBER_NULL_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +TXN_NUMBER_NULL_TESTS: list[CommandTestCase] = [ + CommandTestCase( "txn_number_null", command={"abortTransaction": 1, "txnNumber": None}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -117,7 +117,7 @@ ), ] -TXN_NUMBER_TESTS: list[SessionCommandTestCase] = ( +TXN_NUMBER_TESTS: list[CommandTestCase] = ( TXN_NUMBER_INT64_TESTS + TXN_NUMBER_TYPE_REJECTION_TESTS + TXN_NUMBER_NULL_TESTS ) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py index a72c41cb4..755a63a6e 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py @@ -10,8 +10,8 @@ import pytest from bson import Int64 -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import UNRECOGNIZED_COMMAND_FIELD_ERROR @@ -22,14 +22,14 @@ # Property [Unrecognized Field Rejection]: unknown fields are rejected. -UNRECOGNIZED_FIELD_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +UNRECOGNIZED_FIELD_TESTS: list[CommandTestCase] = [ + CommandTestCase( "unknown_single_field", command={"abortTransaction": 1, "unknownField": 1}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="abortTransaction should reject single unknown field", ), - SessionCommandTestCase( + CommandTestCase( "unknown_multiple_fields", command={"abortTransaction": 1, "foo": 1, "bar": 2}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, @@ -38,26 +38,26 @@ ] # Property [Case Sensitivity]: field names are case-sensitive and wrong-case variants are rejected. -CASE_SENSITIVITY_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +CASE_SENSITIVITY_TESTS: list[CommandTestCase] = [ + CommandTestCase( "case_WriteConcern", command={"abortTransaction": 1, "WriteConcern": {"w": 1}}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="abortTransaction should reject 'WriteConcern' (capital W) as unrecognized", ), - SessionCommandTestCase( + CommandTestCase( "case_Autocommit", command={"abortTransaction": 1, "Autocommit": False}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="abortTransaction should reject 'Autocommit' (capital A) as unrecognized", ), - SessionCommandTestCase( + CommandTestCase( "case_TxnNumber", command={"abortTransaction": 1, "TxnNumber": Int64(1)}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="abortTransaction should reject 'TxnNumber' (capital T) as unrecognized", ), - SessionCommandTestCase( + CommandTestCase( "case_Comment", command={"abortTransaction": 1, "Comment": "test"}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, @@ -66,14 +66,14 @@ ] # Property [Foreign Field Rejection]: fields from other commands are rejected. -FOREIGN_FIELD_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +FOREIGN_FIELD_TESTS: list[CommandTestCase] = [ + CommandTestCase( "foreign_query", command={"abortTransaction": 1, "query": {"x": 1}}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="abortTransaction should reject 'query' field from other commands", ), - SessionCommandTestCase( + CommandTestCase( "dollar_prefixed", command={"abortTransaction": 1, "$unknown": 1}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, @@ -82,8 +82,8 @@ ] # Property [writeConcern Unknown Sub-Field]: unknown writeConcern sub-fields are rejected. -WRITECONCERN_UNKNOWN_SUBFIELD_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +WRITECONCERN_UNKNOWN_SUBFIELD_TESTS: list[CommandTestCase] = [ + CommandTestCase( "wc_unknown_subfield", command={"abortTransaction": 1, "writeConcern": {"w": 1, "unknownOption": True}}, error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, @@ -91,7 +91,7 @@ ), ] -UNRECOGNIZED_TESTS: list[SessionCommandTestCase] = ( +UNRECOGNIZED_TESTS: list[CommandTestCase] = ( UNRECOGNIZED_FIELD_TESTS + CASE_SENSITIVITY_TESTS + FOREIGN_FIELD_TESTS diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py index e215bfe27..b7930a6ec 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py @@ -10,8 +10,8 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR @@ -21,26 +21,20 @@ pytestmark = pytest.mark.admin # Property [writeConcern Document Acceptance]: writeConcern accepts document values. -WRITECONCERN_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( - "writeconcern_doc_w1", - command={"abortTransaction": 1, "writeConcern": {"w": 1}}, - error_code=NO_SUCH_TRANSACTION_ERROR, - msg="abortTransaction should accept writeConcern document with w:1", - ), - SessionCommandTestCase( +WRITECONCERN_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "writeconcern_empty_doc", command={"abortTransaction": 1, "writeConcern": {}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept empty writeConcern document", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_null", command={"abortTransaction": 1, "writeConcern": None}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern:null", ), - SessionCommandTestCase( + CommandTestCase( "wc_combined_w_j_wtimeout", command={ "abortTransaction": 1, @@ -49,13 +43,13 @@ error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept combined w + j + wtimeout", ), - SessionCommandTestCase( + CommandTestCase( "wc_w0_j_true", command={"abortTransaction": 1, "writeConcern": {"w": 0, "j": True}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept conflicting w:0 with j:true", ), - SessionCommandTestCase( + CommandTestCase( "wc_fsync_true", command={"abortTransaction": 1, "writeConcern": {"fsync": True}}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -64,44 +58,44 @@ ] # Property [w Accepted Values]: w accepts int and string "majority" values. -W_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +W_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "w_int32_one", command={"abortTransaction": 1, "writeConcern": {"w": 1}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.w:1", ), - SessionCommandTestCase( + CommandTestCase( "w_int32_zero", command={"abortTransaction": 1, "writeConcern": {"w": 0}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.w:0 (unacknowledged)", ), - SessionCommandTestCase( + CommandTestCase( "w_majority", command={"abortTransaction": 1, "writeConcern": {"w": "majority"}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.w:'majority'", ), - SessionCommandTestCase( + CommandTestCase( "w_int64", command={"abortTransaction": 1, "writeConcern": {"w": Int64(1)}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.w:Int64(1)", ), - SessionCommandTestCase( + CommandTestCase( "w_double_whole", command={"abortTransaction": 1, "writeConcern": {"w": 1.0}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.w:1.0", ), - SessionCommandTestCase( + CommandTestCase( "w_double_fractional", command={"abortTransaction": 1, "writeConcern": {"w": 1.5}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.w:1.5", ), - SessionCommandTestCase( + CommandTestCase( "w_decimal128", command={"abortTransaction": 1, "writeConcern": {"w": Decimal128("1")}}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -110,32 +104,32 @@ ] # Property [j Accepted Values]: j accepts boolean and numeric types. -J_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +J_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "j_bool_true", command={"abortTransaction": 1, "writeConcern": {"j": True}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.j:true", ), - SessionCommandTestCase( + CommandTestCase( "j_bool_false", command={"abortTransaction": 1, "writeConcern": {"j": False}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.j:false", ), - SessionCommandTestCase( + CommandTestCase( "j_int32_one", command={"abortTransaction": 1, "writeConcern": {"j": 1}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.j:1 (coerced to true)", ), - SessionCommandTestCase( + CommandTestCase( "j_int32_zero", command={"abortTransaction": 1, "writeConcern": {"j": 0}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.j:0 (coerced to false)", ), - SessionCommandTestCase( + CommandTestCase( "j_null", command={"abortTransaction": 1, "writeConcern": {"j": None}}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -144,62 +138,62 @@ ] # Property [wtimeout Accepted Values]: wtimeout accepts numeric types broadly. -WTIMEOUT_ACCEPTANCE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +WTIMEOUT_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "wtimeout_int32_positive", command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:1000", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_int32_zero", command={"abortTransaction": 1, "writeConcern": {"wtimeout": 0}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:0 (no timeout)", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_int64", command={"abortTransaction": 1, "writeConcern": {"wtimeout": Int64(1000)}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:Int64(1000)", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_double_whole", command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000.0}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:1000.0", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_negative", command={"abortTransaction": 1, "writeConcern": {"wtimeout": -1}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:-1", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_string", command={"abortTransaction": 1, "writeConcern": {"wtimeout": "1000"}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:'1000'", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_bool", command={"abortTransaction": 1, "writeConcern": {"wtimeout": True}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:true", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_null", command={"abortTransaction": 1, "writeConcern": {"wtimeout": None}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:null", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_object", command={"abortTransaction": 1, "writeConcern": {"wtimeout": {}}}, error_code=NO_SUCH_TRANSACTION_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:{}", ), - SessionCommandTestCase( + CommandTestCase( "wtimeout_array", command={"abortTransaction": 1, "writeConcern": {"wtimeout": []}}, error_code=NO_SUCH_TRANSACTION_ERROR, @@ -207,7 +201,7 @@ ), ] -WRITECONCERN_ACCEPTANCE_ALL_TESTS: list[SessionCommandTestCase] = ( +WRITECONCERN_ACCEPTANCE_ALL_TESTS: list[CommandTestCase] = ( WRITECONCERN_ACCEPTANCE_TESTS + W_ACCEPTANCE_TESTS + J_ACCEPTANCE_TESTS diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py index 72f70027a..08d1d4232 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py @@ -11,8 +11,8 @@ import pytest from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp -from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_command_test_case import ( # noqa: E501 - SessionCommandTestCase, +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import ( @@ -26,104 +26,104 @@ pytestmark = pytest.mark.admin # Property [writeConcern Type Rejection]: non-document types are rejected with TypeMismatch. -WRITECONCERN_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +WRITECONCERN_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( "writeconcern_string", command={"abortTransaction": 1, "writeConcern": "majority"}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:string as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_int32", command={"abortTransaction": 1, "writeConcern": 1}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:int32 as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_int64", command={"abortTransaction": 1, "writeConcern": Int64(1)}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:Int64 as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_double", command={"abortTransaction": 1, "writeConcern": 1.0}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:double as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_decimal128", command={"abortTransaction": 1, "writeConcern": Decimal128("1")}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:Decimal128 as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_bool_true", command={"abortTransaction": 1, "writeConcern": True}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:true as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_bool_false", command={"abortTransaction": 1, "writeConcern": False}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:false as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_array_empty", command={"abortTransaction": 1, "writeConcern": []}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:[] as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_array_nonempty", command={"abortTransaction": 1, "writeConcern": [{"w": 1}]}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:[{w:1}] as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_binary", command={"abortTransaction": 1, "writeConcern": Binary(b"\x00")}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:Binary as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_objectid", command={"abortTransaction": 1, "writeConcern": ObjectId()}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:ObjectId as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_datetime", command={"abortTransaction": 1, "writeConcern": datetime(2024, 1, 1, tzinfo=timezone.utc)}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:datetime as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_regex", command={"abortTransaction": 1, "writeConcern": Regex(".*")}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:Regex as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_timestamp", command={"abortTransaction": 1, "writeConcern": Timestamp(0, 0)}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:Timestamp as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_code", command={"abortTransaction": 1, "writeConcern": Code("function(){}")}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:Code as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_minkey", command={"abortTransaction": 1, "writeConcern": MinKey()}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern:MinKey as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "writeconcern_maxkey", command={"abortTransaction": 1, "writeConcern": MaxKey()}, error_code=TYPE_MISMATCH_ERROR, @@ -132,56 +132,56 @@ ] # Property [w Invalid Values]: invalid w values are rejected with BadValue or FailedToParse. -W_INVALID_VALUE_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +W_INVALID_VALUE_TESTS: list[CommandTestCase] = [ + CommandTestCase( "w_custom_tag", command={"abortTransaction": 1, "writeConcern": {"w": "myTag"}}, error_code=BAD_VALUE_ERROR, msg="abortTransaction should reject writeConcern.w:'myTag' with BadValue", ), - SessionCommandTestCase( + CommandTestCase( "w_empty_string", command={"abortTransaction": 1, "writeConcern": {"w": ""}}, error_code=BAD_VALUE_ERROR, msg="abortTransaction should reject writeConcern.w:'' with BadValue", ), - SessionCommandTestCase( + CommandTestCase( "w_null", command={"abortTransaction": 1, "writeConcern": {"w": None}}, error_code=BAD_VALUE_ERROR, msg="abortTransaction should reject writeConcern.w:null with BadValue", ), - SessionCommandTestCase( + CommandTestCase( "w_negative_int", command={"abortTransaction": 1, "writeConcern": {"w": -1}}, error_code=FAILED_TO_PARSE_ERROR, msg="abortTransaction should reject writeConcern.w:-1 with FailedToParse", ), - SessionCommandTestCase( + CommandTestCase( "w_int32_max", command={"abortTransaction": 1, "writeConcern": {"w": 2_147_483_647}}, error_code=FAILED_TO_PARSE_ERROR, msg="abortTransaction should reject writeConcern.w:INT32_MAX with FailedToParse", ), - SessionCommandTestCase( + CommandTestCase( "w_bool_false", command={"abortTransaction": 1, "writeConcern": {"w": False}}, error_code=FAILED_TO_PARSE_ERROR, msg="abortTransaction should reject writeConcern.w:false with FailedToParse", ), - SessionCommandTestCase( + CommandTestCase( "w_bool_true", command={"abortTransaction": 1, "writeConcern": {"w": True}}, error_code=FAILED_TO_PARSE_ERROR, msg="abortTransaction should reject writeConcern.w:true with FailedToParse", ), - SessionCommandTestCase( + CommandTestCase( "w_object", command={"abortTransaction": 1, "writeConcern": {"w": {}}}, error_code=FAILED_TO_PARSE_ERROR, msg="abortTransaction should reject writeConcern.w:{} with FailedToParse", ), - SessionCommandTestCase( + CommandTestCase( "w_array", command={"abortTransaction": 1, "writeConcern": {"w": []}}, error_code=FAILED_TO_PARSE_ERROR, @@ -190,20 +190,20 @@ ] # Property [j Type Rejection]: non-boolean non-numeric types are rejected with TypeMismatch. -J_TYPE_REJECTION_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +J_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( "j_string", command={"abortTransaction": 1, "writeConcern": {"j": "true"}}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern.j:'true' as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "j_object", command={"abortTransaction": 1, "writeConcern": {"j": {}}}, error_code=TYPE_MISMATCH_ERROR, msg="abortTransaction should reject writeConcern.j:{} as wrong type", ), - SessionCommandTestCase( + CommandTestCase( "j_array", command={"abortTransaction": 1, "writeConcern": {"j": []}}, error_code=TYPE_MISMATCH_ERROR, @@ -212,8 +212,8 @@ ] # Property [wtimeout Overflow]: Int64 max value overflows and produces FailedToParse. -WTIMEOUT_OVERFLOW_TESTS: list[SessionCommandTestCase] = [ - SessionCommandTestCase( +WTIMEOUT_OVERFLOW_TESTS: list[CommandTestCase] = [ + CommandTestCase( "wtimeout_int64_max", command={ "abortTransaction": 1, @@ -224,7 +224,7 @@ ), ] -WRITECONCERN_ERROR_TESTS: list[SessionCommandTestCase] = ( +WRITECONCERN_ERROR_TESTS: list[CommandTestCase] = ( WRITECONCERN_TYPE_REJECTION_TESTS + W_INVALID_VALUE_TESTS + J_TYPE_REJECTION_TESTS diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py index 37b8a5302..2dd88f6e9 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py @@ -6,7 +6,8 @@ import pytest -from documentdb_tests.framework.assertions import assertFailure +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR from documentdb_tests.framework.executor import execute_admin_command pytestmark = pytest.mark.smoke @@ -15,6 +16,6 @@ def test_smoke_abortTransaction(collection): """Test basic abortTransaction command behavior.""" result = execute_admin_command(collection, {"abortTransaction": 1}) - - expected_error = {"code": 125, "msg": "abortTransaction must be run within a transaction"} - assertFailure(result, expected_error, msg="Should support abortTransaction command") + assertFailureCode( + result, NO_SUCH_TRANSACTION_ERROR, msg="Should support abortTransaction command" + ) From 0e13435a6c4f42e6a4a7df16014ddcd9f43f0f03 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 16:38:09 -0700 Subject: [PATCH 04/15] use SessionTestCase instead of AbortSessionTestCase Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_core.py | 40 +++++++++---------- .../commands/utils/session_test_case.py | 30 -------------- documentdb_tests/framework/executor.py | 14 +++---- 3 files changed, 27 insertions(+), 57 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index 76dabff2c..63a395ae3 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -16,9 +16,9 @@ CommandTestCase, ) from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( - AbortSessionTestCase, SessionOp, SessionOperation, + SessionTestCase, ) from documentdb_tests.framework.assertions import ( assertFailureCode, @@ -116,14 +116,14 @@ def test_abortTransaction_admin_db_required(collection, test): # Property [Abort Rollback]: aborted operations are rolled back. -ABORT_ROLLBACK_TESTS: list[AbortSessionTestCase] = [ - AbortSessionTestCase( +ABORT_ROLLBACK_TESTS: list[SessionTestCase] = [ + SessionTestCase( "abort_insert", ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1, "x": "inserted"})], expected=[], msg="abortTransaction should roll back the inserted document", ), - AbortSessionTestCase( + SessionTestCase( "abort_update", docs=[{"_id": 1, "x": "before"}], ops=[ @@ -136,14 +136,14 @@ def test_abortTransaction_admin_db_required(collection, test): expected=[{"_id": 1, "x": "before"}], msg="abortTransaction should roll back the updated value", ), - AbortSessionTestCase( + SessionTestCase( "abort_delete", docs=[{"_id": 1, "x": "to_delete"}], ops=[SessionOperation(op=SessionOp.DELETE, filter={"_id": 1})], expected=[{"_id": 1, "x": "to_delete"}], msg="abortTransaction should roll back the deletion", ), - AbortSessionTestCase( + SessionTestCase( "abort_multi_operation", docs=[{"_id": 1, "x": "original"}], ops=[ @@ -157,7 +157,7 @@ def test_abortTransaction_admin_db_required(collection, test): expected=[{"_id": 1, "x": "original"}], msg="abortTransaction should roll back all operations from a multi-op transaction", ), - AbortSessionTestCase( + SessionTestCase( "abort_with_writeconcern", docs=[{"_id": 1, "x": "before"}], ops=[ @@ -167,11 +167,11 @@ def test_abortTransaction_admin_db_required(collection, test): update={"$set": {"x": "after"}}, ) ], - abort_command={"abortTransaction": 1, "writeConcern": {"w": 1}}, + commit_command={"abortTransaction": 1, "writeConcern": {"w": 1}}, expected=[{"_id": 1, "x": "before"}], msg="abortTransaction with writeConcern should roll back changes", ), - AbortSessionTestCase( + SessionTestCase( "abort_insert_delete_same_doc", ops=[ SessionOperation(op=SessionOp.INSERT, document={"_id": 1}), @@ -180,7 +180,7 @@ def test_abortTransaction_admin_db_required(collection, test): expected=[], msg="abortTransaction should roll back insert+delete of the same document", ), - AbortSessionTestCase( + SessionTestCase( "abort_multiple_inserts", ops=[ SessionOperation(op=SessionOp.INSERT, document={"_id": 1}), @@ -189,7 +189,7 @@ def test_abortTransaction_admin_db_required(collection, test): expected=[], msg="abortTransaction should roll back multiple inserts", ), - AbortSessionTestCase( + SessionTestCase( "abort_update_insert_different_docs", docs=[{"_id": 1, "x": "original"}], ops=[ @@ -215,8 +215,8 @@ def test_abortTransaction_core_rollback(collection, test): # Property [Pre-Transaction Data Survival]: seed data survives abort. -PRE_TRANSACTION_TESTS: list[AbortSessionTestCase] = [ - AbortSessionTestCase( +PRE_TRANSACTION_TESTS: list[SessionTestCase] = [ + SessionTestCase( "pre_existing_data_survives", docs=[{"_id": 1, "x": "seed"}], ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 2, "x": "txn"})], @@ -235,8 +235,8 @@ def test_abortTransaction_core_pre_transaction_data(collection, test): # Property [Empty Transaction]: aborting a transaction with no ops succeeds. -EMPTY_TRANSACTION_TESTS: list[AbortSessionTestCase] = [ - AbortSessionTestCase( +EMPTY_TRANSACTION_TESTS: list[SessionTestCase] = [ + SessionTestCase( "abort_empty_transaction", ops=[], msg="abortTransaction on empty transaction should not error", @@ -253,18 +253,18 @@ def test_abortTransaction_core_empty(collection, test): # Property [Response Structure]: abort response contains ok:1 on success. -RESPONSE_STRUCTURE_TESTS: list[AbortSessionTestCase] = [ - AbortSessionTestCase( +RESPONSE_STRUCTURE_TESTS: list[SessionTestCase] = [ + SessionTestCase( "abort_response_ok", ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], - abort_command={"abortTransaction": 1}, + commit_command={"abortTransaction": 1}, expected_response={"ok": 1.0}, msg="abortTransaction response should have ok:1 on success", ), - AbortSessionTestCase( + SessionTestCase( "abort_with_comment", ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], - abort_command={"abortTransaction": 1, "comment": "test abort"}, + commit_command={"abortTransaction": 1, "comment": "test abort"}, expected_response={"ok": 1.0}, msg="abortTransaction with comment should succeed", ), diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py index f8d509496..aa635f521 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py @@ -75,33 +75,3 @@ class SessionTestCase(CommandTestCase): expected_response: dict[str, Any] | None = None readback_filter: dict[str, Any] = field(default_factory=dict) readback_sort: dict[str, Any] = field(default_factory=lambda: {"_id": 1}) - - -@dataclass(frozen=True) -class AbortSessionTestCase(CommandTestCase): - """Test case for abortTransaction success tests. - - Extends CommandTestCase to model a multi-step transaction workflow: - seed documents, run operations inside a transaction, abort, and - verify the result via readback (expecting rollback). - - Attributes: - ops: Operations to execute inside the transaction before aborting. - abort_command: Optional raw command dict for aborting (e.g. to - include writeConcern or comment). When None, uses - ``session.abort_transaction()``. - expected_response: Expected fields from the abort command response. - When set, the assertion targets the abort response instead of - a readback query. Defaults to ``None``. - Mutually exclusive with ``expected``. - readback_filter: Filter for the post-abort readback query. Defaults - to ``{}``. - readback_sort: Sort for the post-abort readback query. Defaults - to ``{"_id": 1}``. - """ - - ops: list[SessionOperation] = field(default_factory=list) - abort_command: dict[str, Any] | None = None - expected_response: dict[str, Any] | None = None - readback_filter: dict[str, Any] = field(default_factory=dict) - readback_sort: dict[str, Any] = field(default_factory=lambda: {"_id": 1}) diff --git a/documentdb_tests/framework/executor.py b/documentdb_tests/framework/executor.py index ab3e1df51..96de7881a 100644 --- a/documentdb_tests/framework/executor.py +++ b/documentdb_tests/framework/executor.py @@ -118,7 +118,7 @@ def execute_session_command(collection, test_case) -> Any: def execute_abort_session_command(collection, test_case) -> Any: - """Execute an AbortSessionTestCase: seed, transact, abort, and return the result. + """Execute a SessionTestCase as an abort: seed, transact, abort, and return the result. Runs the full transaction lifecycle described by *test_case*: @@ -126,7 +126,7 @@ def execute_abort_session_command(collection, test_case) -> Any: 2. Open a client session and start a transaction. 3. Execute each ``SessionOperation`` in ``test_case.ops``. 4. Abort — either via ``session.abort_transaction()`` or by sending - ``test_case.abort_command`` as a raw admin command. + ``test_case.commit_command`` as a raw admin command. 5. Return the appropriate result for assertion: - If ``test_case.expected_response`` is set, return the abort command response (a dict). @@ -135,16 +135,16 @@ def execute_abort_session_command(collection, test_case) -> Any: Args: collection: The pytest ``collection`` fixture. - test_case: An ``AbortSessionTestCase`` instance. + test_case: A ``SessionTestCase`` instance. Returns: Result dict (abort response or readback) or Exception. """ from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( # noqa: E501 - AbortSessionTestCase, + SessionTestCase, ) - assert isinstance(test_case, AbortSessionTestCase) + assert isinstance(test_case, SessionTestCase) # 1. Seed documents. if test_case.docs is not None: @@ -158,9 +158,9 @@ def execute_abort_session_command(collection, test_case) -> Any: session.start_transaction() for op in test_case.ops: op.execute(collection, session) - if test_case.abort_command is not None: + if test_case.commit_command is not None: try: - abort_result = client.admin.command(test_case.abort_command, session=session) + abort_result = client.admin.command(test_case.commit_command, session=session) except Exception as e: abort_result = e else: From f0855323b31f25d02d8058d88f29c51b5e5c228b Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 16:42:13 -0700 Subject: [PATCH 05/15] apply other PR comments rename NO_SUCH_TRANSACTION_ERROR, and Added readback verification to execute_abort_session_command Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_autocommit.py | 4 +- .../test_abortTransaction_comment.py | 44 +++++++------- .../test_abortTransaction_core.py | 4 +- .../test_abortTransaction_field_types.py | 58 +++++++++---------- .../test_abortTransaction_txn_number.py | 4 +- .../test_abortTransaction_writeconcern.py | 56 +++++++++--------- .../test_smoke_abortTransaction.py | 6 +- documentdb_tests/framework/error_codes.py | 2 +- documentdb_tests/framework/executor.py | 18 +++++- 9 files changed, 105 insertions(+), 91 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py index 880ba9bfd..a8624913a 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py @@ -16,8 +16,8 @@ ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import ( + COMMAND_FAILED_ERROR, INVALID_OPTIONS_ERROR, - NO_SUCH_TRANSACTION_ERROR, TYPE_MISMATCH_ERROR, ) from documentdb_tests.framework.executor import execute_admin_command @@ -99,7 +99,7 @@ CommandTestCase( "autocommit_null", command={"abortTransaction": 1, "autocommit": None}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should treat autocommit:null as omitted", ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py index 93490c074..5d603c889 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py @@ -16,7 +16,7 @@ CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR +from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params @@ -28,127 +28,127 @@ CommandTestCase( "comment_string", command={"abortTransaction": 1, "comment": "test comment"}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:string", ), CommandTestCase( "comment_string_empty", command={"abortTransaction": 1, "comment": ""}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:empty string", ), CommandTestCase( "comment_int32", command={"abortTransaction": 1, "comment": 42}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:int32", ), CommandTestCase( "comment_int64", command={"abortTransaction": 1, "comment": Int64(42)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:Int64", ), CommandTestCase( "comment_double", command={"abortTransaction": 1, "comment": 3.14}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:double", ), CommandTestCase( "comment_decimal128", command={"abortTransaction": 1, "comment": Decimal128("1.5")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:Decimal128", ), CommandTestCase( "comment_bool_true", command={"abortTransaction": 1, "comment": True}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:true", ), CommandTestCase( "comment_bool_false", command={"abortTransaction": 1, "comment": False}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:false", ), CommandTestCase( "comment_null", command={"abortTransaction": 1, "comment": None}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:null", ), CommandTestCase( "comment_object", command={"abortTransaction": 1, "comment": {"key": "value"}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:object", ), CommandTestCase( "comment_object_empty", command={"abortTransaction": 1, "comment": {}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:empty object", ), CommandTestCase( "comment_array", command={"abortTransaction": 1, "comment": [1, 2, 3]}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:array", ), CommandTestCase( "comment_array_empty", command={"abortTransaction": 1, "comment": []}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:empty array", ), CommandTestCase( "comment_objectid", command={"abortTransaction": 1, "comment": ObjectId()}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:ObjectId", ), CommandTestCase( "comment_datetime", command={"abortTransaction": 1, "comment": datetime(2024, 1, 1, tzinfo=timezone.utc)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:datetime", ), CommandTestCase( "comment_binary", command={"abortTransaction": 1, "comment": Binary(b"\x00")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:Binary", ), CommandTestCase( "comment_regex", command={"abortTransaction": 1, "comment": Regex(".*")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:Regex", ), CommandTestCase( "comment_timestamp", command={"abortTransaction": 1, "comment": Timestamp(0, 0)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:Timestamp", ), CommandTestCase( "comment_minkey", command={"abortTransaction": 1, "comment": MinKey()}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:MinKey", ), CommandTestCase( "comment_maxkey", command={"abortTransaction": 1, "comment": MaxKey()}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:MaxKey", ), CommandTestCase( "comment_code", command={"abortTransaction": 1, "comment": Code("function(){}")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept comment:Code", ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index 63a395ae3..a0e239980 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -27,9 +27,9 @@ assertSuccessPartial, ) from documentdb_tests.framework.error_codes import ( + COMMAND_FAILED_ERROR, ILLEGAL_OPERATION_ERROR, INVALID_OPTIONS_ERROR, - NO_SUCH_TRANSACTION_ERROR, UNAUTHORIZED_ERROR, ) from documentdb_tests.framework.executor import ( @@ -80,7 +80,7 @@ CommandTestCase( "interaction_lsid", command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction with explicit lsid should accept the field", ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py index a894a1e0b..27aaeab21 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py @@ -16,7 +16,7 @@ CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR +from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params @@ -28,169 +28,169 @@ CommandTestCase( "field_int32_positive", command={"abortTransaction": 1}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept int32 positive value", ), CommandTestCase( "field_int32_negative", command={"abortTransaction": -1}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept int32 negative value", ), CommandTestCase( "field_int32_zero", command={"abortTransaction": 0}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept int32 zero value", ), CommandTestCase( "field_int64", command={"abortTransaction": Int64(1)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept int64 value", ), CommandTestCase( "field_int64_max", command={"abortTransaction": Int64(9_223_372_036_854_775_807)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept int64 max value", ), CommandTestCase( "field_double", command={"abortTransaction": 1.0}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept double value", ), CommandTestCase( "field_double_negative", command={"abortTransaction": -1.0}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept negative double value", ), CommandTestCase( "field_double_zero", command={"abortTransaction": 0.0}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept double zero value", ), CommandTestCase( "field_decimal128", command={"abortTransaction": Decimal128("1")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept Decimal128 value", ), CommandTestCase( "field_bool_true", command={"abortTransaction": True}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept bool true value", ), CommandTestCase( "field_bool_false", command={"abortTransaction": False}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept bool false value", ), CommandTestCase( "field_nan", command={"abortTransaction": float("nan")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept NaN value", ), CommandTestCase( "field_infinity", command={"abortTransaction": float("inf")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept Infinity value", ), CommandTestCase( "field_string", command={"abortTransaction": "abortTransaction"}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept string value", ), CommandTestCase( "field_string_empty", command={"abortTransaction": ""}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept empty string value", ), CommandTestCase( "field_null", command={"abortTransaction": None}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept null value", ), CommandTestCase( "field_object_empty", command={"abortTransaction": {}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept empty object value", ), CommandTestCase( "field_object_nonempty", command={"abortTransaction": {"key": "value"}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept non-empty object value", ), CommandTestCase( "field_array_empty", command={"abortTransaction": []}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept empty array value", ), CommandTestCase( "field_array_nonempty", command={"abortTransaction": [1, 2]}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept non-empty array value", ), CommandTestCase( "field_binary", command={"abortTransaction": Binary(b"\x00")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept Binary value", ), CommandTestCase( "field_objectid", command={"abortTransaction": ObjectId()}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept ObjectId value", ), CommandTestCase( "field_datetime", command={"abortTransaction": datetime(2024, 1, 1, tzinfo=timezone.utc)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept datetime value", ), CommandTestCase( "field_regex", command={"abortTransaction": Regex(".*")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept Regex value", ), CommandTestCase( "field_timestamp", command={"abortTransaction": Timestamp(0, 0)}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept Timestamp value", ), CommandTestCase( "field_code", command={"abortTransaction": Code("function(){}")}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept Code value", ), CommandTestCase( "field_minkey", command={"abortTransaction": MinKey()}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept MinKey value", ), CommandTestCase( "field_maxkey", command={"abortTransaction": MaxKey()}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept MaxKey value", ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py index 8618a7148..4c7c5ee6e 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py @@ -17,8 +17,8 @@ ) from documentdb_tests.framework.assertions import assertFailureCode from documentdb_tests.framework.error_codes import ( + COMMAND_FAILED_ERROR, ILLEGAL_OPERATION_ERROR, - NO_SUCH_TRANSACTION_ERROR, TYPE_MISMATCH_ERROR, ) from documentdb_tests.framework.executor import execute_admin_command @@ -112,7 +112,7 @@ CommandTestCase( "txn_number_null", command={"abortTransaction": 1, "txnNumber": None}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should treat txnNumber:null as omitted", ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py index b7930a6ec..e4d48437e 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py @@ -14,7 +14,7 @@ CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR +from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params @@ -25,13 +25,13 @@ CommandTestCase( "writeconcern_empty_doc", command={"abortTransaction": 1, "writeConcern": {}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept empty writeConcern document", ), CommandTestCase( "writeconcern_null", command={"abortTransaction": 1, "writeConcern": None}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern:null", ), CommandTestCase( @@ -40,19 +40,19 @@ "abortTransaction": 1, "writeConcern": {"w": "majority", "j": True, "wtimeout": 10_000}, }, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept combined w + j + wtimeout", ), CommandTestCase( "wc_w0_j_true", command={"abortTransaction": 1, "writeConcern": {"w": 0, "j": True}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept conflicting w:0 with j:true", ), CommandTestCase( "wc_fsync_true", command={"abortTransaction": 1, "writeConcern": {"fsync": True}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept legacy writeConcern.fsync:true", ), ] @@ -62,43 +62,43 @@ CommandTestCase( "w_int32_one", command={"abortTransaction": 1, "writeConcern": {"w": 1}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:1", ), CommandTestCase( "w_int32_zero", command={"abortTransaction": 1, "writeConcern": {"w": 0}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:0 (unacknowledged)", ), CommandTestCase( "w_majority", command={"abortTransaction": 1, "writeConcern": {"w": "majority"}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:'majority'", ), CommandTestCase( "w_int64", command={"abortTransaction": 1, "writeConcern": {"w": Int64(1)}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:Int64(1)", ), CommandTestCase( "w_double_whole", command={"abortTransaction": 1, "writeConcern": {"w": 1.0}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:1.0", ), CommandTestCase( "w_double_fractional", command={"abortTransaction": 1, "writeConcern": {"w": 1.5}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:1.5", ), CommandTestCase( "w_decimal128", command={"abortTransaction": 1, "writeConcern": {"w": Decimal128("1")}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.w:Decimal128('1')", ), ] @@ -108,31 +108,31 @@ CommandTestCase( "j_bool_true", command={"abortTransaction": 1, "writeConcern": {"j": True}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.j:true", ), CommandTestCase( "j_bool_false", command={"abortTransaction": 1, "writeConcern": {"j": False}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.j:false", ), CommandTestCase( "j_int32_one", command={"abortTransaction": 1, "writeConcern": {"j": 1}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.j:1 (coerced to true)", ), CommandTestCase( "j_int32_zero", command={"abortTransaction": 1, "writeConcern": {"j": 0}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.j:0 (coerced to false)", ), CommandTestCase( "j_null", command={"abortTransaction": 1, "writeConcern": {"j": None}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.j:null", ), ] @@ -142,61 +142,61 @@ CommandTestCase( "wtimeout_int32_positive", command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:1000", ), CommandTestCase( "wtimeout_int32_zero", command={"abortTransaction": 1, "writeConcern": {"wtimeout": 0}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:0 (no timeout)", ), CommandTestCase( "wtimeout_int64", command={"abortTransaction": 1, "writeConcern": {"wtimeout": Int64(1000)}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:Int64(1000)", ), CommandTestCase( "wtimeout_double_whole", command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000.0}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:1000.0", ), CommandTestCase( "wtimeout_negative", command={"abortTransaction": 1, "writeConcern": {"wtimeout": -1}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:-1", ), CommandTestCase( "wtimeout_string", command={"abortTransaction": 1, "writeConcern": {"wtimeout": "1000"}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:'1000'", ), CommandTestCase( "wtimeout_bool", command={"abortTransaction": 1, "writeConcern": {"wtimeout": True}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:true", ), CommandTestCase( "wtimeout_null", command={"abortTransaction": 1, "writeConcern": {"wtimeout": None}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:null", ), CommandTestCase( "wtimeout_object", command={"abortTransaction": 1, "writeConcern": {"wtimeout": {}}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:{}", ), CommandTestCase( "wtimeout_array", command={"abortTransaction": 1, "writeConcern": {"wtimeout": []}}, - error_code=NO_SUCH_TRANSACTION_ERROR, + error_code=COMMAND_FAILED_ERROR, msg="abortTransaction should accept writeConcern.wtimeout:[]", ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py index 2dd88f6e9..da8e16806 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py @@ -7,7 +7,7 @@ import pytest from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import NO_SUCH_TRANSACTION_ERROR +from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR from documentdb_tests.framework.executor import execute_admin_command pytestmark = pytest.mark.smoke @@ -16,6 +16,4 @@ def test_smoke_abortTransaction(collection): """Test basic abortTransaction command behavior.""" result = execute_admin_command(collection, {"abortTransaction": 1}) - assertFailureCode( - result, NO_SUCH_TRANSACTION_ERROR, msg="Should support abortTransaction command" - ) + assertFailureCode(result, COMMAND_FAILED_ERROR, msg="Should support abortTransaction command") diff --git a/documentdb_tests/framework/error_codes.py b/documentdb_tests/framework/error_codes.py index ee90ca498..7cac989e9 100644 --- a/documentdb_tests/framework/error_codes.py +++ b/documentdb_tests/framework/error_codes.py @@ -34,7 +34,7 @@ OPERATION_FAILED_ERROR = 96 DOCUMENT_VALIDATION_FAILURE_ERROR = 121 NOT_A_REPLICA_SET_ERROR = 123 -NO_SUCH_TRANSACTION_ERROR = 125 +COMMAND_FAILED_ERROR = 125 CAPPED_POSITION_LOST_ERROR = 136 INCOMPATIBLE_COLLATION_VERSION_ERROR = 161 VIEW_DEPTH_LIMIT_ERROR = 165 diff --git a/documentdb_tests/framework/executor.py b/documentdb_tests/framework/executor.py index 96de7881a..087aa7bb1 100644 --- a/documentdb_tests/framework/executor.py +++ b/documentdb_tests/framework/executor.py @@ -168,7 +168,23 @@ def execute_abort_session_command(collection, test_case) -> Any: # 5. Return abort response or readback. if test_case.expected_response is not None: - execute_command(collection, {"find": collection.name, "filter": {}}) + # Verify that aborted data did NOT persist (the raw admin + # command path bypasses pymongo's session bookkeeping; we + # assert rollback explicitly by checking that transacted + # inserts are not visible after abort). + if not isinstance(abort_result, Exception) and test_case.ops: + readback = execute_command( + collection, + {"find": collection.name, "filter": test_case.readback_filter}, + ) + assert not isinstance(readback, Exception), f"Readback after abort failed: {readback}" + cursor = readback.get("cursor", {}) + docs = cursor.get("firstBatch", []) + seed_count = len(test_case.docs) if test_case.docs else 0 + assert len(docs) == seed_count, ( + f"Aborted transaction data persisted — " + f"expected {seed_count} docs (seed only), got {len(docs)}" + ) return abort_result return execute_command( From 052b3c50aab1cf2192a4fb0a82af915f2dd7ce68 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 16:52:44 -0700 Subject: [PATCH 06/15] split files to avoid mixing success and error cases in same file Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_core.py | 102 ++---------------- .../test_abortTransaction_core_error.py | 98 +++++++++++++++++ 2 files changed, 104 insertions(+), 96 deletions(-) create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index a0e239980..de227bca6 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -1,120 +1,30 @@ -"""Tests for abortTransaction command core behavior and success cases. +"""Tests for abortTransaction command success cases. -Validates fundamental command behavior including the admin database -requirement and parameter interactions. Also validates that abortTransaction -rolls back operations within a real transaction context, including insert, -update, delete, and multi-operation transactions, verifies the response -structure on success, and that pre-transaction data survives abort. +Validates that abortTransaction rolls back operations within a real +transaction context, including insert, update, delete, and multi-operation +transactions, verifies the response structure on success, and that +pre-transaction data survives abort. """ from __future__ import annotations import pytest -from bson import Binary, Int64 -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( - CommandTestCase, -) from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( SessionOp, SessionOperation, SessionTestCase, ) from documentdb_tests.framework.assertions import ( - assertFailureCode, assertNotError, assertSuccess, assertSuccessPartial, ) -from documentdb_tests.framework.error_codes import ( - COMMAND_FAILED_ERROR, - ILLEGAL_OPERATION_ERROR, - INVALID_OPTIONS_ERROR, - UNAUTHORIZED_ERROR, -) -from documentdb_tests.framework.executor import ( - execute_abort_session_command, - execute_admin_command, - execute_command, -) +from documentdb_tests.framework.executor import execute_abort_session_command from documentdb_tests.framework.parametrize import pytest_params pytestmark = pytest.mark.admin -# Property [Parameter Acceptance]: all valid parameters combined are syntactically accepted. -CORE_PARAMETER_ACCEPTANCE_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "all_valid_params", - command={ - "abortTransaction": 1, - "autocommit": False, - "txnNumber": Int64(1), - "writeConcern": {"w": "majority", "j": True, "wtimeout": 10_000}, - "comment": "full abort", - }, - error_code=ILLEGAL_OPERATION_ERROR, - msg="abortTransaction with all valid params should not produce a parsing error", - ), -] - -# Property [Parameter Interactions]: combinations of valid parameters behave correctly. -CORE_PARAMETER_INTERACTION_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "interaction_autocommit_only", - command={"abortTransaction": 1, "autocommit": False}, - error_code=INVALID_OPTIONS_ERROR, - msg="abortTransaction with autocommit:false only should fail with InvalidOptions", - ), - CommandTestCase( - "interaction_txn_number_only", - command={"abortTransaction": 1, "txnNumber": Int64(1)}, - error_code=ILLEGAL_OPERATION_ERROR, - msg="abortTransaction with txnNumber only should fail with IllegalOperation", - ), - CommandTestCase( - "interaction_autocommit_txn_number", - command={"abortTransaction": 1, "autocommit": False, "txnNumber": Int64(1)}, - error_code=ILLEGAL_OPERATION_ERROR, - msg="abortTransaction with autocommit + txnNumber should fail with IllegalOperation", - ), - CommandTestCase( - "interaction_lsid", - command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction with explicit lsid should accept the field", - ), -] - -CORE_TESTS: list[CommandTestCase] = ( - CORE_PARAMETER_ACCEPTANCE_TESTS + CORE_PARAMETER_INTERACTION_TESTS -) - - -@pytest.mark.parametrize("test", pytest_params(CORE_TESTS)) -def test_abortTransaction_core(collection, test): - """Test abortTransaction core behavior.""" - result = execute_admin_command(collection, test.command) - assertFailureCode(result, test.error_code, msg=test.msg) - - -# Property [Admin Database Requirement]: abortTransaction must run against the admin database. -ADMIN_DB_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "non_admin_database", - command={"abortTransaction": 1}, - error_code=UNAUTHORIZED_ERROR, - msg="abortTransaction on a non-admin database should fail with Unauthorized", - ), -] - - -@pytest.mark.parametrize("test", pytest_params(ADMIN_DB_TESTS)) -def test_abortTransaction_admin_db_required(collection, test): - """Test abortTransaction requires admin database.""" - result = execute_command(collection, test.command) - assertFailureCode(result, test.error_code, msg=test.msg) - - # Property [Abort Rollback]: aborted operations are rolled back. ABORT_ROLLBACK_TESTS: list[SessionTestCase] = [ SessionTestCase( diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py new file mode 100644 index 000000000..a6898763b --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py @@ -0,0 +1,98 @@ +"""Tests for abortTransaction command core error cases. + +Validates fundamental command error behavior including parameter acceptance, +parameter interactions, and the admin database requirement. +""" + +from __future__ import annotations + +import pytest +from bson import Binary, Int64 + +from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import ( + COMMAND_FAILED_ERROR, + ILLEGAL_OPERATION_ERROR, + INVALID_OPTIONS_ERROR, + UNAUTHORIZED_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command, execute_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = pytest.mark.admin + +# Property [Parameter Acceptance]: all valid parameters combined are syntactically accepted. +CORE_PARAMETER_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "all_valid_params", + command={ + "abortTransaction": 1, + "autocommit": False, + "txnNumber": Int64(1), + "writeConcern": {"w": "majority", "j": True, "wtimeout": 10_000}, + "comment": "full abort", + }, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction with all valid params should not produce a parsing error", + ), +] + +# Property [Parameter Interactions]: combinations of valid parameters behave correctly. +CORE_PARAMETER_INTERACTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "interaction_autocommit_only", + command={"abortTransaction": 1, "autocommit": False}, + error_code=INVALID_OPTIONS_ERROR, + msg="abortTransaction with autocommit:false only should fail with InvalidOptions", + ), + CommandTestCase( + "interaction_txn_number_only", + command={"abortTransaction": 1, "txnNumber": Int64(1)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction with txnNumber only should fail with IllegalOperation", + ), + CommandTestCase( + "interaction_autocommit_txn_number", + command={"abortTransaction": 1, "autocommit": False, "txnNumber": Int64(1)}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="abortTransaction with autocommit + txnNumber should fail with IllegalOperation", + ), + CommandTestCase( + "interaction_lsid", + command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, + error_code=COMMAND_FAILED_ERROR, + msg="abortTransaction with explicit lsid should accept the field", + ), +] + +CORE_ERROR_TESTS: list[CommandTestCase] = ( + CORE_PARAMETER_ACCEPTANCE_TESTS + CORE_PARAMETER_INTERACTION_TESTS +) + + +@pytest.mark.parametrize("test", pytest_params(CORE_ERROR_TESTS)) +def test_abortTransaction_core_error(collection, test): + """Test abortTransaction core error cases.""" + result = execute_admin_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) + + +# Property [Admin Database Requirement]: abortTransaction must run against the admin database. +ADMIN_DB_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "non_admin_database", + command={"abortTransaction": 1}, + error_code=UNAUTHORIZED_ERROR, + msg="abortTransaction on a non-admin database should fail with Unauthorized", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(ADMIN_DB_TESTS)) +def test_abortTransaction_admin_db_required(collection, test): + """Test abortTransaction requires admin database.""" + result = execute_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) From d052664c0b87b6c34dcdb8b5ea6df52e3209a6eb Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 16:55:37 -0700 Subject: [PATCH 07/15] rename to have _error.py suffix Signed-off-by: Alina (Xi) Li --- ...utocommit.py => test_abortTransaction_autocommit_error.py} | 4 ++-- ...tion_comment.py => test_abortTransaction_comment_error.py} | 4 ++-- ...ld_types.py => test_abortTransaction_field_types_error.py} | 4 ++-- ...xn_number.py => test_abortTransaction_txn_number_error.py} | 4 ++-- ....py => test_abortTransaction_unrecognized_fields_error.py} | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/{test_abortTransaction_autocommit.py => test_abortTransaction_autocommit_error.py} (97%) rename documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/{test_abortTransaction_comment.py => test_abortTransaction_comment_error.py} (97%) rename documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/{test_abortTransaction_field_types.py => test_abortTransaction_field_types_error.py} (98%) rename documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/{test_abortTransaction_txn_number.py => test_abortTransaction_txn_number_error.py} (97%) rename documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/{test_abortTransaction_unrecognized_fields.py => test_abortTransaction_unrecognized_fields_error.py} (96%) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py similarity index 97% rename from documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py rename to documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py index a8624913a..4b7a2aa14 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py @@ -110,7 +110,7 @@ @pytest.mark.parametrize("test", pytest_params(AUTOCOMMIT_TESTS)) -def test_abortTransaction_autocommit(collection, test): - """Test abortTransaction autocommit parameter validation.""" +def test_abortTransaction_autocommit_error(collection, test): + """Test abortTransaction autocommit error cases.""" result = execute_admin_command(collection, test.command) assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py similarity index 97% rename from documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py rename to documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py index 5d603c889..60ae43f36 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py @@ -155,7 +155,7 @@ @pytest.mark.parametrize("test", pytest_params(COMMENT_TYPE_TESTS)) -def test_abortTransaction_comment(collection, test): - """Test abortTransaction comment parameter type acceptance.""" +def test_abortTransaction_comment_error(collection, test): + """Test abortTransaction comment error cases.""" result = execute_admin_command(collection, test.command) assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py similarity index 98% rename from documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py rename to documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py index 27aaeab21..440de7620 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py @@ -197,7 +197,7 @@ @pytest.mark.parametrize("test", pytest_params(FIELD_TYPE_TESTS)) -def test_abortTransaction_field_types(collection, test): - """Test abortTransaction command field type acceptance.""" +def test_abortTransaction_field_types_error(collection, test): + """Test abortTransaction field type error cases.""" result = execute_admin_command(collection, test.command) assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py similarity index 97% rename from documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py rename to documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py index 4c7c5ee6e..0894ffb48 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py @@ -123,7 +123,7 @@ @pytest.mark.parametrize("test", pytest_params(TXN_NUMBER_TESTS)) -def test_abortTransaction_txn_number(collection, test): - """Test abortTransaction txnNumber parameter validation.""" +def test_abortTransaction_txn_number_error(collection, test): + """Test abortTransaction txnNumber error cases.""" result = execute_admin_command(collection, test.command) assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py similarity index 96% rename from documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py rename to documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py index 755a63a6e..d6bc13947 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py @@ -100,7 +100,7 @@ @pytest.mark.parametrize("test", pytest_params(UNRECOGNIZED_TESTS)) -def test_abortTransaction_unrecognized_fields(collection, test): - """Test abortTransaction unrecognized field handling.""" +def test_abortTransaction_unrecognized_fields_error(collection, test): + """Test abortTransaction unrecognized field error cases.""" result = execute_admin_command(collection, test.command) assertFailureCode(result, test.error_code, msg=test.msg) From 6c420c29dae5769f90265cb0de2b90837cc4a2c0 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 17:06:29 -0700 Subject: [PATCH 08/15] convert to success cases with replica_set Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_comment.py | 184 ++++++++++++++ .../test_abortTransaction_comment_error.py | 161 ------------ .../test_abortTransaction_field_types.py | 230 ++++++++++++++++++ ...test_abortTransaction_field_types_error.py | 203 ---------------- .../test_abortTransaction_writeconcern.py | 225 +++++++++-------- 5 files changed, 541 insertions(+), 462 deletions(-) create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py delete mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py create mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py delete mode 100644 documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py new file mode 100644 index 000000000..7c57d4fd3 --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment.py @@ -0,0 +1,184 @@ +"""Tests for abortTransaction comment parameter type acceptance in a real transaction. + +Validates that the comment parameter accepts any BSON type when +abortTransaction is issued inside an active transaction on a replica set. +""" + +from __future__ import annotations + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( + SessionOp, + SessionOperation, + SessionTestCase, +) +from documentdb_tests.framework.assertions import assertSuccessPartial +from documentdb_tests.framework.executor import execute_abort_session_command +from documentdb_tests.framework.parametrize import pytest_params + +# Property [comment Type Acceptance]: comment accepts any BSON type. +COMMENT_TYPE_TESTS: list[SessionTestCase] = [ + SessionTestCase( + "comment_string", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": "test comment"}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:string", + ), + SessionTestCase( + "comment_string_empty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": ""}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:empty string", + ), + SessionTestCase( + "comment_int32", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": 42}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:int32", + ), + SessionTestCase( + "comment_int64", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": Int64(42)}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:Int64", + ), + SessionTestCase( + "comment_double", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": 3.14}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:double", + ), + SessionTestCase( + "comment_decimal128", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": Decimal128("1.5")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:Decimal128", + ), + SessionTestCase( + "comment_bool_true", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": True}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:true", + ), + SessionTestCase( + "comment_bool_false", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": False}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:false", + ), + SessionTestCase( + "comment_null", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": None}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:null", + ), + SessionTestCase( + "comment_object", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": {"key": "value"}}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:object", + ), + SessionTestCase( + "comment_object_empty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": {}}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:empty object", + ), + SessionTestCase( + "comment_array", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": [1, 2, 3]}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:array", + ), + SessionTestCase( + "comment_array_empty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": []}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:empty array", + ), + SessionTestCase( + "comment_objectid", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": ObjectId()}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:ObjectId", + ), + SessionTestCase( + "comment_datetime", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={ + "abortTransaction": 1, + "comment": datetime(2024, 1, 1, tzinfo=timezone.utc), + }, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:datetime", + ), + SessionTestCase( + "comment_binary", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": Binary(b"\x00")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:Binary", + ), + SessionTestCase( + "comment_regex", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": Regex(".*")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:Regex", + ), + SessionTestCase( + "comment_timestamp", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": Timestamp(0, 0)}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:Timestamp", + ), + SessionTestCase( + "comment_minkey", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": MinKey()}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:MinKey", + ), + SessionTestCase( + "comment_maxkey", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": MaxKey()}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:MaxKey", + ), + SessionTestCase( + "comment_code", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "comment": Code("function(){}")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept comment:Code", + ), +] + + +@pytest.mark.admin +@pytest.mark.replica_set +@pytest.mark.parametrize("test", pytest_params(COMMENT_TYPE_TESTS)) +def test_abortTransaction_comment(collection, test): + """Test abortTransaction comment parameter type acceptance in a transaction.""" + result = execute_abort_session_command(collection, test) + assertSuccessPartial(result, test.expected_response, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py deleted file mode 100644 index 60ae43f36..000000000 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_comment_error.py +++ /dev/null @@ -1,161 +0,0 @@ -"""Tests for abortTransaction comment parameter type acceptance. - -Validates that the comment parameter accepts any BSON type. All types produce -NoSuchTransaction because no transaction is active, confirming the comment -field itself is not type-checked. -""" - -from __future__ import annotations - -from datetime import datetime, timezone - -import pytest -from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp - -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( - CommandTestCase, -) -from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR -from documentdb_tests.framework.executor import execute_admin_command -from documentdb_tests.framework.parametrize import pytest_params - -pytestmark = pytest.mark.admin - - -# Property [comment Type Acceptance]: comment accepts any BSON type. -COMMENT_TYPE_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "comment_string", - command={"abortTransaction": 1, "comment": "test comment"}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:string", - ), - CommandTestCase( - "comment_string_empty", - command={"abortTransaction": 1, "comment": ""}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:empty string", - ), - CommandTestCase( - "comment_int32", - command={"abortTransaction": 1, "comment": 42}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:int32", - ), - CommandTestCase( - "comment_int64", - command={"abortTransaction": 1, "comment": Int64(42)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:Int64", - ), - CommandTestCase( - "comment_double", - command={"abortTransaction": 1, "comment": 3.14}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:double", - ), - CommandTestCase( - "comment_decimal128", - command={"abortTransaction": 1, "comment": Decimal128("1.5")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:Decimal128", - ), - CommandTestCase( - "comment_bool_true", - command={"abortTransaction": 1, "comment": True}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:true", - ), - CommandTestCase( - "comment_bool_false", - command={"abortTransaction": 1, "comment": False}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:false", - ), - CommandTestCase( - "comment_null", - command={"abortTransaction": 1, "comment": None}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:null", - ), - CommandTestCase( - "comment_object", - command={"abortTransaction": 1, "comment": {"key": "value"}}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:object", - ), - CommandTestCase( - "comment_object_empty", - command={"abortTransaction": 1, "comment": {}}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:empty object", - ), - CommandTestCase( - "comment_array", - command={"abortTransaction": 1, "comment": [1, 2, 3]}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:array", - ), - CommandTestCase( - "comment_array_empty", - command={"abortTransaction": 1, "comment": []}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:empty array", - ), - CommandTestCase( - "comment_objectid", - command={"abortTransaction": 1, "comment": ObjectId()}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:ObjectId", - ), - CommandTestCase( - "comment_datetime", - command={"abortTransaction": 1, "comment": datetime(2024, 1, 1, tzinfo=timezone.utc)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:datetime", - ), - CommandTestCase( - "comment_binary", - command={"abortTransaction": 1, "comment": Binary(b"\x00")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:Binary", - ), - CommandTestCase( - "comment_regex", - command={"abortTransaction": 1, "comment": Regex(".*")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:Regex", - ), - CommandTestCase( - "comment_timestamp", - command={"abortTransaction": 1, "comment": Timestamp(0, 0)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:Timestamp", - ), - CommandTestCase( - "comment_minkey", - command={"abortTransaction": 1, "comment": MinKey()}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:MinKey", - ), - CommandTestCase( - "comment_maxkey", - command={"abortTransaction": 1, "comment": MaxKey()}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:MaxKey", - ), - CommandTestCase( - "comment_code", - command={"abortTransaction": 1, "comment": Code("function(){}")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept comment:Code", - ), -] - - -@pytest.mark.parametrize("test", pytest_params(COMMENT_TYPE_TESTS)) -def test_abortTransaction_comment_error(collection, test): - """Test abortTransaction comment error cases.""" - result = execute_admin_command(collection, test.command) - assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py new file mode 100644 index 000000000..73fa69b1f --- /dev/null +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types.py @@ -0,0 +1,230 @@ +"""Tests for abortTransaction command field type acceptance in a real transaction. + +Validates that the abortTransaction command's primary field accepts all BSON +types when issued inside an active transaction on a replica set. +""" + +from __future__ import annotations + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( + SessionOp, + SessionOperation, + SessionTestCase, +) +from documentdb_tests.framework.assertions import assertSuccessPartial +from documentdb_tests.framework.executor import execute_abort_session_command +from documentdb_tests.framework.parametrize import pytest_params + +# Property [Field Type Acceptance]: the command field accepts any BSON type. +FIELD_TYPE_TESTS: list[SessionTestCase] = [ + SessionTestCase( + "field_int32_positive", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept int32 positive value", + ), + SessionTestCase( + "field_int32_negative", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": -1}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept int32 negative value", + ), + SessionTestCase( + "field_int32_zero", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 0}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept int32 zero value", + ), + SessionTestCase( + "field_int64", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Int64(1)}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept int64 value", + ), + SessionTestCase( + "field_int64_max", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Int64(9_223_372_036_854_775_807)}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept int64 max value", + ), + SessionTestCase( + "field_double", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1.0}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept double value", + ), + SessionTestCase( + "field_double_negative", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": -1.0}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept negative double value", + ), + SessionTestCase( + "field_double_zero", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 0.0}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept double zero value", + ), + SessionTestCase( + "field_decimal128", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Decimal128("1")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept Decimal128 value", + ), + SessionTestCase( + "field_bool_true", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": True}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept bool true value", + ), + SessionTestCase( + "field_bool_false", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": False}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept bool false value", + ), + SessionTestCase( + "field_nan", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": float("nan")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept NaN value", + ), + SessionTestCase( + "field_infinity", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": float("inf")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept Infinity value", + ), + SessionTestCase( + "field_string", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": "abortTransaction"}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept string value", + ), + SessionTestCase( + "field_string_empty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": ""}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept empty string value", + ), + SessionTestCase( + "field_null", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": None}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept null value", + ), + SessionTestCase( + "field_object_empty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": {}}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept empty object value", + ), + SessionTestCase( + "field_object_nonempty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": {"key": "value"}}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept non-empty object value", + ), + SessionTestCase( + "field_array_empty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": []}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept empty array value", + ), + SessionTestCase( + "field_array_nonempty", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": [1, 2]}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept non-empty array value", + ), + SessionTestCase( + "field_binary", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Binary(b"\x00")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept Binary value", + ), + SessionTestCase( + "field_objectid", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": ObjectId()}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept ObjectId value", + ), + SessionTestCase( + "field_datetime", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": datetime(2024, 1, 1, tzinfo=timezone.utc)}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept datetime value", + ), + SessionTestCase( + "field_regex", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Regex(".*")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept Regex value", + ), + SessionTestCase( + "field_timestamp", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Timestamp(0, 0)}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept Timestamp value", + ), + SessionTestCase( + "field_code", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": Code("function(){}")}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept Code value", + ), + SessionTestCase( + "field_minkey", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": MinKey()}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept MinKey value", + ), + SessionTestCase( + "field_maxkey", + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": MaxKey()}, + expected_response={"ok": 1.0}, + msg="abortTransaction should accept MaxKey value", + ), +] + + +@pytest.mark.admin +@pytest.mark.replica_set +@pytest.mark.parametrize("test", pytest_params(FIELD_TYPE_TESTS)) +def test_abortTransaction_field_types(collection, test): + """Test abortTransaction command field type acceptance in a transaction.""" + result = execute_abort_session_command(collection, test) + assertSuccessPartial(result, test.expected_response, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py deleted file mode 100644 index 440de7620..000000000 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_field_types_error.py +++ /dev/null @@ -1,203 +0,0 @@ -"""Tests for abortTransaction command field type acceptance. - -Validates that the abortTransaction command's primary field accepts all BSON -types. All types produce NoSuchTransaction because no transaction is active, -confirming the field value itself is not type-checked. -""" - -from __future__ import annotations - -from datetime import datetime, timezone - -import pytest -from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp - -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( - CommandTestCase, -) -from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR -from documentdb_tests.framework.executor import execute_admin_command -from documentdb_tests.framework.parametrize import pytest_params - -pytestmark = pytest.mark.admin - - -# Property [Field Type Acceptance]: the command field accepts any BSON type. -FIELD_TYPE_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "field_int32_positive", - command={"abortTransaction": 1}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept int32 positive value", - ), - CommandTestCase( - "field_int32_negative", - command={"abortTransaction": -1}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept int32 negative value", - ), - CommandTestCase( - "field_int32_zero", - command={"abortTransaction": 0}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept int32 zero value", - ), - CommandTestCase( - "field_int64", - command={"abortTransaction": Int64(1)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept int64 value", - ), - CommandTestCase( - "field_int64_max", - command={"abortTransaction": Int64(9_223_372_036_854_775_807)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept int64 max value", - ), - CommandTestCase( - "field_double", - command={"abortTransaction": 1.0}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept double value", - ), - CommandTestCase( - "field_double_negative", - command={"abortTransaction": -1.0}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept negative double value", - ), - CommandTestCase( - "field_double_zero", - command={"abortTransaction": 0.0}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept double zero value", - ), - CommandTestCase( - "field_decimal128", - command={"abortTransaction": Decimal128("1")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept Decimal128 value", - ), - CommandTestCase( - "field_bool_true", - command={"abortTransaction": True}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept bool true value", - ), - CommandTestCase( - "field_bool_false", - command={"abortTransaction": False}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept bool false value", - ), - CommandTestCase( - "field_nan", - command={"abortTransaction": float("nan")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept NaN value", - ), - CommandTestCase( - "field_infinity", - command={"abortTransaction": float("inf")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept Infinity value", - ), - CommandTestCase( - "field_string", - command={"abortTransaction": "abortTransaction"}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept string value", - ), - CommandTestCase( - "field_string_empty", - command={"abortTransaction": ""}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept empty string value", - ), - CommandTestCase( - "field_null", - command={"abortTransaction": None}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept null value", - ), - CommandTestCase( - "field_object_empty", - command={"abortTransaction": {}}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept empty object value", - ), - CommandTestCase( - "field_object_nonempty", - command={"abortTransaction": {"key": "value"}}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept non-empty object value", - ), - CommandTestCase( - "field_array_empty", - command={"abortTransaction": []}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept empty array value", - ), - CommandTestCase( - "field_array_nonempty", - command={"abortTransaction": [1, 2]}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept non-empty array value", - ), - CommandTestCase( - "field_binary", - command={"abortTransaction": Binary(b"\x00")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept Binary value", - ), - CommandTestCase( - "field_objectid", - command={"abortTransaction": ObjectId()}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept ObjectId value", - ), - CommandTestCase( - "field_datetime", - command={"abortTransaction": datetime(2024, 1, 1, tzinfo=timezone.utc)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept datetime value", - ), - CommandTestCase( - "field_regex", - command={"abortTransaction": Regex(".*")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept Regex value", - ), - CommandTestCase( - "field_timestamp", - command={"abortTransaction": Timestamp(0, 0)}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept Timestamp value", - ), - CommandTestCase( - "field_code", - command={"abortTransaction": Code("function(){}")}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept Code value", - ), - CommandTestCase( - "field_minkey", - command={"abortTransaction": MinKey()}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept MinKey value", - ), - CommandTestCase( - "field_maxkey", - command={"abortTransaction": MaxKey()}, - error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction should accept MaxKey value", - ), -] - - -@pytest.mark.parametrize("test", pytest_params(FIELD_TYPE_TESTS)) -def test_abortTransaction_field_types_error(collection, test): - """Test abortTransaction field type error cases.""" - result = execute_admin_command(collection, test.command) - assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py index e4d48437e..0f76f12a3 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern.py @@ -1,8 +1,9 @@ -"""Tests for abortTransaction writeConcern parameter acceptance. +"""Tests for abortTransaction writeConcern parameter acceptance in a real transaction. Validates that accepted writeConcern variants (document types, w sub-field values, j sub-field values, wtimeout sub-field values, and combinations) -are syntactically accepted by abortTransaction outside a transaction. +succeed when abortTransaction is issued inside an active transaction on a +replica set. """ from __future__ import annotations @@ -10,198 +11,224 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( - CommandTestCase, +from documentdb_tests.compatibility.tests.core.sessions.commands.utils.session_test_case import ( + SessionOp, + SessionOperation, + SessionTestCase, ) -from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR -from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.assertions import assertSuccessPartial +from documentdb_tests.framework.executor import execute_abort_session_command from documentdb_tests.framework.parametrize import pytest_params -pytestmark = pytest.mark.admin - # Property [writeConcern Document Acceptance]: writeConcern accepts document values. -WRITECONCERN_ACCEPTANCE_TESTS: list[CommandTestCase] = [ - CommandTestCase( +WRITECONCERN_ACCEPTANCE_TESTS: list[SessionTestCase] = [ + SessionTestCase( "writeconcern_empty_doc", - command={"abortTransaction": 1, "writeConcern": {}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept empty writeConcern document", ), - CommandTestCase( + SessionTestCase( "writeconcern_null", - command={"abortTransaction": 1, "writeConcern": None}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": None}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern:null", ), - CommandTestCase( + SessionTestCase( "wc_combined_w_j_wtimeout", - command={ + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={ "abortTransaction": 1, "writeConcern": {"w": "majority", "j": True, "wtimeout": 10_000}, }, - error_code=COMMAND_FAILED_ERROR, + expected_response={"ok": 1.0}, msg="abortTransaction should accept combined w + j + wtimeout", ), - CommandTestCase( + SessionTestCase( "wc_w0_j_true", - command={"abortTransaction": 1, "writeConcern": {"w": 0, "j": True}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": 0, "j": True}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept conflicting w:0 with j:true", ), - CommandTestCase( + SessionTestCase( "wc_fsync_true", - command={"abortTransaction": 1, "writeConcern": {"fsync": True}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"fsync": True}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept legacy writeConcern.fsync:true", ), ] # Property [w Accepted Values]: w accepts int and string "majority" values. -W_ACCEPTANCE_TESTS: list[CommandTestCase] = [ - CommandTestCase( +W_ACCEPTANCE_TESTS: list[SessionTestCase] = [ + SessionTestCase( "w_int32_one", - command={"abortTransaction": 1, "writeConcern": {"w": 1}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": 1}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:1", ), - CommandTestCase( + SessionTestCase( "w_int32_zero", - command={"abortTransaction": 1, "writeConcern": {"w": 0}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": 0}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:0 (unacknowledged)", ), - CommandTestCase( + SessionTestCase( "w_majority", - command={"abortTransaction": 1, "writeConcern": {"w": "majority"}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": "majority"}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:'majority'", ), - CommandTestCase( + SessionTestCase( "w_int64", - command={"abortTransaction": 1, "writeConcern": {"w": Int64(1)}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": Int64(1)}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:Int64(1)", ), - CommandTestCase( + SessionTestCase( "w_double_whole", - command={"abortTransaction": 1, "writeConcern": {"w": 1.0}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": 1.0}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:1.0", ), - CommandTestCase( + SessionTestCase( "w_double_fractional", - command={"abortTransaction": 1, "writeConcern": {"w": 1.5}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": 1.5}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:1.5", ), - CommandTestCase( + SessionTestCase( "w_decimal128", - command={"abortTransaction": 1, "writeConcern": {"w": Decimal128("1")}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"w": Decimal128("1")}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.w:Decimal128('1')", ), ] # Property [j Accepted Values]: j accepts boolean and numeric types. -J_ACCEPTANCE_TESTS: list[CommandTestCase] = [ - CommandTestCase( +J_ACCEPTANCE_TESTS: list[SessionTestCase] = [ + SessionTestCase( "j_bool_true", - command={"abortTransaction": 1, "writeConcern": {"j": True}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"j": True}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.j:true", ), - CommandTestCase( + SessionTestCase( "j_bool_false", - command={"abortTransaction": 1, "writeConcern": {"j": False}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"j": False}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.j:false", ), - CommandTestCase( + SessionTestCase( "j_int32_one", - command={"abortTransaction": 1, "writeConcern": {"j": 1}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"j": 1}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.j:1 (coerced to true)", ), - CommandTestCase( + SessionTestCase( "j_int32_zero", - command={"abortTransaction": 1, "writeConcern": {"j": 0}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"j": 0}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.j:0 (coerced to false)", ), - CommandTestCase( + SessionTestCase( "j_null", - command={"abortTransaction": 1, "writeConcern": {"j": None}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"j": None}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.j:null", ), ] # Property [wtimeout Accepted Values]: wtimeout accepts numeric types broadly. -WTIMEOUT_ACCEPTANCE_TESTS: list[CommandTestCase] = [ - CommandTestCase( +WTIMEOUT_ACCEPTANCE_TESTS: list[SessionTestCase] = [ + SessionTestCase( "wtimeout_int32_positive", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:1000", ), - CommandTestCase( + SessionTestCase( "wtimeout_int32_zero", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": 0}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": 0}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:0 (no timeout)", ), - CommandTestCase( + SessionTestCase( "wtimeout_int64", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": Int64(1000)}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": Int64(1000)}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:Int64(1000)", ), - CommandTestCase( + SessionTestCase( "wtimeout_double_whole", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000.0}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": 1000.0}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:1000.0", ), - CommandTestCase( + SessionTestCase( "wtimeout_negative", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": -1}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": -1}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:-1", ), - CommandTestCase( + SessionTestCase( "wtimeout_string", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": "1000"}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": "1000"}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:'1000'", ), - CommandTestCase( + SessionTestCase( "wtimeout_bool", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": True}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": True}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:true", ), - CommandTestCase( + SessionTestCase( "wtimeout_null", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": None}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": None}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:null", ), - CommandTestCase( + SessionTestCase( "wtimeout_object", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": {}}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": {}}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:{}", ), - CommandTestCase( + SessionTestCase( "wtimeout_array", - command={"abortTransaction": 1, "writeConcern": {"wtimeout": []}}, - error_code=COMMAND_FAILED_ERROR, + ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], + commit_command={"abortTransaction": 1, "writeConcern": {"wtimeout": []}}, + expected_response={"ok": 1.0}, msg="abortTransaction should accept writeConcern.wtimeout:[]", ), ] -WRITECONCERN_ACCEPTANCE_ALL_TESTS: list[CommandTestCase] = ( +WRITECONCERN_ACCEPTANCE_ALL_TESTS: list[SessionTestCase] = ( WRITECONCERN_ACCEPTANCE_TESTS + W_ACCEPTANCE_TESTS + J_ACCEPTANCE_TESTS @@ -209,8 +236,10 @@ ) +@pytest.mark.admin +@pytest.mark.replica_set @pytest.mark.parametrize("test", pytest_params(WRITECONCERN_ACCEPTANCE_ALL_TESTS)) def test_abortTransaction_writeconcern(collection, test): - """Test abortTransaction writeConcern parameter acceptance.""" - result = execute_admin_command(collection, test.command) - assertFailureCode(result, test.error_code, msg=test.msg) + """Test abortTransaction writeConcern parameter acceptance in a transaction.""" + result = execute_abort_session_command(collection, test) + assertSuccessPartial(result, test.expected_response, msg=test.msg) From 16d6d45eeb477582f0d14108a15864a821a9adb0 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 17:09:06 -0700 Subject: [PATCH 09/15] revert test_smoke_abortTransaction to match Signed-off-by: Alina (Xi) Li --- .../abortTransaction/test_smoke_abortTransaction.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py index da8e16806..37b8a5302 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_smoke_abortTransaction.py @@ -6,8 +6,7 @@ import pytest -from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import COMMAND_FAILED_ERROR +from documentdb_tests.framework.assertions import assertFailure from documentdb_tests.framework.executor import execute_admin_command pytestmark = pytest.mark.smoke @@ -16,4 +15,6 @@ def test_smoke_abortTransaction(collection): """Test basic abortTransaction command behavior.""" result = execute_admin_command(collection, {"abortTransaction": 1}) - assertFailureCode(result, COMMAND_FAILED_ERROR, msg="Should support abortTransaction command") + + expected_error = {"code": 125, "msg": "abortTransaction must be run within a transaction"} + assertFailure(result, expected_error, msg="Should support abortTransaction command") From 7641ddfbac67a7e749fc7357bcc3a75cb9ad547a Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 17:17:22 -0700 Subject: [PATCH 10/15] remove duplicates and rename tests Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_core.py | 21 ------------------- .../test_abortTransaction_core_error.py | 16 +++++--------- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index de227bca6..b8e14cf39 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -67,20 +67,6 @@ expected=[{"_id": 1, "x": "original"}], msg="abortTransaction should roll back all operations from a multi-op transaction", ), - SessionTestCase( - "abort_with_writeconcern", - docs=[{"_id": 1, "x": "before"}], - ops=[ - SessionOperation( - op=SessionOp.UPDATE, - filter={"_id": 1}, - update={"$set": {"x": "after"}}, - ) - ], - commit_command={"abortTransaction": 1, "writeConcern": {"w": 1}}, - expected=[{"_id": 1, "x": "before"}], - msg="abortTransaction with writeConcern should roll back changes", - ), SessionTestCase( "abort_insert_delete_same_doc", ops=[ @@ -171,13 +157,6 @@ def test_abortTransaction_core_empty(collection, test): expected_response={"ok": 1.0}, msg="abortTransaction response should have ok:1 on success", ), - SessionTestCase( - "abort_with_comment", - ops=[SessionOperation(op=SessionOp.INSERT, document={"_id": 1})], - commit_command={"abortTransaction": 1, "comment": "test abort"}, - expected_response={"ok": 1.0}, - msg="abortTransaction with comment should succeed", - ), ] diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py index a6898763b..c248253c0 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py @@ -16,7 +16,6 @@ from documentdb_tests.framework.error_codes import ( COMMAND_FAILED_ERROR, ILLEGAL_OPERATION_ERROR, - INVALID_OPTIONS_ERROR, UNAUTHORIZED_ERROR, ) from documentdb_tests.framework.executor import execute_admin_command, execute_command @@ -27,7 +26,7 @@ # Property [Parameter Acceptance]: all valid parameters combined are syntactically accepted. CORE_PARAMETER_ACCEPTANCE_TESTS: list[CommandTestCase] = [ CommandTestCase( - "all_valid_params", + "all_valid_params_no_parse_error", command={ "abortTransaction": 1, "autocommit": False, @@ -36,18 +35,13 @@ "comment": "full abort", }, error_code=ILLEGAL_OPERATION_ERROR, - msg="abortTransaction with all valid params should not produce a parsing error", + msg="All valid params combined should be accepted (no parse error), " + "failing only because no session exists", ), ] # Property [Parameter Interactions]: combinations of valid parameters behave correctly. CORE_PARAMETER_INTERACTION_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "interaction_autocommit_only", - command={"abortTransaction": 1, "autocommit": False}, - error_code=INVALID_OPTIONS_ERROR, - msg="abortTransaction with autocommit:false only should fail with InvalidOptions", - ), CommandTestCase( "interaction_txn_number_only", command={"abortTransaction": 1, "txnNumber": Int64(1)}, @@ -61,10 +55,10 @@ msg="abortTransaction with autocommit + txnNumber should fail with IllegalOperation", ), CommandTestCase( - "interaction_lsid", + "lsid_recognized_field", command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, error_code=COMMAND_FAILED_ERROR, - msg="abortTransaction with explicit lsid should accept the field", + msg="lsid should be recognized (NoSuchTransaction, not UnrecognizedField)", ), ] From cb65a6d872e9402d110a2219d65a04bfe909cdfb Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 17:19:51 -0700 Subject: [PATCH 11/15] merge identical test functions into 1 Signed-off-by: Alina (Xi) Li --- .../test_abortTransaction_core.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py index b8e14cf39..66c24d9b7 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core.py @@ -101,15 +101,6 @@ ), ] - -@pytest.mark.replica_set -@pytest.mark.parametrize("test", pytest_params(ABORT_ROLLBACK_TESTS)) -def test_abortTransaction_core_rollback(collection, test): - """Test abortTransaction rolls back operations.""" - result = execute_abort_session_command(collection, test) - assertSuccess(result, test.expected, msg=test.msg) - - # Property [Pre-Transaction Data Survival]: seed data survives abort. PRE_TRANSACTION_TESTS: list[SessionTestCase] = [ SessionTestCase( @@ -121,11 +112,13 @@ def test_abortTransaction_core_rollback(collection, test): ), ] +ABORT_READBACK_TESTS: list[SessionTestCase] = ABORT_ROLLBACK_TESTS + PRE_TRANSACTION_TESTS + @pytest.mark.replica_set -@pytest.mark.parametrize("test", pytest_params(PRE_TRANSACTION_TESTS)) -def test_abortTransaction_core_pre_transaction_data(collection, test): - """Test pre-transaction data survives abort.""" +@pytest.mark.parametrize("test", pytest_params(ABORT_READBACK_TESTS)) +def test_abortTransaction_core(collection, test): + """Test abortTransaction rolls back operations and preserves pre-existing data.""" result = execute_abort_session_command(collection, test) assertSuccess(result, test.expected, msg=test.msg) From 222553ba9836ac80560492c51e441bf982accc48 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 17:23:26 -0700 Subject: [PATCH 12/15] clear init.py Signed-off-by: Alina (Xi) Li --- .../tests/core/sessions/commands/abortTransaction/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py index 8848fcb30..e69de29bb 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/__init__.py @@ -1 +0,0 @@ -"""Tests for abortTransaction command.""" From c9ce280b9689f6ec2fa781354a31bda84fb68360 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 11 Jun 2026 17:27:32 -0700 Subject: [PATCH 13/15] copy the replica_set CI job Signed-off-by: Alina (Xi) Li --- .github/workflows/pr-tests.yml | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 0bb7ae967..316297035 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -60,6 +60,71 @@ jobs: echo '```' >> $GITHUB_STEP_SUMMARY fi + test-mongodb-replica-set: + name: Tests (MongoDB Replica Set) + runs-on: ubuntu-latest + + services: + mongodb: + image: mongo:8.2.4 + ports: + - 27017:27017 + command: --replSet rs0 + options: >- + --health-cmd "mongosh --eval 'db.runCommand({ ping: 1 })'" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v6 + + - name: Initialize replica set + run: | + docker exec "${{ job.services.mongodb.id }}" mongosh --eval ' + rs.initiate({_id: "rs0", members: [{_id: 0, host: "localhost:27017"}]}) + ' + # Wait for the primary to be elected + sleep 3 + + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Run replica set tests against MongoDB + run: | + pytest documentdb_tests/compatibility/tests/ \ + -m replica_set \ + --connection-string "mongodb://localhost:27017/?directConnection=true" \ + --engine-name mongodb \ + -n auto \ + -v \ + --json-report --json-report-file=${{ github.workspace }}/.test-results/replica-set-report.json \ + --junitxml=${{ github.workspace }}/.test-results/replica-set-results.xml + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: test-results-replica-set + include-hidden-files: true + path: ${{ github.workspace }}/.test-results/ + if-no-files-found: warn + + - name: Generate test summary + if: always() + run: | + if [ -f ${{ github.workspace }}/.test-results/replica-set-report.json ]; then + python -m documentdb_tests.compatibility.result_analyzer -i ${{ github.workspace }}/.test-results/replica-set-report.json -o ${{ github.workspace }}/.test-results/replica-set-analysis.txt -f text || true + echo "## MongoDB Replica Set Test Results" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + cat ${{ github.workspace }}/.test-results/replica-set-analysis.txt >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + fi + collect-xcrash: name: Collect crash tests runs-on: ubuntu-latest From b27b9508c358fdd7c3dcc660d8d03e4162f53cfd Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 12 Jun 2026 14:45:41 -0700 Subject: [PATCH 14/15] update paths Signed-off-by: Alina (Xi) Li --- .../abortTransaction/test_abortTransaction_autocommit_error.py | 2 +- .../abortTransaction/test_abortTransaction_core_error.py | 2 +- .../abortTransaction/test_abortTransaction_txn_number_error.py | 2 +- .../test_abortTransaction_unrecognized_fields_error.py | 2 +- .../test_abortTransaction_writeconcern_error.py | 2 +- .../tests/core/sessions/commands/utils/session_test_case.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py index 4b7a2aa14..c6f2e7a50 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_autocommit_error.py @@ -11,7 +11,7 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py index c248253c0..0d9efdda9 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py @@ -9,7 +9,7 @@ import pytest from bson import Binary, Int64 -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py index 0894ffb48..a6b022745 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_txn_number_error.py @@ -12,7 +12,7 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py index d6bc13947..b677db8dc 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_unrecognized_fields_error.py @@ -10,7 +10,7 @@ import pytest from bson import Int64 -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py index 08d1d4232..79f7ab819 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_writeconcern_error.py @@ -11,7 +11,7 @@ import pytest from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandTestCase, ) from documentdb_tests.framework.assertions import assertFailureCode diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py index aa635f521..e20906860 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/utils/session_test_case.py @@ -8,7 +8,7 @@ from pymongo.collection import Collection -from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import ( +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandTestCase, ) From b7fb27494cedff3cf81bbfd18e518257a30ae441 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 17 Jun 2026 10:27:48 -0700 Subject: [PATCH 15/15] change comment Signed-off-by: Alina (Xi) Li --- .../abortTransaction/test_abortTransaction_core_error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py index 0d9efdda9..e31a85252 100644 --- a/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py +++ b/documentdb_tests/compatibility/tests/core/sessions/commands/abortTransaction/test_abortTransaction_core_error.py @@ -58,7 +58,7 @@ "lsid_recognized_field", command={"abortTransaction": 1, "lsid": {"id": Binary(b"\x00" * 16, 4)}}, error_code=COMMAND_FAILED_ERROR, - msg="lsid should be recognized (NoSuchTransaction, not UnrecognizedField)", + msg="lsid should be recognized (CommandFailed, not UnrecognizedField)", ), ]