Files
yovision/tests/test_sense_control_implementation.py
T
QiuSW a0d239811f
Harness governance / validate (push) Has been cancelled
Harness governance / validate (pull_request) Has been cancelled
feat(sense): implement Control API v1 [T-011]
2026-08-07 20:54:41 +08:00

100 lines
4.5 KiB
Python

"""Static safety checks for the T-011 Sense Control API implementation."""
from __future__ import annotations
import json
import pathlib
import re
import unittest
ROOT = pathlib.Path(__file__).resolve().parents[1]
def text(relative: str) -> str:
return (ROOT / relative).read_text(encoding="utf-8")
def normalized(value: str) -> str:
return re.sub(r"\s+", " ", value.lower())
class SenseControlImplementationTests(unittest.TestCase):
def test_generated_server_covers_all_frozen_operations(self) -> None:
generated = text("Sense/internal/controlapi/generated.gen.go")
self.assertIn("Code generated by github.com/oapi-codegen/oapi-codegen/v2", generated)
for operation in (
"ListDevices",
"CreateDevice",
"GetDevice",
"UpdateDevice",
"SetDeviceDesiredState",
"BatchSetDeviceDesiredState",
"GetOperation",
):
self.assertIn(operation, generated)
config = text("Sense/internal/controlapi/oapi-codegen.yaml")
self.assertIn("std-http-server: true", config)
self.assertIn("./internal/controlapi", text("init.ps1"))
def test_control_api_is_feature_gated_to_postgres(self) -> None:
config = text("Sense/internal/config/config.go")
main = text("Sense/cmd/sense-api/main.go")
self.assertIn('SENSE_CONTROL_API_ENABLED', config)
self.assertIn('Control API requires SENSE_DB_DRIVER=postgres', config)
self.assertIn('mux.Handle("/api/v1/", controlHandler)', main)
self.assertNotIn('mux.Handle("/api/v1/"', text("Sense/internal/store/sqlite.go"))
def test_static_authentication_stores_only_digests(self) -> None:
source = text("Sense/internal/auth/auth.go")
example = json.loads(text("Sense/api/control-auth.example.json"))
self.assertIn("subtle.ConstantTimeCompare", source)
self.assertIn("sha256.Sum256([]byte(token))", source)
self.assertNotIn('json:"token"', source)
for principal in example["principals"]:
self.assertRegex(principal["token_sha256"], r"^[0-9a-f]{64}$")
self.assertNotIn("token", principal.keys() - {"token_sha256"})
def test_postgres_receipts_are_hashed_durable_and_at_least_24_hours(self) -> None:
migration = normalized(text("deploy/postgres/008_control_api.sql"))
implementation = text("Sense/internal/store/control_postgres.go")
self.assertIn("create table if not exists sense.control_idempotency_receipts", migration)
self.assertIn("scope_hash bytea primary key", migration)
self.assertIn("expires_at >= created_at + interval '24 hours'", migration)
self.assertNotIn("idempotency_key", migration)
self.assertIn("pg_advisory_xact_lock", implementation)
self.assertIn("ConstantTimeCompare", implementation)
def test_concurrency_batch_and_limits_are_not_hardcoded_to_16(self) -> None:
migration = normalized(text("deploy/postgres/008_control_api.sql"))
server = text("Sense/internal/controlapi/server.go")
store = text("Sense/internal/store/control_postgres.go")
self.assertIn("resource_version bigint not null default 1", migration)
self.assertIn("len(body.Items) > 128", server)
self.assertIn("limit > 100", server)
self.assertIn("SAVEPOINT ", store)
self.assertNotIn("len(body.Items) > 16", server)
def test_audit_v1_is_unchanged_and_v2_is_a_strict_superset(self) -> None:
first = json.loads(text("docs/contracts/sense-device-audit-v1.schema.json"))
second = json.loads(text("docs/contracts/sense-device-audit-v2.schema.json"))
v1_events = set(first["properties"]["event_type"]["enum"])
v2_events = set(second["properties"]["event_type"]["enum"])
self.assertEqual(
{"device.created", "device.desired_state.accepted"}, v1_events
)
self.assertEqual(v1_events | {"device.configuration.accepted"}, v2_events)
self.assertIn("configurationData", second["$defs"])
def test_disabled_reconciliation_deletes_only_exact_path(self) -> None:
reconciler = text("Sense/internal/reconcile/reconciler.go")
media = text("Sense/internal/mtx/client.go")
self.assertIn("candidate.Device.DesiredState == device.DesiredDisabled", reconciler)
self.assertIn("r.media.DeletePath(ctx, candidate.Device.PathName)", reconciler)
self.assertIn("Deletion is an idempotent convergence operation", media)
self.assertNotIn("ListPaths", reconciler)
if __name__ == "__main__":
unittest.main()