import json import os from pathlib import Path from jira_hub.core import cli, paths, projects, release, settings FIXTURE = Path(__file__).parent / "fixtures" / "config.example.json" def test_init_import_tokens(tmp_path, monkeypatch, capsys, open_db): monkeypatch.setenv("JIRA_HUB_HOME", str(tmp_path / "home")) assert cli.main(["init", "--config", str(FIXTURE)]) == 0 out = capsys.readouterr().out assert "transitions_map" in out and "агент jira: " in out assert cli.main(["init", "--config", str(FIXTURE)]) == 1 assert "уже инициализирован" in capsys.readouterr().err conn = open_db(paths.db_path()) assert [(x["label"], x["name"], x["board_id"]) for x in projects.list_projects(conn)] == [("AWPCA", "АРМ КА", 4216)] assert settings.get(conn, "board_id") is None assert "проект AWPCA «АРМ КА», доска 4216" in out assert cli.main(["init", "--config", str(FIXTURE), "--force"]) == 0 capsys.readouterr() assert [(x["label"], x["board_id"]) for x in projects.list_projects(conn)] == [("AWPCA", 4216)] (tmp_path / "pkg").mkdir() (tmp_path / "pkg" / "tasks.csv").write_text("Код,Статус по факту,Вид работы\nAURORA-1,В работе,UI\n", encoding="utf-8") assert cli.main(["import", str(tmp_path / "pkg")]) == 0 rep = json.loads(capsys.readouterr().out) assert rep["notes"] == 1 and rep["missing_keys"] == ["AURORA-1"] assert cli.main(["tokens"]) == 0 assert settings.tokens(conn)["client"] in capsys.readouterr().out def test_agent_publish(tmp_path, monkeypatch, capsys): monkeypatch.setenv("JIRA_HUB_HOME", str(tmp_path / "home")) src = tmp_path / "agent.py" src.write_text("AGENT_VERSION = 6\n", encoding="utf-8") assert cli.main(["agent", "publish", str(src)]) == 0 out = capsys.readouterr().out assert out.startswith("опубликована v6, sha256 ") and "…, 18 байт" in out assert (paths.release_dir() / "manifest.json").exists() assert cli.main(["agent", "publish", str(src)]) == 1 assert "опубликована v6, новая должна быть больше" in capsys.readouterr().err def test_agent_publish_write_failure(tmp_path, monkeypatch, capsys): """Диск полон при записи манифеста: сообщение и код 1 без трейсбека, опубликованной остаётся v8 (M-1 #25).""" monkeypatch.setenv("JIRA_HUB_HOME", str(tmp_path / "home")) src = tmp_path / "agent.py" src.write_text("AGENT_VERSION = 8\n", encoding="utf-8") assert cli.main(["agent", "publish", str(src)]) == 0 capsys.readouterr() real = os.replace def fake(s, d, *a, **kw): if Path(d).name == "manifest.json": raise OSError(28, "No space left on device") return real(s, d, *a, **kw) monkeypatch.setattr(os, "replace", fake) src.write_text("AGENT_VERSION = 9\n", encoding="utf-8") assert cli.main(["agent", "publish", str(src)]) == 1 err = capsys.readouterr().err assert err.startswith("не удалось записать публикацию: ") and "Traceback" not in err monkeypatch.setattr(os, "replace", real) assert release.load(paths.release_dir())["version"] == 8 assert sorted(p.name for p in paths.release_dir().iterdir()) == ["agent.py", "manifest.json"] def test_mcp_default_module(monkeypatch): from jira_hub.core import mcp as core_mcp from jira_hub.modules.jira import mcp as jira_mcp seen = [] monkeypatch.setattr(core_mcp, "PROJECT", None) monkeypatch.setattr(jira_mcp.mcp, "run", lambda transport="stdio": seen.append((transport, core_mcp.PROJECT))) assert cli.main(["mcp", "--project", "AWPCA"]) == 0 assert cli.main(["mcp", "jira", "--project", "AWPCA"]) == 0 assert seen == [("stdio", "AWPCA"), ("stdio", "AWPCA")] # без --project сессия не привязана к проекту monkeypatch.setattr(core_mcp, "PROJECT", "STALE") assert cli.main(["mcp"]) == 0 assert seen[-1] == ("stdio", None) def test_mcp_unknown_module(monkeypatch, capsys): from jira_hub.modules.jira import mcp as jira_mcp seen = [] monkeypatch.setattr(jira_mcp.mcp, "run", lambda transport="stdio": seen.append(transport)) assert cli.main(["mcp", "nope"]) == 2 err = capsys.readouterr().err assert "неизвестный модуль nope" in err and "jira" in err assert seen == []