"""Tests for catalog loader.""" import textwrap import pytest from bridge.catalog.loader import CatalogLoadError, load_catalog from bridge.catalog.models import Catalog @pytest.fixture def catalog_dir(tmp_path): """Build a minimal valid catalog fixture.""" root = tmp_path / "opscatalog" domain_dir = root / "domains" / "coulombcore" (domain_dir / "targets").mkdir(parents=True) (domain_dir / "bridges").mkdir(parents=True) (domain_dir / "docs").mkdir(parents=True) actors_dir = root / "actors" actors_dir.mkdir(parents=True) (domain_dir / "domain.yaml").write_text(textwrap.dedent("""\ type: domain id: coulombcore name: CoulombCore Infrastructure description: Core infra environment: production """)) (domain_dir / "targets" / "state-hub.yaml").write_text(textwrap.dedent("""\ type: target id: state-hub domain: coulombcore kind: service description: State coordination service reachable_via: - state-hub-coulombcore """)) (domain_dir / "bridges" / "state-hub-coulombcore.yaml").write_text(textwrap.dedent("""\ type: bridge id: state-hub-coulombcore domain: coulombcore target: state-hub description: Ops bridge access_method: ssh-reverse host: coulombcore.local remote_port: 18000 local_port: 8000 ssh_user: ubuntu ssh_key: ~/.ssh/id_ops actor: agent.claude-coulombcore health_check: url: http://127.0.0.1:18000/health interval_seconds: 30 timeout_seconds: 5 reconnect: max_attempts: 0 backoff_initial: 5 backoff_max: 60 """)) (actors_dir / "agents.yaml").write_text(textwrap.dedent("""\ type: actor id: agent.claude-coulombcore class: automation description: Claude Code agent on CoulombCore """)) (domain_dir / "docs" / "overview.md").write_text("# Overview\nSome ops notes.") return root class TestLoadCatalog: def test_loads_domain(self, catalog_dir): cat = load_catalog(catalog_dir) assert "coulombcore" in cat.domains d = cat.domains["coulombcore"] assert d.name == "CoulombCore Infrastructure" assert d.environment == "production" def test_loads_target(self, catalog_dir): cat = load_catalog(catalog_dir) assert "state-hub" in cat.targets t = cat.targets["state-hub"] assert t.domain == "coulombcore" assert t.kind == "service" assert "state-hub-coulombcore" in t.reachable_via def test_loads_bridge(self, catalog_dir): cat = load_catalog(catalog_dir) assert "state-hub-coulombcore" in cat.bridges b = cat.bridges["state-hub-coulombcore"] assert b.host == "coulombcore.local" assert b.remote_port == 18000 assert b.health_check is not None assert b.health_check.url == "http://127.0.0.1:18000/health" assert b.reconnect is not None assert b.reconnect.max_attempts == 0 def test_loads_actor(self, catalog_dir): cat = load_catalog(catalog_dir) assert "agent.claude-coulombcore" in cat.actors a = cat.actors["agent.claude-coulombcore"] assert a.actor_class == "automation" def test_unknown_type_skipped(self, catalog_dir): (catalog_dir / "domains" / "coulombcore" / "unknown.yaml").write_text( "type: mystery\nid: x\n" ) # Should not raise cat = load_catalog(catalog_dir) assert isinstance(cat, Catalog) def test_empty_catalog_dir(self, tmp_path): root = tmp_path / "empty" root.mkdir() cat = load_catalog(root) assert cat.domains == {} assert cat.bridges == {} def test_missing_required_field_raises(self, tmp_path): root = tmp_path / "bad" domain_dir = root / "domains" / "x" domain_dir.mkdir(parents=True) (domain_dir / "domain.yaml").write_text("type: domain\nname: X\n") with pytest.raises(CatalogLoadError, match="id"): load_catalog(root) def test_nonexistent_path_raises(self, tmp_path): with pytest.raises(CatalogLoadError, match="not found"): load_catalog(tmp_path / "nonexistent") def test_invalid_yaml_raises(self, tmp_path): root = tmp_path / "bad" domain_dir = root / "domains" / "x" domain_dir.mkdir(parents=True) (domain_dir / "domain.yaml").write_text("type: domain\n[\nbad: yaml") with pytest.raises(CatalogLoadError): load_catalog(root)