from __future__ import annotations from copy import deepcopy from dataclasses import dataclass from .differential import DifferentialProbe from .model import Response @dataclass class FixtureService: enforce_tenant: bool def __post_init__(self) -> None: self.objects = { "object-a": {"id": "object-a", "tenant": "tenant-a", "label": "fixture-a"}, "object-b": {"id": "object-b", "tenant": "tenant-b", "label": "fixture-b"}, } def snapshot_b(self) -> object: return deepcopy(self.objects.get("object-b")) def read(self, actor_tenant: str, object_id: str) -> Response: item = self.objects.get(object_id) if item is None or (self.enforce_tenant and item["tenant"] != actor_tenant): return Response(404, {"error": "not_found"}) return Response(200, deepcopy(item)) def list_for(self, actor_tenant: str, requested_tenant: str) -> Response: tenant = actor_tenant if self.enforce_tenant else requested_tenant items = [deepcopy(item) for item in self.objects.values() if item["tenant"] == tenant] return Response(200, {"items": items}) def create_for(self, actor_tenant: str, requested_tenant: str, object_id: str) -> Response: if self.enforce_tenant and actor_tenant != requested_tenant: return Response(403, {"error": "forbidden"}) self.objects[object_id] = { "id": object_id, "tenant": requested_tenant, "label": "fixture-created", } return Response(201, {"id": object_id, "tenant": requested_tenant}) def update(self, actor_tenant: str, object_id: str) -> Response: item = self.objects.get(object_id) if item is None or (self.enforce_tenant and item["tenant"] != actor_tenant): return Response(404, {"error": "not_found"}) item["label"] = "fixture-mutated" return Response(200, deepcopy(item)) def delete(self, actor_tenant: str, object_id: str) -> Response: item = self.objects.get(object_id) if item is None or (self.enforce_tenant and item["tenant"] != actor_tenant): return Response(404, {"error": "not_found"}) del self.objects[object_id] return Response(200, {"deleted": object_id}) def probe_suite(service: FixtureService) -> list[DifferentialProbe]: markers = ("object-b", "tenant-b", "fixture-b", "fixture-mutated") return [ DifferentialProbe( "read-by-id", "read", lambda: service.read("tenant-b", "object-b"), lambda: service.read("tenant-a", "object-b"), lambda: service.read("tenant-a", "absent"), markers, ), DifferentialProbe( "list-filter", "read", lambda: service.list_for("tenant-b", "tenant-b"), lambda: service.list_for("tenant-a", "tenant-b"), lambda: Response(200, {"items": []}), markers, hide_existence=False, ), DifferentialProbe( "create-attributed-to-b", "create", lambda: Response(201, {"id": "owner-control"}), lambda: service.create_for("tenant-a", "tenant-b", "object-created"), lambda: Response(403, {"error": "forbidden"}), markers + ("object-created",), state=lambda: deepcopy(service.objects), hide_existence=False, ), DifferentialProbe( "update-b", "update", lambda: Response(200, service.snapshot_b()), lambda: service.update("tenant-a", "object-b"), lambda: service.read("tenant-a", "absent"), markers, state=service.snapshot_b, ), DifferentialProbe( "delete-b", "delete", lambda: Response(200, service.snapshot_b()), lambda: service.delete("tenant-a", "object-b"), lambda: service.read("tenant-a", "absent"), markers, state=service.snapshot_b, ), ]