import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { SessionStore } from './store.js'; import { unlinkSync, existsSync } from 'fs'; import { join } from 'path'; import { tmpdir } from 'os'; describe('SessionStore', () => { const dbPath = join(tmpdir(), 'flynn-test-sessions.db'); let store: SessionStore; beforeEach(() => { store = new SessionStore(dbPath); }); afterEach(() => { store.close(); if (existsSync(dbPath)) { unlinkSync(dbPath); } }); it('saves and retrieves messages', () => { const sessionId = 'test-session'; store.addMessage(sessionId, { role: 'user', content: 'Hello' }); store.addMessage(sessionId, { role: 'assistant', content: 'Hi there!' }); const messages = store.getMessages(sessionId); expect(messages).toHaveLength(2); expect(messages[0].role).toBe('user'); expect(messages[0].content).toBe('Hello'); expect(messages[1].role).toBe('assistant'); expect(messages[1].content).toBe('Hi there!'); }); it('clears session messages', () => { const sessionId = 'test-session'; store.addMessage(sessionId, { role: 'user', content: 'Hello' }); store.clearSession(sessionId); const messages = store.getMessages(sessionId); expect(messages).toHaveLength(0); }); it('handles multiple sessions independently', () => { store.addMessage('session-1', { role: 'user', content: 'Session 1' }); store.addMessage('session-2', { role: 'user', content: 'Session 2' }); expect(store.getMessages('session-1')).toHaveLength(1); expect(store.getMessages('session-2')).toHaveLength(1); expect(store.getMessages('session-1')[0].content).toBe('Session 1'); }); it('lists all sessions', () => { store.addMessage('session-a', { role: 'user', content: 'A' }); store.addMessage('session-b', { role: 'user', content: 'B' }); const sessions = store.listSessions(); expect(sessions).toContain('session-a'); expect(sessions).toContain('session-b'); }); describe('pairing persistence', () => { it('getPairingStore returns a PairingStore', () => { const pairingStore = store.getPairingStore(); expect(pairingStore).toBeDefined(); expect(pairingStore.loadApproved).toBeInstanceOf(Function); expect(pairingStore.saveApproved).toBeInstanceOf(Function); expect(pairingStore.removeApproved).toBeInstanceOf(Function); }); it('saveApproved and loadApproved round-trip', () => { const ps = store.getPairingStore(); ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 1000, codeUsed: 'AABB11' }); ps.saveApproved({ channel: 'discord', senderId: '456', approvedAt: 2000, codeUsed: 'CC33DD' }); const loaded = ps.loadApproved(); expect(loaded).toHaveLength(2); expect(loaded).toEqual(expect.arrayContaining([ expect.objectContaining({ channel: 'telegram', senderId: '123', codeUsed: 'AABB11' }), expect.objectContaining({ channel: 'discord', senderId: '456', codeUsed: 'CC33DD' }), ])); }); it('removeApproved deletes a sender', () => { const ps = store.getPairingStore(); ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 1000, codeUsed: 'AABB11' }); ps.removeApproved('telegram', '123'); expect(ps.loadApproved()).toHaveLength(0); }); it('saveApproved upserts on duplicate channel+senderId', () => { const ps = store.getPairingStore(); ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 1000, codeUsed: 'FIRST1' }); ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 2000, codeUsed: 'SECOND' }); const loaded = ps.loadApproved(); expect(loaded).toHaveLength(1); expect(loaded[0].codeUsed).toBe('SECOND'); }); }); });