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,73 @@
"""Tests for single field index key sort order BSON type validation.

Verifies that single field index key values (sort order specifiers) reject
invalid BSON types and accept valid numeric types.
"""

import pytest
from bson import Decimal128, Int64

from documentdb_tests.framework.assertions import assertFailureCode, assertNotError
from documentdb_tests.framework.bson_type_validator import (
BsonType,
BsonTypeTestCase,
generate_bson_acceptance_test_cases,
generate_bson_rejection_test_cases,
)
from documentdb_tests.framework.error_codes import CANNOT_CREATE_INDEX_ERROR
from documentdb_tests.framework.executor import execute_command

pytestmark = pytest.mark.index

SINGLE_KEY_SORT_ORDER_PARAMS = [
BsonTypeTestCase(
id="sort_order",
msg="single key sort order should reject non-numeric types",
keyword="sort_order",
valid_types=[BsonType.DOUBLE, BsonType.INT, BsonType.LONG, BsonType.DECIMAL],
default_error_code=CANNOT_CREATE_INDEX_ERROR,
valid_inputs={
BsonType.DOUBLE: 1.0,
BsonType.INT: 1,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is INT(1) would fail

BsonType.LONG: Int64(1),
BsonType.DECIMAL: Decimal128("1"),
},
),
]


REJECTION_CASES = generate_bson_rejection_test_cases(SINGLE_KEY_SORT_ORDER_PARAMS)


@pytest.mark.parametrize("bson_type,sample_value,spec", REJECTION_CASES)
def test_single_key_sort_order_rejected(collection, bson_type, sample_value, spec):
"""Test single field index creation rejects invalid BSON types for key sort order."""
result = execute_command(
collection,
{
"createIndexes": collection.name,
"indexes": [{"key": {"a": sample_value}, "name": "test_idx"}],
},
)
assertFailureCode(result, spec.expected_code(bson_type), msg=spec.msg)


ACCEPTANCE_CASES = generate_bson_acceptance_test_cases(SINGLE_KEY_SORT_ORDER_PARAMS)


