"""Unit tests for navi.store.KvStore."""
import pytest
from navi.store import KvStore
from tests.conftest_factory import FakeConnection, FakePool, FakeRecord
class TestKvStore:
@pytest.fixture
def store(self):
s = KvStore(dsn="postgresql://fake")
s._pool = FakePool()
return s
@pytest.mark.asyncio
async def test_get_missing(self, store):
store._pool._conn.enqueue(None)
result = await store.get(None, "sess1", "todo", "task1")
assert result is None
@pytest.mark.asyncio
async def test_set_and_get(self, store):
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "task1", "value1")
store._pool._conn.enqueue(FakeRecord(value="value1"))
result = await store.get(None, "sess1", "todo", "task1")
assert result == "value1"
@pytest.mark.asyncio
async def test_set_overwrites(self, store):
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key", "first")
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key", "second")
store._pool._conn.enqueue(FakeRecord(value="second"))
result = await store.get(None, "sess1", "todo", "key")
assert result == "second"
@pytest.mark.asyncio
async def test_get_all(self, store):
store._pool._conn.enqueue([
FakeRecord(key="a", value="1"),
FakeRecord(key="b", value="2"),
])
result = await store.get_all(None, "sess1", "todo")
assert result == {"a": "1", "b": "2"}
@pytest.mark.asyncio
async def test_delete(self, store):
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key", "val")
store._pool._conn.enqueue("OK")
await store.delete(None, "sess1", "todo", "key")
store._pool._conn.enqueue(None)
result = await store.get(None, "sess1", "todo", "key")
assert result is None
@pytest.mark.asyncio
async def test_clear_scope(self, store):
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key1", "val1")
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key2", "val2")
store._pool._conn.enqueue("OK")
await store.clear_scope(None, "sess1", "todo")
store._pool._conn.enqueue([])
result = await store.get_all(None, "sess1", "todo")
assert result == {}
@pytest.mark.asyncio
async def test_null_user_id_normalized(self, store):
"""None user_id is normalized to '' before queries — prevents duplicate
rows because PostgreSQL treats NULL as distinct in unique constraints."""
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key", "val")
# Verify the query used '' not NULL
calls = store._pool._conn.calls
execute_call = [c for c in calls if c[0] == "execute"][0]
assert execute_call[2][0] == "" # first arg is user_id = ''
@pytest.mark.asyncio
async def test_different_sessions_isolated(self, store):
store._pool._conn.enqueue("OK")
await store.set(None, "sess1", "todo", "key", "val1")
store._pool._conn.enqueue("OK")
await store.set(None, "sess2", "todo", "key", "val2")
store._pool._conn.enqueue(FakeRecord(value="val1"))
result1 = await store.get(None, "sess1", "todo", "key")
store._pool._conn.enqueue(FakeRecord(value="val2"))
result2 = await store.get(None, "sess2", "todo", "key")
assert result1 == "val1"
assert result2 == "val2"