import { SqliteStorage } from '../src/index.js'; import { cleanupDir, createDbPath, createTempDir } from './helpers.js'; describe('SqliteStorage', () => { it('creates, updates, and completes jobs', () => { const dir = createTempDir(); const storage = new SqliteStorage<{ url: string }>(createDbPath(dir)); try { const job = storage.createJob( 'job-1', { url: 'https://example.com' }, [ { name: 'download', status: 'pending', progress: 0, message: null, startedAt: null, completedAt: null, error: null, }, ], {}, 3, ); expect(job.status).toBe('pending'); expect(storage.claimPendingJob(job.id)).toBe(true); const inProgress = storage.saveProgress( job.id, 'download', [ { name: 'download', status: 'active', progress: 50, message: 'halfway', startedAt: new Date().toISOString(), completedAt: null, error: null, }, ], 50, 'halfway', ); expect(inProgress.status).toBe('active'); expect(inProgress.progress).toBe(50); const completed = storage.completeJob( job.id, [ { name: 'download', status: 'completed', progress: 100, message: null, startedAt: new Date().toISOString(), completedAt: new Date().toISOString(), error: null, }, ], { download: { filePath: '/tmp/file' } }, ); expect(completed.status).toBe('completed'); expect(completed.progress).toBe(100); expect(completed.phaseResults.download).toEqual({ filePath: '/tmp/file' }); } finally { storage.close(); cleanupDir(dir); } }); it('preserves phase results when resetting for partial retry', () => { const dir = createTempDir(); const storage = new SqliteStorage<{ url: string }>(createDbPath(dir)); try { const job = storage.createJob( 'job-1', { url: 'https://example.com' }, [ { name: 'download', status: 'pending', progress: 0, message: null, startedAt: null, completedAt: null, error: null, }, { name: 'process', status: 'pending', progress: 0, message: null, startedAt: null, completedAt: null, error: null, }, ], {}, 3, ); const retried = storage.resetForRetry( job.id, [ { name: 'download', status: 'completed', progress: 100, message: null, startedAt: new Date().toISOString(), completedAt: new Date().toISOString(), error: null, }, { name: 'process', status: 'pending', progress: 0, message: null, startedAt: null, completedAt: null, error: null, }, ], { download: { filePath: '/tmp/file' } }, 3, null, ); expect(retried.status).toBe('pending'); expect(retried.progress).toBe(0); expect(retried.phaseResults.download).toEqual({ filePath: '/tmp/file' }); } finally { storage.close(); cleanupDir(dir); } }); it('preserves interrupted phase when resetting active jobs on restart', () => { const dir = createTempDir(); const storage = new SqliteStorage<{ url: string }>(createDbPath(dir)); try { const job = storage.createJob( 'job-1', { url: 'https://example.com' }, [ { name: 'download', status: 'pending', progress: 0, message: null, startedAt: null, completedAt: null, error: null, }, ], {}, 3, ); expect(storage.claimPendingJob(job.id)).toBe(true); storage.saveProgress( job.id, 'download', [ { name: 'download', status: 'active', progress: 25, message: 'working', startedAt: new Date().toISOString(), completedAt: null, error: null, }, ], 25, 'working', ); const reset = storage.resetActiveJobs('Interrupted by process restart'); expect(reset).toHaveLength(1); expect(reset[0]?.status).toBe('failed'); expect(reset[0]?.error?.phase).toBe('download'); expect(reset[0]?.error?.attempt).toBe(1); } finally { storage.close(); cleanupDir(dir); } }); });