"""Агенты модулей: токен определяет модуль, миграция v7 сохраняет агента jira (wiki-module, решения 1–3, 6, 15).""" import pytest from jira_hub.core import cli, db, queue, settings from jira_hub.core.client import HubError from v6db import make_v6_db def test_v6_upgrade_keeps_jira_agent(tmp_path): make_v6_db(tmp_path / "hub.sqlite") conn = db.connect(tmp_path / "hub.sqlite") try: assert db._schema_version(conn) == 7 tok = settings.tokens(conn) assert tok["client"] == "T-client" and tok["agents"]["jira"] == "T-agent" and "agent" not in tok row = conn.execute("SELECT * FROM agent_status WHERE agent = 'jira'").fetchone() assert row["agent_version"] == "14" assert conn.execute("SELECT COUNT(*) AS n FROM agent_status").fetchone()["n"] == 1 assert list((tmp_path / "backups").glob("*schema-v6*")) # копия перед миграцией finally: conn.close() def test_v6_upgrade_keeps_settings_and_projects(tmp_path): make_v6_db(tmp_path / "hub.sqlite") conn = db.connect(tmp_path / "hub.sqlite") try: assert settings.get(conn, "min_agent_version") == 1 rows = conn.execute("SELECT label, board_id, board_type FROM project ORDER BY label").fetchall() assert [tuple(r) for r in rows] == [("AWPCA", 4216, "scrum"), ("sfm_kedr", None, None)] finally: conn.close() def test_migrate_adds_status_row_for_new_agent_module(conn_two_modules): """R-1: строки agent_status для модулей реестра вставляются при каждом migrate, а не только в шаге 6 → 7.""" names = {r["agent"] for r in conn_two_modules.execute("SELECT agent FROM agent_status")} assert names == {"jira", "stub"} def test_ensure_defaults_adds_missing_agent_token(conn_two_modules): tok = settings.tokens(conn_two_modules) assert set(tok["agents"]) == {"jira", "stub"} and tok["agents"]["jira"] != tok["agents"]["stub"] def test_agent_token_routes(hub_server): assert hub_server["agent"].post("/agent/claim", {})["command"] is None assert hub_server["agent"].get("/agent/settings")["settings_version"] >= 1 with pytest.raises(HubError) as e: hub_server["client"].post("/agent/claim", {}) assert e.value.status == 401 def test_module_agent_route_requires_own_module(hub_server_two_modules): jira, stub = hub_server_two_modules["agents"]["jira"], hub_server_two_modules["agents"]["stub"] with pytest.raises(HubError) as e: stub.post("/agent/state", {}) assert e.value.status == 401 with pytest.raises(HubError) as e: jira.post("/agent/stub", {}) assert e.value.status == 401 assert stub.post("/agent/stub", {}) == {"agent": "stub"} assert jira.post("/agent/claim", {})["command"] is None # маршруты ядра открыты обоим агентам assert stub.post("/agent/claim", {})["command"] is None def test_agent_settings_per_module(hub_server_two_modules): jira = hub_server_two_modules["agents"]["jira"].get("/agent/settings") stub = hub_server_two_modules["agents"]["stub"].get("/agent/settings") assert "project_key" in jira and "transitions_map" in jira and "settings_version" in jira assert "stub_key" not in jira and "board_id" not in jira assert set(stub) == {"stub_key", "settings_version"} def test_agent_query_cannot_be_forged(hub_server_two_modules): """Служебный ключ запроса приходит только от диспетчера: _agent в адресе перезаписывается.""" stub = hub_server_two_modules["agents"]["stub"] assert stub.call("POST", "/agent/stub", {}, params={"_agent": "jira"}) == {"agent": "stub"} def test_tokens_cli_lists_agents(tmp_path, monkeypatch, capsys): monkeypatch.setenv("JIRA_HUB_HOME", str(tmp_path)) assert cli.main(["tokens"]) == 0 lines = capsys.readouterr().out.splitlines() assert lines[0].startswith("клиентский токен: ") and lines[1].startswith("агент jira: ") assert lines[2].startswith("база: ") def test_agent_view_min_version_from_module_key(conn_two_modules): conn_two_modules.execute("UPDATE agent_status SET agent_version = '3' WHERE agent = 'jira'") settings.set_(conn_two_modules, "min_agent_version", 5) assert queue.agent_view(conn_two_modules, "jira")["warning"] == "обновите агента" assert queue.agent_view(conn_two_modules, "stub")["warning"] is None