sdlc-hub/tests/test_cli.py

142 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import os
from pathlib import Path
import pytest
from sdlc_hub.core import api, cli, paths, release, settings
FIXTURE = Path(__file__).parent / "fixtures" / "config.example.json"
def test_init_import_tokens(tmp_path, monkeypatch, capsys, open_db):
monkeypatch.setenv("SDLC_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 api.project_rows(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 api.project_rows(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("SDLC_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 (release.module_dir(paths.release_root(), "jira") / "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("SDLC_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(release.module_dir(paths.release_root(), "jira"))["version"] == 8
assert sorted(p.name for p in release.module_dir(paths.release_root(), "jira").iterdir()) == ["agent.py", "manifest.json"]
def test_mcp_module_required(monkeypatch, capsys):
from sdlc_hub.core import mcp as core_mcp
from sdlc_hub.modules.jira import mcp as jira_mcp
seen = []
monkeypatch.setattr(core_mcp, "PROJECT", None) # run() пишет глобал; monkeypatch вернёт прежнее значение
monkeypatch.setattr(jira_mcp.mcp, "run", lambda transport="stdio": seen.append(core_mcp.PROJECT))
assert cli.main(["mcp", "--project", "AWPCA"]) == 2
err = capsys.readouterr().err
assert "укажите модуль: sdlc-hub mcp <модуль>" in err and "jira, wiki" in err
assert seen == []
assert cli.main(["mcp", "jira", "--project", "AWPCA"]) == 0
assert seen == ["AWPCA"]
monkeypatch.setattr(core_mcp, "PROJECT", "STALE")
assert cli.main(["mcp", "jira"]) == 0
assert seen[-1] is None
def test_mcp_unknown_module(monkeypatch, capsys):
from sdlc_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 == []
def test_agent_publish_migrates_old_layout(tmp_path, monkeypatch, capsys):
"""M-3: корневые agent.py/manifest.json прежней раскладки переезжают в release/jira/ до проверки «только вверх»."""
monkeypatch.setenv("SDLC_HUB_HOME", str(tmp_path))
rel = tmp_path / "release"
rel.mkdir()
old = tmp_path / "old.py"
old.write_text("AGENT_VERSION = 14\n", encoding="utf-8")
release.publish(rel, old) # прежняя раскладка: release/agent.py + manifest.json
new = tmp_path / "new.py"
new.write_text("AGENT_VERSION = 13\n", encoding="utf-8")
assert cli.main(["agent", "publish", str(new)]) == 1 # v13 < v14: «только вверх» видит прежнюю публикацию
assert not (rel / "agent.py").exists() and not (rel / "manifest.json").exists()
assert json.loads((rel / "jira" / "manifest.json").read_text(encoding="utf-8"))["version"] == 14
def _homes(monkeypatch, tmp_path, legacy=True, new=False):
monkeypatch.delenv("SDLC_HUB_HOME", raising=False)
monkeypatch.setenv("HOME", str(tmp_path))
share = tmp_path / ".local" / "share"
if legacy: (share / "jira-hub").mkdir(parents=True)
if new: (share / "sdlc-hub").mkdir(parents=True)
return share
@pytest.mark.parametrize("argv", [["serve"], ["tokens"], ["mcp", "jira"], ["agent", "publish", "x.py"]])
def test_legacy_home_refused(monkeypatch, tmp_path, capsys, argv):
share = _homes(monkeypatch, tmp_path)
assert cli.main(argv) == 2
err = capsys.readouterr().err
assert "~/.local/share/jira-hub" in err and "scripts/cutover.sh" in err
assert not (share / "sdlc-hub").exists()
assert sorted(p.name for p in (share / "jira-hub").iterdir()) == []
def test_both_homes_warn(monkeypatch, tmp_path, capsys):
_homes(monkeypatch, tmp_path, new=True)
cli.main(["tokens"])
assert "прежний каталог ~/.local/share/jira-hub можно удалить" in capsys.readouterr().err
def test_env_home_skips_legacy_check(monkeypatch, tmp_path, capsys):
_homes(monkeypatch, tmp_path)
monkeypatch.setenv("SDLC_HUB_HOME", str(tmp_path / "x"))
assert cli.main(["tokens"]) == 0