116 lines
3.9 KiB
Python
116 lines
3.9 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from cmvr_edge_ai.application import (
|
|
create_default_capability_registry,
|
|
create_default_registry,
|
|
)
|
|
from cmvr_edge_ai.capabilities import ServingMode
|
|
from cmvr_edge_ai.compiler import compile_pipeline
|
|
from cmvr_edge_ai.config import load_config_data
|
|
from cmvr_edge_ai.gauge import GAUGE_CATEGORY, GAUGE_MODEL_ID, GAUGE_PLUGIN_ID
|
|
from cmvr_edge_ai.server.catalog import build_deployed_catalog
|
|
|
|
|
|
def _node_params(tmp_path: Path) -> dict[str, object]:
|
|
for name in ("detection.pt", "keypoints.pt", "segmentation.pt"):
|
|
(tmp_path / name).write_bytes(b"model")
|
|
return {
|
|
"category": GAUGE_CATEGORY,
|
|
"model_id": GAUGE_MODEL_ID,
|
|
"python_executable": sys.executable,
|
|
"project_root": str(tmp_path),
|
|
"detection_model_path": "detection.pt",
|
|
"key_point_model_path": "keypoints.pt",
|
|
"segmentation_model_path": "segmentation.pt",
|
|
}
|
|
|
|
|
|
def _config(tmp_path: Path): # type: ignore[no-untyped-def]
|
|
return load_config_data(
|
|
{
|
|
"api_version": "cmvr.edge.ai/v1",
|
|
"pipelines": {
|
|
"gauge_remote": {
|
|
"nodes": {
|
|
"request": {
|
|
"uses": "server.request_source@1",
|
|
"with": {"category": GAUGE_CATEGORY},
|
|
},
|
|
"reader": {
|
|
"uses": GAUGE_PLUGIN_ID,
|
|
"with": _node_params(tmp_path),
|
|
},
|
|
"sink": {"uses": "server.response_sink@1"},
|
|
},
|
|
"edges": [
|
|
{
|
|
"from": "request.requests",
|
|
"to": "reader.requests",
|
|
},
|
|
{
|
|
"from": "reader.responses",
|
|
"to": "sink.responses",
|
|
},
|
|
],
|
|
}
|
|
},
|
|
"server": {
|
|
"enabled": True,
|
|
"routes": {
|
|
GAUGE_CATEGORY: {
|
|
"pipeline": "gauge_remote",
|
|
"model_id": GAUGE_MODEL_ID,
|
|
}
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
|
|
def test_default_registries_expose_gauge_plugin_and_capability() -> None:
|
|
plugins = create_default_registry(discover_entry_points=False)
|
|
capabilities = create_default_capability_registry(discover_entry_points=False)
|
|
|
|
plugin = plugins.resolve(GAUGE_PLUGIN_ID)
|
|
capability = capabilities.resolve(GAUGE_MODEL_ID)
|
|
assert plugin.inputs == {"requests": "InferenceRequest/v1"}
|
|
assert plugin.outputs == {"responses": "InferenceResponse/v1"}
|
|
assert capability.category == GAUGE_CATEGORY
|
|
assert capability.family == "gauge"
|
|
assert capability.serving_modes == (ServingMode.PASSIVE_INVOKE,)
|
|
assert capability.input_kinds == ("image",)
|
|
assert capability.output_kinds == ("scalar",)
|
|
assert capability.artifact_roles == (
|
|
"original",
|
|
"annotated",
|
|
"diagnostics",
|
|
)
|
|
|
|
|
|
def test_gauge_invocation_pipeline_compiles_without_detection_adapters(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
config = _config(tmp_path)
|
|
compiled = compile_pipeline(
|
|
config,
|
|
"gauge_remote",
|
|
create_default_registry(discover_entry_points=False),
|
|
)
|
|
|
|
assert compiled.plugin_specs["reader"].plugin_id == GAUGE_PLUGIN_ID
|
|
assert set(compiled.plugin_specs) == {"request", "reader", "sink"}
|
|
|
|
|
|
def test_deployed_catalog_classifies_gauge_as_passive_only(tmp_path: Path) -> None:
|
|
catalog = build_deployed_catalog(
|
|
_config(tmp_path),
|
|
create_default_capability_registry(discover_entry_points=False),
|
|
)
|
|
|
|
assert catalog.active_push == ()
|
|
assert [item.model_id for item in catalog.passive_invoke] == [GAUGE_MODEL_ID]
|
|
assert catalog.passive_invoke[0].category == GAUGE_CATEGORY
|