"""Hardening tests for ``muse domain-info`` — agent supercharge series. Tests added in this pass ------------------------ - ``duration_ms`` present and valid in every JSON output path - ``exit_code`` present and zero in every JSON output path - JSON is compact (no ``indent=2``) - Schema sub-object includes ``domain`` key - ``plugin_class`` is a non-empty string - ``--all-domains`` carries both new fields - ``--capabilities-only`` carries both new fields - Data integrity: exit_code always int, duration_ms always non-negative float - Performance: 100 sequential calls complete under 10 s - Security: no traceback, error JSON goes to stderr """ from __future__ import annotations from collections.abc import Mapping import json import pathlib import time import pytest from tests.cli_test_helper import CliRunner, InvokeResult from muse.core.paths import muse_dir runner = CliRunner() # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _make_repo(tmp_path: pathlib.Path, domain: str = "code") -> pathlib.Path: repo = tmp_path / "repo" dot_muse = muse_dir(repo) for sub in ("objects", "commits", "snapshots", "refs/heads"): (dot_muse / sub).mkdir(parents=True) (dot_muse / "HEAD").write_text("ref: refs/heads/main") (dot_muse / "repo.json").write_text( json.dumps({"repo_id": "test-repo", "domain": domain}) ) return repo def _di(repo: pathlib.Path | None, *args: str) -> InvokeResult: from muse.cli.app import main as cli env = {"MUSE_REPO_ROOT": str(repo)} if repo is not None else {} return runner.invoke(cli, ["domain-info", "--json", *args], env=env) def _json(result: InvokeResult) -> Mapping[str, object]: return json.loads(result.output) # --------------------------------------------------------------------------- # JSON schema — main output (active-repo / --domain) # --------------------------------------------------------------------------- class TestJsonSchemaComplete: """Every success path must include duration_ms and exit_code.""" def test_active_repo_has_duration_ms(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "duration_ms" in data def test_active_repo_has_exit_code(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "exit_code" in data def test_exit_code_is_zero_on_success(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert data["exit_code"] == 0 def test_duration_ms_is_float(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert isinstance(data["duration_ms"], float) def test_duration_ms_non_negative(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert data["duration_ms"] >= 0.0 def test_duration_ms_six_decimal_places(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) # round(..., 6) → at most 6 decimal places assert data["duration_ms"] == round(data["duration_ms"], 6) def test_domain_flag_has_duration_ms(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code")) assert "duration_ms" in data def test_domain_flag_has_exit_code(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code")) assert "exit_code" in data assert data["exit_code"] == 0 def test_all_base_fields_present(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) for key in ( "domain", "plugin_class", "capabilities", "schema", "registered_domains", "duration_ms", "exit_code", ): assert key in data, f"missing key: {key}" # --------------------------------------------------------------------------- # JSON schema — --all-domains # --------------------------------------------------------------------------- class TestAllDomainsSchema: def test_all_domains_has_duration_ms(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--all-domains")) assert "duration_ms" in data def test_all_domains_has_exit_code(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--all-domains")) assert "exit_code" in data def test_all_domains_exit_code_zero(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--all-domains")) assert data["exit_code"] == 0 def test_all_domains_elapsed_non_negative(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--all-domains")) assert data["duration_ms"] >= 0.0 # --------------------------------------------------------------------------- # JSON schema — --capabilities-only # --------------------------------------------------------------------------- class TestCapabilitiesOnlySchema: def test_capabilities_only_has_duration_ms(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code", "--capabilities-only")) assert "duration_ms" in data def test_capabilities_only_has_exit_code(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code", "--capabilities-only")) assert "exit_code" in data def test_capabilities_only_exit_code_zero(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code", "--capabilities-only")) assert data["exit_code"] == 0 def test_capabilities_only_elapsed_non_negative(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code", "--capabilities-only")) assert data["duration_ms"] >= 0.0 def test_capabilities_only_no_schema_key(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code", "--capabilities-only")) assert "domain_schema" not in data def test_capabilities_only_repo_mode_has_elapsed(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo, "--capabilities-only")) assert "duration_ms" in data # --------------------------------------------------------------------------- # Compact JSON (no indent=2) # --------------------------------------------------------------------------- class TestCompactJson: def test_main_output_is_compact(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) result = _di(repo) assert result.exit_code == 0 # compact JSON has no leading whitespace on lines after the first lines = result.output.strip().splitlines() assert len(lines) == 1, "JSON must be a single line (compact)" def test_all_domains_is_compact(self, tmp_path: pathlib.Path) -> None: result = _di(None, "--all-domains") lines = result.output.strip().splitlines() assert len(lines) == 1 def test_capabilities_only_is_compact(self, tmp_path: pathlib.Path) -> None: result = _di(None, "--domain", "code", "--capabilities-only") lines = result.output.strip().splitlines() assert len(lines) == 1 # --------------------------------------------------------------------------- # Schema sub-object integrity # --------------------------------------------------------------------------- class TestSchemaSubObject: def test_schema_has_domain_key(self, tmp_path: pathlib.Path) -> None: """schema.domain must match the top-level domain field.""" repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "domain" in data["domain_schema"] assert data["domain_schema"]["domain"] == data["domain"] def test_schema_has_merge_mode(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "merge_mode" in data["domain_schema"] assert isinstance(data["domain_schema"]["merge_mode"], str) def test_schema_has_description(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "description" in data["domain_schema"] assert len(data["domain_schema"]["description"]) > 0 def test_schema_has_dimensions(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "dimensions" in data["domain_schema"] assert isinstance(data["domain_schema"]["dimensions"], list) def test_schema_version_present(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert "schema_version" in data["domain_schema"] # --------------------------------------------------------------------------- # plugin_class field # --------------------------------------------------------------------------- class TestPluginClass: def test_plugin_class_is_non_empty_string(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert isinstance(data["plugin_class"], str) assert len(data["plugin_class"]) > 0 def test_plugin_class_ends_with_plugin(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert data["plugin_class"].endswith("Plugin") def test_domain_flag_plugin_class(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--domain", "code")) assert data["plugin_class"] == "CodePlugin" # --------------------------------------------------------------------------- # Data integrity # --------------------------------------------------------------------------- class TestDataIntegrity: def test_exit_code_is_int_not_bool(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert type(data["exit_code"]) is int def test_duration_ms_is_float_not_int(self, tmp_path: pathlib.Path) -> None: """Must be a float (e.g. 0.001234) not a plain integer.""" repo = _make_repo(tmp_path) data = _json(_di(repo)) # JSON 0 deserialises as int — make sure we always get a float assert isinstance(data["duration_ms"], float) def test_capabilities_values_are_bool(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) for k, v in data["capabilities"].items(): assert isinstance(v, bool), f"capabilities.{k} must be bool, got {type(v)}" def test_registered_domains_no_duplicates(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--all-domains")) domains = data["registered_domains"] assert len(domains) == len(set(domains)) def test_registered_domains_sorted(self, tmp_path: pathlib.Path) -> None: data = _json(_di(None, "--all-domains")) domains = data["registered_domains"] assert domains == sorted(domains) def test_domain_in_registered_domains(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path, domain="code") data = _json(_di(repo)) assert data["domain"] in data["registered_domains"] # --------------------------------------------------------------------------- # Performance # --------------------------------------------------------------------------- class TestPerformance: def test_single_call_under_1s(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) t0 = time.monotonic() _di(repo) assert time.monotonic() - t0 < 1.0 def test_duration_ms_plausible(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) data = _json(_di(repo)) assert data["duration_ms"] < 10.0 def test_100_calls_under_10s(self, tmp_path: pathlib.Path) -> None: t0 = time.monotonic() for i in range(100): result = _di(None, "--all-domains") assert result.exit_code == 0 assert time.monotonic() - t0 < 10.0