Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Tests for killCursors comment field type acceptance."""

from __future__ import annotations

from datetime import datetime, timezone

import pytest
from bson import (
Binary,
Code,
Int64,
MaxKey,
MinKey,
ObjectId,
Regex,
Timestamp,
)

from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import (
CommandContext,
CommandTestCase,
)
from documentdb_tests.framework.assertions import assertResult
from documentdb_tests.framework.executor import execute_command
from documentdb_tests.framework.parametrize import pytest_params
from documentdb_tests.framework.test_constants import DECIMAL128_ONE_AND_HALF

# Property [comment Field Universal Type Acceptance]: all BSON types
# representable by pymongo are accepted for the comment field without
# restriction.
KILLCURSORS_COMMENT_TYPE_TESTS: list[CommandTestCase] = [
CommandTestCase(
f"comment_{tid}",
command=lambda ctx, v=val: {
"killCursors": ctx.collection,
"cursors": [Int64(1)],
"comment": v,
},
expected={
"cursorsKilled": [],
"cursorsNotFound": [Int64(1)],
"cursorsAlive": [],
"cursorsUnknown": [],
"ok": 1.0,
},
msg=f"killCursors should accept {tid} comment",
)
for tid, val in [
("string", "hello"),
("int32", 42),
("int64", Int64(123)),
("double", 3.14),
("decimal128", DECIMAL128_ONE_AND_HALF),
("bool", True),
("null", None),
("array", [1, "two", 3.0]),
("object", {"key": "value"}),
("objectid", ObjectId("507f1f77bcf86cd799439011")),
("datetime", datetime(2024, 1, 1, tzinfo=timezone.utc)),
("timestamp", Timestamp(1, 1)),
("binary", Binary(b"\x01\x02\x03")),
("regex", Regex(".*", "i")),
("code", Code("function(){}")),
("minkey", MinKey()),
("maxkey", MaxKey()),
]
]


@pytest.mark.parametrize("test", pytest_params(KILLCURSORS_COMMENT_TYPE_TESTS))
def test_killCursors_comment(collection, test):
"""Test killCursors comment field type acceptance."""
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,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""Tests for killCursors cursors field acceptance."""

from __future__ import annotations

import pytest
from bson import Int64

from documentdb_tests.compatibility.tests.core.collections.commands.utils.command_test_case import (
CommandContext,
CommandTestCase,
)
from documentdb_tests.framework.assertions import assertResult
from documentdb_tests.framework.executor import execute_command
from documentdb_tests.framework.parametrize import pytest_params
from documentdb_tests.framework.test_constants import (
INT32_MAX,
INT32_MIN,
INT32_OVERFLOW,
INT32_UNDERFLOW,
INT64_MAX,
INT64_MAX_MINUS_1,
INT64_MIN,
INT64_MIN_PLUS_1,
INT64_ZERO,
)

# Property [Int64 Boundary Values]: Int64 boundary values are accepted in
# the cursors array and reported in cursorsNotFound when they do not match
# an active cursor.
KILLCURSORS_INT64_BOUNDARY_TESTS: list[CommandTestCase] = [
CommandTestCase(
f"boundary_{tid}",
command=lambda ctx, v=val: {
"killCursors": ctx.collection,
"cursors": [v],
},
expected={
"cursorsKilled": [],
"cursorsNotFound": [val],
"cursorsAlive": [],
"cursorsUnknown": [],
"ok": 1.0,
},
msg=f"killCursors should accept Int64 {tid}",
)
for tid, val in [
("zero", INT64_ZERO),
("positive_one", Int64(1)),
("negative_one", Int64(-1)),
("int32_max", Int64(INT32_MAX)),
("int32_min", Int64(INT32_MIN)),
("int32_max_plus_one", Int64(INT32_OVERFLOW)),
("int32_min_minus_one", Int64(INT32_UNDERFLOW)),
("int64_max", INT64_MAX),
("int64_min", INT64_MIN),
("int64_max_minus_one", INT64_MAX_MINUS_1),
("int64_min_plus_one", INT64_MIN_PLUS_1),
]
]

# Property [Null Element Silent Skip]: null elements in the cursors array
# are silently skipped without triggering type-validation rejection, and
# valid Int64 elements alongside nulls are still processed normally.
KILLCURSORS_NULL_ELEMENT_TESTS: list[CommandTestCase] = [
CommandTestCase(
"null_element_interspersed_with_valid",
command=lambda ctx: {
"killCursors": ctx.collection,
"cursors": [None, Int64(1), None, Int64(2), None],
},
expected={
"cursorsKilled": [],
"cursorsNotFound": [Int64(1), Int64(2)],
"cursorsAlive": [],
"cursorsUnknown": [],
"ok": 1.0,
},
msg="killCursors should process valid Int64 elements and skip interspersed nulls",
),
]

# Property [cursors Field Empty Array]: an empty cursors array is a valid
# no-op that succeeds with ok 1.0 and all response arrays empty.
KILLCURSORS_EMPTY_ARRAY_TESTS: list[CommandTestCase] = [
CommandTestCase(
"empty_array_noop",
command=lambda ctx: {
"killCursors": ctx.collection,
"cursors": [],
},
expected={
"cursorsKilled": [],
"cursorsNotFound": [],
"cursorsAlive": [],
"cursorsUnknown": [],
"ok": 1.0,
},
msg="killCursors should succeed as a no-op with an empty cursors array",
),
]

# Property [cursors Field Array Size]: large arrays are accepted,
# limited only by the 16MB BSON document size.
KILLCURSORS_LARGE_ARRAY_TESTS: list[CommandTestCase] = [
CommandTestCase(
"large_array_10k",
command=lambda ctx: {
"killCursors": ctx.collection,
"cursors": [Int64(i) for i in range(10_000)],
},
expected={
"cursorsKilled": [],
"cursorsNotFound": [Int64(i) for i in range(10_000)],
"cursorsAlive": [],
"cursorsUnknown": [],
"ok": 1.0,
},
msg="killCursors should accept a cursors array with 10,000 elements",
),
]

KILLCURSORS_CURSORS_ACCEPTANCE_TESTS: list[CommandTestCase] = (
KILLCURSORS_INT64_BOUNDARY_TESTS
+ KILLCURSORS_NULL_ELEMENT_TESTS
+ KILLCURSORS_EMPTY_ARRAY_TESTS
+ KILLCURSORS_LARGE_ARRAY_TESTS
)


@pytest.mark.parametrize("test", pytest_params(KILLCURSORS_CURSORS_ACCEPTANCE_TESTS))
def test_killCursors_cursors_acceptance(collection, test):
"""Test killCursors cursors field acceptance."""
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,
)
Loading
Loading