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
Expand Up @@ -72,26 +72,33 @@ class CommandTestCase(BaseTestCase):
docs: list[dict[str, Any]] | None = None
command: dict[str, Any] | Callable[..., dict[str, Any]] | None = None
expected: dict[str, Any] | list[dict[str, Any]] | Callable[..., dict[str, Any]] | None = None
ignore_order_in: list[str] | None = None

def prepare(self, db: Database, collection: Collection) -> Collection:
"""Resolve the target collection and apply indexes/docs.

Documents and indexes are inserted into the collection returned
by ``target_collection.writable(source, resolved)``. For views
this is the source; for regular collections it is the resolved
collection itself.

- If ``docs=None``, the collection is not created and will not exist.
- If ``docs=[]``, the collection is explicitly created but left empty.
- If ``docs=[...]``, the collection is created and documents are inserted.
"""
collection = self.target_collection.resolve(db, collection)
resolved = self.target_collection.resolve(db, collection)
target = self.target_collection.writable(collection, resolved)
if self.indexes:
collection.create_indexes(self.indexes)
target.create_indexes(self.indexes)
if self.docs is not None:
if collection.name not in collection.database.list_collection_names():
collection.database.create_collection(collection.name)
if target.name not in target.database.list_collection_names():
target.database.create_collection(target.name)
if self.docs:
collection.insert_many(self.docs)
target.insert_many(self.docs)
if self.siblings:
for sibling in self.siblings:
sibling.create(db, collection)
return collection
sibling.create(db, resolved)
return resolved

def build_command(self, ctx: CommandContext) -> dict[str, Any]:
"""Resolve the command dict from a callable or plain dict."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Tests for view chaining and depth limits."""

from __future__ import annotations

import pytest

from documentdb_tests.framework.assertions import assertFailureCode, assertSuccess
from documentdb_tests.framework.error_codes import VIEW_DEPTH_LIMIT_ERROR
from documentdb_tests.framework.executor import execute_command


# Property [View-on-View Composition]: a view referencing another view
# composes both pipelines correctly.
@pytest.mark.collection_mgmt
def test_views_chaining_composition(database_client, collection):
"""Test view-on-view pipeline composition."""
collection.insert_many(
[
{"_id": 1, "x": 10, "y": "a"},
{"_id": 2, "x": 20, "y": "b"},
{"_id": 3, "x": 30, "y": "a"},
]
)
view1 = f"{collection.name}_v1"
view2 = f"{collection.name}_v2"
database_client.command(
"create",
view1,
viewOn=collection.name,
pipeline=[{"$match": {"x": {"$gte": 20}}}],
)
database_client.command(
"create",
view2,
viewOn=view1,
pipeline=[{"$project": {"x": 1}}],
)
result = execute_command(
database_client[view2],
{"find": view2, "sort": {"_id": 1}},
)
assertSuccess(
result,
[{"_id": 2, "x": 20}, {"_id": 3, "x": 30}],
msg="view-on-view should compose both pipelines correctly",
)


# Property [Depth Limit Exceeded]: querying a view chain deeper than 20
# levels produces the view-depth-limit error.
@pytest.mark.collection_mgmt
def test_views_depth_limit_exceeded(database_client, collection):
"""Test view depth limit is enforced at query time."""
collection.insert_many([{"_id": 1, "x": 10}])
prev = collection.name
for i in range(1, 21):
name = f"{collection.name}_d{i}"
database_client.command("create", name, viewOn=prev, pipeline=[])
prev = name
result = execute_command(
database_client[prev],
{"find": prev},
)
assertFailureCode(
result,
VIEW_DEPTH_LIMIT_ERROR,
msg="querying a view chain exceeding depth 20 should fail",
)


# Property [Depth Limit Boundary]: a view chain at exactly depth 19 is
# queryable without error.
@pytest.mark.collection_mgmt
def test_views_depth_limit_at_boundary(database_client, collection):
"""Test view at exactly depth 19 is queryable."""
collection.insert_many([{"_id": 1, "x": 10}])
prev = collection.name
for i in range(1, 20):
name = f"{collection.name}_b{i}"
database_client.command("create", name, viewOn=prev, pipeline=[])
prev = name
result = execute_command(
database_client[prev],
{"find": prev, "sort": {"_id": 1}},
)
assertSuccess(
result,
[{"_id": 1, "x": 10}],
msg="view chain at depth 19 should be queryable",
)
Loading
Loading