Newer
Older
navi-1 / tests / unit / test_content_store.py
@Eugene Sukhodolskiy Eugene Sukhodolskiy on 29 Apr 3 KB Complete phase 7 regression test coverage
"""Unit tests for session content metadata store."""

import pytest

import navi.content_store as content_store
from tests.conftest_factory import FakeConnection, FakePool


class TestEnsureTables:
    async def test_creates_session_content_table_and_indexes(self, monkeypatch):
        conn = FakeConnection()

        async def fake_pool():
            return FakePool(conn)

        monkeypatch.setattr(content_store, "_get_db_pool", fake_pool)

        await content_store.ensure_tables()

        executed = "\n".join(call[1] for call in conn.calls if call[0] == "execute")
        assert "CREATE TABLE IF NOT EXISTS session_content" in executed
        assert "idx_session_content_session" in executed
        assert "CREATE UNIQUE INDEX IF NOT EXISTS idx_session_content_file" in executed
        assert "ON session_content (session_id, filename)" in executed

    async def test_ensure_tables_is_idempotent(self, monkeypatch):
        conn = FakeConnection()

        async def fake_pool():
            return FakePool(conn)

        monkeypatch.setattr(content_store, "_get_db_pool", fake_pool)

        await content_store.ensure_tables()
        await content_store.ensure_tables()

        unique_index_calls = [
            call for call in conn.calls
            if call[0] == "execute" and "idx_session_content_file" in call[1]
        ]
        assert len(unique_index_calls) == 2
        assert all("IF NOT EXISTS" in call[1] for call in unique_index_calls)


class TestPublish:
    @pytest.fixture(autouse=True)
    def _session_dir(self, monkeypatch, tmp_path):
        monkeypatch.setattr(content_store.settings, "session_files_dir", str(tmp_path / "sessions"))
        monkeypatch.setattr(content_store.settings, "public_url", "http://localhost:8000")

    async def test_upserts_by_session_and_filename(self, monkeypatch, tmp_path):
        conn = FakeConnection()
        conn.enqueue("INSERT 0 1")

        async def fake_pool():
            return FakePool(conn)

        monkeypatch.setattr(content_store, "_get_db_pool", fake_pool)
        sess_dir = tmp_path / "sessions" / "sess-1"
        sess_dir.mkdir(parents=True)
        (sess_dir / "logo.svg").write_text("<svg></svg>")

        info = await content_store.publish(
            session_id="sess-1",
            filename="logo.svg",
            title="Logo",
        )

        assert info["id"] == "sess-1_logo.svg"
        assert info["url"] == "http://localhost:8000/sessions/sess-1/files/logo.svg"
        call = conn.calls[0]
        assert call[0] == "execute"
        assert "ON CONFLICT (session_id, filename) DO UPDATE" in call[1]
        assert call[2][1:5] == ("sess-1", "logo.svg", "svg", "Logo")

    async def test_repeated_publish_uses_same_content_id_and_upsert(self, monkeypatch, tmp_path):
        conn = FakeConnection()
        conn.enqueue("INSERT 0 1")
        conn.enqueue("INSERT 0 1")

        async def fake_pool():
            return FakePool(conn)

        monkeypatch.setattr(content_store, "_get_db_pool", fake_pool)
        sess_dir = tmp_path / "sessions" / "sess-1"
        sess_dir.mkdir(parents=True)
        (sess_dir / "logo.svg").write_text("<svg></svg>")

        first = await content_store.publish(session_id="sess-1", filename="logo.svg", title="Logo")
        second = await content_store.publish(session_id="sess-1", filename="logo.svg", title="Logo 2")

        assert first["id"] == second["id"] == "sess-1_logo.svg"
        execute_calls = [call for call in conn.calls if call[0] == "execute"]
        assert len(execute_calls) == 2
        assert all("ON CONFLICT (session_id, filename) DO UPDATE" in call[1] for call in execute_calls)

    async def test_missing_file_raises(self, monkeypatch, tmp_path):
        async def fake_pool():
            return FakePool(FakeConnection())

        monkeypatch.setattr(content_store, "_get_db_pool", fake_pool)

        with pytest.raises(FileNotFoundError):
            await content_store.publish(session_id="sess-1", filename="missing.svg")