From 95dce3fd792b8e60c9cf72b0c84168b56acf3b72 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:18:51 -0700 Subject: [PATCH 1/9] add setParameter tests Signed-off-by: Alina (Xi) Li --- .../commands/setParameter/__init__.py | 0 .../test_setParameter_argument_validation.py | 218 +++++++++++++++++ .../test_setParameter_bson_type_validation.py | 117 ++++++++++ .../test_setParameter_core_behavior.py | 196 ++++++++++++++++ .../setParameter/test_setParameter_errors.py | 79 +++++++ .../test_setParameter_hierarchical_params.py | 221 ++++++++++++++++++ 6 files changed, 831 insertions(+) create mode 100644 documentdb_tests/compatibility/tests/system/administration/commands/setParameter/__init__.py create mode 100644 documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py create mode 100644 documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py create mode 100644 documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py create mode 100644 documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py create mode 100644 documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/__init__.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py new file mode 100644 index 000000000..f604e67e0 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -0,0 +1,218 @@ +"""Tests for setParameter argument validation. + +Validates control field types, parameter name validation, parameter value +type/range validation, and bounded integer parameter behavior. +""" + +import pytest +from bson import Int64 + +from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +from documentdb_tests.framework.error_codes import ( + BAD_VALUE_ERROR, + INVALID_OPTIONS_ERROR, + OVERFLOW_ERROR, + TYPE_MISMATCH_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# --- Control Field Type Validation --- + + +@pytest.mark.parametrize( + "control_value,desc", + [ + (1, "int 1"), + (1.0, "double 1.0"), + (Int64(1), "Int64"), + (True, "bool true"), + ("1", "string"), + (None, "null"), + ([1], "array"), + ({"a": 1}, "document"), + (0, "int 0"), + (-1, "negative int"), + ], + ids=[ + "int", + "double", + "long", + "bool", + "string", + "null", + "array", + "document", + "zero", + "negative", + ], +) +def test_setParameter_control_field_type(collection, control_value, desc): + """Test setParameter control field accepts various BSON types.""" + result = execute_admin_command(collection, {"setParameter": control_value, "logLevel": 0}) + assertSuccessPartial(result, {"ok": 1.0}, msg=f"Control field should accept {desc}") + + +# --- Parameter Name Validation --- + + +def test_setParameter_known_param_succeeds(collection): + """Test a known runtime parameter name succeeds.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Known param should succeed") + + +def test_setParameter_empty_string_name_fails(collection): + """Test empty-string parameter name fails with InvalidOptions error.""" + result = execute_admin_command(collection, {"setParameter": 1, "": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Empty name should fail") + + +def test_setParameter_unknown_name_fails(collection): + """Test arbitrary/unknown parameter name fails with InvalidOptions error.""" + result = execute_admin_command(collection, {"setParameter": 1, "unknownXYZ999": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Unknown name should fail") + + +def test_setParameter_case_sensitive_name(collection): + """Test parameter names are case-sensitive (altered case fails).""" + result = execute_admin_command(collection, {"setParameter": 1, "LogLevel": 0}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Wrong case should fail") + + +def test_setParameter_long_param_name_fails(collection): + """Test very long parameter name (1000+ chars) fails as unknown.""" + result = execute_admin_command(collection, {"setParameter": 1, "a" * 1000: 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Long name should fail") + + +def test_setParameter_dotted_param_name_fails(collection): + """Test parameter name containing dots fails as unknown.""" + result = execute_admin_command(collection, {"setParameter": 1, "log.level": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Dotted name should fail") + + +def test_setParameter_dollar_param_name_fails(collection): + """Test parameter name with dollar sign fails as unknown.""" + result = execute_admin_command(collection, {"setParameter": 1, "$logLevel": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Dollar name should fail") + + +# --- Parameter Value — Type Validation --- + + +def test_setParameter_boolean_param_with_bool_succeeds(collection): + """Test a boolean-typed parameter set with a boolean value succeeds.""" + original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) + result = execute_admin_command(collection, {"setParameter": 1, "quiet": True}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Boolean value should succeed for boolean param") + execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) + + +def test_setParameter_boolean_param_with_int_coerces(collection): + """Test a boolean-typed parameter set with integer coerces (1 -> true).""" + original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) + result = execute_admin_command(collection, {"setParameter": 1, "quiet": 1}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Int should coerce to bool") + execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) + + +def test_setParameter_integer_param_with_int_succeeds(collection): + """Test an integer-typed parameter set with an integer value succeeds.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Int value should succeed for int param") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +def test_setParameter_integer_param_with_whole_double_succeeds(collection): + """Test an integer-typed parameter set with a whole-number double succeeds.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.0}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Whole double should succeed for int param") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +def test_setParameter_integer_param_with_string_fails(collection): + """Test an integer-typed parameter set with a string value fails.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": "abc"}) + assertFailureCode(result, BAD_VALUE_ERROR, msg="String should fail for int param") + + +def test_setParameter_integer_param_with_fractional_double_coerces(collection): + """Test an integer-typed parameter set with a fractional double truncates to integer.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.5}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Fractional double should truncate for int param") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +# --- Parameter Value — Range Validation --- + + +def test_setParameter_integer_param_out_of_range_negative(collection): + """Test an integer parameter set below minimum fails with BadValue error.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": -1}) + assertFailureCode(result, BAD_VALUE_ERROR, msg="Negative logLevel should fail") + + +def test_setParameter_integer_param_valid_range(collection): + """Test an integer parameter at valid bounds succeeds (logLevel 0 and 5).""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 5}) + assertSuccessPartial(result, {"ok": 1.0}, msg="logLevel 5 should succeed") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +# --- JS-based: Type and length validation (automation_setparameter.js) --- + + +def test_setParameter_string_param_with_numeric_fails(collection): + """Test setting a string-typed parameter to a numeric value fails.""" + result = execute_admin_command( + collection, {"setParameter": 1, "automationServiceDescriptor": 12345} + ) + assertFailureCode(result, TYPE_MISMATCH_ERROR, msg="Numeric value should fail for string param") + + +def test_setParameter_string_param_overlength_fails(collection): + """Test setting a string-typed parameter to an over-length string fails with Overflow.""" + result = execute_admin_command( + collection, {"setParameter": 1, "automationServiceDescriptor": "x" * 65} + ) + assertFailureCode(result, OVERFLOW_ERROR, msg="Over-length string should fail") + + +def test_setParameter_string_param_valid_succeeds(collection): + """Test setting a string-typed parameter to a short valid string succeeds.""" + result = execute_admin_command( + collection, {"setParameter": 1, "automationServiceDescriptor": "test"} + ) + assertSuccessPartial(result, {"ok": 1.0}, msg="Valid short string should succeed") + execute_admin_command(collection, {"setParameter": 1, "automationServiceDescriptor": ""}) + + +def test_setParameter_whitespace_param_name_fails(collection): + """Test parameter name with leading/trailing whitespace fails as unknown.""" + result = execute_admin_command(collection, {"setParameter": 1, " logLevel ": 0}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Whitespace name should fail") + + +def test_setParameter_numeric_string_param_name_fails(collection): + """Test numeric-looking string parameter name fails as unknown.""" + result = execute_admin_command(collection, {"setParameter": 1, "12345": 0}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Numeric string name should fail") + + +def test_setParameter_control_field_int64_max(collection): + """Test control field with Int64 max value is accepted.""" + result = execute_admin_command( + collection, {"setParameter": Int64(9223372036854775807), "logLevel": 0} + ) + assertSuccessPartial(result, {"ok": 1.0}, msg="Int64 max control field should be accepted") + + +def test_setParameter_name_collides_with_control_field(collection): + """Test parameter name 'setParameter' (same as control field) fails.""" + result = execute_admin_command(collection, {"setParameter": 1, "setParameter": 2}) # noqa: F601 + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="Name collision with control field should fail" + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py new file mode 100644 index 000000000..7b04287eb --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py @@ -0,0 +1,117 @@ +"""Tests for setParameter BSON type validation. + +Validates control field acceptance of all BSON types, and type coercion +behavior for boolean and integer parameter values. +""" + +import pytest +from bson import Decimal128, Int64 + +from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +from documentdb_tests.framework.bson_type_validator import ( + BsonType, + BsonTypeTestCase, + generate_bson_acceptance_test_cases, +) +from documentdb_tests.framework.error_codes import BAD_VALUE_ERROR +from documentdb_tests.framework.executor import execute_admin_command + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# --- Control Field — accepts all BSON types --- + +CONTROL_FIELD_PARAM = [ + BsonTypeTestCase( + id="setParameter_control", + msg="setParameter control field should accept all BSON types", + keyword="setParameter", + valid_types=list(BsonType), + requires={"logLevel": 0}, + ), +] + +CONTROL_FIELD_ACCEPTANCE = generate_bson_acceptance_test_cases(CONTROL_FIELD_PARAM) + + +@pytest.mark.parametrize("bson_type,sample_value,spec", CONTROL_FIELD_ACCEPTANCE) +def test_setParameter_control_field_bson_type_accepted(collection, bson_type, sample_value, spec): + """Test setParameter control field accepts all BSON types.""" + result = execute_admin_command(collection, {"setParameter": sample_value, "logLevel": 0}) + assertSuccessPartial(result, {"ok": 1.0}, msg=f"{spec.msg} (bson_type={bson_type.value})") + + +# --- Boolean Parameter Coercion Matrix --- + + +@pytest.mark.parametrize( + "value,desc", + [ + (True, "bool True"), + (False, "bool False"), + (1, "int 1"), + (0, "int 0"), + (1.0, "double 1.0"), + (0.0, "double 0.0"), + (Int64(1), "Int64(1)"), + (Int64(0), "Int64(0)"), + ("true", "string 'true'"), + ([True], "array [True]"), + ({"a": True}, "document"), + ], + ids=[ + "true", + "false", + "int1", + "int0", + "double1", + "double0", + "long1", + "long0", + "string", + "array", + "document", + ], +) +def test_setParameter_boolean_coercion_accepted(collection, value, desc): + """Test boolean parameter coercion — MongoDB 8.2 coerces many types to boolean.""" + original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) + result = execute_admin_command(collection, {"setParameter": 1, "quiet": value}) + assertSuccessPartial(result, {"ok": 1.0}, msg=f"Boolean param should accept {desc}") + execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) + + +# --- Integer Parameter Coercion Matrix --- + + +@pytest.mark.parametrize( + "value,desc", + [ + (1, "int32"), + (Int64(1), "Int64"), + (1.0, "whole double"), + (Decimal128("1"), "Decimal128 whole"), + (True, "bool True"), + ], + ids=["int32", "long", "whole_double", "decimal128_whole", "bool"], +) +def test_setParameter_integer_coercion_accepted(collection, value, desc): + """Test integer parameter coercion — whole-number numeric types and bool accepted.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": value}) + assertSuccessPartial(result, {"ok": 1.0}, msg=f"Integer param should accept {desc}") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +@pytest.mark.parametrize( + "value,error_code,desc", + [ + ("1", BAD_VALUE_ERROR, "string '1'"), + ([1], BAD_VALUE_ERROR, "array [1]"), + ({"a": 1}, BAD_VALUE_ERROR, "document"), + ], + ids=["string", "array", "document"], +) +def test_setParameter_integer_coercion_rejected(collection, value, error_code, desc): + """Test integer parameter rejects non-numeric types.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": value}) + assertFailureCode(result, error_code, msg=f"Integer param should reject {desc}") diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py new file mode 100644 index 000000000..c0c086320 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py @@ -0,0 +1,196 @@ +"""Tests for setParameter command core behavior. + +Validates single/multiple parameter modification, admin database requirement, +runtime vs startup-only parameters, command shape, response structure, and +getParameter interaction. +""" + +import pytest + +from documentdb_tests.framework.assertions import ( + assertFailureCode, + assertSuccessPartial, +) +from documentdb_tests.framework.error_codes import ( + INVALID_OPTIONS_ERROR, + UNAUTHORIZED_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command, execute_command + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# --- Single Parameter Modification --- + + +def test_setParameter_single_param_returns_ok(collection): + """Test setParameter with one runtime-settable parameter returns ok:1.""" + original = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + original_val = original["logLevel"] + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Should return ok:1") + execute_admin_command(collection, {"setParameter": 1, "logLevel": original_val}) + + +def test_setParameter_returns_was_field(collection): + """Test setParameter response includes the previous value in 'was' field.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 2}) + assertSuccessPartial(result, {"ok": 1.0, "was": 0}, msg="Should report previous value in 'was'") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +def test_setParameter_actually_changes_value(collection): + """Test setParameter actually changes the parameter value verified via getParameter.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 3}) + result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial(result, {"logLevel": 3}, msg="Should reflect new value via getParameter") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +def test_setParameter_idempotent_set(collection): + """Test setting a parameter to its current value returns ok:1 with was equal to new value.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + assertSuccessPartial(result, {"ok": 1.0, "was": 0}, msg="Idempotent set should succeed") + + +# --- Multiple Parameter Modification --- + + +def test_setParameter_two_params_returns_ok(collection): + """Test setParameter with two runtime-settable parameters in one command sets both.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1, "quiet": True}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Should set both parameters") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) + + +# --- Admin Database Requirement --- + + +def test_setParameter_on_admin_db_succeeds(collection): + """Test setParameter run against the admin database succeeds.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Should succeed on admin db") + + +def test_setParameter_on_non_admin_db_fails(collection): + """Test setParameter run against a non-admin database fails with Unauthorized error.""" + result = execute_command(collection, {"setParameter": 1, "logLevel": 0}) + assertFailureCode(result, UNAUTHORIZED_ERROR, msg="Should fail on non-admin db") + + +# --- Runtime vs Startup-Only Parameters --- + + +def test_setParameter_runtime_param_succeeds(collection): + """Test setParameter on a runtime-settable parameter succeeds.""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Runtime param should succeed") + + +def test_setParameter_startup_only_param_fails(collection): + """Test setParameter on a startup-only parameter fails with InvalidOptions error.""" + result = execute_admin_command(collection, {"setParameter": 1, "port": 27018}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Startup-only param should fail") + + +def test_setParameter_nonexistent_param_fails(collection): + """Test setParameter on a non-existent parameter name fails with InvalidOptions error.""" + result = execute_admin_command(collection, {"setParameter": 1, "nonExistentParam123": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Non-existent param should fail") + + +# --- Command Shape --- + + +def test_setParameter_no_param_pair_fails(collection): + """Test setParameter with control field but no parameter:value pair fails.""" + result = execute_admin_command(collection, {"setParameter": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="No param pair should fail") + + +def test_setParameter_comment_field_accepted(collection): + """Test comment field accepted alongside setParameter.""" + result = execute_admin_command( + collection, {"setParameter": 1, "logLevel": 0, "comment": "test comment"} + ) + assertSuccessPartial(result, {"ok": 1.0}, msg="Comment field should be accepted") + + +# --- Response Structure --- + + +def test_setParameter_success_was_type_matches_param(collection): + """Test the 'was' field type matches the parameter's declared type (integer for logLevel).""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) + assertSuccessPartial( + result, {"ok": 1.0, "was": 0}, msg="'was' should be integer type matching logLevel" + ) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +def test_setParameter_boolean_was_type(collection): + """Test the 'was' field for a boolean parameter is boolean type.""" + original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) + execute_admin_command(collection, {"setParameter": 1, "quiet": False}) + result = execute_admin_command(collection, {"setParameter": 1, "quiet": True}) + assertSuccessPartial(result, {"ok": 1.0, "was": False}, msg="'was' should be boolean type") + execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) + + +# --- Interaction with getParameter --- + + +def test_setParameter_getParameter_reflects_new_value(collection): + """Test getParameter reflects new value immediately after successful setParameter.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 4}) + result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial(result, {"logLevel": 4}, msg="getParameter should reflect new value") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + +def test_setParameter_getParameter_unchanged_after_failure(collection): + """Test getParameter is unchanged after a failed setParameter.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": "invalid"}) + result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial(result, {"logLevel": 0}, msg="Value should be unchanged after failure") + + +def test_setParameter_round_trip_restore(collection): + """Test round-trip: read, set new, restore original via 'was' field.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + set_result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 3}) + original_val = set_result["was"] + execute_admin_command(collection, {"setParameter": 1, "logLevel": original_val}) + result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial(result, {"logLevel": 0}, msg="Should restore to original") + + +# --- Boolean parameter toggle --- + + +def test_setParameter_boolean_toggle(collection): + """Test setting a boolean-typed parameter to false and reading back.""" + original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) + execute_admin_command(collection, {"setParameter": 1, "quiet": False}) + result = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) + assertSuccessPartial(result, {"quiet": False}, msg="Boolean param should be False") + execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) + + +def test_setParameter_ordering_independence(collection): + """Test setting {logLevel, quiet} vs {quiet, logLevel} yields same final state.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 2, "quiet": True}) + state1 = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) + execute_admin_command(collection, {"setParameter": 1, "quiet": True, "logLevel": 2}) + state2 = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial(state2, {"logLevel": state1["logLevel"]}, msg="Order should not matter") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py new file mode 100644 index 000000000..bc2c9f6f0 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -0,0 +1,79 @@ +"""Tests for setParameter error codes and multi-parameter failure semantics. + +Validates correct error codes are returned for various failure modes and +that multi-parameter commands behave atomically on failure. +""" + +import pytest + +from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +from documentdb_tests.framework.error_codes import ( + BAD_VALUE_ERROR, + INVALID_OPTIONS_ERROR, + UNAUTHORIZED_ERROR, +) +from documentdb_tests.framework.executor import execute_admin_command, execute_command + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# --- Error Code Validation --- + + +def test_setParameter_nonexistent_param_error_code(collection): + """Test setting a non-existent parameter returns InvalidOptions (72).""" + result = execute_admin_command(collection, {"setParameter": 1, "nonExistentXYZ": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Non-existent param should return 72") + + +def test_setParameter_startup_only_param_error_code(collection): + """Test setting a startup-only parameter at runtime returns InvalidOptions (72).""" + result = execute_admin_command(collection, {"setParameter": 1, "port": 27018}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Startup-only param should return 72") + + +def test_setParameter_out_of_range_error_code(collection): + """Test setting a parameter to an out-of-range value returns BadValue (2).""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": -1}) + assertFailureCode(result, BAD_VALUE_ERROR, msg="Out-of-range should return 2") + + +def test_setParameter_wrong_type_error_code(collection): + """Test setting a parameter to a wrong-type value returns BadValue (2).""" + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": "abc"}) + assertFailureCode(result, BAD_VALUE_ERROR, msg="Wrong type should return 2") + + +def test_setParameter_non_admin_db_error_code(collection): + """Test running setParameter on a non-admin database returns Unauthorized (13).""" + result = execute_command(collection, {"setParameter": 1, "logLevel": 0}) + assertFailureCode(result, UNAUTHORIZED_ERROR, msg="Non-admin db should return 13") + + +def test_setParameter_empty_name_error_code(collection): + """Test empty-string parameter name returns InvalidOptions (72).""" + result = execute_admin_command(collection, {"setParameter": 1, "": 1}) + assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Empty name should return 72") + + +# --- Multi-Parameter Failure Semantics --- + + +def test_setParameter_multi_param_second_invalid_is_atomic(collection): + """Test multi-parameter command with invalid second param does not apply first.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 3, "nonExistentXYZ": 1}) + result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial( + result, {"logLevel": 0}, msg="First param should not be applied when second fails" + ) + + +def test_setParameter_multi_param_invalid_returns_error(collection): + """Test multi-parameter command with invalid param returns error code.""" + result = execute_admin_command( + collection, {"setParameter": 1, "logLevel": 0, "nonExistentXYZ": 1} + ) + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="Multi-param with invalid should return 72" + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py new file mode 100644 index 000000000..134127a67 --- /dev/null +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py @@ -0,0 +1,221 @@ +"""Tests for setParameter hierarchical/object parameter handling. + +Validates logComponentVerbosity nested parameter behavior including +read defaults, type/member validation, multi-member set, atomic rejection, +and bare numeric form. +""" + +import pytest + +from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +from documentdb_tests.framework.error_codes import BAD_VALUE_ERROR, TYPE_MISMATCH_ERROR +from documentdb_tests.framework.executor import execute_admin_command + +pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] + + +# --- Read Defaults --- + + +def test_setParameter_hierarchical_param_readable(collection): + """Test reading logComponentVerbosity returns a defined value.""" + result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial(result, {"ok": 1.0}, msg="Should be able to read hierarchical param") + + +def test_setParameter_hierarchical_top_level_verbosity(collection): + """Test top-level verbosity of hierarchical parameter matches scalar logLevel default.""" + execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + result2 = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial( + result2, + {"logComponentVerbosity": {"verbosity": 0}}, + msg="Top-level verbosity should match logLevel", + ) + + +def test_setParameter_hierarchical_nested_field_defined(collection): + """Test a deeply nested verbosity field is defined.""" + result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + # network.asio is a deeply nested component + assertSuccessPartial( + result, + {"logComponentVerbosity": {"network": {"asio": {"verbosity": -1}}}}, + msg="Nested component should have defined verbosity", + ) + + +# --- Type and Member Validation --- + + +def test_setParameter_hierarchical_string_value_fails(collection): + """Test setting logComponentVerbosity to a plain string fails with TypeMismatch.""" + result = execute_admin_command(collection, {"setParameter": 1, "logComponentVerbosity": "abc"}) + assertFailureCode(result, TYPE_MISMATCH_ERROR, msg="String should fail for object param") + + +def test_setParameter_hierarchical_nested_string_verbosity_fails(collection): + """Test setting a nested verbosity member to a non-numeric string fails.""" + result = execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": "abc"}}}, + ) + assertFailureCode(result, BAD_VALUE_ERROR, msg="String verbosity should fail") + + +def test_setParameter_hierarchical_nested_overflow_fails(collection): + """Test setting a nested verbosity member above max safe integer fails.""" + result = execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": 2147483648}}}, + ) + assertFailureCode(result, BAD_VALUE_ERROR, msg="Overflow verbosity should fail") + + +def test_setParameter_hierarchical_nested_underflow_fails(collection): + """Test setting a nested verbosity member below min safe integer fails.""" + result = execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -2147483649}}}, + ) + assertFailureCode(result, BAD_VALUE_ERROR, msg="Underflow verbosity should fail") + + +def test_setParameter_hierarchical_unknown_component_fails(collection): + """Test setting an unrecognized nested component name fails.""" + result = execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"unknownComponent": {"verbosity": 1}}}, + ) + assertFailureCode(result, BAD_VALUE_ERROR, msg="Unknown component should fail") + + +# --- Multi-Member Set and Atomic Rejection --- + + +def test_setParameter_hierarchical_multi_member_set(collection): + """Test setting several nested members in one command succeeds.""" + execute_admin_command( + collection, + { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": -1}, "network": {"verbosity": -1}}, + }, + ) + result = execute_admin_command( + collection, + { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": 2}, "network": {"verbosity": 3}}, + }, + ) + assertSuccessPartial(result, {"ok": 1.0}, msg="Multi-member set should succeed") + # Cleanup + execute_admin_command( + collection, + { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": -1}, "network": {"verbosity": -1}}, + }, + ) + + +def test_setParameter_hierarchical_multi_member_readback(collection): + """Test reading back reflects each member set in a multi-member command.""" + execute_admin_command( + collection, + { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": 2}, "network": {"verbosity": 3}}, + }, + ) + read_result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial( + read_result, + {"logComponentVerbosity": {"command": {"verbosity": 2}, "network": {"verbosity": 3}}}, + msg="Both members should be set", + ) + # Cleanup + execute_admin_command( + collection, + { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": -1}, "network": {"verbosity": -1}}, + }, + ) + + +def test_setParameter_hierarchical_atomic_rejection(collection): + """Test no members are changed when a multi-member set is rejected.""" + execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, + ) + execute_admin_command( + collection, + { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": 2}, "unknownXYZ": {"verbosity": 1}}, + }, + ) + result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial( + result, + {"logComponentVerbosity": {"command": {"verbosity": -1}}}, + msg="Command verbosity should remain unchanged after atomic rejection", + ) + + +def test_setParameter_hierarchical_clear_with_negative(collection): + """Test clearing nested members with -1 resets them to inherited default.""" + execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": 3}}}, + ) + execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, + ) + result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial( + result, + {"logComponentVerbosity": {"command": {"verbosity": -1}}}, + msg="Cleared member should fall back to -1 (inherited)", + ) + + +def test_setParameter_hierarchical_bare_numeric_form(collection): + """Test setting a nested component verbosity using bare numeric level succeeds.""" + result = execute_admin_command( + collection, {"setParameter": 1, "logComponentVerbosity": {"command": 4}} + ) + assertSuccessPartial(result, {"ok": 1.0}, msg="Bare numeric form should succeed") + execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, + ) + + +def test_setParameter_hierarchical_bare_numeric_readback(collection): + """Test bare numeric component set takes effect when read back.""" + execute_admin_command(collection, {"setParameter": 1, "logComponentVerbosity": {"command": 4}}) + read_result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial( + read_result, + {"logComponentVerbosity": {"command": {"verbosity": 4}}}, + msg="Bare numeric should set verbosity", + ) + execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, + ) + + +def test_setParameter_hierarchical_nested_nan_verbosity_fails(collection): + """Test setting a nested verbosity member to NaN fails with BadValue.""" + result = execute_admin_command( + collection, + {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": float("nan")}}}, + ) + assertFailureCode(result, BAD_VALUE_ERROR, msg="NaN verbosity should fail") From 5e410c9a23fa246f028d18f51573f68268481eba Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:26:03 -0700 Subject: [PATCH 2/9] docdb-test-review update Signed-off-by: Alina (Xi) Li --- .../test_setParameter_argument_validation.py | 72 +++---------------- .../test_setParameter_bson_type_validation.py | 8 --- .../test_setParameter_core_behavior.py | 55 +------------- .../setParameter/test_setParameter_errors.py | 42 ++++++----- .../test_setParameter_hierarchical_params.py | 9 --- 5 files changed, 37 insertions(+), 149 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py index f604e67e0..ceed04114 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -9,7 +9,6 @@ from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial from documentdb_tests.framework.error_codes import ( - BAD_VALUE_ERROR, INVALID_OPTIONS_ERROR, OVERFLOW_ERROR, TYPE_MISMATCH_ERROR, @@ -19,34 +18,19 @@ pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] -# --- Control Field Type Validation --- - - @pytest.mark.parametrize( "control_value,desc", [ - (1, "int 1"), - (1.0, "double 1.0"), - (Int64(1), "Int64"), - (True, "bool true"), - ("1", "string"), - (None, "null"), - ([1], "array"), - ({"a": 1}, "document"), - (0, "int 0"), - (-1, "negative int"), - ], - ids=[ - "int", - "double", - "long", - "bool", - "string", - "null", - "array", - "document", - "zero", - "negative", + pytest.param(1, "int 1", id="int"), + pytest.param(1.0, "double 1.0", id="double"), + pytest.param(Int64(1), "Int64", id="long"), + pytest.param(True, "bool true", id="bool"), + pytest.param("1", "string", id="string"), + pytest.param(None, "null", id="null"), + pytest.param([1], "array", id="array"), + pytest.param({"a": 1}, "document", id="document"), + pytest.param(0, "int 0", id="zero"), + pytest.param(-1, "negative int", id="negative"), ], ) def test_setParameter_control_field_type(collection, control_value, desc): @@ -55,27 +39,12 @@ def test_setParameter_control_field_type(collection, control_value, desc): assertSuccessPartial(result, {"ok": 1.0}, msg=f"Control field should accept {desc}") -# --- Parameter Name Validation --- - - def test_setParameter_known_param_succeeds(collection): """Test a known runtime parameter name succeeds.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) assertSuccessPartial(result, {"ok": 1.0}, msg="Known param should succeed") -def test_setParameter_empty_string_name_fails(collection): - """Test empty-string parameter name fails with InvalidOptions error.""" - result = execute_admin_command(collection, {"setParameter": 1, "": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Empty name should fail") - - -def test_setParameter_unknown_name_fails(collection): - """Test arbitrary/unknown parameter name fails with InvalidOptions error.""" - result = execute_admin_command(collection, {"setParameter": 1, "unknownXYZ999": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Unknown name should fail") - - def test_setParameter_case_sensitive_name(collection): """Test parameter names are case-sensitive (altered case fails).""" result = execute_admin_command(collection, {"setParameter": 1, "LogLevel": 0}) @@ -100,9 +69,6 @@ def test_setParameter_dollar_param_name_fails(collection): assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Dollar name should fail") -# --- Parameter Value — Type Validation --- - - def test_setParameter_boolean_param_with_bool_succeeds(collection): """Test a boolean-typed parameter set with a boolean value succeeds.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) @@ -133,12 +99,6 @@ def test_setParameter_integer_param_with_whole_double_succeeds(collection): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) -def test_setParameter_integer_param_with_string_fails(collection): - """Test an integer-typed parameter set with a string value fails.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": "abc"}) - assertFailureCode(result, BAD_VALUE_ERROR, msg="String should fail for int param") - - def test_setParameter_integer_param_with_fractional_double_coerces(collection): """Test an integer-typed parameter set with a fractional double truncates to integer.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.5}) @@ -146,15 +106,6 @@ def test_setParameter_integer_param_with_fractional_double_coerces(collection): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) -# --- Parameter Value — Range Validation --- - - -def test_setParameter_integer_param_out_of_range_negative(collection): - """Test an integer parameter set below minimum fails with BadValue error.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": -1}) - assertFailureCode(result, BAD_VALUE_ERROR, msg="Negative logLevel should fail") - - def test_setParameter_integer_param_valid_range(collection): """Test an integer parameter at valid bounds succeeds (logLevel 0 and 5).""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 5}) @@ -162,9 +113,6 @@ def test_setParameter_integer_param_valid_range(collection): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) -# --- JS-based: Type and length validation (automation_setparameter.js) --- - - def test_setParameter_string_param_with_numeric_fails(collection): """Test setting a string-typed parameter to a numeric value fails.""" result = execute_admin_command( diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py index 7b04287eb..90a85fae9 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py @@ -19,8 +19,6 @@ pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] -# --- Control Field — accepts all BSON types --- - CONTROL_FIELD_PARAM = [ BsonTypeTestCase( id="setParameter_control", @@ -41,9 +39,6 @@ def test_setParameter_control_field_bson_type_accepted(collection, bson_type, sa assertSuccessPartial(result, {"ok": 1.0}, msg=f"{spec.msg} (bson_type={bson_type.value})") -# --- Boolean Parameter Coercion Matrix --- - - @pytest.mark.parametrize( "value,desc", [ @@ -81,9 +76,6 @@ def test_setParameter_boolean_coercion_accepted(collection, value, desc): execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) -# --- Integer Parameter Coercion Matrix --- - - @pytest.mark.parametrize( "value,desc", [ diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py index c0c086320..97ee31347 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py @@ -8,21 +8,13 @@ import pytest from documentdb_tests.framework.assertions import ( - assertFailureCode, assertSuccessPartial, ) -from documentdb_tests.framework.error_codes import ( - INVALID_OPTIONS_ERROR, - UNAUTHORIZED_ERROR, -) -from documentdb_tests.framework.executor import execute_admin_command, execute_command +from documentdb_tests.framework.executor import execute_admin_command pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] -# --- Single Parameter Modification --- - - def test_setParameter_single_param_returns_ok(collection): """Test setParameter with one runtime-settable parameter returns ok:1.""" original = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) @@ -56,9 +48,6 @@ def test_setParameter_idempotent_set(collection): assertSuccessPartial(result, {"ok": 1.0, "was": 0}, msg="Idempotent set should succeed") -# --- Multiple Parameter Modification --- - - def test_setParameter_two_params_returns_ok(collection): """Test setParameter with two runtime-settable parameters in one command sets both.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) @@ -67,51 +56,18 @@ def test_setParameter_two_params_returns_ok(collection): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) -# --- Admin Database Requirement --- - - def test_setParameter_on_admin_db_succeeds(collection): """Test setParameter run against the admin database succeeds.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) assertSuccessPartial(result, {"ok": 1.0}, msg="Should succeed on admin db") -def test_setParameter_on_non_admin_db_fails(collection): - """Test setParameter run against a non-admin database fails with Unauthorized error.""" - result = execute_command(collection, {"setParameter": 1, "logLevel": 0}) - assertFailureCode(result, UNAUTHORIZED_ERROR, msg="Should fail on non-admin db") - - -# --- Runtime vs Startup-Only Parameters --- - - def test_setParameter_runtime_param_succeeds(collection): """Test setParameter on a runtime-settable parameter succeeds.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) assertSuccessPartial(result, {"ok": 1.0}, msg="Runtime param should succeed") -def test_setParameter_startup_only_param_fails(collection): - """Test setParameter on a startup-only parameter fails with InvalidOptions error.""" - result = execute_admin_command(collection, {"setParameter": 1, "port": 27018}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Startup-only param should fail") - - -def test_setParameter_nonexistent_param_fails(collection): - """Test setParameter on a non-existent parameter name fails with InvalidOptions error.""" - result = execute_admin_command(collection, {"setParameter": 1, "nonExistentParam123": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Non-existent param should fail") - - -# --- Command Shape --- - - -def test_setParameter_no_param_pair_fails(collection): - """Test setParameter with control field but no parameter:value pair fails.""" - result = execute_admin_command(collection, {"setParameter": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="No param pair should fail") - - def test_setParameter_comment_field_accepted(collection): """Test comment field accepted alongside setParameter.""" result = execute_admin_command( @@ -120,9 +76,6 @@ def test_setParameter_comment_field_accepted(collection): assertSuccessPartial(result, {"ok": 1.0}, msg="Comment field should be accepted") -# --- Response Structure --- - - def test_setParameter_success_was_type_matches_param(collection): """Test the 'was' field type matches the parameter's declared type (integer for logLevel).""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) @@ -142,9 +95,6 @@ def test_setParameter_boolean_was_type(collection): execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) -# --- Interaction with getParameter --- - - def test_setParameter_getParameter_reflects_new_value(collection): """Test getParameter reflects new value immediately after successful setParameter.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) @@ -172,9 +122,6 @@ def test_setParameter_round_trip_restore(collection): assertSuccessPartial(result, {"logLevel": 0}, msg="Should restore to original") -# --- Boolean parameter toggle --- - - def test_setParameter_boolean_toggle(collection): """Test setting a boolean-typed parameter to false and reading back.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index bc2c9f6f0..254629788 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -17,46 +17,56 @@ pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] -# --- Error Code Validation --- - - def test_setParameter_nonexistent_param_error_code(collection): - """Test setting a non-existent parameter returns InvalidOptions (72).""" + """Test setting a non-existent parameter returns InvalidOptions.""" result = execute_admin_command(collection, {"setParameter": 1, "nonExistentXYZ": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Non-existent param should return 72") + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="setParameter should reject non-existent param" + ) def test_setParameter_startup_only_param_error_code(collection): - """Test setting a startup-only parameter at runtime returns InvalidOptions (72).""" + """Test setting a startup-only parameter at runtime returns InvalidOptions.""" result = execute_admin_command(collection, {"setParameter": 1, "port": 27018}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Startup-only param should return 72") + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="setParameter should reject startup-only param" + ) def test_setParameter_out_of_range_error_code(collection): - """Test setting a parameter to an out-of-range value returns BadValue (2).""" + """Test setting a parameter to an out-of-range value returns BadValue.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": -1}) - assertFailureCode(result, BAD_VALUE_ERROR, msg="Out-of-range should return 2") + assertFailureCode(result, BAD_VALUE_ERROR, msg="setParameter should reject out-of-range value") def test_setParameter_wrong_type_error_code(collection): - """Test setting a parameter to a wrong-type value returns BadValue (2).""" + """Test setting a parameter to a wrong-type value returns BadValue.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": "abc"}) - assertFailureCode(result, BAD_VALUE_ERROR, msg="Wrong type should return 2") + assertFailureCode(result, BAD_VALUE_ERROR, msg="setParameter should reject wrong type value") def test_setParameter_non_admin_db_error_code(collection): - """Test running setParameter on a non-admin database returns Unauthorized (13).""" + """Test running setParameter on a non-admin database returns Unauthorized.""" result = execute_command(collection, {"setParameter": 1, "logLevel": 0}) - assertFailureCode(result, UNAUTHORIZED_ERROR, msg="Non-admin db should return 13") + assertFailureCode( + result, UNAUTHORIZED_ERROR, msg="setParameter should reject non-admin database" + ) def test_setParameter_empty_name_error_code(collection): - """Test empty-string parameter name returns InvalidOptions (72).""" + """Test empty-string parameter name returns InvalidOptions.""" result = execute_admin_command(collection, {"setParameter": 1, "": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Empty name should return 72") + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="setParameter should reject empty param name" + ) -# --- Multi-Parameter Failure Semantics --- +def test_setParameter_no_param_pair_fails(collection): + """Test setParameter with control field but no parameter:value pair fails.""" + result = execute_admin_command(collection, {"setParameter": 1}) + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="setParameter should reject missing param pair" + ) def test_setParameter_multi_param_second_invalid_is_atomic(collection): diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py index 134127a67..8bf79277b 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py @@ -14,9 +14,6 @@ pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] -# --- Read Defaults --- - - def test_setParameter_hierarchical_param_readable(collection): """Test reading logComponentVerbosity returns a defined value.""" result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) @@ -46,9 +43,6 @@ def test_setParameter_hierarchical_nested_field_defined(collection): ) -# --- Type and Member Validation --- - - def test_setParameter_hierarchical_string_value_fails(collection): """Test setting logComponentVerbosity to a plain string fails with TypeMismatch.""" result = execute_admin_command(collection, {"setParameter": 1, "logComponentVerbosity": "abc"}) @@ -91,9 +85,6 @@ def test_setParameter_hierarchical_unknown_component_fails(collection): assertFailureCode(result, BAD_VALUE_ERROR, msg="Unknown component should fail") -# --- Multi-Member Set and Atomic Rejection --- - - def test_setParameter_hierarchical_multi_member_set(collection): """Test setting several nested members in one command succeeds.""" execute_admin_command( From 64deef06832fdbbcc4483a14e2131f49de47871a Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:30:16 -0700 Subject: [PATCH 3/9] convert to CommandTestCase Signed-off-by: Alina (Xi) Li --- .../test_setParameter_argument_validation.py | 225 +++++++++++------- .../setParameter/test_setParameter_errors.py | 148 +++++++----- 2 files changed, 233 insertions(+), 140 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py index ceed04114..2a5a5a3b3 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -7,17 +7,27 @@ import pytest from bson import Int64 -from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, +) +from documentdb_tests.framework.assertions import ( + assertFailureCode, + assertResult, + assertSuccessPartial, +) from documentdb_tests.framework.error_codes import ( INVALID_OPTIONS_ERROR, OVERFLOW_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] +# Property [Control Field Type]: setParameter control field accepts various BSON types. @pytest.mark.parametrize( "control_value,desc", [ @@ -36,131 +46,182 @@ def test_setParameter_control_field_type(collection, control_value, desc): """Test setParameter control field accepts various BSON types.""" result = execute_admin_command(collection, {"setParameter": control_value, "logLevel": 0}) - assertSuccessPartial(result, {"ok": 1.0}, msg=f"Control field should accept {desc}") - - -def test_setParameter_known_param_succeeds(collection): - """Test a known runtime parameter name succeeds.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Known param should succeed") - - -def test_setParameter_case_sensitive_name(collection): - """Test parameter names are case-sensitive (altered case fails).""" - result = execute_admin_command(collection, {"setParameter": 1, "LogLevel": 0}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Wrong case should fail") - - -def test_setParameter_long_param_name_fails(collection): - """Test very long parameter name (1000+ chars) fails as unknown.""" - result = execute_admin_command(collection, {"setParameter": 1, "a" * 1000: 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Long name should fail") - - -def test_setParameter_dotted_param_name_fails(collection): - """Test parameter name containing dots fails as unknown.""" - result = execute_admin_command(collection, {"setParameter": 1, "log.level": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Dotted name should fail") + assertSuccessPartial( + result, {"ok": 1.0}, msg=f"setParameter control field should accept {desc}" + ) -def test_setParameter_dollar_param_name_fails(collection): - """Test parameter name with dollar sign fails as unknown.""" - result = execute_admin_command(collection, {"setParameter": 1, "$logLevel": 1}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Dollar name should fail") +# Property [Name Acceptance]: setParameter accepts known runtime parameter names. +NAME_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "known_param", + command=lambda ctx: {"setParameter": 1, "logLevel": 0}, + expected={"ok": 1.0}, + msg="setParameter should accept known runtime param", + ), + CommandTestCase( + "control_field_int64_max", + command=lambda ctx: {"setParameter": Int64(9_223_372_036_854_775_807), "logLevel": 0}, + expected={"ok": 1.0}, + msg="setParameter should accept Int64 max as control field value", + ), +] + + +# Property [Name Rejection]: setParameter rejects invalid parameter names. +NAME_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "case_sensitive", + command=lambda ctx: {"setParameter": 1, "LogLevel": 0}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject wrong-case param name", + ), + CommandTestCase( + "long_name", + command=lambda ctx: {"setParameter": 1, "a" * 1000: 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject very long param name", + ), + CommandTestCase( + "dotted_name", + command=lambda ctx: {"setParameter": 1, "log.level": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject dotted param name", + ), + CommandTestCase( + "dollar_name", + command=lambda ctx: {"setParameter": 1, "$logLevel": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject dollar-prefixed param name", + ), + CommandTestCase( + "whitespace_name", + command=lambda ctx: {"setParameter": 1, " logLevel ": 0}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject whitespace in param name", + ), + CommandTestCase( + "numeric_string_name", + command=lambda ctx: {"setParameter": 1, "12345": 0}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject numeric string param name", + ), +] + + +# Property [Value Type Rejection]: setParameter rejects invalid value types for typed params. +VALUE_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "string_param_with_numeric", + command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": 12345}, + error_code=TYPE_MISMATCH_ERROR, + msg="setParameter should reject numeric value for string param", + ), + CommandTestCase( + "string_param_overlength", + command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": "x" * 65}, + error_code=OVERFLOW_ERROR, + msg="setParameter should reject over-length string value", + ), +] + +ARGUMENT_REJECTION_TESTS = NAME_REJECTION_TESTS + VALUE_TYPE_REJECTION_TESTS + + +@pytest.mark.parametrize("test", pytest_params(NAME_ACCEPTANCE_TESTS)) +def test_setParameter_name_accepted(database_client, collection, test): + """Test setParameter accepts valid parameter names.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_admin_command(collection, test.build_command(ctx)) + assertSuccessPartial(result, test.build_expected(ctx), msg=test.msg) + + +@pytest.mark.parametrize("test", pytest_params(ARGUMENT_REJECTION_TESTS)) +def test_setParameter_argument_rejected(database_client, collection, test): + """Test setParameter rejects invalid arguments.""" + 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, + ) +# Property [Boolean Coercion]: boolean-typed parameters accept bool and numeric coercion. def test_setParameter_boolean_param_with_bool_succeeds(collection): - """Test a boolean-typed parameter set with a boolean value succeeds.""" + """Test setParameter accepts boolean value for boolean-typed param.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) result = execute_admin_command(collection, {"setParameter": 1, "quiet": True}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Boolean value should succeed for boolean param") + assertSuccessPartial( + result, {"ok": 1.0}, msg="setParameter should accept bool for boolean param" + ) execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) def test_setParameter_boolean_param_with_int_coerces(collection): - """Test a boolean-typed parameter set with integer coerces (1 -> true).""" + """Test setParameter coerces integer to boolean for boolean-typed param.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) result = execute_admin_command(collection, {"setParameter": 1, "quiet": 1}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Int should coerce to bool") + assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should coerce int to bool") execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) +# Property [Integer Coercion]: integer-typed parameters accept numeric coercion. def test_setParameter_integer_param_with_int_succeeds(collection): - """Test an integer-typed parameter set with an integer value succeeds.""" + """Test setParameter accepts integer for integer-typed param.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Int value should succeed for int param") + assertSuccessPartial( + result, {"ok": 1.0}, msg="setParameter should accept int for integer param" + ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) def test_setParameter_integer_param_with_whole_double_succeeds(collection): - """Test an integer-typed parameter set with a whole-number double succeeds.""" + """Test setParameter accepts whole-number double for integer-typed param.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.0}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Whole double should succeed for int param") + assertSuccessPartial( + result, {"ok": 1.0}, msg="setParameter should accept whole double for integer param" + ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) def test_setParameter_integer_param_with_fractional_double_coerces(collection): - """Test an integer-typed parameter set with a fractional double truncates to integer.""" + """Test setParameter truncates fractional double for integer-typed param.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.5}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Fractional double should truncate for int param") + assertSuccessPartial( + result, {"ok": 1.0}, msg="setParameter should truncate fractional double for integer param" + ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) def test_setParameter_integer_param_valid_range(collection): - """Test an integer parameter at valid bounds succeeds (logLevel 0 and 5).""" + """Test setParameter accepts integer at valid upper bound.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 5}) - assertSuccessPartial(result, {"ok": 1.0}, msg="logLevel 5 should succeed") - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - -def test_setParameter_string_param_with_numeric_fails(collection): - """Test setting a string-typed parameter to a numeric value fails.""" - result = execute_admin_command( - collection, {"setParameter": 1, "automationServiceDescriptor": 12345} - ) - assertFailureCode(result, TYPE_MISMATCH_ERROR, msg="Numeric value should fail for string param") - - -def test_setParameter_string_param_overlength_fails(collection): - """Test setting a string-typed parameter to an over-length string fails with Overflow.""" - result = execute_admin_command( - collection, {"setParameter": 1, "automationServiceDescriptor": "x" * 65} + assertSuccessPartial( + result, {"ok": 1.0}, msg="setParameter should accept logLevel at upper bound" ) - assertFailureCode(result, OVERFLOW_ERROR, msg="Over-length string should fail") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) +# Property [String Param Acceptance]: string-typed parameters accept valid strings. def test_setParameter_string_param_valid_succeeds(collection): - """Test setting a string-typed parameter to a short valid string succeeds.""" + """Test setParameter accepts valid short string for string-typed param.""" result = execute_admin_command( collection, {"setParameter": 1, "automationServiceDescriptor": "test"} ) - assertSuccessPartial(result, {"ok": 1.0}, msg="Valid short string should succeed") + assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should accept valid string value") execute_admin_command(collection, {"setParameter": 1, "automationServiceDescriptor": ""}) -def test_setParameter_whitespace_param_name_fails(collection): - """Test parameter name with leading/trailing whitespace fails as unknown.""" - result = execute_admin_command(collection, {"setParameter": 1, " logLevel ": 0}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Whitespace name should fail") - - -def test_setParameter_numeric_string_param_name_fails(collection): - """Test numeric-looking string parameter name fails as unknown.""" - result = execute_admin_command(collection, {"setParameter": 1, "12345": 0}) - assertFailureCode(result, INVALID_OPTIONS_ERROR, msg="Numeric string name should fail") - - -def test_setParameter_control_field_int64_max(collection): - """Test control field with Int64 max value is accepted.""" - result = execute_admin_command( - collection, {"setParameter": Int64(9223372036854775807), "logLevel": 0} - ) - assertSuccessPartial(result, {"ok": 1.0}, msg="Int64 max control field should be accepted") - - +# Property [Name Collision]: parameter name matching control field name fails. def test_setParameter_name_collides_with_control_field(collection): - """Test parameter name 'setParameter' (same as control field) fails.""" + """Test setParameter rejects param name that collides with control field.""" result = execute_admin_command(collection, {"setParameter": 1, "setParameter": 2}) # noqa: F601 assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="Name collision with control field should fail" + result, INVALID_OPTIONS_ERROR, msg="setParameter should reject name collision" ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index 254629788..07f0fde79 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -6,70 +6,112 @@ import pytest -from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +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.error_codes import ( BAD_VALUE_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, pytest.mark.no_parallel] -def test_setParameter_nonexistent_param_error_code(collection): - """Test setting a non-existent parameter returns InvalidOptions.""" - result = execute_admin_command(collection, {"setParameter": 1, "nonExistentXYZ": 1}) - assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="setParameter should reject non-existent param" - ) - - -def test_setParameter_startup_only_param_error_code(collection): - """Test setting a startup-only parameter at runtime returns InvalidOptions.""" - result = execute_admin_command(collection, {"setParameter": 1, "port": 27018}) - assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="setParameter should reject startup-only param" - ) - - -def test_setParameter_out_of_range_error_code(collection): - """Test setting a parameter to an out-of-range value returns BadValue.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": -1}) - assertFailureCode(result, BAD_VALUE_ERROR, msg="setParameter should reject out-of-range value") - - -def test_setParameter_wrong_type_error_code(collection): - """Test setting a parameter to a wrong-type value returns BadValue.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": "abc"}) - assertFailureCode(result, BAD_VALUE_ERROR, msg="setParameter should reject wrong type value") - - -def test_setParameter_non_admin_db_error_code(collection): - """Test running setParameter on a non-admin database returns Unauthorized.""" - result = execute_command(collection, {"setParameter": 1, "logLevel": 0}) - assertFailureCode( - result, UNAUTHORIZED_ERROR, msg="setParameter should reject non-admin database" - ) - - -def test_setParameter_empty_name_error_code(collection): - """Test empty-string parameter name returns InvalidOptions.""" - result = execute_admin_command(collection, {"setParameter": 1, "": 1}) - assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="setParameter should reject empty param name" +# Property [Error Codes]: setParameter returns correct error codes for invalid inputs. +ERROR_CODE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "nonexistent_param", + command=lambda ctx: {"setParameter": 1, "nonExistentXYZ": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject non-existent param", + ), + CommandTestCase( + "startup_only_param", + command=lambda ctx: {"setParameter": 1, "port": 27018}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject startup-only param", + ), + CommandTestCase( + "out_of_range_value", + command=lambda ctx: {"setParameter": 1, "logLevel": -1}, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject out-of-range value", + ), + CommandTestCase( + "wrong_type_value", + command=lambda ctx: {"setParameter": 1, "logLevel": "abc"}, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject wrong type value", + ), + CommandTestCase( + "empty_param_name", + command=lambda ctx: {"setParameter": 1, "": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject empty param name", + ), + CommandTestCase( + "no_param_pair", + command=lambda ctx: {"setParameter": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject missing param pair", + ), + CommandTestCase( + "multi_param_with_invalid", + command=lambda ctx: {"setParameter": 1, "logLevel": 0, "nonExistentXYZ": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject multi-param command when one is invalid", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(ERROR_CODE_TESTS)) +def test_setParameter_errors(database_client, collection, test): + """Test setParameter error cases.""" + 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, ) -def test_setParameter_no_param_pair_fails(collection): - """Test setParameter with control field but no parameter:value pair fails.""" - result = execute_admin_command(collection, {"setParameter": 1}) - assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="setParameter should reject missing param pair" +# Property [Non-Admin Rejection]: setParameter fails on non-admin database. +NON_ADMIN_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "non_admin_db", + command=lambda ctx: {"setParameter": 1, "logLevel": 0}, + error_code=UNAUTHORIZED_ERROR, + msg="setParameter should reject non-admin database", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(NON_ADMIN_TESTS)) +def test_setParameter_non_admin_db(database_client, collection, test): + """Test setParameter fails on non-admin database.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_command(collection, test.build_command(ctx)) + assertResult( + result, + expected=test.build_expected(ctx), + error_code=test.error_code, + msg=test.msg, + raw_res=True, ) -def test_setParameter_multi_param_second_invalid_is_atomic(collection): +# Property [Atomicity]: multi-parameter set is atomic on failure. +def test_setParameter_multi_param_atomic_on_failure(collection): """Test multi-parameter command with invalid second param does not apply first.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) execute_admin_command(collection, {"setParameter": 1, "logLevel": 3, "nonExistentXYZ": 1}) @@ -77,13 +119,3 @@ def test_setParameter_multi_param_second_invalid_is_atomic(collection): assertSuccessPartial( result, {"logLevel": 0}, msg="First param should not be applied when second fails" ) - - -def test_setParameter_multi_param_invalid_returns_error(collection): - """Test multi-parameter command with invalid param returns error code.""" - result = execute_admin_command( - collection, {"setParameter": 1, "logLevel": 0, "nonExistentXYZ": 1} - ) - assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="Multi-param with invalid should return 72" - ) From 8919a25c3e40d4241acf688374e39355252f1bdc Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:37:57 -0700 Subject: [PATCH 4/9] add comments explain why tests are standalone Signed-off-by: Alina (Xi) Li --- .../setParameter/test_setParameter_argument_validation.py | 3 +++ .../commands/setParameter/test_setParameter_core_behavior.py | 3 +++ .../commands/setParameter/test_setParameter_errors.py | 1 + .../setParameter/test_setParameter_hierarchical_params.py | 3 +++ 4 files changed, 10 insertions(+) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py index 2a5a5a3b3..b5948be0c 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -152,6 +152,9 @@ def test_setParameter_argument_rejected(database_client, collection, test): ) +# Standalone tests below require save/restore of server state after each set. + + # Property [Boolean Coercion]: boolean-typed parameters accept bool and numeric coercion. def test_setParameter_boolean_param_with_bool_succeeds(collection): """Test setParameter accepts boolean value for boolean-typed param.""" diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py index 97ee31347..201e2410e 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py @@ -3,6 +3,9 @@ Validates single/multiple parameter modification, admin database requirement, runtime vs startup-only parameters, command shape, response structure, and getParameter interaction. + +Tests are standalone functions because each modifies server state and must +save/restore original values. """ import pytest diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index 07f0fde79..5ee55a767 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -111,6 +111,7 @@ def test_setParameter_non_admin_db(database_client, collection, test): # Property [Atomicity]: multi-parameter set is atomic on failure. +# Standalone because it requires multi-step state verification. def test_setParameter_multi_param_atomic_on_failure(collection): """Test multi-parameter command with invalid second param does not apply first.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py index 8bf79277b..c364ce360 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py @@ -3,6 +3,9 @@ Validates logComponentVerbosity nested parameter behavior including read defaults, type/member validation, multi-member set, atomic rejection, and bare numeric form. + +Tests are standalone functions because each modifies server state and must +save/restore original values. """ import pytest From ddaaf981818d518b30d020abc8d073919528bc5c Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:42:12 -0700 Subject: [PATCH 5/9] partially convert what can be converted Signed-off-by: Alina (Xi) Li --- .../test_setParameter_bson_type_validation.py | 4 + .../test_setParameter_core_behavior.py | 166 +++++++++------ .../test_setParameter_hierarchical_params.py | 189 ++++++++++-------- 3 files changed, 215 insertions(+), 144 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py index 90a85fae9..668aff491 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py @@ -19,6 +19,7 @@ pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] +# Property [Control Field Acceptance]: setParameter control field accepts all BSON types. CONTROL_FIELD_PARAM = [ BsonTypeTestCase( id="setParameter_control", @@ -39,6 +40,7 @@ def test_setParameter_control_field_bson_type_accepted(collection, bson_type, sa assertSuccessPartial(result, {"ok": 1.0}, msg=f"{spec.msg} (bson_type={bson_type.value})") +# Property [Boolean Coercion]: boolean-typed params accept many BSON types via coercion. @pytest.mark.parametrize( "value,desc", [ @@ -76,6 +78,7 @@ def test_setParameter_boolean_coercion_accepted(collection, value, desc): execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) +# Property [Integer Coercion Accepted]: integer-typed params accept whole-number numerics. @pytest.mark.parametrize( "value,desc", [ @@ -94,6 +97,7 @@ def test_setParameter_integer_coercion_accepted(collection, value, desc): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) +# Property [Integer Coercion Rejected]: integer-typed params reject non-numeric types. @pytest.mark.parametrize( "value,error_code,desc", [ diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py index 201e2410e..4380f6600 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py @@ -3,27 +3,63 @@ Validates single/multiple parameter modification, admin database requirement, runtime vs startup-only parameters, command shape, response structure, and getParameter interaction. - -Tests are standalone functions because each modifies server state and must -save/restore original values. """ import pytest -from documentdb_tests.framework.assertions import ( - assertSuccessPartial, +from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( + CommandContext, + CommandTestCase, ) +from documentdb_tests.framework.assertions import assertSuccessPartial 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 [Command Acceptance]: setParameter accepts valid commands on admin db. +COMMAND_ACCEPTANCE_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "admin_db_succeeds", + command=lambda ctx: {"setParameter": 1, "logLevel": 0}, + expected={"ok": 1.0}, + msg="setParameter should succeed on admin db", + ), + CommandTestCase( + "runtime_param_succeeds", + command=lambda ctx: {"setParameter": 1, "logLevel": 0}, + expected={"ok": 1.0}, + msg="setParameter should succeed for runtime-settable param", + ), + CommandTestCase( + "comment_field_accepted", + command=lambda ctx: {"setParameter": 1, "logLevel": 0, "comment": "test"}, + expected={"ok": 1.0}, + msg="setParameter should accept comment field alongside params", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(COMMAND_ACCEPTANCE_TESTS)) +def test_setParameter_accepted(database_client, collection, test): + """Test setParameter command acceptance cases.""" + collection = test.prepare(database_client, collection) + ctx = CommandContext.from_collection(collection) + result = execute_admin_command(collection, test.build_command(ctx)) + assertSuccessPartial(result, test.build_expected(ctx), msg=test.msg) + + +# Standalone tests below require save/restore of server state after each set. + + +# Property [Response Structure]: setParameter returns ok:1 and previous value in 'was'. def test_setParameter_single_param_returns_ok(collection): """Test setParameter with one runtime-settable parameter returns ok:1.""" original = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) original_val = original["logLevel"] result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Should return ok:1") + assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should return ok:1") execute_admin_command(collection, {"setParameter": 1, "logLevel": original_val}) @@ -31,116 +67,116 @@ def test_setParameter_returns_was_field(collection): """Test setParameter response includes the previous value in 'was' field.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 2}) - assertSuccessPartial(result, {"ok": 1.0, "was": 0}, msg="Should report previous value in 'was'") - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - -def test_setParameter_actually_changes_value(collection): - """Test setParameter actually changes the parameter value verified via getParameter.""" - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 3}) - result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) - assertSuccessPartial(result, {"logLevel": 3}, msg="Should reflect new value via getParameter") - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - -def test_setParameter_idempotent_set(collection): - """Test setting a parameter to its current value returns ok:1 with was equal to new value.""" - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - assertSuccessPartial(result, {"ok": 1.0, "was": 0}, msg="Idempotent set should succeed") - - -def test_setParameter_two_params_returns_ok(collection): - """Test setParameter with two runtime-settable parameters in one command sets both.""" - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1, "quiet": True}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Should set both parameters") - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) - - -def test_setParameter_on_admin_db_succeeds(collection): - """Test setParameter run against the admin database succeeds.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Should succeed on admin db") - - -def test_setParameter_runtime_param_succeeds(collection): - """Test setParameter on a runtime-settable parameter succeeds.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Runtime param should succeed") - - -def test_setParameter_comment_field_accepted(collection): - """Test comment field accepted alongside setParameter.""" - result = execute_admin_command( - collection, {"setParameter": 1, "logLevel": 0, "comment": "test comment"} + assertSuccessPartial( + result, {"ok": 1.0, "was": 0}, msg="setParameter should report previous value in 'was'" ) - assertSuccessPartial(result, {"ok": 1.0}, msg="Comment field should be accepted") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) def test_setParameter_success_was_type_matches_param(collection): - """Test the 'was' field type matches the parameter's declared type (integer for logLevel).""" + """Test setParameter 'was' field type matches the parameter's declared type.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) assertSuccessPartial( - result, {"ok": 1.0, "was": 0}, msg="'was' should be integer type matching logLevel" + result, {"ok": 1.0, "was": 0}, msg="setParameter 'was' should be integer for logLevel" ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) def test_setParameter_boolean_was_type(collection): - """Test the 'was' field for a boolean parameter is boolean type.""" + """Test setParameter 'was' field for a boolean parameter is boolean type.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) execute_admin_command(collection, {"setParameter": 1, "quiet": False}) result = execute_admin_command(collection, {"setParameter": 1, "quiet": True}) - assertSuccessPartial(result, {"ok": 1.0, "was": False}, msg="'was' should be boolean type") + assertSuccessPartial( + result, {"ok": 1.0, "was": False}, msg="setParameter 'was' should be boolean for quiet" + ) execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) +# Property [Value Persistence]: setParameter changes are reflected in getParameter. +def test_setParameter_actually_changes_value(collection): + """Test setParameter changes are reflected via getParameter.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 3}) + result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) + assertSuccessPartial( + result, {"logLevel": 3}, msg="setParameter should reflect new value via getParameter" + ) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + + def test_setParameter_getParameter_reflects_new_value(collection): - """Test getParameter reflects new value immediately after successful setParameter.""" + """Test setParameter getParameter reflects new value immediately.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) execute_admin_command(collection, {"setParameter": 1, "logLevel": 4}) result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) - assertSuccessPartial(result, {"logLevel": 4}, msg="getParameter should reflect new value") + assertSuccessPartial( + result, {"logLevel": 4}, msg="setParameter should reflect new value immediately" + ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) def test_setParameter_getParameter_unchanged_after_failure(collection): - """Test getParameter is unchanged after a failed setParameter.""" + """Test setParameter getParameter is unchanged after a failed set.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) execute_admin_command(collection, {"setParameter": 1, "logLevel": "invalid"}) result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) - assertSuccessPartial(result, {"logLevel": 0}, msg="Value should be unchanged after failure") + assertSuccessPartial( + result, {"logLevel": 0}, msg="setParameter should leave value unchanged after failure" + ) +# Property [Idempotency]: setting a parameter to its current value succeeds. +def test_setParameter_idempotent_set(collection): + """Test setParameter setting a parameter to its current value returns ok:1.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + assertSuccessPartial( + result, {"ok": 1.0, "was": 0}, msg="setParameter should succeed idempotently" + ) + + +# Property [Multiple Parameters]: setParameter sets multiple params in one command. +def test_setParameter_two_params_returns_ok(collection): + """Test setParameter with two params in one command sets both.""" + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) + result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1, "quiet": True}) + assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should set both parameters") + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) + + +# Property [Round Trip]: value can be restored via 'was' field. def test_setParameter_round_trip_restore(collection): - """Test round-trip: read, set new, restore original via 'was' field.""" + """Test setParameter round-trip: set new, restore via 'was' field.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) set_result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 3}) original_val = set_result["was"] execute_admin_command(collection, {"setParameter": 1, "logLevel": original_val}) result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) - assertSuccessPartial(result, {"logLevel": 0}, msg="Should restore to original") + assertSuccessPartial(result, {"logLevel": 0}, msg="setParameter should restore to original") +# Property [Boolean Toggle]: boolean-typed parameters toggle correctly. def test_setParameter_boolean_toggle(collection): - """Test setting a boolean-typed parameter to false and reading back.""" + """Test setParameter boolean-typed parameter toggles correctly.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) execute_admin_command(collection, {"setParameter": 1, "quiet": False}) result = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) - assertSuccessPartial(result, {"quiet": False}, msg="Boolean param should be False") + assertSuccessPartial(result, {"quiet": False}, msg="setParameter boolean should be False") execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) +# Property [Ordering Independence]: parameter order in command does not affect result. def test_setParameter_ordering_independence(collection): - """Test setting {logLevel, quiet} vs {quiet, logLevel} yields same final state.""" + """Test setParameter parameter order in command does not affect result.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) execute_admin_command(collection, {"setParameter": 1, "logLevel": 2, "quiet": True}) state1 = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) execute_admin_command(collection, {"setParameter": 1, "quiet": True, "logLevel": 2}) state2 = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) - assertSuccessPartial(state2, {"logLevel": state1["logLevel"]}, msg="Order should not matter") + assertSuccessPartial( + state2, {"logLevel": state1["logLevel"]}, msg="setParameter order should not matter" + ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0, "quiet": False}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py index c364ce360..e2372d17c 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py @@ -3,93 +3,131 @@ Validates logComponentVerbosity nested parameter behavior including read defaults, type/member validation, multi-member set, atomic rejection, and bare numeric form. - -Tests are standalone functions because each modifies server state and must -save/restore original values. """ import pytest -from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +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.error_codes import BAD_VALUE_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] -def test_setParameter_hierarchical_param_readable(collection): - """Test reading logComponentVerbosity returns a defined value.""" - result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) - assertSuccessPartial(result, {"ok": 1.0}, msg="Should be able to read hierarchical param") +# Property [Type Rejection]: logComponentVerbosity rejects invalid types and values. +HIERARCHICAL_ERROR_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "string_value", + command=lambda ctx: {"setParameter": 1, "logComponentVerbosity": "abc"}, + error_code=TYPE_MISMATCH_ERROR, + msg="setParameter should reject string for logComponentVerbosity", + ), + CommandTestCase( + "nested_string_verbosity", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": "abc"}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject string for nested verbosity", + ), + CommandTestCase( + "nested_overflow", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": 2_147_483_648}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject overflow for nested verbosity", + ), + CommandTestCase( + "nested_underflow", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": -2_147_483_649}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject underflow for nested verbosity", + ), + CommandTestCase( + "unknown_component", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"unknownComponent": {"verbosity": 1}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject unknown component name", + ), + CommandTestCase( + "nested_nan_verbosity", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": float("nan")}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject NaN for nested verbosity", + ), +] + + +@pytest.mark.parametrize("test", pytest_params(HIERARCHICAL_ERROR_TESTS)) +def test_setParameter_hierarchical_errors(database_client, collection, test): + """Test setParameter hierarchical parameter error cases.""" + 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, + ) -def test_setParameter_hierarchical_top_level_verbosity(collection): - """Test top-level verbosity of hierarchical parameter matches scalar logLevel default.""" - execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - result2 = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) +# Property [Readability]: logComponentVerbosity is readable with defined defaults. +def test_setParameter_hierarchical_param_readable(collection): + """Test setParameter reading logComponentVerbosity returns a defined value.""" + result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) assertSuccessPartial( - result2, - {"logComponentVerbosity": {"verbosity": 0}}, - msg="Top-level verbosity should match logLevel", + result, {"ok": 1.0}, msg="setParameter should be able to read hierarchical param" ) def test_setParameter_hierarchical_nested_field_defined(collection): - """Test a deeply nested verbosity field is defined.""" + """Test setParameter deeply nested verbosity field is defined.""" result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) - # network.asio is a deeply nested component assertSuccessPartial( result, {"logComponentVerbosity": {"network": {"asio": {"verbosity": -1}}}}, - msg="Nested component should have defined verbosity", - ) - - -def test_setParameter_hierarchical_string_value_fails(collection): - """Test setting logComponentVerbosity to a plain string fails with TypeMismatch.""" - result = execute_admin_command(collection, {"setParameter": 1, "logComponentVerbosity": "abc"}) - assertFailureCode(result, TYPE_MISMATCH_ERROR, msg="String should fail for object param") - - -def test_setParameter_hierarchical_nested_string_verbosity_fails(collection): - """Test setting a nested verbosity member to a non-numeric string fails.""" - result = execute_admin_command( - collection, - {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": "abc"}}}, + msg="setParameter nested component should have defined verbosity", ) - assertFailureCode(result, BAD_VALUE_ERROR, msg="String verbosity should fail") -def test_setParameter_hierarchical_nested_overflow_fails(collection): - """Test setting a nested verbosity member above max safe integer fails.""" - result = execute_admin_command( - collection, - {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": 2147483648}}}, - ) - assertFailureCode(result, BAD_VALUE_ERROR, msg="Overflow verbosity should fail") +# Standalone tests below require save/restore of server state after each set. -def test_setParameter_hierarchical_nested_underflow_fails(collection): - """Test setting a nested verbosity member below min safe integer fails.""" - result = execute_admin_command( - collection, - {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -2147483649}}}, - ) - assertFailureCode(result, BAD_VALUE_ERROR, msg="Underflow verbosity should fail") - - -def test_setParameter_hierarchical_unknown_component_fails(collection): - """Test setting an unrecognized nested component name fails.""" - result = execute_admin_command( - collection, - {"setParameter": 1, "logComponentVerbosity": {"unknownComponent": {"verbosity": 1}}}, +# Property [Top-Level Verbosity]: top-level verbosity matches scalar logLevel. +def test_setParameter_hierarchical_top_level_verbosity(collection): + """Test setParameter top-level verbosity matches scalar logLevel default.""" + execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) + result2 = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) + assertSuccessPartial( + result2, + {"logComponentVerbosity": {"verbosity": 0}}, + msg="setParameter top-level verbosity should match logLevel", ) - assertFailureCode(result, BAD_VALUE_ERROR, msg="Unknown component should fail") +# Property [Multi-Member Set]: setting several nested members in one command succeeds. def test_setParameter_hierarchical_multi_member_set(collection): - """Test setting several nested members in one command succeeds.""" + """Test setParameter setting several nested members in one command succeeds.""" execute_admin_command( collection, { @@ -104,8 +142,7 @@ def test_setParameter_hierarchical_multi_member_set(collection): "logComponentVerbosity": {"command": {"verbosity": 2}, "network": {"verbosity": 3}}, }, ) - assertSuccessPartial(result, {"ok": 1.0}, msg="Multi-member set should succeed") - # Cleanup + assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter multi-member set should succeed") execute_admin_command( collection, { @@ -115,8 +152,9 @@ def test_setParameter_hierarchical_multi_member_set(collection): ) +# Property [Multi-Member Readback]: reading back reflects each member set. def test_setParameter_hierarchical_multi_member_readback(collection): - """Test reading back reflects each member set in a multi-member command.""" + """Test setParameter reading back reflects each member set in a multi-member command.""" execute_admin_command( collection, { @@ -128,9 +166,8 @@ def test_setParameter_hierarchical_multi_member_readback(collection): assertSuccessPartial( read_result, {"logComponentVerbosity": {"command": {"verbosity": 2}, "network": {"verbosity": 3}}}, - msg="Both members should be set", + msg="setParameter should reflect both members after set", ) - # Cleanup execute_admin_command( collection, { @@ -140,8 +177,9 @@ def test_setParameter_hierarchical_multi_member_readback(collection): ) +# Property [Atomic Rejection]: no members change when a multi-member set is rejected. def test_setParameter_hierarchical_atomic_rejection(collection): - """Test no members are changed when a multi-member set is rejected.""" + """Test setParameter no members are changed when a multi-member set is rejected.""" execute_admin_command( collection, {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, @@ -157,12 +195,13 @@ def test_setParameter_hierarchical_atomic_rejection(collection): assertSuccessPartial( result, {"logComponentVerbosity": {"command": {"verbosity": -1}}}, - msg="Command verbosity should remain unchanged after atomic rejection", + msg="setParameter should not change any member on atomic rejection", ) +# Property [Clear With Negative]: setting -1 resets to inherited default. def test_setParameter_hierarchical_clear_with_negative(collection): - """Test clearing nested members with -1 resets them to inherited default.""" + """Test setParameter clearing nested members with -1 resets to inherited default.""" execute_admin_command( collection, {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": 3}}}, @@ -175,16 +214,17 @@ def test_setParameter_hierarchical_clear_with_negative(collection): assertSuccessPartial( result, {"logComponentVerbosity": {"command": {"verbosity": -1}}}, - msg="Cleared member should fall back to -1 (inherited)", + msg="setParameter should reset member to -1 (inherited) after clear", ) +# Property [Bare Numeric Form]: setting component with bare numeric level succeeds. def test_setParameter_hierarchical_bare_numeric_form(collection): - """Test setting a nested component verbosity using bare numeric level succeeds.""" + """Test setParameter setting nested component with bare numeric level succeeds.""" result = execute_admin_command( collection, {"setParameter": 1, "logComponentVerbosity": {"command": 4}} ) - assertSuccessPartial(result, {"ok": 1.0}, msg="Bare numeric form should succeed") + assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should accept bare numeric form") execute_admin_command( collection, {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, @@ -192,24 +232,15 @@ def test_setParameter_hierarchical_bare_numeric_form(collection): def test_setParameter_hierarchical_bare_numeric_readback(collection): - """Test bare numeric component set takes effect when read back.""" + """Test setParameter bare numeric component set takes effect when read back.""" execute_admin_command(collection, {"setParameter": 1, "logComponentVerbosity": {"command": 4}}) read_result = execute_admin_command(collection, {"getParameter": 1, "logComponentVerbosity": 1}) assertSuccessPartial( read_result, {"logComponentVerbosity": {"command": {"verbosity": 4}}}, - msg="Bare numeric should set verbosity", + msg="setParameter bare numeric should set verbosity", ) execute_admin_command( collection, {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": -1}}}, ) - - -def test_setParameter_hierarchical_nested_nan_verbosity_fails(collection): - """Test setting a nested verbosity member to NaN fails with BadValue.""" - result = execute_admin_command( - collection, - {"setParameter": 1, "logComponentVerbosity": {"command": {"verbosity": float("nan")}}}, - ) - assertFailureCode(result, BAD_VALUE_ERROR, msg="NaN verbosity should fail") From cce2610999541d1fc50ad8dc27ffdec4902459a1 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:50:17 -0700 Subject: [PATCH 6/9] add missing test Signed-off-by: Alina (Xi) Li --- .../commands/setParameter/test_setParameter_errors.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index 5ee55a767..f19dae1dd 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -18,6 +18,7 @@ ) from documentdb_tests.framework.executor import execute_admin_command, execute_command from documentdb_tests.framework.parametrize import pytest_params +from documentdb_tests.framework.test_constants import INT32_MAX pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] @@ -40,7 +41,13 @@ "out_of_range_value", command=lambda ctx: {"setParameter": 1, "logLevel": -1}, error_code=BAD_VALUE_ERROR, - msg="setParameter should reject out-of-range value", + msg="setParameter should reject out-of-range value below minimum", + ), + CommandTestCase( + "above_max_value", + command=lambda ctx: {"setParameter": 1, "logLevel": INT32_MAX + 1}, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject value exceeding int32 max", ), CommandTestCase( "wrong_type_value", From a4dfe097d22aec935ae2a1128b3795b1a880a469 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:54:29 -0700 Subject: [PATCH 7/9] put success and error cases together Signed-off-by: Alina (Xi) Li --- .../test_setParameter_argument_validation.py | 101 +--------- .../test_setParameter_bson_type_validation.py | 79 +++----- .../setParameter/test_setParameter_errors.py | 175 +++++++++++++++++- .../test_setParameter_hierarchical_params.py | 90 +-------- 4 files changed, 201 insertions(+), 244 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py index b5948be0c..a44ed8371 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -1,7 +1,7 @@ -"""Tests for setParameter argument validation. +"""Tests for setParameter argument validation (success cases). -Validates control field types, parameter name validation, parameter value -type/range validation, and bounded integer parameter behavior. +Validates control field type acceptance, parameter name acceptance, +and parameter value type coercion behavior. """ import pytest @@ -11,16 +11,7 @@ CommandContext, CommandTestCase, ) -from documentdb_tests.framework.assertions import ( - assertFailureCode, - assertResult, - assertSuccessPartial, -) -from documentdb_tests.framework.error_codes import ( - INVALID_OPTIONS_ERROR, - OVERFLOW_ERROR, - TYPE_MISMATCH_ERROR, -) +from documentdb_tests.framework.assertions import assertSuccessPartial from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params @@ -68,66 +59,6 @@ def test_setParameter_control_field_type(collection, control_value, desc): ] -# Property [Name Rejection]: setParameter rejects invalid parameter names. -NAME_REJECTION_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "case_sensitive", - command=lambda ctx: {"setParameter": 1, "LogLevel": 0}, - error_code=INVALID_OPTIONS_ERROR, - msg="setParameter should reject wrong-case param name", - ), - CommandTestCase( - "long_name", - command=lambda ctx: {"setParameter": 1, "a" * 1000: 1}, - error_code=INVALID_OPTIONS_ERROR, - msg="setParameter should reject very long param name", - ), - CommandTestCase( - "dotted_name", - command=lambda ctx: {"setParameter": 1, "log.level": 1}, - error_code=INVALID_OPTIONS_ERROR, - msg="setParameter should reject dotted param name", - ), - CommandTestCase( - "dollar_name", - command=lambda ctx: {"setParameter": 1, "$logLevel": 1}, - error_code=INVALID_OPTIONS_ERROR, - msg="setParameter should reject dollar-prefixed param name", - ), - CommandTestCase( - "whitespace_name", - command=lambda ctx: {"setParameter": 1, " logLevel ": 0}, - error_code=INVALID_OPTIONS_ERROR, - msg="setParameter should reject whitespace in param name", - ), - CommandTestCase( - "numeric_string_name", - command=lambda ctx: {"setParameter": 1, "12345": 0}, - error_code=INVALID_OPTIONS_ERROR, - msg="setParameter should reject numeric string param name", - ), -] - - -# Property [Value Type Rejection]: setParameter rejects invalid value types for typed params. -VALUE_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "string_param_with_numeric", - command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": 12345}, - error_code=TYPE_MISMATCH_ERROR, - msg="setParameter should reject numeric value for string param", - ), - CommandTestCase( - "string_param_overlength", - command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": "x" * 65}, - error_code=OVERFLOW_ERROR, - msg="setParameter should reject over-length string value", - ), -] - -ARGUMENT_REJECTION_TESTS = NAME_REJECTION_TESTS + VALUE_TYPE_REJECTION_TESTS - - @pytest.mark.parametrize("test", pytest_params(NAME_ACCEPTANCE_TESTS)) def test_setParameter_name_accepted(database_client, collection, test): """Test setParameter accepts valid parameter names.""" @@ -137,21 +68,6 @@ def test_setParameter_name_accepted(database_client, collection, test): assertSuccessPartial(result, test.build_expected(ctx), msg=test.msg) -@pytest.mark.parametrize("test", pytest_params(ARGUMENT_REJECTION_TESTS)) -def test_setParameter_argument_rejected(database_client, collection, test): - """Test setParameter rejects invalid arguments.""" - 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, - ) - - # Standalone tests below require save/restore of server state after each set. @@ -219,12 +135,3 @@ def test_setParameter_string_param_valid_succeeds(collection): ) assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should accept valid string value") execute_admin_command(collection, {"setParameter": 1, "automationServiceDescriptor": ""}) - - -# Property [Name Collision]: parameter name matching control field name fails. -def test_setParameter_name_collides_with_control_field(collection): - """Test setParameter rejects param name that collides with control field.""" - result = execute_admin_command(collection, {"setParameter": 1, "setParameter": 2}) # noqa: F601 - assertFailureCode( - result, INVALID_OPTIONS_ERROR, msg="setParameter should reject name collision" - ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py index 668aff491..2a66afe30 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_bson_type_validation.py @@ -1,4 +1,4 @@ -"""Tests for setParameter BSON type validation. +"""Tests for setParameter BSON type validation (success cases). Validates control field acceptance of all BSON types, and type coercion behavior for boolean and integer parameter values. @@ -7,13 +7,12 @@ import pytest from bson import Decimal128, Int64 -from documentdb_tests.framework.assertions import assertFailureCode, assertSuccessPartial +from documentdb_tests.framework.assertions import assertSuccessPartial from documentdb_tests.framework.bson_type_validator import ( BsonType, BsonTypeTestCase, generate_bson_acceptance_test_cases, ) -from documentdb_tests.framework.error_codes import BAD_VALUE_ERROR from documentdb_tests.framework.executor import execute_admin_command pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] @@ -44,37 +43,26 @@ def test_setParameter_control_field_bson_type_accepted(collection, bson_type, sa @pytest.mark.parametrize( "value,desc", [ - (True, "bool True"), - (False, "bool False"), - (1, "int 1"), - (0, "int 0"), - (1.0, "double 1.0"), - (0.0, "double 0.0"), - (Int64(1), "Int64(1)"), - (Int64(0), "Int64(0)"), - ("true", "string 'true'"), - ([True], "array [True]"), - ({"a": True}, "document"), - ], - ids=[ - "true", - "false", - "int1", - "int0", - "double1", - "double0", - "long1", - "long0", - "string", - "array", - "document", + pytest.param(True, "bool True", id="true"), + pytest.param(False, "bool False", id="false"), + pytest.param(1, "int 1", id="int1"), + pytest.param(0, "int 0", id="int0"), + pytest.param(1.0, "double 1.0", id="double1"), + pytest.param(0.0, "double 0.0", id="double0"), + pytest.param(Int64(1), "Int64(1)", id="long1"), + pytest.param(Int64(0), "Int64(0)", id="long0"), + pytest.param("true", "string 'true'", id="string"), + pytest.param([True], "array [True]", id="array"), + pytest.param({"a": True}, "document", id="document"), ], ) def test_setParameter_boolean_coercion_accepted(collection, value, desc): - """Test boolean parameter coercion — MongoDB 8.2 coerces many types to boolean.""" + """Test setParameter boolean parameter coercion.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) result = execute_admin_command(collection, {"setParameter": 1, "quiet": value}) - assertSuccessPartial(result, {"ok": 1.0}, msg=f"Boolean param should accept {desc}") + assertSuccessPartial( + result, {"ok": 1.0}, msg=f"setParameter boolean param should accept {desc}" + ) execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) @@ -82,32 +70,17 @@ def test_setParameter_boolean_coercion_accepted(collection, value, desc): @pytest.mark.parametrize( "value,desc", [ - (1, "int32"), - (Int64(1), "Int64"), - (1.0, "whole double"), - (Decimal128("1"), "Decimal128 whole"), - (True, "bool True"), + pytest.param(1, "int32", id="int32"), + pytest.param(Int64(1), "Int64", id="long"), + pytest.param(1.0, "whole double", id="whole_double"), + pytest.param(Decimal128("1"), "Decimal128 whole", id="decimal128_whole"), + pytest.param(True, "bool True", id="bool"), ], - ids=["int32", "long", "whole_double", "decimal128_whole", "bool"], ) def test_setParameter_integer_coercion_accepted(collection, value, desc): - """Test integer parameter coercion — whole-number numeric types and bool accepted.""" + """Test setParameter integer parameter coercion.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": value}) - assertSuccessPartial(result, {"ok": 1.0}, msg=f"Integer param should accept {desc}") + assertSuccessPartial( + result, {"ok": 1.0}, msg=f"setParameter integer param should accept {desc}" + ) execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - -# Property [Integer Coercion Rejected]: integer-typed params reject non-numeric types. -@pytest.mark.parametrize( - "value,error_code,desc", - [ - ("1", BAD_VALUE_ERROR, "string '1'"), - ([1], BAD_VALUE_ERROR, "array [1]"), - ({"a": 1}, BAD_VALUE_ERROR, "document"), - ], - ids=["string", "array", "document"], -) -def test_setParameter_integer_coercion_rejected(collection, value, error_code, desc): - """Test integer parameter rejects non-numeric types.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": value}) - assertFailureCode(result, error_code, msg=f"Integer param should reject {desc}") diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index f19dae1dd..434d2da90 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -1,7 +1,6 @@ -"""Tests for setParameter error codes and multi-parameter failure semantics. +"""Tests for setParameter error cases. -Validates correct error codes are returned for various failure modes and -that multi-parameter commands behave atomically on failure. +ALL error assertions for setParameter are consolidated in this file. """ import pytest @@ -10,10 +9,16 @@ CommandContext, CommandTestCase, ) -from documentdb_tests.framework.assertions import assertResult, assertSuccessPartial +from documentdb_tests.framework.assertions import ( + assertFailureCode, + assertResult, + assertSuccessPartial, +) from documentdb_tests.framework.error_codes import ( BAD_VALUE_ERROR, INVALID_OPTIONS_ERROR, + OVERFLOW_ERROR, + TYPE_MISMATCH_ERROR, UNAUTHORIZED_ERROR, ) from documentdb_tests.framework.executor import execute_admin_command, execute_command @@ -38,22 +43,22 @@ msg="setParameter should reject startup-only param", ), CommandTestCase( - "out_of_range_value", + "out_of_range_below_min", command=lambda ctx: {"setParameter": 1, "logLevel": -1}, error_code=BAD_VALUE_ERROR, - msg="setParameter should reject out-of-range value below minimum", + msg="setParameter should reject value below minimum", ), CommandTestCase( - "above_max_value", + "above_int32_max", command=lambda ctx: {"setParameter": 1, "logLevel": INT32_MAX + 1}, error_code=BAD_VALUE_ERROR, msg="setParameter should reject value exceeding int32 max", ), CommandTestCase( - "wrong_type_value", + "wrong_type_string_for_int", command=lambda ctx: {"setParameter": 1, "logLevel": "abc"}, error_code=BAD_VALUE_ERROR, - msg="setParameter should reject wrong type value", + msg="setParameter should reject string for integer param", ), CommandTestCase( "empty_param_name", @@ -75,8 +80,149 @@ ), ] +# Property [Name Rejection]: setParameter rejects invalid parameter names. +NAME_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "case_sensitive", + command=lambda ctx: {"setParameter": 1, "LogLevel": 0}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject wrong-case param name", + ), + CommandTestCase( + "long_name", + command=lambda ctx: {"setParameter": 1, "a" * 1000: 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject very long param name", + ), + CommandTestCase( + "dotted_name", + command=lambda ctx: {"setParameter": 1, "log.level": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject dotted param name", + ), + CommandTestCase( + "dollar_name", + command=lambda ctx: {"setParameter": 1, "$logLevel": 1}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject dollar-prefixed param name", + ), + CommandTestCase( + "whitespace_name", + command=lambda ctx: {"setParameter": 1, " logLevel ": 0}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject whitespace in param name", + ), + CommandTestCase( + "numeric_string_name", + command=lambda ctx: {"setParameter": 1, "12345": 0}, + error_code=INVALID_OPTIONS_ERROR, + msg="setParameter should reject numeric string param name", + ), +] + +# Property [Value Type Rejection]: setParameter rejects invalid value types. +VALUE_TYPE_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "string_param_with_numeric", + command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": 12345}, + error_code=TYPE_MISMATCH_ERROR, + msg="setParameter should reject numeric value for string param", + ), + CommandTestCase( + "string_param_overlength", + command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": "x" * 65}, + error_code=OVERFLOW_ERROR, + msg="setParameter should reject over-length string value", + ), +] + +# Property [Hierarchical Type Rejection]: logComponentVerbosity rejects invalid types. +HIERARCHICAL_ERROR_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "hierarchical_string_value", + command=lambda ctx: {"setParameter": 1, "logComponentVerbosity": "abc"}, + error_code=TYPE_MISMATCH_ERROR, + msg="setParameter should reject string for logComponentVerbosity", + ), + CommandTestCase( + "hierarchical_nested_string_verbosity", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": "abc"}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject string for nested verbosity", + ), + CommandTestCase( + "hierarchical_nested_overflow", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": INT32_MAX + 1}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject overflow for nested verbosity", + ), + CommandTestCase( + "hierarchical_nested_underflow", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": -2_147_483_649}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject underflow for nested verbosity", + ), + CommandTestCase( + "hierarchical_unknown_component", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"unknownComponent": {"verbosity": 1}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject unknown component name", + ), + CommandTestCase( + "hierarchical_nested_nan_verbosity", + command=lambda ctx: { + "setParameter": 1, + "logComponentVerbosity": {"command": {"verbosity": float("nan")}}, + }, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject NaN for nested verbosity", + ), +] + +# Property [Integer Coercion Rejected]: integer-typed params reject non-numeric types. +INTEGER_COERCION_REJECTION_TESTS: list[CommandTestCase] = [ + CommandTestCase( + "integer_rejects_string", + command=lambda ctx: {"setParameter": 1, "logLevel": "1"}, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject string for integer param", + ), + CommandTestCase( + "integer_rejects_array", + command=lambda ctx: {"setParameter": 1, "logLevel": [1]}, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject array for integer param", + ), + CommandTestCase( + "integer_rejects_document", + command=lambda ctx: {"setParameter": 1, "logLevel": {"a": 1}}, + error_code=BAD_VALUE_ERROR, + msg="setParameter should reject document for integer param", + ), +] + +ALL_ERROR_TESTS = ( + ERROR_CODE_TESTS + + NAME_REJECTION_TESTS + + VALUE_TYPE_REJECTION_TESTS + + HIERARCHICAL_ERROR_TESTS + + INTEGER_COERCION_REJECTION_TESTS +) + -@pytest.mark.parametrize("test", pytest_params(ERROR_CODE_TESTS)) +@pytest.mark.parametrize("test", pytest_params(ALL_ERROR_TESTS)) def test_setParameter_errors(database_client, collection, test): """Test setParameter error cases.""" collection = test.prepare(database_client, collection) @@ -127,3 +273,12 @@ def test_setParameter_multi_param_atomic_on_failure(collection): assertSuccessPartial( result, {"logLevel": 0}, msg="First param should not be applied when second fails" ) + + +# Property [Name Collision]: parameter name matching control field name fails. +def test_setParameter_name_collides_with_control_field(collection): + """Test setParameter rejects param name that collides with control field.""" + result = execute_admin_command(collection, {"setParameter": 1, "setParameter": 2}) # noqa: F601 + assertFailureCode( + result, INVALID_OPTIONS_ERROR, msg="setParameter should reject name collision" + ) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py index e2372d17c..418fe67bd 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_hierarchical_params.py @@ -1,95 +1,20 @@ -"""Tests for setParameter hierarchical/object parameter handling. +"""Tests for setParameter hierarchical/object parameter handling (success cases). Validates logComponentVerbosity nested parameter behavior including -read defaults, type/member validation, multi-member set, atomic rejection, -and bare numeric form. +read defaults, multi-member set, atomic rejection, and bare numeric form. + +Tests are standalone functions because each modifies server state and must +save/restore original values. """ 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.error_codes import BAD_VALUE_ERROR, TYPE_MISMATCH_ERROR +from documentdb_tests.framework.assertions import assertSuccessPartial 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 [Type Rejection]: logComponentVerbosity rejects invalid types and values. -HIERARCHICAL_ERROR_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "string_value", - command=lambda ctx: {"setParameter": 1, "logComponentVerbosity": "abc"}, - error_code=TYPE_MISMATCH_ERROR, - msg="setParameter should reject string for logComponentVerbosity", - ), - CommandTestCase( - "nested_string_verbosity", - command=lambda ctx: { - "setParameter": 1, - "logComponentVerbosity": {"command": {"verbosity": "abc"}}, - }, - error_code=BAD_VALUE_ERROR, - msg="setParameter should reject string for nested verbosity", - ), - CommandTestCase( - "nested_overflow", - command=lambda ctx: { - "setParameter": 1, - "logComponentVerbosity": {"command": {"verbosity": 2_147_483_648}}, - }, - error_code=BAD_VALUE_ERROR, - msg="setParameter should reject overflow for nested verbosity", - ), - CommandTestCase( - "nested_underflow", - command=lambda ctx: { - "setParameter": 1, - "logComponentVerbosity": {"command": {"verbosity": -2_147_483_649}}, - }, - error_code=BAD_VALUE_ERROR, - msg="setParameter should reject underflow for nested verbosity", - ), - CommandTestCase( - "unknown_component", - command=lambda ctx: { - "setParameter": 1, - "logComponentVerbosity": {"unknownComponent": {"verbosity": 1}}, - }, - error_code=BAD_VALUE_ERROR, - msg="setParameter should reject unknown component name", - ), - CommandTestCase( - "nested_nan_verbosity", - command=lambda ctx: { - "setParameter": 1, - "logComponentVerbosity": {"command": {"verbosity": float("nan")}}, - }, - error_code=BAD_VALUE_ERROR, - msg="setParameter should reject NaN for nested verbosity", - ), -] - - -@pytest.mark.parametrize("test", pytest_params(HIERARCHICAL_ERROR_TESTS)) -def test_setParameter_hierarchical_errors(database_client, collection, test): - """Test setParameter hierarchical parameter error cases.""" - 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, - ) - - # Property [Readability]: logComponentVerbosity is readable with defined defaults. def test_setParameter_hierarchical_param_readable(collection): """Test setParameter reading logComponentVerbosity returns a defined value.""" @@ -109,9 +34,6 @@ def test_setParameter_hierarchical_nested_field_defined(collection): ) -# Standalone tests below require save/restore of server state after each set. - - # Property [Top-Level Verbosity]: top-level verbosity matches scalar logLevel. def test_setParameter_hierarchical_top_level_verbosity(collection): """Test setParameter top-level verbosity matches scalar logLevel default.""" From 4141fb4b0c42a78687223220a7c8ec348647727d Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 15:56:19 -0700 Subject: [PATCH 8/9] remove dups Signed-off-by: Alina (Xi) Li --- .../test_setParameter_argument_validation.py | 75 +------------------ .../test_setParameter_core_behavior.py | 29 +------ .../setParameter/test_setParameter_errors.py | 6 -- 3 files changed, 5 insertions(+), 105 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py index a44ed8371..8767abf40 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -1,7 +1,7 @@ """Tests for setParameter argument validation (success cases). -Validates control field type acceptance, parameter name acceptance, -and parameter value type coercion behavior. +Validates control field Int64 max, parameter value range, and string param acceptance. +Type coercion matrices are in test_setParameter_bson_type_validation.py. """ import pytest @@ -18,38 +18,8 @@ pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] -# Property [Control Field Type]: setParameter control field accepts various BSON types. -@pytest.mark.parametrize( - "control_value,desc", - [ - pytest.param(1, "int 1", id="int"), - pytest.param(1.0, "double 1.0", id="double"), - pytest.param(Int64(1), "Int64", id="long"), - pytest.param(True, "bool true", id="bool"), - pytest.param("1", "string", id="string"), - pytest.param(None, "null", id="null"), - pytest.param([1], "array", id="array"), - pytest.param({"a": 1}, "document", id="document"), - pytest.param(0, "int 0", id="zero"), - pytest.param(-1, "negative int", id="negative"), - ], -) -def test_setParameter_control_field_type(collection, control_value, desc): - """Test setParameter control field accepts various BSON types.""" - result = execute_admin_command(collection, {"setParameter": control_value, "logLevel": 0}) - assertSuccessPartial( - result, {"ok": 1.0}, msg=f"setParameter control field should accept {desc}" - ) - - -# Property [Name Acceptance]: setParameter accepts known runtime parameter names. +# Property [Name Acceptance]: setParameter accepts edge-case control field values. NAME_ACCEPTANCE_TESTS: list[CommandTestCase] = [ - CommandTestCase( - "known_param", - command=lambda ctx: {"setParameter": 1, "logLevel": 0}, - expected={"ok": 1.0}, - msg="setParameter should accept known runtime param", - ), CommandTestCase( "control_field_int64_max", command=lambda ctx: {"setParameter": Int64(9_223_372_036_854_775_807), "logLevel": 0}, @@ -71,44 +41,7 @@ def test_setParameter_name_accepted(database_client, collection, test): # Standalone tests below require save/restore of server state after each set. -# Property [Boolean Coercion]: boolean-typed parameters accept bool and numeric coercion. -def test_setParameter_boolean_param_with_bool_succeeds(collection): - """Test setParameter accepts boolean value for boolean-typed param.""" - original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) - result = execute_admin_command(collection, {"setParameter": 1, "quiet": True}) - assertSuccessPartial( - result, {"ok": 1.0}, msg="setParameter should accept bool for boolean param" - ) - execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) - - -def test_setParameter_boolean_param_with_int_coerces(collection): - """Test setParameter coerces integer to boolean for boolean-typed param.""" - original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) - result = execute_admin_command(collection, {"setParameter": 1, "quiet": 1}) - assertSuccessPartial(result, {"ok": 1.0}, msg="setParameter should coerce int to bool") - execute_admin_command(collection, {"setParameter": 1, "quiet": original["quiet"]}) - - -# Property [Integer Coercion]: integer-typed parameters accept numeric coercion. -def test_setParameter_integer_param_with_int_succeeds(collection): - """Test setParameter accepts integer for integer-typed param.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) - assertSuccessPartial( - result, {"ok": 1.0}, msg="setParameter should accept int for integer param" - ) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - -def test_setParameter_integer_param_with_whole_double_succeeds(collection): - """Test setParameter accepts whole-number double for integer-typed param.""" - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.0}) - assertSuccessPartial( - result, {"ok": 1.0}, msg="setParameter should accept whole double for integer param" - ) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - +# Property [Integer Range]: integer-typed parameters accept values within valid bounds. def test_setParameter_integer_param_with_fractional_double_coerces(collection): """Test setParameter truncates fractional double for integer-typed param.""" result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1.5}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py index 4380f6600..6394d9cf9 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_core_behavior.py @@ -26,12 +26,6 @@ expected={"ok": 1.0}, msg="setParameter should succeed on admin db", ), - CommandTestCase( - "runtime_param_succeeds", - command=lambda ctx: {"setParameter": 1, "logLevel": 0}, - expected={"ok": 1.0}, - msg="setParameter should succeed for runtime-settable param", - ), CommandTestCase( "comment_field_accepted", command=lambda ctx: {"setParameter": 1, "logLevel": 0, "comment": "test"}, @@ -73,16 +67,6 @@ def test_setParameter_returns_was_field(collection): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) -def test_setParameter_success_was_type_matches_param(collection): - """Test setParameter 'was' field type matches the parameter's declared type.""" - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - result = execute_admin_command(collection, {"setParameter": 1, "logLevel": 1}) - assertSuccessPartial( - result, {"ok": 1.0, "was": 0}, msg="setParameter 'was' should be integer for logLevel" - ) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - def test_setParameter_boolean_was_type(collection): """Test setParameter 'was' field for a boolean parameter is boolean type.""" original = execute_admin_command(collection, {"getParameter": 1, "quiet": 1}) @@ -95,7 +79,7 @@ def test_setParameter_boolean_was_type(collection): # Property [Value Persistence]: setParameter changes are reflected in getParameter. -def test_setParameter_actually_changes_value(collection): +def test_setParameter_getParameter_reflects_new_value(collection): """Test setParameter changes are reflected via getParameter.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) execute_admin_command(collection, {"setParameter": 1, "logLevel": 3}) @@ -106,17 +90,6 @@ def test_setParameter_actually_changes_value(collection): execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) -def test_setParameter_getParameter_reflects_new_value(collection): - """Test setParameter getParameter reflects new value immediately.""" - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 4}) - result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1}) - assertSuccessPartial( - result, {"logLevel": 4}, msg="setParameter should reflect new value immediately" - ) - execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) - - def test_setParameter_getParameter_unchanged_after_failure(collection): """Test setParameter getParameter is unchanged after a failed set.""" execute_admin_command(collection, {"setParameter": 1, "logLevel": 0}) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index 434d2da90..233576d4d 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -54,12 +54,6 @@ error_code=BAD_VALUE_ERROR, msg="setParameter should reject value exceeding int32 max", ), - CommandTestCase( - "wrong_type_string_for_int", - command=lambda ctx: {"setParameter": 1, "logLevel": "abc"}, - error_code=BAD_VALUE_ERROR, - msg="setParameter should reject string for integer param", - ), CommandTestCase( "empty_param_name", command=lambda ctx: {"setParameter": 1, "": 1}, From c6016c307cd5672d1d49aa6033201035d5ecc4f5 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 26 Jun 2026 16:08:28 -0700 Subject: [PATCH 9/9] replace with INT*_MAX/MIN Signed-off-by: Alina (Xi) Li --- .../setParameter/test_setParameter_argument_validation.py | 4 ++-- .../commands/setParameter/test_setParameter_errors.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py index 8767abf40..ee5af9a5b 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_argument_validation.py @@ -5,7 +5,6 @@ """ import pytest -from bson import Int64 from documentdb_tests.compatibility.tests.core.utils.command_test_case import ( CommandContext, @@ -14,6 +13,7 @@ from documentdb_tests.framework.assertions import assertSuccessPartial from documentdb_tests.framework.executor import execute_admin_command from documentdb_tests.framework.parametrize import pytest_params +from documentdb_tests.framework.test_constants import INT64_MAX pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] @@ -22,7 +22,7 @@ NAME_ACCEPTANCE_TESTS: list[CommandTestCase] = [ CommandTestCase( "control_field_int64_max", - command=lambda ctx: {"setParameter": Int64(9_223_372_036_854_775_807), "logLevel": 0}, + command=lambda ctx: {"setParameter": INT64_MAX, "logLevel": 0}, expected={"ok": 1.0}, msg="setParameter should accept Int64 max as control field value", ), diff --git a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py index 233576d4d..8af1f02bc 100644 --- a/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py +++ b/documentdb_tests/compatibility/tests/system/administration/commands/setParameter/test_setParameter_errors.py @@ -23,7 +23,7 @@ ) from documentdb_tests.framework.executor import execute_admin_command, execute_command from documentdb_tests.framework.parametrize import pytest_params -from documentdb_tests.framework.test_constants import INT32_MAX +from documentdb_tests.framework.test_constants import INT32_MAX, INT32_MIN pytestmark = [pytest.mark.admin, pytest.mark.no_parallel] @@ -160,7 +160,7 @@ "hierarchical_nested_underflow", command=lambda ctx: { "setParameter": 1, - "logComponentVerbosity": {"command": {"verbosity": -2_147_483_649}}, + "logComponentVerbosity": {"command": {"verbosity": INT32_MIN - 1}}, }, error_code=BAD_VALUE_ERROR, msg="setParameter should reject underflow for nested verbosity",