Files
ATOCore/tests/test_patch_entity.py

161 lines
4.8 KiB
Python
Raw Normal View History

"""PATCH /entities/{id} — edit mutable fields without cloning (sprint P1)."""
import pytest
from fastapi.testclient import TestClient
from atocore.engineering.service import (
create_entity,
get_entity,
init_engineering_schema,
update_entity,
)
from atocore.main import app
from atocore.models.database import init_db
@pytest.fixture
def env(tmp_data_dir, tmp_path, monkeypatch):
registry_path = tmp_path / "test-registry.json"
registry_path.write_text('{"projects": []}', encoding="utf-8")
monkeypatch.setenv("ATOCORE_PROJECT_REGISTRY_PATH", str(registry_path))
from atocore import config
config.settings = config.Settings()
init_db()
init_engineering_schema()
yield tmp_data_dir
def test_update_entity_description(env):
e = create_entity(entity_type="component", name="t", description="old desc")
updated = update_entity(e.id, description="new desc")
assert updated.description == "new desc"
assert get_entity(e.id).description == "new desc"
def test_update_entity_properties_merge(env):
e = create_entity(
entity_type="component",
name="t2",
properties={"color": "red", "kg": 5},
)
updated = update_entity(
e.id, properties_patch={"color": "blue", "material": "invar"},
)
assert updated.properties == {"color": "blue", "kg": 5, "material": "invar"}
def test_update_entity_properties_null_deletes_key(env):
e = create_entity(
entity_type="component",
name="t3",
properties={"color": "red", "kg": 5},
)
updated = update_entity(e.id, properties_patch={"color": None})
assert "color" not in updated.properties
assert updated.properties.get("kg") == 5
def test_update_entity_confidence_bounds(env):
e = create_entity(entity_type="component", name="t4", confidence=0.5)
with pytest.raises(ValueError):
update_entity(e.id, confidence=1.5)
with pytest.raises(ValueError):
update_entity(e.id, confidence=-0.1)
def test_update_entity_source_refs_append_dedup(env):
e = create_entity(
entity_type="component",
name="t5",
source_refs=["session:a", "session:b"],
)
updated = update_entity(
e.id, append_source_refs=["session:b", "session:c"],
)
assert updated.source_refs == ["session:a", "session:b", "session:c"]
def test_update_entity_returns_none_for_unknown(env):
assert update_entity("nonexistent", description="x") is None
def test_api_patch_happy_path(env):
e = create_entity(
entity_type="component",
name="tower",
description="old",
properties={"material": "steel"},
confidence=0.6,
)
client = TestClient(app)
r = client.patch(
f"/entities/{e.id}",
json={
"description": "three-stage tower",
"properties": {"material": "invar", "height_mm": 1200},
"confidence": 0.9,
"source_refs": ["session:s1"],
"note": "from voice session",
},
)
assert r.status_code == 200, r.text
body = r.json()
assert body["description"] == "three-stage tower"
assert body["properties"]["material"] == "invar"
assert body["properties"]["height_mm"] == 1200
assert body["confidence"] == 0.9
assert "session:s1" in body["source_refs"]
def test_api_patch_omitted_fields_unchanged(env):
e = create_entity(
entity_type="component",
name="keep-desc",
description="keep me",
)
client = TestClient(app)
r = client.patch(
f"/entities/{e.id}",
json={"confidence": 0.7},
)
assert r.status_code == 200
assert r.json()["description"] == "keep me"
def test_api_patch_404_on_missing(env):
client = TestClient(app)
r = client.patch("/entities/does-not-exist", json={"description": "x"})
assert r.status_code == 404
def test_api_patch_rejects_bad_confidence(env):
e = create_entity(entity_type="component", name="bad-conf")
client = TestClient(app)
r = client.patch(f"/entities/{e.id}", json={"confidence": 2.0})
assert r.status_code == 400
def test_api_patch_aliased_under_v1(env):
e = create_entity(entity_type="component", name="v1-patch")
client = TestClient(app)
r = client.patch(
f"/v1/entities/{e.id}",
json={"description": "via v1"},
)
assert r.status_code == 200
assert get_entity(e.id).description == "via v1"
def test_api_patch_audit_row_written(env):
from atocore.engineering.service import get_entity_audit
e = create_entity(entity_type="component", name="audit-check")
client = TestClient(app)
client.patch(
f"/entities/{e.id}",
json={"description": "new", "note": "manual edit"},
)
audit = get_entity_audit(e.id)
actions = [a["action"] for a in audit]
assert "updated" in actions