from __future__ import annotations import pytest from cmvr_edge_ai.application import create_default_registry from cmvr_edge_ai.compiler import PipelineCompileError, compile_pipeline from cmvr_edge_ai.config import load_config_data def _config( rule_label: str, *, attach_frame: bool = False, alert_image: bool = False, ): # type: ignore[no-untyped-def] return load_config_data( { "api_version": "cmvr.edge.ai/v1", "pipelines": { "detection": { "nodes": { "source": { "uses": "core.sequence_source@1", "with": { "items": [], "schema_name": "ImageFrame", }, }, "detector": { "uses": "detection.model@1", "with": { "model": "construction-ppe-yolov8@1", "detect_labels": ["No-Helmet"], "attach_frame": attach_frame, "model_options": {"weights": "/not-loaded.pt"}, }, }, "gate": { "uses": "detection.repeat_gate@1", "with": { "alert_image": {"enabled": alert_image}, "rules": [ { "id": "ppe-rule", "labels": [rule_label], "min_hits": 2, "window_ms": 1000, } ] }, }, }, "edges": [ {"from": "source.output", "to": "detector.frames"}, { "from": "detector.detections", "to": "gate.detections", }, ], } }, } ) def test_compile_accepts_rule_label_selected_by_detector() -> None: compiled = compile_pipeline( _config("No-Helmet"), "detection", create_default_registry(discover_entry_points=False), ) assert set(compiled.plugin_specs) == {"source", "detector", "gate"} def test_compile_rejects_rule_label_ignored_by_detector() -> None: with pytest.raises(PipelineCompileError, match="No-Vest"): compile_pipeline( _config("No-Vest"), "detection", create_default_registry(discover_entry_points=False), ) def test_compile_accepts_alert_images_when_detector_attaches_frames() -> None: compiled = compile_pipeline( _config("No-Helmet", attach_frame=True, alert_image=True), "detection", create_default_registry(discover_entry_points=False), ) assert compiled.runtime.nodes["detector"].attach_frame is True assert compiled.runtime.nodes["gate"].alert_image_enabled is True def test_compile_rejects_alert_images_without_attached_frames() -> None: with pytest.raises( PipelineCompileError, match="enables alert_image.*attach_frame=true", ): compile_pipeline( _config("No-Helmet", attach_frame=False, alert_image=True), "detection", create_default_registry(discover_entry_points=False), )