diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/__init__.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_semantics_error.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_semantics_error.py new file mode 100644 index 000000000..530e6e5b6 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_semantics_error.py @@ -0,0 +1,89 @@ +"""Tests for setFeatureCompatibilityVersion confirm field semantics (error cases). + +Validates that omitting confirm or setting confirm:false prevents FCV changes. +""" + +import pytest + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.error_codes import FCV_CONFIRM_REQUIRED_ERROR +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [Confirm Required]: version change without confirm (omitted or false) is rejected. +CONFIRM_REQUIRED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "downgrade_without_confirm", + command=lambda ctx: {"setFeatureCompatibilityVersion": "OTHER_FCV"}, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should reject downgrade without confirm field", + ), + CommandTestCase( + "confirm_false_rejects_change", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": False, + }, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should reject version change with confirm:false", + ), +] + +# Property [Upgrade Without Confirm]: upgrade without confirm is rejected. +UPGRADE_NO_CONFIRM_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "upgrade_without_confirm", + command=lambda ctx: {"setFeatureCompatibilityVersion": "ORIGINAL_FCV"}, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should reject upgrade without confirm", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(CONFIRM_REQUIRED_TESTS)) +def test_setFeatureCompatibilityVersion_confirm_required(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects change without valid confirm.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + original = get_fcv(collection) + other = "8.0" if original != "8.0" else "8.2" + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = other + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(UPGRADE_NO_CONFIRM_TESTS)) +def test_setFeatureCompatibilityVersion_upgrade_without_confirm(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects upgrade when confirm is omitted.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + original = get_fcv(collection) + other = "8.0" if original != "8.0" else "8.2" + execute_admin_command(collection, {"setFeatureCompatibilityVersion": other, "confirm": True}) + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = original + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + execute_admin_command(collection, {"setFeatureCompatibilityVersion": original, "confirm": True}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_truthy_coercion.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_truthy_coercion.py new file mode 100644 index 000000000..6a976a43a --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_truthy_coercion.py @@ -0,0 +1,102 @@ +"""Tests for setFeatureCompatibilityVersion confirm field truthy coercion. + +Validates that the confirm field accepts truthy numeric values +(int 1, double 1.0, Int64(1), Decimal128("1"), NaN, Infinity, -Infinity). +""" + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [Truthy Coercion]: confirm field accepts truthy numeric values. +CONFIRM_TRUTHY_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "int_1", + command=lambda ctx: {"setFeatureCompatibilityVersion": "OTHER_FCV", "confirm": 1}, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=1 (int) as true", + ), + CommandTestCase( + "double_1", + command=lambda ctx: {"setFeatureCompatibilityVersion": "OTHER_FCV", "confirm": 1.0}, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=1.0 (double) as true", + ), + CommandTestCase( + "long_1", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": Int64(1), + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=Int64(1) as true", + ), + CommandTestCase( + "decimal_1", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": Decimal128("1"), + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=Decimal128('1') as true", + ), + CommandTestCase( + "nan", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": float("nan"), + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=NaN as true", + ), + CommandTestCase( + "infinity", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": float("inf"), + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=Infinity as true", + ), + CommandTestCase( + "negative_infinity", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": float("-inf"), + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept confirm=-Infinity as true", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(CONFIRM_TRUTHY_TESTS)) +def test_setFeatureCompatibilityVersion_confirm_truthy(database_client, collection, test): + """Test setFeatureCompatibilityVersion accepts truthy confirm values.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + current = get_fcv(collection) + other = "8.0" if current != "8.0" else "8.2" + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = other + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + execute_admin_command(collection, {"setFeatureCompatibilityVersion": current, "confirm": True}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_type_coercion_error.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_type_coercion_error.py new file mode 100644 index 000000000..e1260e50e --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_confirm_type_coercion_error.py @@ -0,0 +1,127 @@ +"""Tests for setFeatureCompatibilityVersion confirm field type coercion (error cases). + +Validates that the confirm field treats falsy values as false and rejects +non-numeric, non-bool types. +""" + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.error_codes import ( + FCV_CONFIRM_REQUIRED_ERROR, + TYPE_MISMATCH_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [Confirm Rejected]: confirm field treats falsy values as false +# and rejects non-numeric, non-bool types. +CONFIRM_REJECTED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "int_0", + command=lambda ctx: {"setFeatureCompatibilityVersion": "OTHER_FCV", "confirm": 0}, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should treat confirm=0 as false", + ), + CommandTestCase( + "double_0", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": 0.0, + }, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should treat confirm=0.0 as false", + ), + CommandTestCase( + "long_0", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": Int64(0), + }, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should treat confirm=Int64(0) as false", + ), + CommandTestCase( + "decimal_0", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": Decimal128("0"), + }, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should treat confirm=Decimal128('0') as false", + ), + CommandTestCase( + "null", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": None, + }, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should treat confirm=null as not-true", + ), + CommandTestCase( + "negative_zero", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": -0.0, + }, + error_code=FCV_CONFIRM_REQUIRED_ERROR, + msg="setFeatureCompatibilityVersion should treat confirm=-0.0 as false", + ), + CommandTestCase( + "string_type", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": "true", + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject confirm as string type", + ), + CommandTestCase( + "object_type", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": {"a": 1}, + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject confirm as object type", + ), + CommandTestCase( + "array_type", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "OTHER_FCV", + "confirm": [True], + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject confirm as array type", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(CONFIRM_REJECTED_TESTS)) +def test_setFeatureCompatibilityVersion_confirm_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects invalid confirm values.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + current = get_fcv(collection) + other = "8.0" if current != "8.0" else "8.2" + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = other + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_core_behavior.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_core_behavior.py new file mode 100644 index 000000000..8757587fa --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_core_behavior.py @@ -0,0 +1,139 @@ +"""Tests for setFeatureCompatibilityVersion core behavior (success cases). + +Validates idempotent set, downgrade/upgrade with confirm, and +getParameter readback after change. +""" + +import pytest + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult, assertSuccessPartial +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [Idempotent Set]: setting the current version succeeds and returns ok:1. +IDEMPOTENT_SET_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "idempotent_set_current_version", + command=lambda ctx: {"setFeatureCompatibilityVersion": "CURRENT_FCV", "confirm": True}, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should succeed idempotently when re-setting" + " current version", + ), +] + + +# Property [Downgrade]: setFeatureCompatibilityVersion can downgrade with confirm:true. +DOWNGRADE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "downgrade_with_confirm", + command=lambda ctx: {"setFeatureCompatibilityVersion": "OTHER_FCV", "confirm": True}, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should succeed when downgrading version with confirm", + ), +] + + +# Property [Upgrade]: setFeatureCompatibilityVersion can upgrade back. +UPGRADE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "upgrade_with_confirm", + command=lambda ctx: {"setFeatureCompatibilityVersion": "ORIGINAL_FCV", "confirm": True}, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should succeed when upgrading version with confirm", + ), +] + + +# Property [GetParameter Reflects Change]: getParameter returns the new version after change. +GET_PARAMETER_AFTER_CHANGE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "getParameter_reflects_change", + command=lambda ctx: {"getParameter": 1, "featureCompatibilityVersion": 1}, + expected={"ok": 1.0}, + msg="getParameter should return the new version after setFeatureCompatibilityVersion", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(IDEMPOTENT_SET_TESTS)) +def test_setFeatureCompatibilityVersion_idempotent_set(database_client, collection, test): + """Test setFeatureCompatibilityVersion succeeds when re-setting the current version.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + fcv = get_fcv(collection) + execute_admin_command(collection, {"setFeatureCompatibilityVersion": fcv, "confirm": True}) + result = execute_admin_command( + collection, {"setFeatureCompatibilityVersion": fcv, "confirm": True} + ) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(DOWNGRADE_TESTS)) +def test_setFeatureCompatibilityVersion_downgrade(database_client, collection, test): + """Test setFeatureCompatibilityVersion can downgrade with confirm:true.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + original = get_fcv(collection) + other = "8.0" if original != "8.0" else "8.2" + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = other + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + execute_admin_command(collection, {"setFeatureCompatibilityVersion": original, "confirm": True}) + + +@pytest.mark.parametrize("test", pytest_params(UPGRADE_TESTS)) +def test_setFeatureCompatibilityVersion_upgrade(database_client, collection, test): + """Test setFeatureCompatibilityVersion can upgrade back to the original version.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + original = get_fcv(collection) + other = "8.0" if original != "8.0" else "8.2" + execute_admin_command(collection, {"setFeatureCompatibilityVersion": other, "confirm": True}) + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = original + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(GET_PARAMETER_AFTER_CHANGE_TESTS)) +def test_setFeatureCompatibilityVersion_getParameter_reflects_change( + database_client, collection, test +): + """Test getParameter returns the new version after setFeatureCompatibilityVersion.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + original = get_fcv(collection) + other = "8.0" if original != "8.0" else "8.2" + execute_admin_command(collection, {"setFeatureCompatibilityVersion": other, "confirm": True}) + result = execute_admin_command(collection, test.build_command(ctx)) + expected = {"ok": 1.0, "featureCompatibilityVersion": {"version": other}} + assertSuccessPartial(result, expected, msg=test.msg) + execute_admin_command(collection, {"setFeatureCompatibilityVersion": original, "confirm": True}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_errors.py new file mode 100644 index 000000000..59ec92d10 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_errors.py @@ -0,0 +1,193 @@ +"""Tests for setFeatureCompatibilityVersion error cases. + +Covers database enforcement (user/local/config DB rejection), unknown/extra fields, +error response structure, and setParameter rejection. +""" + +import pytest + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.error_codes import ( + FCV_INVALID_VERSION_ERROR, + ILLEGAL_OPERATION_ERROR, + 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 + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [User DB Rejected]: setFeatureCompatibilityVersion fails on a user database. +USER_DB_REJECTED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "user_db_rejected", + error_code=UNAUTHORIZED_ERROR, + msg="setFeatureCompatibilityVersion should reject execution on a user database", + ), +] + + +# Property [System DB Rejected]: setFeatureCompatibilityVersion fails on local and config databases. +SYSTEM_DB_REJECTED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "local_db_rejected", + error_code=UNAUTHORIZED_ERROR, + msg="setFeatureCompatibilityVersion should reject execution on the local database", + ), + CommandTestCase( + "config_db_rejected", + error_code=UNAUTHORIZED_ERROR, + msg="setFeatureCompatibilityVersion should reject execution on the config database", + ), +] + + +# Property [Unrecognized Fields]: setFeatureCompatibilityVersion rejects unrecognized fields. +UNRECOGNIZED_FIELD_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "unrecognized_field", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "unknownField": 1, + }, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="setFeatureCompatibilityVersion should reject unrecognized fields", + ), + CommandTestCase( + "misspelled_confirm", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confrim": True, + }, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="setFeatureCompatibilityVersion should reject misspelled 'confrim' as unknown field", + ), + CommandTestCase( + "writeConcern_unknown_subfield", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"unknownField": 1}, + }, + error_code=UNRECOGNIZED_COMMAND_FIELD_ERROR, + msg="setFeatureCompatibilityVersion should reject unknown sub-fields in writeConcern", + ), +] + + +# Property [setParameter Rejected]: FCV cannot be set through setParameter. +SET_PARAMETER_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "via_setParameter", + command=lambda ctx: {"setParameter": 1, "featureCompatibilityVersion": "8.0"}, + error_code=ILLEGAL_OPERATION_ERROR, + msg="setFeatureCompatibilityVersion should not be settable via setParameter", + ), +] + + +# Property [Error Contains Code]: invalid version returns FCV_INVALID_VERSION_ERROR. +ERROR_CODE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "invalid_version_returns_error", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "invalid_version", + "confirm": True, + }, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should return FCV_INVALID_VERSION_ERROR" + " for non-existent version string", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(USER_DB_REJECTED_TESTS)) +def test_setFeatureCompatibilityVersion_user_db_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion fails on a user database.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + fcv = get_fcv(collection) + result = execute_command(collection, {"setFeatureCompatibilityVersion": fcv, "confirm": True}) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(SYSTEM_DB_REJECTED_TESTS)) +def test_setFeatureCompatibilityVersion_system_db_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion fails on local and config databases.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + fcv = get_fcv(collection) + db_name = "local" if "local" in test.id else "config" + target_collection = collection.database.client[db_name]["test"] + result = execute_command( + target_collection, {"setFeatureCompatibilityVersion": fcv, "confirm": True} + ) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(UNRECOGNIZED_FIELD_TESTS)) +def test_setFeatureCompatibilityVersion_unrecognized_field(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects unrecognized fields.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = get_fcv(collection) + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(SET_PARAMETER_TESTS)) +def test_setFeatureCompatibilityVersion_set_parameter_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion cannot be set through setParameter.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_admin_command(collection, test.build_command(ctx)) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) + + +@pytest.mark.parametrize("test", pytest_params(ERROR_CODE_TESTS)) +def test_setFeatureCompatibilityVersion_invalid_version_error(database_client, collection, test): + """Test setFeatureCompatibilityVersion returns FCV_INVALID_VERSION_ERROR.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_admin_command(collection, test.build_command(ctx)) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_feature_not_supported.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_feature_not_supported.py new file mode 100644 index 000000000..48563c5be --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_feature_not_supported.py @@ -0,0 +1,34 @@ +"""Tests for setFeatureCompatibilityVersion feature-not-supported behavior. + +Validates that setFeatureCompatibilityVersion is classified as an admin-only +command and returns the appropriate error when the feature is not supported. +""" + +import pytest + +from documentdb_tests.framework.assertions import assertFailureCode +from documentdb_tests.framework.error_codes import COMMAND_NOT_SUPPORTED_ERROR +from documentdb_tests.framework.executor import execute_admin_command + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +def test_setFeatureCompatibilityVersion_unsupported_returns_303(collection): + """Test setFeatureCompatibilityVersion returns error code 303 when feature not supported.""" + result = execute_admin_command( + collection, {"setFeatureCompatibilityVersion": "8.0", "confirm": True} + ) + # This test is only meaningful on engines that do not support FCV (e.g., DocumentDB). + # On engines that support FCV, this test is expected to pass/succeed instead. + if ( + isinstance(result, Exception) + and hasattr(result, "code") + and result.code == COMMAND_NOT_SUPPORTED_ERROR + ): + assertFailureCode( + result, + COMMAND_NOT_SUPPORTED_ERROR, + msg="setFeatureCompatibilityVersion should return 303 when not supported", + ) + else: + pytest.skip("Engine supports setFeatureCompatibilityVersion, skipping not-supported test") diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_version_type_validation_error.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_version_type_validation_error.py new file mode 100644 index 000000000..41d9e87f8 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_version_type_validation_error.py @@ -0,0 +1,81 @@ +"""Tests for setFeatureCompatibilityVersion version field BSON type validation (error cases). + +Validates that the version field rejects all non-string BSON types +with TYPE_MISMATCH_ERROR, and rejects null with MISSING_FIELD_ERROR. +""" + +import pytest + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.bson_type_validator import ( + BsonType, + BsonTypeTestCase, + generate_bson_rejection_test_cases, +) +from documentdb_tests.framework.error_codes import MISSING_FIELD_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, pytest.mark.no_parallel] + + +VERSION_TYPE_PARAM = [ + BsonTypeTestCase( + id="version_value", + msg="setFeatureCompatibilityVersion should only accept string for version", + keyword="setFeatureCompatibilityVersion", + valid_types=[BsonType.STRING], + skip_rejection_types=[BsonType.NULL], + default_error_code=TYPE_MISMATCH_ERROR, + requires={"confirm": True}, + ), +] + +VERSION_TYPE_REJECTIONS = generate_bson_rejection_test_cases(VERSION_TYPE_PARAM) + + +@pytest.mark.parametrize("bson_type,sample_value,spec", VERSION_TYPE_REJECTIONS) +def test_setFeatureCompatibilityVersion_version_type_rejected( + collection, bson_type, sample_value, spec +): + """Test setFeatureCompatibilityVersion rejects non-string BSON types for version.""" + result = execute_admin_command( + collection, + {"setFeatureCompatibilityVersion": sample_value, "confirm": True}, + ) + assertResult( + result, + error_code=spec.expected_code(bson_type), + msg=f"setFeatureCompatibilityVersion should reject {bson_type.value} for version", + raw_res=True, + ) + + +# Property [Null Rejected]: setFeatureCompatibilityVersion rejects null for version. +VERSION_NULL_REJECTED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "version_null_rejected", + command=lambda ctx: {"setFeatureCompatibilityVersion": None, "confirm": True}, + error_code=MISSING_FIELD_ERROR, + msg="setFeatureCompatibilityVersion should reject null for version", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(VERSION_NULL_REJECTED_TESTS)) +def test_setFeatureCompatibilityVersion_version_null_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects null for version.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_admin_command(collection, test.build_command(ctx)) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_version_value_validation_error.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_version_value_validation_error.py new file mode 100644 index 000000000..9c68b6059 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_version_value_validation_error.py @@ -0,0 +1,117 @@ +"""Tests for setFeatureCompatibilityVersion version value validation (error cases). + +Validates that the version field rejects unsupported, malformed, and +edge-case string values. +""" + +import pytest + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.error_codes import FCV_INVALID_VERSION_ERROR +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [Invalid Version Rejected]: setFeatureCompatibilityVersion rejects +# unsupported, malformed, and edge-case version strings. +VERSION_VALUE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "below_floor", + command=lambda ctx: {"setFeatureCompatibilityVersion": "3.0", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject version below supported floor", + ), + CommandTestCase( + "above_max", + command=lambda ctx: {"setFeatureCompatibilityVersion": "99.0", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject version above supported max", + ), + CommandTestCase( + "major_only", + command=lambda ctx: {"setFeatureCompatibilityVersion": "8", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject major-only version string", + ), + CommandTestCase( + "full_semver", + command=lambda ctx: {"setFeatureCompatibilityVersion": "8.0.0", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject full semver version string", + ), + CommandTestCase( + "leading_whitespace", + command=lambda ctx: {"setFeatureCompatibilityVersion": " 7.0", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject version with leading whitespace", + ), + CommandTestCase( + "trailing_whitespace", + command=lambda ctx: {"setFeatureCompatibilityVersion": "7.0 ", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject version with trailing whitespace", + ), + CommandTestCase( + "empty_string", + command=lambda ctx: {"setFeatureCompatibilityVersion": "", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject empty string version", + ), + CommandTestCase( + "zero_version", + command=lambda ctx: {"setFeatureCompatibilityVersion": "0.0", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject '0.0' as unsupported", + ), + CommandTestCase( + "future_version", + command=lambda ctx: {"setFeatureCompatibilityVersion": "10.0", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject future unsupported version", + ), + CommandTestCase( + "non_ascii", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "\uff18.\uff10", + "confirm": True, + }, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject non-ASCII version string", + ), + CommandTestCase( + "very_long_string", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "8" * 10_000, + "confirm": True, + }, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject a very long version string", + ), + CommandTestCase( + "intermediate_value", + command=lambda ctx: {"setFeatureCompatibilityVersion": "7.5", "confirm": True}, + error_code=FCV_INVALID_VERSION_ERROR, + msg="setFeatureCompatibilityVersion should reject intermediate version value", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(VERSION_VALUE_REJECTION_TESTS)) +def test_setFeatureCompatibilityVersion_version_value_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects invalid version values.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_admin_command(collection, test.build_command(ctx)) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_writeConcern_accepted.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_writeConcern_accepted.py new file mode 100644 index 000000000..c4ec4661e --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_writeConcern_accepted.py @@ -0,0 +1,132 @@ +"""Tests for setFeatureCompatibilityVersion writeConcern field acceptance. + +Validates that writeConcern accepts valid object values, null-as-omitted, +empty-doc, omission, and various numeric types for wtimeout. +""" + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [writeConcern Accepted]: setFeatureCompatibilityVersion accepts +# valid writeConcern values and various numeric types for wtimeout. +WRITE_CONCERN_ACCEPTED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "object", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"wtimeout": 5000}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept writeConcern as object", + ), + CommandTestCase( + "empty_object", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept writeConcern as empty object", + ), + CommandTestCase( + "null_as_omitted", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": None, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should treat writeConcern=null as omitted", + ), + CommandTestCase( + "omitted", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should succeed when writeConcern is omitted", + ), + CommandTestCase( + "wtimeout_double", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"wtimeout": 5000.0}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept wtimeout as double", + ), + CommandTestCase( + "wtimeout_long", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"wtimeout": Int64(5000)}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept wtimeout as Int64", + ), + CommandTestCase( + "wtimeout_decimal_whole", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"wtimeout": Decimal128("5000")}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept wtimeout as Decimal128", + ), + CommandTestCase( + "wtimeout_fractional_double", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"wtimeout": 5000.5}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept wtimeout as fractional double", + ), + CommandTestCase( + "wtimeout_negative", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": {"wtimeout": -1}, + }, + expected={"ok": 1.0}, + msg="setFeatureCompatibilityVersion should accept wtimeout as negative value", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(WRITE_CONCERN_ACCEPTED_TESTS)) +def test_setFeatureCompatibilityVersion_writeConcern_accepted(database_client, collection, test): + """Test setFeatureCompatibilityVersion accepts valid writeConcern values.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = get_fcv(collection) + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_writeConcern_validation_error.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_writeConcern_validation_error.py new file mode 100644 index 000000000..4855b7459 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_setFeatureCompatibilityVersion_writeConcern_validation_error.py @@ -0,0 +1,113 @@ +"""Tests for setFeatureCompatibilityVersion writeConcern field rejection (error cases). + +Validates that writeConcern rejects non-object types with TYPE_MISMATCH_ERROR. +""" + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import assertResult +from documentdb_tests.framework.error_codes import TYPE_MISMATCH_ERROR +from documentdb_tests.framework.executor import execute_admin_command +from documentdb_tests.framework.parametrize import pytest_params + +from .utils.setFeatureCompatibilityVersion_common import get_fcv + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# Property [writeConcern Rejected]: setFeatureCompatibilityVersion rejects +# non-object writeConcern types. +WRITE_CONCERN_REJECTED_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "string", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": "majority", + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as string", + ), + CommandTestCase( + "int", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": 1, + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as int", + ), + CommandTestCase( + "bool", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": True, + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as bool", + ), + CommandTestCase( + "array", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": [{"w": 1}], + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as array", + ), + CommandTestCase( + "long", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": Int64(1), + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as long", + ), + CommandTestCase( + "double", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": 1.0, + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as double", + ), + CommandTestCase( + "decimal128", + command=lambda ctx: { + "setFeatureCompatibilityVersion": "CURRENT_FCV", + "confirm": True, + "writeConcern": Decimal128("1"), + }, + error_code=TYPE_MISMATCH_ERROR, + msg="setFeatureCompatibilityVersion should reject writeConcern as Decimal128", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(WRITE_CONCERN_REJECTED_TESTS)) +def test_setFeatureCompatibilityVersion_writeConcern_rejected(database_client, collection, test): + """Test setFeatureCompatibilityVersion rejects non-object writeConcern types.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + cmd = test.build_command(ctx) + cmd["setFeatureCompatibilityVersion"] = get_fcv(collection) + result = execute_admin_command(collection, cmd) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_smoke_setFeatureCompatibilityVersion.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_smoke_setFeatureCompatibilityVersion.py index f343fb194..0c381df45 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_smoke_setFeatureCompatibilityVersion.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/test_smoke_setFeatureCompatibilityVersion.py @@ -9,33 +9,23 @@ from documentdb_tests.framework.assertions import assertSuccessPartial from documentdb_tests.framework.executor import execute_admin_command +from .utils.setFeatureCompatibilityVersion_common import get_fcv + pytestmark = [pytest.mark.smoke, pytest.mark.no_parallel] def test_smoke_setFeatureCompatibilityVersion(collection): """Test basic setFeatureCompatibilityVersion behavior.""" - get_result = execute_admin_command( - collection, {"getParameter": 1, "featureCompatibilityVersion": 1} - ) - - original_fcv = "8.2" - if not isinstance(get_result, Exception): - fcv_data = get_result.get("featureCompatibilityVersion", {}) - if isinstance(fcv_data, dict): - original_fcv = fcv_data.get("version", "8.2") - else: - original_fcv = str(fcv_data) - - new_fcv = "8.2" if original_fcv != "8.2" else "8.0" + original_fcv = get_fcv(collection) + new_fcv = "8.0" if original_fcv != "8.0" else "8.2" result = execute_admin_command( collection, {"setFeatureCompatibilityVersion": new_fcv, "confirm": True} ) - - expected = {"ok": 1.0} assertSuccessPartial( - result, expected, msg="Should support setFeatureCompatibilityVersion command" + result, + {"ok": 1.0}, + msg="setFeatureCompatibilityVersion should succeed with a valid version change", ) - execute_admin_command( collection, {"setFeatureCompatibilityVersion": original_fcv, "confirm": True} ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/utils/__init__.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/utils/setFeatureCompatibilityVersion_common.py b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/utils/setFeatureCompatibilityVersion_common.py new file mode 100644 index 000000000..efe74a378 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setFeatureCompatibilityVersion/utils/setFeatureCompatibilityVersion_common.py @@ -0,0 +1,16 @@ +"""Utilities for setFeatureCompatibilityVersion tests.""" + +from documentdb_tests.framework.executor import execute_admin_command + + +def get_fcv(collection): + """Read the current FCV via getParameter.""" + result = execute_admin_command( + collection, {"getParameter": 1, "featureCompatibilityVersion": 1} + ) + if isinstance(result, Exception): + return "8.2" + fcv_data = result.get("featureCompatibilityVersion", {}) + if isinstance(fcv_data, dict): + return fcv_data.get("version", "8.2") + return str(fcv_data) diff --git a/documentdb_tests/framework/error_codes.py b/documentdb_tests/framework/error_codes.py index 423b3fe65..db111a2fe 100644 --- a/documentdb_tests/framework/error_codes.py +++ b/documentdb_tests/framework/error_codes.py @@ -58,6 +58,7 @@ CHANGE_STREAM_HISTORY_LOST_ERROR = 286 NO_QUERY_EXECUTION_PLANS_ERROR = 291 QUERY_EXCEEDED_MEMORY_NO_DISK_USE_ERROR = 292 +COMMAND_NOT_SUPPORTED_ERROR = 303 API_VERSION_ERROR = 322 API_STRICT_ERROR = 323 COLLECTION_UUID_MISMATCH_ERROR = 361 @@ -446,6 +447,7 @@ MODULO_BY_ZERO_V2_ERROR = 4848403 API_VERSION_REQUIRED_ERROR = 4886600 LET_FIELD_REFERENCE_IN_VALUE_ERROR = 4890500 +FCV_INVALID_VERSION_ERROR = 4926900 COLLECTION_UUID_NOT_SUPPORTED_AGNOSTIC_ERROR = 4928901 ARRAY_TO_OBJECT_NULL_BYTE_PAIR_KEY_ERROR = 4940400 ARRAY_TO_OBJECT_NULL_BYTE_KV_KEY_ERROR = 4940401 @@ -516,6 +518,7 @@ WILDCARD_MULTIPLE_FIELDS_ERROR = 7246201 WILDCARD_STRING_TYPE_ERROR = 7246202 OUT_TIMESERIES_COLLECTION_TYPE_ERROR = 7268700 +FCV_CONFIRM_REQUIRED_ERROR = 7369100 OUT_TIMESERIES_OPTIONS_MISMATCH_ERROR = 7406103 SORT_DUPLICATE_KEY_ERROR = 7472500 N_ACCUMULATOR_INVALID_N_ERROR = 7548606