@pytest.mark.parametrize("bson_type,sample_value,spec", ACCEPTANCE_CASES)
def test_single_key_sort_order_accepted(collection, bson_type, sample_value, spec):
"""Test single field index creation accepts valid BSON types for key sort order.

Note: This is a type validation test, not a functional test. We only verify
the command does not error — we do not check listIndexes to confirm the index
was created with the correct option value.
"""
result = execute_command(
collection,
{
"createIndexes": collection.name,
"indexes": [{"key": {"a": sample_value}, "name": "test_idx"}],
},
)
assertNotError(result, msg=f"sort order should accept {bson_type.value}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""Tests for single field index creation.

Validates valid argument handling, idempotency, and duplicate prevention.
"""

import pytest

from documentdb_tests.compatibility.tests.core.indexes.commands.utils.index_test_case import (
IndexTestCase,
index_created_response,
)
from documentdb_tests.framework.assertions import assertSuccessPartial
from documentdb_tests.framework.executor import execute_command
from documentdb_tests.framework.parametrize import pytest_params

pytestmark = pytest.mark.index

CREATION_SUCCESS_TESTS: list[IndexTestCase] = [
IndexTestCase(
id="creation_ascending",
indexes=({"key": {"a": 1}, "name": "a_1"},),
msg="Ascending order succeeds",
),
IndexTestCase(
id="creation_descending",
indexes=({"key": {"a": -1}, "name": "a_neg1"},),
msg="Descending order succeeds",
),
IndexTestCase(
id="creation_dot_notation",
indexes=({"key": {"a.b": 1}, "name": "a.b_1"},),
msg="Dot notation field succeeds",
),
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing: multiple fields in a single createIndexes call.



@pytest.mark.parametrize("test", pytest_params(CREATION_SUCCESS_TESTS))
def test_single_creation_success(collection, test):
"""Test single field index creation with valid arguments."""
result = execute_command(
collection,
{"createIndexes": collection.name, "indexes": list(test.indexes)},
)
assertSuccessPartial(result, index_created_response(), test.msg)


def test_single_creation_on_nonexistent_collection(collection):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the same as above

"""Test createIndexes on non-existent collection creates collection and index."""
result = execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"x": 1}, "name": "x_1"}]},
)
assertSuccessPartial(
result,
{"ok": 1.0, "numIndexesBefore": 1, "numIndexesAfter": 2},
msg="Should create collection and index",
)


def test_single_creation_idempotent(collection):
"""Test creating same index twice is idempotent."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
result = execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
assertSuccessPartial(
result,
{"ok": 1.0, "numIndexesBefore": 2, "numIndexesAfter": 2},
msg="Duplicate index creation should be no-op",
)


def test_single_creation_different_sort_creates_two(collection):
"""Test creating index with same field but different sort order creates two indexes."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
result = execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": -1}, "name": "a_neg1"}]},
)
assertSuccessPartial(
result,
{"ok": 1.0, "numIndexesBefore": 2, "numIndexesAfter": 3},
msg="Different sort order should create separate index",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing: dropIndexes after creation.

Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""Tests for single field index error cases.

Validates invalid sort values, field name errors, and index conflicts.
"""

import pytest

from documentdb_tests.compatibility.tests.core.indexes.commands.utils.index_test_case import (
IndexTestCase,
)
from documentdb_tests.framework.assertions import assertFailureCode
from documentdb_tests.framework.error_codes import (
CANNOT_CREATE_INDEX_ERROR,
INDEX_KEY_SPECS_CONFLICT_ERROR,
INDEX_OPTIONS_CONFLICT_ERROR,
)
from documentdb_tests.framework.executor import execute_command
from documentdb_tests.framework.parametrize import pytest_params

pytestmark = pytest.mark.index

CREATION_ERROR_TESTS: list[IndexTestCase] = [
IndexTestCase(
id="invalid_sort_zero",
indexes=({"key": {"a": 0}, "name": "a_0"},),
error_code=CANNOT_CREATE_INDEX_ERROR,
msg="Sort order 0 should fail",
),
IndexTestCase(
id="invalid_dollar_prefix",
indexes=({"key": {"$field": 1}, "name": "dollar_1"},),
error_code=CANNOT_CREATE_INDEX_ERROR,
msg="$ prefix field should fail",
),
IndexTestCase(
id="invalid_empty_field",
indexes=({"key": {"": 1}, "name": "empty_1"},),
error_code=CANNOT_CREATE_INDEX_ERROR,
msg="Empty field name should fail",
),
]


@pytest.mark.parametrize("test", pytest_params(CREATION_ERROR_TESTS))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing: empty key {}.

def test_single_creation_error(collection, test):
"""Test single field index creation with invalid arguments."""
result = execute_command(
collection,
{"createIndexes": collection.name, "indexes": list(test.indexes)},
)
assertFailureCode(result, test.error_code, test.msg)


CONFLICT_ERROR_TESTS: list[IndexTestCase] = [
IndexTestCase(
id="conflict_same_field_different_name",
setup_indexes=[{"key": {"a": 1}, "name": "a_1"}],
indexes=({"key": {"a": 1}, "name": "a_different"},),
error_code=INDEX_OPTIONS_CONFLICT_ERROR,
msg="Same field/order with different name should fail",
),
IndexTestCase(
id="conflict_same_name_different_field",
setup_indexes=[{"key": {"a": 1}, "name": "my_idx"}],
indexes=({"key": {"b": 1}, "name": "my_idx"},),
error_code=INDEX_KEY_SPECS_CONFLICT_ERROR,
msg="Same name with different field should fail",
),
]


@pytest.mark.parametrize("test", pytest_params(CONFLICT_ERROR_TESTS))
def test_single_conflict_error(collection, test):
"""Test single field index creation conflicts."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": list(test.setup_indexes)},
)
result = execute_command(
collection,
{"createIndexes": collection.name, "indexes": list(test.indexes)},
)
assertFailureCode(result, test.error_code, test.msg)


def test_single_option_conflict_same_key_name(collection):
"""Test recreating index with same key+name but different options fails."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
result = execute_command(
collection,
{
"createIndexes": collection.name,
"indexes": [{"key": {"a": 1}, "name": "a_1", "unique": True}],
},
)
assertFailureCode(
result,
INDEX_KEY_SPECS_CONFLICT_ERROR,
msg="Same key+name with different options should fail",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where are partial index , sparse and hidden properties tested for index creation success and failure.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Tests for single field index properties.

Validates NaN and Infinity handling on single field indexes.
"""

import pytest

from documentdb_tests.framework.assertions import (
assertSuccess,
assertSuccessNaN,
)
from documentdb_tests.framework.executor import execute_command

pytestmark = pytest.mark.index


def test_single_nan_indexed_and_queryable(collection):
"""Test NaN in indexed field is queryable."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
collection.insert_one({"_id": 1, "a": float("nan")})
result = execute_command(collection, {"find": collection.name, "filter": {"a": float("nan")}})
assertSuccessNaN(result, [{"_id": 1, "a": float("nan")}], msg="Should find NaN document")


def test_single_infinity_indexed(collection):
"""Test Infinity in indexed field is queryable."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
collection.insert_one({"_id": 1, "a": float("inf")})
result = execute_command(collection, {"find": collection.name, "filter": {"a": float("inf")}})
assertSuccess(result, [{"_id": 1, "a": float("inf")}], msg="Should find Infinity document")


def test_single_negative_infinity_indexed(collection):
"""Test -Infinity in indexed field is queryable."""
execute_command(
collection,
{"createIndexes": collection.name, "indexes": [{"key": {"a": 1}, "name": "a_1"}]},
)
collection.insert_one({"_id": 1, "a": float("-inf")})
result = execute_command(collection, {"find": collection.name, "filter": {"a": float("-inf")}})
assertSuccess(result, [{"_id": 1, "a": float("-inf")}], msg="Should find -Infinity document")
Loading
Loading