"""Tests for the builtin Jira skill helper and workspace wiring.""" from __future__ import annotations import base64 import importlib.util import json from pathlib import Path from urllib.parse import parse_qs, urlparse PROJECT_ROOT = Path(__file__).resolve().parents[2] JIRA_SCRIPT = PROJECT_ROOT / "agentkit/skills/builtin/jira/scripts/jira_api.py" def _load_jira_api(): spec = importlib.util.spec_from_file_location("jira_api", JIRA_SCRIPT) assert spec and spec.loader module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module class FakeResponse: def __init__(self, payload: dict): self.payload = payload def __enter__(self): return self def __exit__(self, *args): return False def read(self): return json.dumps(self.payload).encode("utf-8") def _set_jira_env(monkeypatch): monkeypatch.setenv("INVESTIBOOK_JIRA_BASE_URL", "https://jira.example.com") monkeypatch.setenv("INVESTIBOOK_JIRA_USERNAME", "user@example.com") monkeypatch.setenv("INVESTIBOOK_JIRA_API_TOKEN", "secret-token") def test_jira_skill_get_issue_request(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request seen["timeout"] = timeout return FakeResponse({"key": "O11Y-1"}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) result = jira_api.jira_request("GET", "/rest/api/2/issue/O11Y-1") request = seen["request"] assert result == {"key": "O11Y-1"} assert request.full_url == "https://jira.example.com/rest/api/2/issue/O11Y-1" assert request.get_method() == "GET" expected_auth = base64.b64encode( b"user@example.com:secret-token" ).decode("ascii") assert request.get_header("Authorization") == f"Basic {expected_auth}" assert seen["timeout"] == 30 def _parse_search_body(request): """Extract POST body from a v3 search request.""" assert request.get_method() == "POST" parsed = urlparse(request.full_url) assert parsed.path == "/rest/api/3/search/jql" return json.loads(request.data.decode("utf-8")) def test_jira_skill_search_by_cluster_request_params(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"total": 1, "issues": [{"key": "O11Y-2"}]}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-cluster", "--cluster-id", "cluster-1", "--max-results", "25", "--start-at", "50", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["jql"] == 'project = O11Y AND "Cluster ID" = "cluster-1" ORDER BY created DESC' assert "key" in body["fields"] assert body["maxResults"] == 25 assert "startAt" not in body def test_jira_skill_search_by_cluster_next_page_token(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"issues": [], "isLast": True}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-cluster", "--cluster-id", "cluster-1", "--next-page-token", "next-token-1", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["nextPageToken"] == "next-token-1" def test_jira_skill_search_by_cluster_custom_project(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"total": 0, "issues": []}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-cluster", "--cluster-id", "cluster-1", "--project", "TCOC", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["jql"] == 'project = TCOC AND "Cluster ID" = "cluster-1" ORDER BY created DESC' def test_jira_skill_search_by_tenant_request_params(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"total": 2, "issues": [{"key": "O11Y-10"}, {"key": "O11Y-11"}]}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-tenant", "--tenant-id", "tenant-abc", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["jql"] == 'project = O11Y AND "Tenant ID" = "tenant-abc" ORDER BY created DESC' assert "key" in body["fields"] def test_jira_skill_search_by_tenant_custom_project(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"total": 0, "issues": []}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-tenant", "--tenant-id", "tenant-abc", "--project", "TCOC", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["jql"] == 'project = TCOC AND "Tenant ID" = "tenant-abc" ORDER BY created DESC' def test_jira_skill_search_by_alert_name_request_params(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"total": 3, "issues": [{"key": "O11Y-20"}]}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-alert-name", "--alert-name", "HighCPUUsage", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["jql"] == 'project = O11Y AND summary ~ "HighCPUUsage" ORDER BY created DESC' assert "key" in body["fields"] def test_jira_skill_search_by_alert_name_custom_project(monkeypatch): jira_api = _load_jira_api() _set_jira_env(monkeypatch) seen = {} def fake_urlopen(request, timeout): seen["request"] = request return FakeResponse({"total": 0, "issues": []}) monkeypatch.setattr(jira_api.urllib.request, "urlopen", fake_urlopen) code = jira_api.main([ "search-by-alert-name", "--alert-name", "HighCPUUsage", "--project", "TCOC", "--max-results", "20", ]) assert code == 0 body = _parse_search_body(seen["request"]) assert body["jql"] == 'project = TCOC AND summary ~ "HighCPUUsage" ORDER BY created DESC' assert body["maxResults"] == 20 def test_jira_skill_extract_alert_info(): jira_api = _load_jira_api() issue = { "fields": { "customfield_10086": "org-1", "customfield_10088": "cluster-1", "customfield_10160": json.dumps( {"labels": {"o11y_tenant_id": "tenant-1", "alertname": "HighCPU"}} ), } } assert jira_api.extract_alert_info(issue) == { "tenant_id": "tenant-1", "cluster_id": "cluster-1", "alert_name": "HighCPU", "org_id": "org-1", } def test_jira_skill_missing_credentials_exits_without_secret(monkeypatch, capsys): jira_api = _load_jira_api() monkeypatch.delenv("INVESTIBOOK_JIRA_USERNAME", raising=False) monkeypatch.delenv("JIRA_USERNAME", raising=False) monkeypatch.delenv("INVESTIBOOK_JIRA_API_TOKEN", raising=False) monkeypatch.delenv("JIRA_PASSWORD", raising=False) code = jira_api.main(["get-issue", "--issue-key", "O11Y-1"]) captured = capsys.readouterr() assert code == 2 assert "Jira credentials are missing" in captured.err assert "secret" not in captured.err.lower() def test_jira_builtin_skill_is_default_enabled(tmp_path): from investibook.core.workspace_setup import _copy_default_enabled_skills all_skills = tmp_path / ".all-skills" jira_skill = all_skills / "builtin" / "jira" jira_skill.mkdir(parents=True) (jira_skill / "SKILL.md").write_text("# jira\n") enabled = tmp_path / "skills" _copy_default_enabled_skills(all_skills, enabled) assert (enabled / "builtin" / "jira" / "SKILL.md").exists() def test_o11y_alert_rule_lookup_builtin_skill_is_default_enabled(tmp_path): from investibook.core.workspace_setup import _copy_default_enabled_skills all_skills = tmp_path / ".all-skills" skill_dir = all_skills / "builtin" / "o11y-alert-rule-lookup" skill_dir.mkdir(parents=True) (skill_dir / "SKILL.md").write_text("# o11y-alert-rule-lookup\n") enabled = tmp_path / "skills" _copy_default_enabled_skills(all_skills, enabled) assert (enabled / "builtin" / "o11y-alert-rule-lookup" / "SKILL.md").exists() def test_evidence_report_builtin_skill_is_not_default_enabled(tmp_path): from investibook.core.workspace_setup import _copy_default_enabled_skills all_skills = tmp_path / ".all-skills" evidence_report_skill = all_skills / "builtin" / "evidence-report" evidence_report_skill.mkdir(parents=True) (evidence_report_skill / "SKILL.md").write_text("# evidence-report\n") enabled = tmp_path / "skills" _copy_default_enabled_skills(all_skills, enabled) assert not (enabled / "builtin" / "evidence-report" / "SKILL.md").exists() def test_refresh_managed_skills_removes_agent_facing_diagnosis_skills(tmp_path): from investibook.core.workspace_setup import _refresh_managed_skills all_skills = tmp_path / ".all-skills" enabled = tmp_path / "skills" diagnosis_src = all_skills / "builtin" / "tidb-clinic-diagnosis" diagnosis_src.mkdir(parents=True) (diagnosis_src / "SKILL.md").write_text("# new diagnosis skill\n") diagnosis_enabled = enabled / "builtin" / "tidb-clinic-diagnosis" diagnosis_enabled.mkdir(parents=True) (diagnosis_enabled / "SKILL.md").write_text("# old diagnosis skill\n") evidence_report_enabled = enabled / "builtin" / "evidence-report" evidence_report_enabled.mkdir(parents=True) (evidence_report_enabled / "SKILL.md").write_text("# evidence-report\n") query_tuning_enabled = enabled / "tidb-query-tuning" query_tuning_enabled.mkdir(parents=True) (query_tuning_enabled / "SKILL.md").write_text("# query tuning\n") _refresh_managed_skills(all_skills, enabled) assert not diagnosis_enabled.exists() assert not query_tuning_enabled.exists() assert not evidence_report_enabled.exists() def test_existing_jira_skill_is_refreshed(tmp_path): from investibook.core.workspace_setup import _copy_default_enabled_skills all_skills = tmp_path / ".all-skills" jira_skill = all_skills / "builtin" / "jira" jira_skill.mkdir(parents=True) (jira_skill / "SKILL.md").write_text("# new jira\n") enabled_skill = tmp_path / "skills" / "builtin" / "jira" enabled_skill.mkdir(parents=True) (enabled_skill / "SKILL.md").write_text("# existing jira\n") from investibook.core.workspace_setup import _refresh_managed_skills _refresh_managed_skills(all_skills, tmp_path / "skills") assert (enabled_skill / "SKILL.md").read_text() == "# new jira\n" def test_refresh_managed_skills_does_not_reenable_disabled_default(tmp_path): from investibook.core.workspace_setup import _refresh_managed_skills all_skills = tmp_path / ".all-skills" jira_skill = all_skills / "builtin" / "jira" jira_skill.mkdir(parents=True) (jira_skill / "SKILL.md").write_text("# current jira\n") enabled = tmp_path / "skills" _refresh_managed_skills(all_skills, enabled) assert not (enabled / "builtin" / "jira").exists() def test_jira_removed_from_tool_server_config(): template_path = PROJECT_ROOT / "agentkit/config/opencode.json.template" config = json.loads(template_path.read_text()) assert "m" + "cp" not in config