98 lines
3.8 KiB
Python
98 lines
3.8 KiB
Python
"""Tests for the per-session KIMI_CODE_HOME builder."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import tomllib
|
|
|
|
from omnigent.kimi_native_credentials import (
|
|
KIMI_CODE_HOME_ENV_VAR,
|
|
build_kimi_session_home,
|
|
render_kimi_hooks_toml,
|
|
)
|
|
|
|
|
|
def _fake_user_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
|
|
"""Point ``resolve_user_kimi_home`` at a populated fake global home."""
|
|
user_home = tmp_path / "user-kimi"
|
|
user_home.mkdir()
|
|
(user_home / "config.toml").write_text(
|
|
'default_model = "kimi-code/x"\n[providers."managed"]\ntype = "kimi"\n', encoding="utf-8"
|
|
)
|
|
(user_home / "oauth").mkdir()
|
|
(user_home / "oauth" / "token").write_text("secret", encoding="utf-8")
|
|
monkeypatch.setenv(KIMI_CODE_HOME_ENV_VAR, str(user_home))
|
|
return user_home
|
|
|
|
|
|
def test_render_hooks_toml_is_valid_and_complete() -> None:
|
|
toml = render_kimi_hooks_toml(bridge_dir=Path("/tmp/b r"), python_executable="/py")
|
|
parsed = tomllib.loads(toml)
|
|
events = {h["event"] for h in parsed["hooks"]}
|
|
assert events == {"PreToolUse", "PermissionRequest"}
|
|
for hook in parsed["hooks"]:
|
|
assert "omnigent.kimi_native_hook" in hook["command"]
|
|
assert "/tmp/b r" in hook["command"] # space-bearing path round-trips
|
|
# ``-I`` (isolated mode) is mandatory: kimi runs the hook with cwd set to
|
|
# the session workspace, so without it a workspace containing its own
|
|
# ``omnigent/`` shadows the install and the hook dies on ImportError
|
|
# before publishing the approval card.
|
|
assert " -I -m omnigent.kimi_native_hook" in hook["command"]
|
|
# Pinned above kimi's 30s default so the permission hook survives a slow
|
|
# web verdict (else the injected keystroke never lands); 600 is kimi's
|
|
# ceiling.
|
|
assert hook["timeout"] == 600
|
|
|
|
|
|
def test_build_session_home_preserves_user_config_and_appends_hooks(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
_fake_user_home(tmp_path, monkeypatch)
|
|
session_home = tmp_path / "session-home"
|
|
bridge_dir = tmp_path / "bridge"
|
|
bridge_dir.mkdir()
|
|
|
|
env = build_kimi_session_home(session_home, bridge_dir=bridge_dir)
|
|
|
|
assert env == {KIMI_CODE_HOME_ENV_VAR: str(session_home)}
|
|
parsed = tomllib.loads((session_home / "config.toml").read_text(encoding="utf-8"))
|
|
# User config preserved …
|
|
assert parsed["default_model"] == "kimi-code/x"
|
|
assert "managed" in parsed["providers"]
|
|
# … and the Omnigent hooks appended.
|
|
assert {h["event"] for h in parsed["hooks"]} == {"PreToolUse", "PermissionRequest"}
|
|
|
|
|
|
def test_build_session_home_symlinks_auth_but_not_config(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
_fake_user_home(tmp_path, monkeypatch)
|
|
session_home = tmp_path / "session-home"
|
|
bridge_dir = tmp_path / "bridge"
|
|
bridge_dir.mkdir()
|
|
|
|
build_kimi_session_home(session_home, bridge_dir=bridge_dir)
|
|
|
|
# oauth is symlinked through to the user's tokens (auth keeps working) …
|
|
oauth_link = session_home / "oauth"
|
|
assert oauth_link.is_symlink()
|
|
assert (oauth_link / "token").read_text(encoding="utf-8") == "secret"
|
|
# … but config.toml is a real file (we own its content), not a symlink.
|
|
assert not (session_home / "config.toml").is_symlink()
|
|
|
|
|
|
def test_build_session_home_without_user_home_writes_hooks_only(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
monkeypatch.setenv(KIMI_CODE_HOME_ENV_VAR, str(tmp_path / "does-not-exist"))
|
|
session_home = tmp_path / "session-home"
|
|
bridge_dir = tmp_path / "bridge"
|
|
bridge_dir.mkdir()
|
|
|
|
build_kimi_session_home(session_home, bridge_dir=bridge_dir)
|
|
|
|
parsed = tomllib.loads((session_home / "config.toml").read_text(encoding="utf-8"))
|
|
assert {h["event"] for h in parsed["hooks"]} == {"PreToolUse", "PermissionRequest"}
|