From 3664f87798fd21e42ce096de35f87d607bdf4aab Mon Sep 17 00:00:00 2001 From: PatersonProjects Date: Tue, 16 Jun 2026 08:42:54 -0700 Subject: [PATCH 1/3] Base tests Signed-off-by: PatersonProjects --- .../diagnostic/commands/lockInfo/__init__.py | 1 + .../test_lockInfo_argument_validation.py | 133 ++++++++++++++++++ .../lockInfo/test_lockInfo_core_behavior.py | 26 ++++ .../commands/lockInfo/test_lockInfo_errors.py | 21 +++ .../test_lockInfo_response_structure.py | 77 ++++++++++ 5 files changed, 258 insertions(+) create mode 100644 documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/__init__.py create mode 100644 documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py create mode 100644 documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py create mode 100644 documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py create mode 100644 documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/__init__.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/__init__.py new file mode 100644 index 000000000..49a4f47a0 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/__init__.py @@ -0,0 +1 @@ +"""Tests for the lockInfo diagnostic command.""" diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py new file mode 100644 index 000000000..8df01b70b --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py @@ -0,0 +1,133 @@ +"""Tests for lockInfo command argument validation. + +Verifies that lockInfo accepts various values for the command field and +rejects unrecognized fields with error code 40415. +""" + +from datetime import datetime, timezone + +import pytest +from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp + +from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import ( + DiagnosticTestCase, +) +from documentdb_tests.framework.assertions import assertFailureCode, assertProperties +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 +from documentdb_tests.framework.property_checks import Eq + +pytestmark = pytest.mark.admin + + +ARG_TYPE_TESTS: list[DiagnosticTestCase] = [ + DiagnosticTestCase( + "int_1", command={"lockInfo": 1}, checks={"ok": Eq(1.0)}, msg="int 1 should succeed" + ), + DiagnosticTestCase( + "int_0", command={"lockInfo": 0}, checks={"ok": Eq(1.0)}, msg="int 0 should succeed" + ), + DiagnosticTestCase( + "double", command={"lockInfo": 1.5}, checks={"ok": Eq(1.0)}, msg="double should succeed" + ), + DiagnosticTestCase( + "long", command={"lockInfo": Int64(1)}, checks={"ok": Eq(1.0)}, msg="long should succeed" + ), + DiagnosticTestCase( + "decimal128", + command={"lockInfo": Decimal128("1")}, + checks={"ok": Eq(1.0)}, + msg="decimal128 should succeed", + ), + DiagnosticTestCase( + "string", + command={"lockInfo": "test"}, + checks={"ok": Eq(1.0)}, + msg="string should succeed", + ), + DiagnosticTestCase( + "bool_true", + command={"lockInfo": True}, + checks={"ok": Eq(1.0)}, + msg="bool true should succeed", + ), + DiagnosticTestCase( + "bool_false", + command={"lockInfo": False}, + checks={"ok": Eq(1.0)}, + msg="bool false should succeed", + ), + DiagnosticTestCase( + "date", + command={"lockInfo": datetime(2024, 1, 1, tzinfo=timezone.utc)}, + checks={"ok": Eq(1.0)}, + msg="date should succeed", + ), + DiagnosticTestCase( + "null", command={"lockInfo": None}, checks={"ok": Eq(1.0)}, msg="null should succeed" + ), + DiagnosticTestCase( + "object", command={"lockInfo": {}}, checks={"ok": Eq(1.0)}, msg="object should succeed" + ), + DiagnosticTestCase( + "array", command={"lockInfo": []}, checks={"ok": Eq(1.0)}, msg="array should succeed" + ), + DiagnosticTestCase( + "binData", + command={"lockInfo": Binary(b"")}, + checks={"ok": Eq(1.0)}, + msg="binData should succeed", + ), + DiagnosticTestCase( + "objectId", + command={"lockInfo": ObjectId()}, + checks={"ok": Eq(1.0)}, + msg="objectId should succeed", + ), + DiagnosticTestCase( + "regex", + command={"lockInfo": Regex("test")}, + checks={"ok": Eq(1.0)}, + msg="regex should succeed", + ), + DiagnosticTestCase( + "timestamp", + command={"lockInfo": Timestamp(0, 0)}, + checks={"ok": Eq(1.0)}, + msg="timestamp should succeed", + ), + DiagnosticTestCase( + "minKey", + command={"lockInfo": MinKey()}, + checks={"ok": Eq(1.0)}, + msg="minKey should succeed", + ), + DiagnosticTestCase( + "maxKey", + command={"lockInfo": MaxKey()}, + checks={"ok": Eq(1.0)}, + msg="maxKey should succeed", + ), + DiagnosticTestCase( + "code", + command={"lockInfo": Code("function(){}")}, + checks={"ok": Eq(1.0)}, + msg="code should succeed", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(ARG_TYPE_TESTS)) +def test_lockInfo_accepts_any_type(collection, test): + """Verify lockInfo succeeds when the command field value is a given BSON type.""" + result = execute_admin_command(collection, test.command) + assertProperties(result, test.checks, msg=test.msg, raw_res=True) + + +def test_lockInfo_unrecognized_field(collection): + """Test lockInfo with unrecognized extra field returns error 40415.""" + result = execute_admin_command(collection, {"lockInfo": 1, "foo": 1}) + assertFailureCode( + result, UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="Unrecognized field should error" + ) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py new file mode 100644 index 000000000..6ae58b5b1 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py @@ -0,0 +1,26 @@ +"""Tests for lockInfo command core behavior. + +Verifies that lockInfo succeeds on admin database and returns a lockInfo array. +""" + +import pytest + +from documentdb_tests.framework.assertions import assertProperties, assertSuccessPartial +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.property_checks import IsType + +pytestmark = pytest.mark.admin + + +def test_lockInfo_returns_ok(collection): + """Test lockInfo returns ok:1 on admin database.""" + result = execute_admin_command(collection, {"lockInfo": 1}) + assertSuccessPartial(result, {"ok": 1.0}, msg="lockInfo should return ok:1") + + +def test_lockInfo_returns_lockInfo_array(collection): + """Test lockInfo response contains a lockInfo array field.""" + result = execute_admin_command(collection, {"lockInfo": 1}) + assertProperties( + result, {"lockInfo": IsType("array")}, msg="lockInfo field should be array", raw_res=True + ) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py new file mode 100644 index 000000000..6db42e212 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py @@ -0,0 +1,21 @@ +"""Tests for lockInfo command error cases. + +Verifies that lockInfo returns correct error codes when run on non-admin +database or with unrecognized fields. +""" + +import pytest + +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import UNAUTHORIZED_ERROR +from documentdb_tests.framework.executor import execute_command + +pytestmark = pytest.mark.admin + + +def test_lockInfo_non_admin_database_returns_unauthorized(collection): + """Test lockInfo on non-admin database returns error code 13 (Unauthorized).""" + result = execute_command(collection, {"lockInfo": 1}) + assertFailureCode( + result, UNAUTHORIZED_ERROR, msg="lockInfo on non-admin db should be unauthorized" + ) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py new file mode 100644 index 000000000..2805c57ee --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py @@ -0,0 +1,77 @@ +"""Tests for lockInfo command response structure. + +Verifies the structure of the lockInfo response including field types +and lock mode values in granted/pending entries. +""" + +import pytest + +from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import ( + DiagnosticTestCase, +) +from documentdb_tests.framework.assertions import assertProperties +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params +from documentdb_tests.framework.property_checks import Eq, IsType + +pytestmark = pytest.mark.admin + + +RESPONSE_STRUCTURE_TESTS: list[DiagnosticTestCase] = [ + DiagnosticTestCase( + "ok_field", + checks={"ok": Eq(1.0)}, + msg="Response should contain ok: 1.0", + ), + DiagnosticTestCase( + "lockInfo_is_array", + checks={"lockInfo": IsType("array")}, + msg="lockInfo field should be an array", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(RESPONSE_STRUCTURE_TESTS)) +def test_lockInfo_response_structure(collection, test): + """Verify lockInfo response contains expected fields with correct types.""" + result = execute_admin_command(collection, {"lockInfo": 1}) + assertProperties(result, test.checks, msg=test.msg, raw_res=True) + + +def test_lockInfo_entry_resourceId_is_string(collection): + """Test lock entry contains resourceId field as a string.""" + collection.insert_one({"_id": 1}) + result = execute_admin_command(collection, {"lockInfo": 1}) + entry = result.get("lockInfo", [{}])[0] if result.get("lockInfo") else {} + assertProperties( + {"resourceId": entry.get("resourceId", "")}, + {"resourceId": IsType("string")}, + msg="resourceId should be a string", + raw_res=True, + ) + + +def test_lockInfo_entry_granted_is_array(collection): + """Test lock entry contains granted field as an array.""" + collection.insert_one({"_id": 1}) + result = execute_admin_command(collection, {"lockInfo": 1}) + entry = result.get("lockInfo", [{}])[0] if result.get("lockInfo") else {} + assertProperties( + {"granted": entry.get("granted", [])}, + {"granted": IsType("array")}, + msg="granted should be an array", + raw_res=True, + ) + + +def test_lockInfo_entry_pending_is_array(collection): + """Test lock entry contains pending field as an array.""" + collection.insert_one({"_id": 1}) + result = execute_admin_command(collection, {"lockInfo": 1}) + entry = result.get("lockInfo", [{}])[0] if result.get("lockInfo") else {} + assertProperties( + {"pending": entry.get("pending", [])}, + {"pending": IsType("array")}, + msg="pending should be an array", + raw_res=True, + ) From 7a775f7b54bbbb10f7f662461b8e4f717d3739d5 Mon Sep 17 00:00:00 2001 From: PatersonProjects Date: Tue, 16 Jun 2026 11:14:32 -0700 Subject: [PATCH 2/3] Removed out of scope tests, ensured response validation actually checks fields through use of fsynclock Signed-off-by: PatersonProjects --- .../test_lockInfo_argument_validation.py | 139 +++++------------- .../lockInfo/test_lockInfo_core_behavior.py | 52 +++++-- .../commands/lockInfo/test_lockInfo_errors.py | 43 +++++- .../test_lockInfo_response_structure.py | 58 +++----- 4 files changed, 130 insertions(+), 162 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py index 8df01b70b..261049e40 100644 --- a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py @@ -4,16 +4,17 @@ rejects unrecognized fields with error code 40415. """ -from datetime import datetime, timezone - import pytest -from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import ( DiagnosticTestCase, ) -from documentdb_tests.framework.assertions import assertFailureCode, assertProperties -from documentdb_tests.framework.error_codes import UNRECOGNIZED_COMMAND_FIELD_ERROR +from documentdb_tests.framework.assertions import assertProperties +from documentdb_tests.framework.bson_type_validator import ( + BsonType, + BsonTypeTestCase, + generate_bson_acceptance_test_cases, +) from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params from documentdb_tests.framework.property_checks import Eq @@ -21,113 +22,43 @@ pytestmark = pytest.mark.admin -ARG_TYPE_TESTS: list[DiagnosticTestCase] = [ - DiagnosticTestCase( - "int_1", command={"lockInfo": 1}, checks={"ok": Eq(1.0)}, msg="int 1 should succeed" - ), - DiagnosticTestCase( - "int_0", command={"lockInfo": 0}, checks={"ok": Eq(1.0)}, msg="int 0 should succeed" - ), - DiagnosticTestCase( - "double", command={"lockInfo": 1.5}, checks={"ok": Eq(1.0)}, msg="double should succeed" - ), - DiagnosticTestCase( - "long", command={"lockInfo": Int64(1)}, checks={"ok": Eq(1.0)}, msg="long should succeed" - ), - DiagnosticTestCase( - "decimal128", - command={"lockInfo": Decimal128("1")}, - checks={"ok": Eq(1.0)}, - msg="decimal128 should succeed", - ), - DiagnosticTestCase( - "string", - command={"lockInfo": "test"}, - checks={"ok": Eq(1.0)}, - msg="string should succeed", - ), - DiagnosticTestCase( - "bool_true", - command={"lockInfo": True}, - checks={"ok": Eq(1.0)}, - msg="bool true should succeed", - ), - DiagnosticTestCase( - "bool_false", - command={"lockInfo": False}, - checks={"ok": Eq(1.0)}, - msg="bool false should succeed", - ), - DiagnosticTestCase( - "date", - command={"lockInfo": datetime(2024, 1, 1, tzinfo=timezone.utc)}, - checks={"ok": Eq(1.0)}, - msg="date should succeed", - ), - DiagnosticTestCase( - "null", command={"lockInfo": None}, checks={"ok": Eq(1.0)}, msg="null should succeed" - ), - DiagnosticTestCase( - "object", command={"lockInfo": {}}, checks={"ok": Eq(1.0)}, msg="object should succeed" - ), - DiagnosticTestCase( - "array", command={"lockInfo": []}, checks={"ok": Eq(1.0)}, msg="array should succeed" - ), - DiagnosticTestCase( - "binData", - command={"lockInfo": Binary(b"")}, - checks={"ok": Eq(1.0)}, - msg="binData should succeed", - ), - DiagnosticTestCase( - "objectId", - command={"lockInfo": ObjectId()}, - checks={"ok": Eq(1.0)}, - msg="objectId should succeed", - ), - DiagnosticTestCase( - "regex", - command={"lockInfo": Regex("test")}, - checks={"ok": Eq(1.0)}, - msg="regex should succeed", - ), - DiagnosticTestCase( - "timestamp", - command={"lockInfo": Timestamp(0, 0)}, - checks={"ok": Eq(1.0)}, - msg="timestamp should succeed", - ), - DiagnosticTestCase( - "minKey", - command={"lockInfo": MinKey()}, - checks={"ok": Eq(1.0)}, - msg="minKey should succeed", - ), +LOCKINFO_BSON_TYPE_SPECS = [ + BsonTypeTestCase( + id="command_field", + msg="lockInfo accepts any BSON type for the command field", + keyword="lockInfo", + valid_types=list(BsonType), + ) +] + +ACCEPTANCE_TESTS = generate_bson_acceptance_test_cases(LOCKINFO_BSON_TYPE_SPECS) + + +@pytest.mark.parametrize("bson_type,sample_value,spec", ACCEPTANCE_TESTS) +def test_lockInfo_accepts_any_type(collection, bson_type, sample_value, spec): + """Verify lockInfo succeeds when the command field value is a given BSON type.""" + result = execute_admin_command(collection, {"lockInfo": sample_value}) + assertProperties(result, {"ok": Eq(1.0)}, msg=spec.msg, raw_res=True) + + +INT_EDGE_TESTS: list[DiagnosticTestCase] = [ DiagnosticTestCase( - "maxKey", - command={"lockInfo": MaxKey()}, + id="int_zero", + command={"lockInfo": 0}, checks={"ok": Eq(1.0)}, - msg="maxKey should succeed", + msg="lockInfo should accept int 0", ), DiagnosticTestCase( - "code", - command={"lockInfo": Code("function(){}")}, + id="int_neg1", + command={"lockInfo": -1}, checks={"ok": Eq(1.0)}, - msg="code should succeed", + msg="lockInfo should accept int -1", ), ] -@pytest.mark.parametrize("test", pytest_params(ARG_TYPE_TESTS)) -def test_lockInfo_accepts_any_type(collection, test): - """Verify lockInfo succeeds when the command field value is a given BSON type.""" +@pytest.mark.parametrize("test", pytest_params(INT_EDGE_TESTS)) +def test_lockInfo_accepts_int_edge_values(collection, test): + """Verify lockInfo accepts zero and negative int values for the command field.""" result = execute_admin_command(collection, test.command) assertProperties(result, test.checks, msg=test.msg, raw_res=True) - - -def test_lockInfo_unrecognized_field(collection): - """Test lockInfo with unrecognized extra field returns error 40415.""" - result = execute_admin_command(collection, {"lockInfo": 1, "foo": 1}) - assertFailureCode( - result, UNRECOGNIZED_COMMAND_FIELD_ERROR, msg="Unrecognized field should error" - ) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py index 6ae58b5b1..1cb8e68db 100644 --- a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_core_behavior.py @@ -1,26 +1,50 @@ """Tests for lockInfo command core behavior. -Verifies that lockInfo succeeds on admin database and returns a lockInfo array. +Verifies that lockInfo succeeds on admin database, returns a lockInfo array, +and behaves correctly under successive calls. """ import pytest -from documentdb_tests.framework.assertions import assertProperties, assertSuccessPartial +from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import ( + DiagnosticTestCase, +) +from documentdb_tests.framework.assertions import assertProperties from documentdb_tests.framework.executor import execute_admin_command -from documentdb_tests.framework.property_checks import IsType +from documentdb_tests.framework.parametrize import pytest_params +from documentdb_tests.framework.property_checks import ( # IsType used in CORE_BEHAVIOR_TESTS + Eq, + IsType, +) pytestmark = pytest.mark.admin -def test_lockInfo_returns_ok(collection): - """Test lockInfo returns ok:1 on admin database.""" +CORE_BEHAVIOR_TESTS: list[DiagnosticTestCase] = [ + DiagnosticTestCase( + id="returns_ok", + command={"lockInfo": 1}, + checks={"ok": Eq(1.0)}, + msg="lockInfo should return ok:1", + ), + DiagnosticTestCase( + id="returns_lockInfo_array", + command={"lockInfo": 1}, + checks={"lockInfo": IsType("array")}, + msg="lockInfo field should be array", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(CORE_BEHAVIOR_TESTS)) +def test_lockInfo_core_behavior(collection, test): + """Verifies lockInfo returns expected fields on the admin database.""" + result = execute_admin_command(collection, test.command) + assertProperties(result, test.checks, msg=test.msg, raw_res=True) + + +def test_lockInfo_point_in_time_snapshot(collection): + """Test lockInfo result is a point-in-time snapshot (successive calls succeed).""" + execute_admin_command(collection, {"lockInfo": 1}) result = execute_admin_command(collection, {"lockInfo": 1}) - assertSuccessPartial(result, {"ok": 1.0}, msg="lockInfo should return ok:1") - - -def test_lockInfo_returns_lockInfo_array(collection): - """Test lockInfo response contains a lockInfo array field.""" - result = execute_admin_command(collection, {"lockInfo": 1}) - assertProperties( - result, {"lockInfo": IsType("array")}, msg="lockInfo field should be array", raw_res=True - ) + assertProperties(result, {"ok": Eq(1.0)}, msg="Successive calls should succeed", raw_res=True) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py index 6db42e212..bcbdc1efe 100644 --- a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_errors.py @@ -6,16 +6,43 @@ import pytest +from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import ( + DiagnosticTestCase, +) from documentdb_tests.framework.assertions import assertFailureCode -from documentdb_tests.framework.error_codes import UNAUTHORIZED_ERROR -from documentdb_tests.framework.executor import execute_command +from documentdb_tests.framework.error_codes import ( + UNAUTHORIZED_ERROR, + UNRECOGNIZED_COMMAND_FIELD_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command, execute_command +from documentdb_tests.framework.parametrize import pytest_params pytestmark = pytest.mark.admin -def test_lockInfo_non_admin_database_returns_unauthorized(collection): - """Test lockInfo on non-admin database returns error code 13 (Unauthorized).""" - result = execute_command(collection, {"lockInfo": 1}) - assertFailureCode( - result, UNAUTHORIZED_ERROR, msg="lockInfo on non-admin db should be unauthorized" - ) +ERROR_TESTS: list[DiagnosticTestCase] = [ + DiagnosticTestCase( + id="non_admin_database", + command={"lockInfo": 1}, + use_admin=False, + error_code=UNAUTHORIZED_ERROR, + msg="lockInfo on non-admin db should be unauthorized", + ), + DiagnosticTestCase( + id="unrecognized_field", + command={"lockInfo": 1, "foo": 1}, + use_admin=True, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="Unrecognized field should error", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(ERROR_TESTS)) +def test_lockInfo_error_conditions(collection, test): + """Verifies lockInfo returns appropriate error codes for invalid usages.""" + if test.use_admin: + result = execute_admin_command(collection, test.command) + else: + result = execute_command(collection, test.command) + assertFailureCode(result, test.error_code, msg=test.msg) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py index 2805c57ee..2fe7edd12 100644 --- a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py @@ -1,7 +1,7 @@ """Tests for lockInfo command response structure. -Verifies the structure of the lockInfo response including field types -and lock mode values in granted/pending entries. +Verifies the top-level structure of the lockInfo response: ok field and +lockInfo array field. """ import pytest @@ -14,7 +14,7 @@ from documentdb_tests.framework.parametrize import pytest_params from documentdb_tests.framework.property_checks import Eq, IsType -pytestmark = pytest.mark.admin +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] RESPONSE_STRUCTURE_TESTS: list[DiagnosticTestCase] = [ @@ -38,40 +38,26 @@ def test_lockInfo_response_structure(collection, test): assertProperties(result, test.checks, msg=test.msg, raw_res=True) -def test_lockInfo_entry_resourceId_is_string(collection): - """Test lock entry contains resourceId field as a string.""" - collection.insert_one({"_id": 1}) - result = execute_admin_command(collection, {"lockInfo": 1}) - entry = result.get("lockInfo", [{}])[0] if result.get("lockInfo") else {} - assertProperties( - {"resourceId": entry.get("resourceId", "")}, - {"resourceId": IsType("string")}, - msg="resourceId should be a string", - raw_res=True, - ) - - -def test_lockInfo_entry_granted_is_array(collection): - """Test lock entry contains granted field as an array.""" - collection.insert_one({"_id": 1}) - result = execute_admin_command(collection, {"lockInfo": 1}) - entry = result.get("lockInfo", [{}])[0] if result.get("lockInfo") else {} - assertProperties( - {"granted": entry.get("granted", [])}, - {"granted": IsType("array")}, - msg="granted should be an array", - raw_res=True, - ) - +def test_lockInfo_entry_structure(collection): + """Test a lock entry exposes resourceId (string), granted (array), and pending (array). -def test_lockInfo_entry_pending_is_array(collection): - """Test lock entry contains pending field as an array.""" - collection.insert_one({"_id": 1}) - result = execute_admin_command(collection, {"lockInfo": 1}) - entry = result.get("lockInfo", [{}])[0] if result.get("lockInfo") else {} + Acquires a global fsync lock so the lock manager reports at least one entry, + guaranteeing the assertion runs against a real lock entry rather than an + empty snapshot. Must not run in parallel — fsyncLock is a global server lock. + """ + execute_admin_command(collection, {"fsync": 1, "lock": True}) + try: + result = execute_admin_command(collection, {"lockInfo": 1}) + entry = result["lockInfo"][0] + finally: + execute_admin_command(collection, {"fsyncUnlock": 1}) assertProperties( - {"pending": entry.get("pending", [])}, - {"pending": IsType("array")}, - msg="pending should be an array", + entry, + { + "resourceId": IsType("string"), + "granted": IsType("array"), + "pending": IsType("array"), + }, + msg="lock entry should expose resourceId (string), granted (array), pending (array)", raw_res=True, ) From 2717067c46a08c1b0e33ffd8681e8e0858cde882 Mon Sep 17 00:00:00 2001 From: PatersonProjects Date: Tue, 16 Jun 2026 12:09:19 -0700 Subject: [PATCH 3/3] Fixed docstrings Signed-off-by: PatersonProjects --- .../commands/lockInfo/test_lockInfo_argument_validation.py | 3 +-- .../commands/lockInfo/test_lockInfo_response_structure.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py index 261049e40..d4f9504bd 100644 --- a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_argument_validation.py @@ -1,7 +1,6 @@ """Tests for lockInfo command argument validation. -Verifies that lockInfo accepts various values for the command field and -rejects unrecognized fields with error code 40415. +Verifies that lockInfo accepts any BSON type for the command field value. """ import pytest diff --git a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py index 2fe7edd12..42e27eabf 100644 --- a/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py +++ b/documentdb_tests/compatibility/tests/system/diagnostic/commands/lockInfo/test_lockInfo_response_structure.py @@ -1,7 +1,8 @@ """Tests for lockInfo command response structure. Verifies the top-level structure of the lockInfo response: ok field and -lockInfo array field. +lockInfo array field. Also verifies the structure of individual lock entries +using an fsync lock to guarantee a non-empty snapshot. """ import pytest