import { describe, it, expect, beforeEach, afterEach } from "vitest"; import * as fs from "fs"; import * as os from "os"; import * as path from "path"; import { DisclawDatabase } from "../../src/db/database"; /** * Integration tests for DisclawDatabase schema initialization. * * Each test uses a fresh SQLite file in os.tmpdir() to ensure full isolation. * The DB file is cleaned up after each test. */ function makeTmpDbPath(): string { return path.join(os.tmpdir(), `disclaw-test-${Date.now()}-${Math.random().toString(36).slice(2)}.db`); } describe("db-init: schema initialization", () => { let dbPath: string; let db: DisclawDatabase; beforeEach(() => { dbPath = makeTmpDbPath(); }); afterEach(() => { try { db.close(); } catch { // ignore if already closed } try { fs.unlinkSync(dbPath); } catch { // best-effort cleanup } }); // (a) All expected tables exist after initialization it("creates all expected tables on first init", () => { db = new DisclawDatabase(dbPath); // Query sqlite_master for user-created tables const rawDb = (db as unknown as { db: import("better-sqlite3").Database }).db; const tables = rawDb .prepare("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name") .all() as { name: string }[]; const tableNames = tables.map((t) => t.name); expect(tableNames).toContain("workspaces"); expect(tableNames).toContain("conversations"); }); // (b) Initializing the same DB path twice is idempotent (IF NOT EXISTS) it("is idempotent when initialized twice (IF NOT EXISTS)", () => { db = new DisclawDatabase(dbPath); db.close(); // Second initialization must not throw expect(() => { db = new DisclawDatabase(dbPath); }).not.toThrow(); const rawDb = (db as unknown as { db: import("better-sqlite3").Database }).db; const tables = rawDb .prepare("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name") .all() as { name: string }[]; const tableNames = tables.map((t) => t.name); expect(tableNames).toContain("workspaces"); expect(tableNames).toContain("conversations"); }); // (c) Basic CRUD: create a workspace and retrieve it by channel_id it("supports basic workspace CRUD", () => { db = new DisclawDatabase(dbPath); const created = db.createWorkspace( "channel-001", "guild-001", "test-agent", "/tmp/test-agent" ); expect(created.id).toBeGreaterThan(0); expect(created.channel_id).toBe("channel-001"); expect(created.guild_id).toBe("guild-001"); expect(created.agent_name).toBe("test-agent"); expect(created.workspace_path).toBe("/tmp/test-agent"); expect(created.created_at).toBeTruthy(); const fetched = db.getWorkspaceByChannelId("channel-001"); expect(fetched).toBeDefined(); expect(fetched!.id).toBe(created.id); expect(fetched!.agent_name).toBe("test-agent"); }); });