Thicket/tests/test_layout.py

106 lines
3.9 KiB
Python

"""AI layout awareness and path expansion."""
from __future__ import annotations
from pathlib import Path
import pytest
import thicket.layout as layout
from thicket.pipeline_core import IngestConfig
@pytest.fixture
def fake_ai(tmp_path: Path, monkeypatch):
(tmp_path / "corpus" / "cold").mkdir(parents=True)
(tmp_path / "corpus" / "hot").mkdir(parents=True)
(tmp_path / "corpus" / "books").mkdir(parents=True)
monkeypatch.setattr(layout, "AI_ROOT", tmp_path)
return tmp_path
def test_layout_detected_with_corpus_taxonomy(fake_ai):
profile = layout.detect_layout()
assert profile is not None
assert profile.corpus_cold == fake_ai / "corpus" / "cold"
assert profile.corpus_hot == fake_ai / "corpus" / "hot"
assert profile.books_present is True
assert profile.archive == fake_ai / "corpus" / "archive"
def test_layout_absent_without_corpus(tmp_path, monkeypatch):
monkeypatch.setattr(layout, "AI_ROOT", tmp_path)
assert layout.detect_layout() is None
def test_defaults_follow_the_layout(fake_ai):
assert layout.default_input() == fake_ai / "corpus" / "cold"
assert layout.default_vault() == fake_ai / "corpus" / "hot"
assert layout.default_archive(Path("/anywhere/in")) == fake_ai / "corpus" / "archive"
def test_defaults_fall_home_without_layout(tmp_path, monkeypatch):
monkeypatch.setattr(layout, "AI_ROOT", tmp_path)
assert layout.default_input() == Path.home() / "Downloads" / "Raw_Books_And_Papers"
assert layout.default_vault() == Path.home() / "Documents" / "ObsidianVault"
assert layout.default_archive(Path("/data/in")) == Path("/data/ingested-archive")
def test_archive_falls_back_to_sibling_without_layout(tmp_path, monkeypatch):
monkeypatch.setattr(layout, "AI_ROOT", tmp_path)
assert layout.default_archive(Path("/data/in")) == Path("/data/ingested-archive")
def test_expand_path_tilde_and_env(monkeypatch):
monkeypatch.setenv("THICKET_TEST_DIR", "/tmp/thicket-expanded")
assert layout.expand_path("~/books") == Path.home() / "books"
assert layout.expand_path("$THICKET_TEST_DIR/x") == Path("/tmp/thicket-expanded/x")
assert layout.expand_path("/plain/path") == Path("/plain/path")
def test_ingest_config_expands_paths(monkeypatch):
monkeypatch.setenv("THICKET_TEST_DIR", "/tmp/thicket-expanded")
config = IngestConfig(input_dir="~/in", vault_dir="$THICKET_TEST_DIR/vault",
archive_dir="$THICKET_TEST_DIR/archive",
use_qdrant=False)
assert config.input_dir == Path.home() / "in"
assert config.vault_dir == Path("/tmp/thicket-expanded/vault")
assert config.archive_dir == Path("/tmp/thicket-expanded/archive")
def test_backend_profiles_fill_gaps_env_wins(tmp_path, monkeypatch):
import os
import thicket.layout as layout
backends = tmp_path / "backends"
backends.mkdir()
(backends / "thicket.env").write_text(
"# profile\n"
"PGHOST=db.local\n"
"PGUSER='fileuser'\n"
"MINIO_ENDPOINT=\"127.0.0.1:9000\"\n"
"NOT_A_LINE\n", encoding="utf-8")
monkeypatch.setattr(layout, "AI_ROOT", tmp_path)
for key in ("PGHOST", "PGUSER", "MINIO_ENDPOINT"):
monkeypatch.delenv(key, raising=False)
applied = layout.apply_backend_profiles()
assert applied == {"PGHOST": "db.local", "PGUSER": "fileuser",
"MINIO_ENDPOINT": "127.0.0.1:9000"}
assert os.environ["PGUSER"] == "fileuser"
monkeypatch.setenv("PGUSER", "shelluser")
monkeypatch.delenv("PGHOST", raising=False)
applied = layout.apply_backend_profiles()
assert "PGUSER" not in applied # environment wins
assert applied["PGHOST"] == "db.local" # gaps still filled
assert os.environ["PGUSER"] == "shelluser"
def test_backend_profiles_absent_file_is_noop(tmp_path, monkeypatch):
import thicket.layout as layout
monkeypatch.setattr(layout, "AI_ROOT", tmp_path)
assert layout.apply_backend_profiles() == {}