"""Unit: the shared source resolver (phase 35, task 03; local kind, phase 38, task 03). ``effective_sources`` is driven with a stubbed session (no Postgres) and a fresh ``Settings(_env_file=None)`` env (monkeypatched into the resolver's module — the dev ``.env`` never leaks in, same pattern as the integration suites): DB rows of **both kinds** win in ``(added_at, id)`` order (env ignored), the ``BOR_GIT_SOURCES`` list is a git-only fallback while the table is empty (surfaced as synthetic ``kind='git'`` rows, phase-28 CSV parse reused), and both-empty yields ``([], "env")`` so the callers keep their fail-loud behavior. The phase-35 ``effective_git_sources`` alias is kept covered as well: it returns the repo URLs of the git rows only, same origin. """ from __future__ import annotations import re from typing import Any import pytest from app.config import Settings from app.models import GitSource from app.rag import git_sources as resolver class _FakeScalars: """The ``.scalars(stmt).all()`` tail of the resolver's query.""" def __init__(self, rows: list[GitSource]) -> None: self._rows = rows def all(self) -> list[GitSource]: return self._rows class _FakeSession: """Just enough of a SQLAlchemy session for the resolver (test_steering pattern). Records the statement so the ordering can be asserted.""" def __init__(self, rows: list[GitSource]) -> None: self._rows = rows self.statements: list[Any] = [] def scalars(self, stmt: Any) -> _FakeScalars: self.statements.append(stmt) return _FakeScalars(self._rows) def _stub_env(monkeypatch: pytest.MonkeyPatch, git_sources: str) -> None: """Point the resolver's env fallback at a fresh Settings (no .env).""" monkeypatch.setattr( resolver, "get_settings", lambda: Settings(_env_file=None, git_sources=git_sources), # pyright: ignore[reportCallIssue] ) def _git(url: str) -> GitSource: return GitSource(url=url, kind="git") def _local(path: str) -> GitSource: """A local row as phase-38 task 02 stores it: the expanded path in both ``path`` and the NOT-NULL ``url`` location column.""" return GitSource(url=path, kind="local", path=path) # --- the three branches ---------------------------------------------------- def test_db_rows_win_over_env(monkeypatch: pytest.MonkeyPatch) -> None: """Seeded table + env set → the DB rows, origin ``db`` (env ignored).""" _stub_env(monkeypatch, "https://env.example/ignored.git") session = _FakeSession( [GitSource(url="https://db.example/a.git"), GitSource(url="https://db.example/b.git")] ) rows, origin = resolver.effective_sources(session) # pyright: ignore[reportArgumentType] assert [row.url for row in rows] == ["https://db.example/a.git", "https://db.example/b.git"] assert origin == "db" def test_mixed_kinds_returned_in_row_order(monkeypatch: pytest.MonkeyPatch) -> None: """Phase 38: the table holds git **and** local rows — both come back, in ``(added_at, id)`` row order, kinds and paths intact, env ignored.""" _stub_env(monkeypatch, "https://env.example/ignored.git") local = "/abs/notes" session = _FakeSession( [_git("https://db.example/a.git"), _local(local), _git("git@db.example:b.git")] ) rows, origin = resolver.effective_sources(session) # pyright: ignore[reportArgumentType] assert origin == "db" assert [row.kind for row in rows] == ["git", "local", "git"] assert [row.url for row in rows] == [ "https://db.example/a.git", local, "git@db.example:b.git", ] assert [row.path for row in rows] == [None, local, None] def test_env_fallback_git_only_while_table_empty(monkeypatch: pytest.MonkeyPatch) -> None: """Empty table + env set → synthetic ``kind='git'`` rows, origin ``env``. The env fallback is git-only (no local rows can come from it); the CSV parse is ``Settings.git_source_list`` itself (phase 28): whitespace-trimmed, empty entries dropped, order preserved. """ _stub_env(monkeypatch, " https://env.example/one.git , ,git@env.example:two.git ") session = _FakeSession([]) rows, origin = resolver.effective_sources(session) # pyright: ignore[reportArgumentType] assert origin == "env" assert [row.url for row in rows] == ["https://env.example/one.git", "git@env.example:two.git"] assert all(row.kind == "git" for row in rows) assert all(row.path is None for row in rows) def test_both_empty_returns_empty_env(monkeypatch: pytest.MonkeyPatch) -> None: """Empty table + unset env → ``([], "env")`` — the callers fail loudly.""" _stub_env(monkeypatch, " , ") # whitespace-only is just as unconfigured as empty session = _FakeSession([]) rows, origin = resolver.effective_sources(session) # pyright: ignore[reportArgumentType] assert rows == [] assert origin == "env" # --- the ordering ---------------------------------------------------------- def test_db_rows_ordered_by_added_at_then_id(monkeypatch: pytest.MonkeyPatch) -> None: """The statement orders by ``(added_at, id)`` — oldest first, the id tie-break deciding same-timestamp inserts (matches the API's GET).""" _stub_env(monkeypatch, "") session = _FakeSession([_git("https://db.example/a.git")]) resolver.effective_sources(session) # pyright: ignore[reportArgumentType] assert len(session.statements) == 1 compiled = str(session.statements[0].compile(compile_kwargs={"literal_binds": True})) assert re.search( r"ORDER BY\s+git_sources\.added_at ASC,\s+git_sources\.id ASC", compiled ), compiled # --- the phase-35 back-compat alias ---------------------------------------- def test_alias_returns_git_urls_only(monkeypatch: pytest.MonkeyPatch) -> None: """``effective_git_sources`` (phase-35 name) — repo URLs of the git rows only; local rows are filtered out (they carry no clone URL), origin unchanged.""" _stub_env(monkeypatch, "") session = _FakeSession( [_git("https://db.example/a.git"), _local("/abs/notes"), _git("git@db.example:b.git")] ) urls, origin = resolver.effective_git_sources(session) # pyright: ignore[reportArgumentType] assert urls == ["https://db.example/a.git", "git@db.example:b.git"] assert origin == "db" def test_alias_env_fallback_unchanged(monkeypatch: pytest.MonkeyPatch) -> None: """The alias's env fallback is byte-identical to the phase-35 one (git-only CSV list, origin ``env``).""" _stub_env(monkeypatch, " https://env.example/one.git , ") session = _FakeSession([]) urls, origin = resolver.effective_git_sources(session) # pyright: ignore[reportArgumentType] assert urls == ["https://env.example/one.git"] assert origin == "env"