// Archivage automatique des sessions terminées (P10) : scheduler sweep() sur base :memory:. import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { isSessionArchived, openDb, setSetting, type Db } from '../src/db/index.js'; import { RETENTION_DAYS_KEY } from '../src/core/retention-settings.js'; import { SessionArchiveService } from '../src/core/session-archive.js'; let db: Db; function insertSession(id: string, endedAt: string | null): void { db.prepare('INSERT INTO sessions (id, cwd, command, created_at, ended_at) VALUES (?, ?, ?, ?, ?)').run( id, '/tmp/x', 'bash', '2020-01-01T00:00:00.000Z', endedAt, ); } beforeEach(() => { db = openDb(':memory:'); insertSession('old', '2020-01-01T00:00:00.000Z'); // terminée il y a longtemps insertSession('recent', new Date().toISOString()); // terminée à l'instant insertSession('live', null); // vivante (jamais archivée) }); afterEach(() => db.close()); describe('SessionArchiveService.sweep', () => { it('archive seulement les sessions terminées plus anciennes que la rétention', () => { setSetting(db, RETENTION_DAYS_KEY, '30'); const svc = new SessionArchiveService({ db }); const events: string[] = []; svc.on('session_archived', (e) => events.push(e.id)); const n = svc.sweep(); expect(n).toBe(1); expect(events).toEqual(['old']); expect(isSessionArchived(db, 'old')).toBe(true); expect(isSessionArchived(db, 'recent')).toBe(false); expect(isSessionArchived(db, 'live')).toBe(false); }); it('est idempotent : un second balayage n’archive rien de plus', () => { setSetting(db, RETENTION_DAYS_KEY, '30'); const svc = new SessionArchiveService({ db }); expect(svc.sweep()).toBe(1); const events: string[] = []; svc.on('session_archived', (e) => events.push(e.id)); expect(svc.sweep()).toBe(0); expect(events).toEqual([]); }); it('rétention = 0 → no-op (archivage désactivé)', () => { setSetting(db, RETENTION_DAYS_KEY, '0'); const svc = new SessionArchiveService({ db }); expect(svc.sweep()).toBe(0); expect(isSessionArchived(db, 'old')).toBe(false); }); it('start() déclenche un balayage immédiat puis stop() est sûr', () => { setSetting(db, RETENTION_DAYS_KEY, '30'); const svc = new SessionArchiveService({ db, intervalMs: 60_000 }); svc.start(); expect(isSessionArchived(db, 'old')).toBe(true); svc.stop(); svc.stop(); // idempotent }); });