from __future__ import annotations import sqlite3 import pytest from investibook.api import auth from investibook.db import queries as dbq from investibook.models.requests import ( AgentRuntimePreferenceRequest, SandboxPreferenceRequest, SessionPrewarmPreferenceRequest, ) def test_agent_runtime_preference_and_sessions_are_user_scoped(tmp_path, monkeypatch): db_path = tmp_path / "investibook.db" monkeypatch.setattr(dbq, "DB_PATH", db_path) dbq._db_init() first = dbq._db_get_or_create_user("first@example.com") second = dbq._db_get_or_create_user("second@example.com") assert first["agent_runtime"] == "" assert first["sandbox_provider"] == "" assert first["session_prewarm_enabled"] == 0 dbq._db_set_user_agent_runtime(first["id"], "pi") dbq._db_set_user_sandbox_provider(first["id"], "run9") assert dbq._db_get_user_by_id(first["id"])["agent_runtime"] == "pi" assert dbq._db_get_user_by_id(first["id"])["sandbox_provider"] == "run9" dbq._db_set_agent_session("ws-1", "pi", "session-first", first["id"]) dbq._db_set_agent_session("ws-1", "pi", "session-second", second["id"]) assert dbq._db_get_agent_session("ws-1", "pi", first["id"]) == "session-first" assert dbq._db_get_agent_session("ws-1", "pi", second["id"]) == "session-second" dbq._db_set_agent_session( "ws-1", "pi", "session-first-run9", first["id"], "run9" ) assert ( dbq._db_get_agent_session("ws-1", "pi", first["id"], "run9") == "session-first-run9" ) assert dbq._db_get_agent_session("ws-1", "pi", first["id"], "local") is None dbq._db_set_agent_session("ws-1", "pi", "legacy-shared-session") assert dbq._db_get_agent_session("ws-1", "pi", "new-user") is None def test_db_init_migrates_user_runtime_preference(tmp_path, monkeypatch): db_path = tmp_path / "investibook.db" conn = sqlite3.connect(db_path) conn.execute( "CREATE TABLE users (id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE, " "password_hash TEXT, created_at TEXT NOT NULL)" ) conn.execute( "INSERT INTO users (id, email, password_hash, created_at) VALUES (?, ?, ?, ?)", ("user-1", "user@example.com", None, "2026-01-01T00:00:00Z"), ) conn.commit() conn.close() monkeypatch.setattr(dbq, "DB_PATH", db_path) dbq._db_init() user = dbq._db_get_user_by_id("user-1") assert user is not None assert user["agent_runtime"] == "" assert user["sandbox_provider"] == "" def test_db_init_migrates_legacy_run9_preference(tmp_path, monkeypatch): db_path = tmp_path / "investibook.db" conn = sqlite3.connect(db_path) conn.execute( "CREATE TABLE users (id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE, " "password_hash TEXT, agent_runtime TEXT NOT NULL DEFAULT '', " "run9_enabled INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL)" ) conn.execute( "INSERT INTO users " "(id, email, password_hash, agent_runtime, run9_enabled, created_at) " "VALUES (?, ?, ?, ?, ?, ?)", ("user-1", "user@example.com", None, "", 1, "2026-01-01T00:00:00Z"), ) conn.commit() conn.close() monkeypatch.setattr(dbq, "DB_PATH", db_path) dbq._db_init() user = dbq._db_get_user_by_id("user-1") assert user is not None assert user["sandbox_provider"] == "run9" assert user["session_prewarm_enabled"] == 0 @pytest.mark.asyncio async def test_agent_runtime_preference_api(monkeypatch): writes: list[tuple[str, str]] = [] monkeypatch.setattr( auth, "_db_set_user_agent_runtime", lambda user_id, runtime: writes.append((user_id, runtime)), ) response = await auth.set_agent_runtime( AgentRuntimePreferenceRequest(agent_runtime="pi"), current_user={"id": "user-1", "email": "user@example.com"}, ) assert response == {"agent_runtime": "pi"} assert writes == [("user-1", "pi")] @pytest.mark.asyncio async def test_sandbox_preference_api(monkeypatch): writes: list[tuple[str, str]] = [] monkeypatch.setattr(auth, "available_sandbox_provider_names", lambda: ("run9",)) monkeypatch.setattr( auth, "_db_set_user_sandbox_provider", lambda user_id, provider: writes.append((user_id, provider)), ) response = await auth.set_sandbox_preference( SandboxPreferenceRequest(provider="run9"), current_user={"id": "user-1", "email": "user@example.com"}, ) assert response == {"sandbox_provider": "run9"} assert writes == [("user-1", "run9")] @pytest.mark.asyncio async def test_sandbox_preference_rejects_unavailable_provider(monkeypatch): monkeypatch.setattr(auth, "available_sandbox_provider_names", lambda: ()) with pytest.raises(auth.HTTPException) as exc_info: await auth.set_sandbox_preference( SandboxPreferenceRequest(provider="run9"), current_user={"id": "user-1", "email": "user@example.com"}, ) assert exc_info.value.status_code == 409 @pytest.mark.asyncio async def test_session_prewarm_preference_api(monkeypatch): writes: list[tuple[str, bool]] = [] monkeypatch.setattr( auth, "_db_set_user_session_prewarm", lambda user_id, enabled: writes.append((user_id, enabled)), ) response = await auth.set_session_prewarm_preference( SessionPrewarmPreferenceRequest(enabled=True), current_user={"id": "user-1", "email": "user@example.com"}, ) assert response == {"session_prewarm_enabled": True} assert writes == [("user-1", True)]