from __future__ import annotations import importlib.util import json from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] SCRIPT_PATH = ( PROJECT_ROOT / "agentkit" / "skills" / "builtin" / "o11y-alert-rule-lookup" / "scripts" / "find_alert_rule.py" ) def _load_module(): spec = importlib.util.spec_from_file_location("find_alert_rule", SCRIPT_PATH) assert spec and spec.loader module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def test_find_alert_rule_returns_exact_match(tmp_path, capsys): module = _load_module() runbooks_dir = tmp_path / "runbooks" rules_dir = runbooks_dir / "rules" / "tidb" rules_dir.mkdir(parents=True) (rules_dir / "cpu.yaml").write_text( """ groups: - name: tidb.rules rules: - alert: HighCPUUsage expr: sum(rate(process_cpu_seconds_total[5m])) > 0.8 for: 10m annotations: summary: CPU is high - alert: HighMemoryUsage expr: process_resident_memory_bytes > 1024 """.strip() ) code = module.main(["--alert-name", "HighCPUUsage", "--runbooks-dir", str(runbooks_dir)]) captured = capsys.readouterr() payload = json.loads(captured.out) assert code == 0 assert payload["status"] == "ok" assert payload["searched_files"] == 1 assert payload["top_match"]["alert"] == "HighCPUUsage" assert len(payload["exact_matches"]) == 1 assert payload["exact_matches"][0]["alert"] == "HighCPUUsage" assert payload["exact_matches"][0]["file"] == "rules/tidb/cpu.yaml" assert payload["exact_matches"][0]["for"] == "10m" assert "process_cpu_seconds_total" in payload["exact_matches"][0]["expr"] def test_find_alert_rule_returns_fuzzy_candidates_when_exact_missing(tmp_path, capsys): module = _load_module() runbooks_dir = tmp_path / "runbooks" rules_dir = runbooks_dir / "rules" / "tidb" rules_dir.mkdir(parents=True) (rules_dir / "cpu.yaml").write_text( """ groups: - name: tidb.rules rules: - alert: TiDBHighCPUUsage expr: sum(rate(process_cpu_seconds_total[5m])) > 0.8 """.strip() ) code = module.main(["--alert-name", "HighCPUUsage", "--runbooks-dir", str(runbooks_dir)]) captured = capsys.readouterr() payload = json.loads(captured.out) assert code == 0 assert payload["status"] == "ok" assert payload["exact_matches"] == [] assert len(payload["fuzzy_matches"]) == 1 assert payload["top_match"]["alert"] == "TiDBHighCPUUsage" assert payload["fuzzy_matches"][0]["alert"] == "TiDBHighCPUUsage" assert payload["fuzzy_matches"][0]["match_type"] in {"substring", "token_overlap"} def test_find_alert_rule_uses_component_and_messages_to_rank_same_name_matches(tmp_path, capsys): module = _load_module() runbooks_dir = tmp_path / "runbooks" rules_dir = runbooks_dir / "rules" (rules_dir / "tidb").mkdir(parents=True) (rules_dir / "tikv").mkdir(parents=True) (rules_dir / "tidb" / "cpu.yaml").write_text( """ groups: - name: tidb.rules rules: - alert: HighCPUUsage expr: tidb_server_cpu_usage > 0.8 annotations: summary: tidb cpu is high message: executor busy """.strip() ) (rules_dir / "tikv" / "cpu.yaml").write_text( """ groups: - name: tikv.rules rules: - alert: HighCPUUsage expr: tikv_thread_cpu_seconds_total > 0.8 annotations: summary: tikv raftstore cpu is high message: raftstore busy """.strip() ) code = module.main( [ "--alert-name", "HighCPUUsage", "--component", "tikv", "--message", "raftstore busy", "--runbooks-dir", str(runbooks_dir), ] ) captured = capsys.readouterr() payload = json.loads(captured.out) assert code == 0 assert payload["status"] == "ok" assert len(payload["exact_matches"]) == 2 assert payload["top_match"]["file"] == "rules/tikv/cpu.yaml" assert payload["exact_matches"][0]["context_score"] > payload["exact_matches"][1]["context_score"] def test_find_alert_rule_extracts_multiline_expr_blocks(tmp_path, capsys): module = _load_module() runbooks_dir = tmp_path / "runbooks" rules_dir = runbooks_dir / "rules" / "tidb" rules_dir.mkdir(parents=True) (rules_dir / "cpu.yaml").write_text( """ groups: - name: tidb.rules rules: - alert: TiDBCPUCoreUsageOver75ForBig3 expr: | 100 * max by (tenant, cluster_id, cluster) ( sum(rate(node_cpu_seconds_total{component=~"tidb"}[1m])) ) > 75 for: 5m """.strip() ) code = module.main( [ "--alert-name", "TiDBCPUCoreUsageOver75ForBig3", "--runbooks-dir", str(runbooks_dir), ] ) captured = capsys.readouterr() payload = json.loads(captured.out) assert code == 0 assert payload["top_match"]["for"] == "5m" assert "100 * max by" in payload["top_match"]["expr"] assert "sum(rate(node_cpu_seconds_total" in payload["top_match"]["expr"] assert payload["top_match"]["expr"] != "|" def test_find_alert_rule_reports_missing_runbooks_dir(capsys): module = _load_module() code = module.main(["--alert-name", "HighCPUUsage", "--runbooks-dir", "/tmp/does-not-exist"]) captured = capsys.readouterr() payload = json.loads(captured.out) assert code == 2 assert payload["status"] == "error" assert "rules/" in payload["error"]