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,95 @@
"""Tests for $push BSON type validation.

Verifies that $push rejects non-array target field types with error code 2,
and can push any BSON type as a value into an array.
"""

import pytest
from bson import Binary

from documentdb_tests.framework.assertions import assertFailureCode, assertSuccess
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 BAD_VALUE_ERROR
from documentdb_tests.framework.executor import execute_command

PUSH_PARAMS = [
BsonTypeTestCase(
id="target_field",
msg="$push should reject non-array target field types",
valid_types=[BsonType.ARRAY],
default_error_code=BAD_VALUE_ERROR,
expected=[{"_id": 1, "arr": [1, 2, 99]}],
valid_inputs={BsonType.ARRAY: [1, 2]},
),
BsonTypeTestCase(
id="value_element",
msg="$push should accept any BSON type as value to push",
valid_types=list(BsonType),
default_error_code=BAD_VALUE_ERROR,
valid_inputs={BsonType.BIN_DATA: Binary(b"\x00\x01\x02", 128)},
),
]


def _setup_doc(spec, sample_value) -> dict:
"""Build the setup document based on which aspect is being tested."""
if spec.id == "target_field":
return {"_id": 1, "arr": sample_value}
return {"_id": 1, "arr": []}


def _build_update(spec, sample_value) -> dict:
"""Build the update command based on which aspect is being tested."""
if spec.id == "target_field":
return {"$push": {"arr": 99}}
return {"$push": {"arr": sample_value}}


@pytest.mark.parametrize(
"bson_type,sample_value,spec", generate_bson_rejection_test_cases(PUSH_PARAMS)
)
def test_push_bson_type_rejected(collection, bson_type, sample_value, spec):
"""Test $push rejects non-array target field types with error."""
setup_doc = _setup_doc(spec, sample_value)
update = _build_update(spec, sample_value)
collection.insert_one(setup_doc)
result = execute_command(
collection,
{
"update": collection.name,
"updates": [{"q": {"_id": 1}, "u": update}],
},
)
assertFailureCode(
result,
spec.expected_code(bson_type),
msg=f"$push should reject {bson_type.value} for {spec.id}",
)


@pytest.mark.parametrize(
"bson_type,sample_value,spec", generate_bson_acceptance_test_cases(PUSH_PARAMS)
)
def test_push_bson_type_accepted(collection, bson_type, sample_value, spec):
"""Test $push accepts valid BSON types for target field and value element."""
setup_doc = _setup_doc(spec, sample_value)
update = _build_update(spec, sample_value)
collection.insert_one(setup_doc)
execute_command(
collection,
{
"update": collection.name,
"updates": [{"q": {"_id": 1}, "u": update}],
},
)
result = execute_command(collection, {"find": collection.name, "filter": {"_id": 1}})
if spec.id == "target_field":
expected = spec.expected
else:
expected = [{"_id": 1, "arr": [sample_value]}]
assertSuccess(result, expected, msg=f"$push should accept {bson_type.value} for {spec.id}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""Tests for $push update command behavior.

Covers: updateOne, updateMany, upsert, bulkWrite.
"""

from documentdb_tests.framework.assertions import assertSuccess, assertSuccessPartial
from documentdb_tests.framework.executor import execute_command


def test_push_updateOne_response(collection):
"""Test $push with updateOne reports correct response."""
collection.insert_one({"_id": 1, "arr": [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.

add muliple value then update

result = execute_command(
collection,
{
"update": collection.name,
"updates": [{"q": {"_id": 1}, "u": {"$push": {"arr": 2}}}],
},
)
assertSuccessPartial(
result, {"n": 1, "nModified": 1, "ok": 1.0}, msg="updateOne should report nModified=1"
)


def test_push_updateOne_result(collection):
"""Test $push with updateOne produces correct document."""
collection.insert_one({"_id": 1, "arr": [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.

have multiple values and then verify. it has only one value

execute_command(
collection,
{
"update": collection.name,
"updates": [{"q": {"_id": 1}, "u": {"$push": {"arr": 2}}}],
},
)
result = execute_command(collection, {"find": collection.name, "filter": {"_id": 1}})
assertSuccess(result, [{"_id": 1, "arr": [1, 2]}], msg="updateOne should append value")


def test_push_updateMany(collection):
"""Test $push with updateMany updates all matched docs."""
collection.insert_many(
[{"_id": 1, "arr": [1]}, {"_id": 2, "arr": [10]}, {"_id": 3, "arr": [100]}]
)
execute_command(
collection,
{
"update": collection.name,
"updates": [{"q": {}, "u": {"$push": {"arr": 99}}, "multi": True}],
},
)
result = execute_command(
collection, {"find": collection.name, "filter": {}, "sort": {"_id": 1}}
)
assertSuccess(
result,
[
{"_id": 1, "arr": [1, 99]},
{"_id": 2, "arr": [10, 99]},
{"_id": 3, "arr": [100, 99]},
],
msg="updateMany should push to each matched document",
)


def test_push_upsert_creates_doc(collection):
"""Test $push with upsert:true creates document when not found."""
execute_command(
collection,
{
"update": collection.name,
"updates": [{"q": {"_id": 99}, "u": {"$push": {"arr": 5}}, "upsert": True}],
},
)
result = execute_command(collection, {"find": collection.name, "filter": {"_id": 99}})
assertSuccess(
result,
[{"_id": 99, "arr": [5]}],
msg="Upsert should create doc with array containing the value",
)


def test_push_upsert_with_each(collection):
"""Test $push with $each and upsert:true creates document with all values."""
execute_command(
collection,
{
"update": collection.name,
"updates": [
{"q": {"_id": 99}, "u": {"$push": {"arr": {"$each": [1, 2, 3]}}}, "upsert": True}
],
},
)
result = execute_command(collection, {"find": collection.name, "filter": {"_id": 99}})
assertSuccess(
result,
[{"_id": 99, "arr": [1, 2, 3]}],
msg="Upsert with $each should create doc with all values",
)


def test_push_bulk_write_response(collection):
"""Test $push in bulkWrite reports correct response."""
collection.insert_many([{"_id": 1, "arr": [1]}, {"_id": 2, "arr": [10]}])
result = execute_command(
collection,
{
"update": collection.name,
"updates": [
{"q": {"_id": 1}, "u": {"$push": {"arr": 2}}},
{"q": {"_id": 2}, "u": {"$push": {"arr": 20}}},
],
},
)
assertSuccessPartial(
result, {"n": 2, "nModified": 2, "ok": 1.0}, msg="Bulk update should report nModified=2"
)


def test_push_bulk_write_result(collection):
"""Test $push in bulkWrite produces correct documents."""
collection.insert_many([{"_id": 1, "arr": [1]}, {"_id": 2, "arr": [10]}])
execute_command(
collection,
{
"update": collection.name,
"updates": [
{"q": {"_id": 1}, "u": {"$push": {"arr": 2}}},
{"q": {"_id": 2}, "u": {"$push": {"arr": 20}}},
],
},
)
result = execute_command(
collection, {"find": collection.name, "filter": {}, "sort": {"_id": 1}}
)
assertSuccess(
result,
[{"_id": 1, "arr": [1, 2]}, {"_id": 2, "arr": [10, 20]}],
msg="Bulk update should push to each doc",
)
Loading
Loading