From 533283219a8179b9482b2ce4a68ed30a34f21860 Mon Sep 17 00:00:00 2001 From: Gros Frumos Date: Wed, 18 Mar 2026 22:31:10 +0200 Subject: [PATCH] =?UTF-8?q?kin:=20KIN-ARCH-023=20=D0=98=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=B8=D0=BD=D0=B6=D0=B5=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D1=8E=20analyst=20=E2=80=94=20steps=20=D0=BD=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D1=8E=D1=82=D1=81=D1=8F?= =?UTF-8?q?=20=D0=B2=20subprocess?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_db.py | 42 ++++++++++++++++++++++++++++++++++++++++++ tests/test_runner.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/tests/test_db.py b/tests/test_db.py index a622171..9d26f19 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -1,7 +1,11 @@ """Tests for core/db.py — schema and migration (KIN-071, KIN-073).""" +import importlib +import os import sqlite3 import pytest +from pathlib import Path +from unittest.mock import patch from core.db import init_db, _migrate @@ -541,3 +545,41 @@ def test_migrate_creates_pipeline_log_if_missing(): tables = {r["name"] for r in conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()} assert "pipeline_log" in tables conn.close() + + +# --------------------------------------------------------------------------- +# KIN-129: DB_PATH резолвинг — KIN_DB_PATH env var и fallback на ~/.kin/kin.db +# --------------------------------------------------------------------------- + +class TestDbPathResolution: + """DB_PATH должен брать путь из KIN_DB_PATH или падать на ~/.kin/kin.db (KIN-129).""" + + def test_db_path_uses_kin_db_path_when_set(self): + """Если KIN_DB_PATH задан — DB_PATH равен именно ему.""" + import core.db as db_module + custom = "/tmp/custom_kin_test_129.db" + with patch.dict("os.environ", {"KIN_DB_PATH": custom}): + importlib.reload(db_module) + assert str(db_module.DB_PATH) == custom + importlib.reload(db_module) # восстановить модуль после теста + + def test_db_path_fallback_to_home_kin_when_env_absent(self): + """Если KIN_DB_PATH не задан — DB_PATH = ~/.kin/kin.db.""" + import core.db as db_module + env_without = {k: v for k, v in os.environ.items() if k != "KIN_DB_PATH"} + with patch.dict("os.environ", env_without, clear=True): + importlib.reload(db_module) + expected = Path.home() / ".kin" / "kin.db" + assert db_module.DB_PATH == expected + importlib.reload(db_module) # восстановить модуль после теста + + def test_db_path_not_relative_to_source_file(self): + """DB_PATH не должен быть относительным путём вида parent.parent/kin.db (регрессия KIN-129).""" + import core.db as db_module + env_without = {k: v for k, v in os.environ.items() if k != "KIN_DB_PATH"} + with patch.dict("os.environ", env_without, clear=True): + importlib.reload(db_module) + # Путь должен быть абсолютным и вести в ~/.kin/, а не в директорию проекта + assert db_module.DB_PATH.is_absolute() + assert ".kin" in db_module.DB_PATH.parts + importlib.reload(db_module) diff --git a/tests/test_runner.py b/tests/test_runner.py index fc127cb..581c1be 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -1715,6 +1715,47 @@ class TestClaudePath: env = _build_claude_env() assert "SSH_AUTH_SOCK" not in env + # --------------------------------------------------------------------------- + # KIN-129: KIN_DB_PATH инъекция в subprocesses агентов + # --------------------------------------------------------------------------- + + def test_build_claude_env_injects_kin_db_path_when_absent(self): + """Если KIN_DB_PATH не задан — _build_claude_env добавляет ~/.kin/kin.db (KIN-129).""" + import os as _os + from pathlib import Path as _Path + env_without = {k: v for k, v in _os.environ.items() if k != "KIN_DB_PATH"} + with patch.dict("os.environ", env_without, clear=True): + env = _build_claude_env() + expected = str(_Path.home() / ".kin" / "kin.db") + assert env["KIN_DB_PATH"] == expected, ( + "KIN-129: KIN_DB_PATH должен быть установлен в ~/.kin/kin.db при отсутствии в env" + ) + + def test_build_claude_env_preserves_existing_kin_db_path(self): + """Если KIN_DB_PATH уже задан — _build_claude_env не перетирает его (KIN-129).""" + custom = "/custom/worktree/path/kin.db" + with patch.dict("os.environ", {"KIN_DB_PATH": custom}): + env = _build_claude_env() + assert env["KIN_DB_PATH"] == custom, ( + "KIN-129: существующий KIN_DB_PATH не должен быть перезаписан" + ) + + @patch("agents.runner.subprocess.run") + def test_subprocess_receives_kin_db_path_in_env(self, mock_run, conn): + """run_agent передаёт KIN_DB_PATH в subprocess через env= (KIN-129).""" + import os as _os + from pathlib import Path as _Path + mock_run.return_value = _mock_claude_success({"result": "ok"}) + env_without = {k: v for k, v in _os.environ.items() if k != "KIN_DB_PATH"} + with patch.dict("os.environ", env_without, clear=True): + run_agent(conn, "debugger", "VDOL-001", "vdol") + call_kwargs = mock_run.call_args[1] + env = call_kwargs.get("env", {}) + assert "KIN_DB_PATH" in env, ( + "KIN-129: subprocess.run должен получать KIN_DB_PATH в env" + ) + assert env["KIN_DB_PATH"] == str(_Path.home() / ".kin" / "kin.db") + # --------------------------------------------------------------------------- # KIN-063: TestCompletionMode — auto_complete + last-step role check