Skip to content

Commit 9e59c4e

Browse files
alinaliBQRyanGarfinkel
authored andcommitted
Add whatsmyuri command tests (#643)
Signed-off-by: Alina (Xi) Li <Alina.Li@improving.com> Signed-off-by: RyanGarfinkel <113050972+RyanGarfinkel@users.noreply.github.com>
1 parent bc164fc commit 9e59c4e

5 files changed

Lines changed: 449 additions & 0 deletions

File tree

documentdb_tests/compatibility/tests/system/diagnostic/commands/whatsmyuri/__init__.py

Whitespace-only changes.
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
"""Tests for whatsmyuri command argument handling.
2+
3+
Validates that whatsmyuri accepts any BSON type as its argument value
4+
and ignores unrecognized fields.
5+
"""
6+
7+
from datetime import datetime, timezone
8+
9+
import pytest
10+
from bson import Binary, Code, Decimal128, Int64, MaxKey, MinKey, ObjectId, Regex, Timestamp
11+
12+
from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import (
13+
DiagnosticTestCase,
14+
)
15+
from documentdb_tests.framework.assertions import assertProperties
16+
from documentdb_tests.framework.executor import execute_admin_command
17+
from documentdb_tests.framework.parametrize import pytest_params
18+
from documentdb_tests.framework.property_checks import Eq
19+
20+
pytestmark = pytest.mark.admin
21+
22+
23+
# Property [Type Acceptance]: whatsmyuri accepts all BSON types as the command field value.
24+
ARGUMENT_TYPE_TESTS: list[DiagnosticTestCase] = [
25+
DiagnosticTestCase(
26+
"int_1",
27+
command={"whatsmyuri": 1},
28+
checks={"ok": Eq(1.0)},
29+
msg="whatsmyuri should accept int 1",
30+
),
31+
DiagnosticTestCase(
32+
"int_0",
33+
command={"whatsmyuri": 0},
34+
checks={"ok": Eq(1.0)},
35+
msg="whatsmyuri should accept int 0",
36+
),
37+
DiagnosticTestCase(
38+
"int_neg1",
39+
command={"whatsmyuri": -1},
40+
checks={"ok": Eq(1.0)},
41+
msg="whatsmyuri should accept int -1",
42+
),
43+
DiagnosticTestCase(
44+
"bool_true",
45+
command={"whatsmyuri": True},
46+
checks={"ok": Eq(1.0)},
47+
msg="whatsmyuri should accept true",
48+
),
49+
DiagnosticTestCase(
50+
"bool_false",
51+
command={"whatsmyuri": False},
52+
checks={"ok": Eq(1.0)},
53+
msg="whatsmyuri should accept false",
54+
),
55+
DiagnosticTestCase(
56+
"string",
57+
command={"whatsmyuri": "hello"},
58+
checks={"ok": Eq(1.0)},
59+
msg="whatsmyuri should accept string",
60+
),
61+
DiagnosticTestCase(
62+
"empty_string",
63+
command={"whatsmyuri": ""},
64+
checks={"ok": Eq(1.0)},
65+
msg="whatsmyuri should accept empty string",
66+
),
67+
DiagnosticTestCase(
68+
"null",
69+
command={"whatsmyuri": None},
70+
checks={"ok": Eq(1.0)},
71+
msg="whatsmyuri should accept null",
72+
),
73+
DiagnosticTestCase(
74+
"empty_object",
75+
command={"whatsmyuri": {}},
76+
checks={"ok": Eq(1.0)},
77+
msg="whatsmyuri should accept empty object",
78+
),
79+
DiagnosticTestCase(
80+
"nested_object",
81+
command={"whatsmyuri": {"a": {"b": 1}}},
82+
checks={"ok": Eq(1.0)},
83+
msg="whatsmyuri should accept nested object",
84+
),
85+
DiagnosticTestCase(
86+
"empty_array",
87+
command={"whatsmyuri": []},
88+
checks={"ok": Eq(1.0)},
89+
msg="whatsmyuri should accept empty array",
90+
),
91+
DiagnosticTestCase(
92+
"array_with_elements",
93+
command={"whatsmyuri": [1, 2, 3]},
94+
checks={"ok": Eq(1.0)},
95+
msg="whatsmyuri should accept array with elements",
96+
),
97+
DiagnosticTestCase(
98+
"double",
99+
command={"whatsmyuri": 1.5},
100+
checks={"ok": Eq(1.0)},
101+
msg="whatsmyuri should accept double",
102+
),
103+
DiagnosticTestCase(
104+
"negative_double",
105+
command={"whatsmyuri": -1.5},
106+
checks={"ok": Eq(1.0)},
107+
msg="whatsmyuri should accept negative double",
108+
),
109+
DiagnosticTestCase(
110+
"large_int",
111+
command={"whatsmyuri": 999_999_999},
112+
checks={"ok": Eq(1.0)},
113+
msg="whatsmyuri should accept large int",
114+
),
115+
DiagnosticTestCase(
116+
"int64",
117+
command={"whatsmyuri": Int64(1)},
118+
checks={"ok": Eq(1.0)},
119+
msg="whatsmyuri should accept int64",
120+
),
121+
DiagnosticTestCase(
122+
"decimal128",
123+
command={"whatsmyuri": Decimal128("1")},
124+
checks={"ok": Eq(1.0)},
125+
msg="whatsmyuri should accept decimal128",
126+
),
127+
DiagnosticTestCase(
128+
"decimal128_nan",
129+
command={"whatsmyuri": Decimal128("NaN")},
130+
checks={"ok": Eq(1.0)},
131+
msg="whatsmyuri should accept decimal128 NaN",
132+
),
133+
DiagnosticTestCase(
134+
"decimal128_infinity",
135+
command={"whatsmyuri": Decimal128("Infinity")},
136+
checks={"ok": Eq(1.0)},
137+
msg="whatsmyuri should accept decimal128 Infinity",
138+
),
139+
DiagnosticTestCase(
140+
"decimal128_neg_zero",
141+
command={"whatsmyuri": Decimal128("-0")},
142+
checks={"ok": Eq(1.0)},
143+
msg="whatsmyuri should accept decimal128 negative zero",
144+
),
145+
DiagnosticTestCase(
146+
"infinity",
147+
command={"whatsmyuri": float("inf")},
148+
checks={"ok": Eq(1.0)},
149+
msg="whatsmyuri should accept infinity",
150+
),
151+
DiagnosticTestCase(
152+
"neg_infinity",
153+
command={"whatsmyuri": float("-inf")},
154+
checks={"ok": Eq(1.0)},
155+
msg="whatsmyuri should accept negative infinity",
156+
),
157+
DiagnosticTestCase(
158+
"nan",
159+
command={"whatsmyuri": float("nan")},
160+
checks={"ok": Eq(1.0)},
161+
msg="whatsmyuri should accept NaN",
162+
),
163+
DiagnosticTestCase(
164+
"date",
165+
command={"whatsmyuri": datetime(2024, 1, 1, tzinfo=timezone.utc)},
166+
checks={"ok": Eq(1.0)},
167+
msg="whatsmyuri should accept date",
168+
),
169+
DiagnosticTestCase(
170+
"binData",
171+
command={"whatsmyuri": Binary(b"")},
172+
checks={"ok": Eq(1.0)},
173+
msg="whatsmyuri should accept binData",
174+
),
175+
DiagnosticTestCase(
176+
"objectId",
177+
command={"whatsmyuri": ObjectId()},
178+
checks={"ok": Eq(1.0)},
179+
msg="whatsmyuri should accept objectId",
180+
),
181+
DiagnosticTestCase(
182+
"regex",
183+
command={"whatsmyuri": Regex("test")},
184+
checks={"ok": Eq(1.0)},
185+
msg="whatsmyuri should accept regex",
186+
),
187+
DiagnosticTestCase(
188+
"timestamp",
189+
command={"whatsmyuri": Timestamp(0, 0)},
190+
checks={"ok": Eq(1.0)},
191+
msg="whatsmyuri should accept timestamp",
192+
),
193+
DiagnosticTestCase(
194+
"minKey",
195+
command={"whatsmyuri": MinKey()},
196+
checks={"ok": Eq(1.0)},
197+
msg="whatsmyuri should accept minKey",
198+
),
199+
DiagnosticTestCase(
200+
"maxKey",
201+
command={"whatsmyuri": MaxKey()},
202+
checks={"ok": Eq(1.0)},
203+
msg="whatsmyuri should accept maxKey",
204+
),
205+
DiagnosticTestCase(
206+
"code",
207+
command={"whatsmyuri": Code("function(){}")},
208+
checks={"ok": Eq(1.0)},
209+
msg="whatsmyuri should accept JavaScript code",
210+
),
211+
]
212+
213+
# Property [Extra Fields Ignored]: whatsmyuri ignores unrecognized fields.
214+
EXTRA_FIELD_TESTS: list[DiagnosticTestCase] = [
215+
DiagnosticTestCase(
216+
"extra_field_ignored",
217+
command={"whatsmyuri": 1, "unknownField": 1},
218+
checks={"ok": Eq(1.0)},
219+
msg="whatsmyuri should succeed even with unrecognized fields",
220+
),
221+
]
222+
223+
ALL_TESTS = ARGUMENT_TYPE_TESTS + EXTRA_FIELD_TESTS
224+
225+
226+
@pytest.mark.parametrize("test", pytest_params(ALL_TESTS))
227+
def test_whatsmyuri_argument_handling(collection, test):
228+
"""Test whatsmyuri argument handling."""
229+
result = execute_admin_command(collection, test.command)
230+
assertProperties(result, test.checks, msg=test.msg, raw_res=True)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Tests for whatsmyuri command consistency and database independence.
2+
3+
Validates that whatsmyuri returns consistent results across calls,
4+
databases, and is unaffected by server settings.
5+
"""
6+
7+
import pytest
8+
9+
from documentdb_tests.compatibility.tests.system.diagnostic.utils.diagnostic_test_case import (
10+
DiagnosticTestCase,
11+
)
12+
from documentdb_tests.framework.assertions import (
13+
assertProperties,
14+
assertSuccess,
15+
assertSuccessPartial,
16+
)
17+
from documentdb_tests.framework.executor import execute_admin_command, execute_command
18+
from documentdb_tests.framework.parametrize import pytest_params
19+
from documentdb_tests.framework.property_checks import Eq
20+
21+
pytestmark = pytest.mark.admin
22+
23+
24+
# Property [Database Independence]: whatsmyuri succeeds on any database.
25+
DATABASE_INDEPENDENCE_TESTS: list[DiagnosticTestCase] = [
26+
DiagnosticTestCase(
27+
"any_database",
28+
command={"whatsmyuri": 1},
29+
use_admin=False,
30+
checks={"ok": Eq(1.0)},
31+
msg="whatsmyuri should succeed on non-admin database",
32+
),
33+
]
34+
35+
36+
@pytest.mark.parametrize("test", pytest_params(DATABASE_INDEPENDENCE_TESTS))
37+
def test_whatsmyuri_consistency(collection, test):
38+
"""Test whatsmyuri consistency."""
39+
result = execute_command(collection, test.command)
40+
assertProperties(result, test.checks, msg=test.msg, raw_res=True)
41+
42+
43+
def test_whatsmyuri_idempotent(collection):
44+
"""Test whatsmyuri idempotency."""
45+
result1 = execute_admin_command(collection, {"whatsmyuri": 1})
46+
result2 = execute_admin_command(collection, {"whatsmyuri": 1})
47+
assertSuccess(
48+
result2,
49+
expected=result1,
50+
msg="whatsmyuri should return identical results across calls",
51+
raw_res=True,
52+
)
53+
54+
55+
def test_whatsmyuri_same_result_any_database(collection):
56+
"""Test whatsmyuri returns same result from admin and non-admin database."""
57+
admin_result = execute_admin_command(collection, {"whatsmyuri": 1})
58+
db_result = execute_command(collection, {"whatsmyuri": 1})
59+
assertSuccess(
60+
db_result,
61+
expected=admin_result,
62+
msg="whatsmyuri should return same result from any database",
63+
raw_res=True,
64+
)
65+
66+
67+
def test_whatsmyuri_nonexistent_database(collection):
68+
"""Test whatsmyuri on a non-existent database."""
69+
other_db = f"{collection.name}_nonexistent_db"
70+
other_col = collection.database.client[other_db][collection.name]
71+
result = execute_command(other_col, {"whatsmyuri": 1})
72+
assertSuccessPartial(
73+
result,
74+
{"ok": 1.0},
75+
msg="whatsmyuri should succeed on non-existent database",
76+
)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""Tests for whatsmyuri command error conditions.
2+
3+
Validates that invalid usages of whatsmyuri produce appropriate errors.
4+
Uses CommandTestCase because the aggregation stage test needs ctx.collection
5+
for the aggregate command.
6+
"""
7+
8+
import pytest
9+
10+
from documentdb_tests.compatibility.tests.core.utils.command_test_case import (
11+
CommandContext,
12+
CommandTestCase,
13+
)
14+
from documentdb_tests.framework.assertions import assertResult
15+
from documentdb_tests.framework.error_codes import (
16+
COMMAND_NOT_FOUND_ERROR,
17+
UNKNOWN_PIPELINE_STAGE_ERROR,
18+
)
19+
from documentdb_tests.framework.executor import execute_admin_command, execute_command
20+
from documentdb_tests.framework.parametrize import pytest_params
21+
22+
pytestmark = pytest.mark.admin
23+
24+
25+
# Property [Case Sensitivity]: whatsmyuri is case-sensitive and rejects mismatched casing.
26+
CASE_SENSITIVITY_TESTS: list[CommandTestCase] = [
27+
CommandTestCase(
28+
"case_sensitive_capital_w",
29+
command={"WhatsMyUri": 1},
30+
error_code=COMMAND_NOT_FOUND_ERROR,
31+
msg="whatsmyuri should reject camel-cased command name",
32+
),
33+
CommandTestCase(
34+
"case_sensitive_all_upper",
35+
command={"WHATSMYURI": 1},
36+
error_code=COMMAND_NOT_FOUND_ERROR,
37+
msg="whatsmyuri should reject all-uppercase command name",
38+
),
39+
]
40+
41+
# Property [Not a Pipeline Stage]: whatsmyuri is not usable as an aggregation stage.
42+
PIPELINE_STAGE_TESTS: list[CommandTestCase] = [
43+
CommandTestCase(
44+
"as_aggregation_stage",
45+
command=lambda ctx: {
46+
"aggregate": ctx.collection,
47+
"pipeline": [{"$whatsmyuri": {}}],
48+
"cursor": {},
49+
},
50+
error_code=UNKNOWN_PIPELINE_STAGE_ERROR,
51+
msg="whatsmyuri should not be usable as an aggregation stage",
52+
),
53+
]
54+
55+
ALL_TESTS = CASE_SENSITIVITY_TESTS + PIPELINE_STAGE_TESTS
56+
57+
58+
@pytest.mark.parametrize("test", pytest_params(ALL_TESTS))
59+
def test_whatsmyuri_error_conditions(collection, test):
60+
"""Test whatsmyuri error conditions."""
61+
ctx = CommandContext.from_collection(collection)
62+
cmd = test.build_command(ctx)
63+
# Case sensitivity tests target the admin db; the aggregate test does not.
64+
if next(iter(cmd)).lower() == "whatsmyuri":
65+
result = execute_admin_command(collection, cmd)
66+
else:
67+
result = execute_command(collection, cmd)
68+
assertResult(result, error_code=test.error_code, msg=test.msg)

0 commit comments

Comments
 (0)