The aggregate containers_not_running event carried service=None, which the observer skips when building service state and incidents — stability-agent's flagship signal never opened an incident (recon D15). Emit one event per non-running container instead, tagged with the compose service name from the com.docker.compose.service label (same pattern as node-agent's _canonical_container_name fix from May), falling back to the container name with Docker's stale-state hash prefix stripped; never crashes on unlabeled containers. 'created' compose tracking artifacts are skipped — they are not running services and would open fake incidents now that the event is actionable. Adds the service's first test suite covering the label-extraction helper. Smoke-run performed with runtime paths redirected (no docker build, authoring only): main loop runs, service names resolve on live solaria containers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
48 lines
1.7 KiB
Python
48 lines
1.7 KiB
Python
"""Tests for container_service_name — the compose-label extraction that fixes
|
|
the service=None containers_not_running events (recon D15: observer skips
|
|
events without a service, so stability-agent's flagship signal never opened
|
|
an incident). Input shape is a /containers/json (Docker list API) entry.
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
|
|
|
from stability_agent import container_service_name
|
|
|
|
|
|
def test_compose_label_wins_over_container_name():
|
|
c = {
|
|
"Names": ["/kb-postgres-db-1"],
|
|
"Labels": {"com.docker.compose.service": "kb-postgres"},
|
|
}
|
|
assert container_service_name(c) == "kb-postgres"
|
|
|
|
|
|
def test_unlabeled_falls_back_to_container_name():
|
|
assert container_service_name({"Names": ["/paperless"], "Labels": {}}) == "paperless"
|
|
|
|
|
|
def test_missing_labels_key_does_not_crash():
|
|
assert container_service_name({"Names": ["/mosquitto"]}) == "mosquitto"
|
|
|
|
|
|
def test_null_labels_does_not_crash():
|
|
assert container_service_name({"Names": ["/mosquitto"], "Labels": None}) == "mosquitto"
|
|
|
|
|
|
def test_blank_label_falls_back_to_name():
|
|
c = {"Names": ["/zigbee2mqtt"], "Labels": {"com.docker.compose.service": " "}}
|
|
assert container_service_name(c) == "zigbee2mqtt"
|
|
|
|
|
|
def test_stale_state_hash_prefix_stripped():
|
|
# Docker stores stale project-state records as "<12-hex>_<original-name>";
|
|
# same ghost-key corruption node-agent's _canonical_container_name handles.
|
|
c = {"Names": ["/9e36297651e7_control-plane-observer"], "Labels": {}}
|
|
assert container_service_name(c) == "control-plane-observer"
|
|
|
|
|
|
def test_empty_container_dict_degrades_to_unknown():
|
|
assert container_service_name({}) == "unknown"
|