Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Shared fixtures for setParameter tests.

Provides an autouse fixture that snapshots mutable server parameters before
each test and unconditionally restores them after, preventing leaked state
even when a test fails.
"""

import pytest

from documentdb_tests.framework.executor import execute_admin_command


@pytest.fixture(autouse=True)
def restore_server_params(collection):
"""Snapshot mutable server parameters before the test, restore after.

This runs unconditionally (autouse) so that any test modifying server state
cannot leak changes into subsequent tests — whether it passes, fails, or errors.
"""
# Snapshot current values
snapshot = {}
for param in ["logLevel", "quiet", "automationServiceDescriptor", "logComponentVerbosity"]:
result = execute_admin_command(collection, {"getParameter": 1, param: 1})
if isinstance(result, dict) and param in result:
snapshot[param] = result[param]

yield

# Restore original values unconditionally
for param, value in snapshot.items():
execute_admin_command(collection, {"setParameter": 1, param: value})
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Tests for setParameter argument validation (success cases).

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

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
from documentdb_tests.framework.test_constants import INT64_MAX

pytestmark = [pytest.mark.admin, pytest.mark.no_parallel]


# Property [Argument Validation]: setParameter accepts valid argument variations.
ARGUMENT_VALIDATION_TESTS: list[CommandTestCase] = [
CommandTestCase(
"control_field_int64_max",
command=lambda ctx: {"setParameter": INT64_MAX, "logLevel": 0},
expected={"ok": 1.0},
msg="setParameter should accept Int64 max as control field value",
),
CommandTestCase(
"fractional_double_coerces",
command=lambda ctx: {"setParameter": 1, "logLevel": 1.5},
expected={"ok": 1.0},
msg="setParameter should truncate fractional double for integer param",
),
CommandTestCase(
"integer_valid_range",
command=lambda ctx: {"setParameter": 1, "logLevel": 5},
expected={"ok": 1.0},
msg="setParameter should accept logLevel at upper bound",
),
CommandTestCase(
"string_param_valid",
command=lambda ctx: {"setParameter": 1, "automationServiceDescriptor": "test"},
expected={"ok": 1.0},
msg="setParameter should accept valid string value",
),
]


@pytest.mark.parametrize("test", pytest_params(ARGUMENT_VALIDATION_TESTS))
def test_setParameter_argument_validation(database_client, collection, test):
"""Test setParameter argument validation 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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""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.
"""

import pytest
from bson import Decimal128, Int64

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.executor import execute_admin_command

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",
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})")


# Property [Boolean Coercion]: boolean-typed params accept many BSON types via coercion.
@pytest.mark.parametrize(
"value,desc",
[
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 setParameter boolean parameter coercion."""
result = execute_admin_command(collection, {"setParameter": 1, "quiet": value})
assertSuccessPartial(
result, {"ok": 1.0}, msg=f"setParameter boolean param should accept {desc}"
)


# Property [Integer Coercion Accepted]: integer-typed params accept whole-number numerics.
@pytest.mark.parametrize(
"value,desc",
[
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"),
],
)
def test_setParameter_integer_coercion_accepted(collection, value, desc):
"""Test setParameter integer parameter coercion."""
result = execute_admin_command(collection, {"setParameter": 1, "logLevel": value})
assertSuccessPartial(
result, {"ok": 1.0}, msg=f"setParameter integer param should accept {desc}"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""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.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(
"comment_field_accepted",
command=lambda ctx: {"setParameter": 1, "logLevel": 0, "comment": "test"},
expected={"ok": 1.0},
msg="setParameter should accept comment field alongside params",
),
CommandTestCase(
"single_param_returns_ok",
command=lambda ctx: {"setParameter": 1, "logLevel": 1},
expected={"ok": 1.0},
msg="setParameter should return ok:1",
),
]


@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)


# Property [Response Structure]: setParameter returns ok:1 and previous value in 'was'.
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="setParameter should report previous value in 'was'"
)


def test_setParameter_boolean_was_type(collection):
"""Test setParameter 'was' field for a boolean parameter is boolean type."""
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="setParameter 'was' should be boolean for quiet"
)


# Property [Value Persistence]: setParameter changes are reflected in getParameter.
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})
result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1})
assertSuccessPartial(
result, {"logLevel": 3}, msg="setParameter should reflect new value via getParameter"
)


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})
execute_admin_command(collection, {"setParameter": 1, "logLevel": "invalid"})
result = execute_admin_command(collection, {"getParameter": 1, "logLevel": 1})
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")


# Property [Round Trip]: value can be restored via 'was' field.
def test_setParameter_round_trip_restore(collection):
"""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="setParameter should restore to original")


# Property [Boolean Toggle]: boolean-typed parameters toggle correctly.
def test_setParameter_boolean_toggle(collection):
"""Test setParameter boolean-typed parameter toggles correctly."""
execute_admin_command(collection, {"setParameter": 1, "quiet": False})
result = execute_admin_command(collection, {"getParameter": 1, "quiet": 1})
assertSuccessPartial(result, {"quiet": False}, msg="setParameter boolean should be False")


# Property [Ordering Independence]: parameter order in command does not affect result.
def test_setParameter_ordering_independence(collection):
"""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="setParameter order should not matter"
)
Loading
Loading