import { expect, test } from 'bun:test' import { patchCollectionTask, upsertCollectionTask, isStaleTaskUpdate, type CollectionQueueItem } from '../src/admin/pages/datasource-task-queue' const item = (id: number | string | null, status: CollectionQueueItem['status'] = 'failed', type = 'collect'): CollectionQueueItem => ({ key: id == null ? `source:${type}:20` : `task:${type}:${id}`, taskId: id, sourceId: '20', source: 'celestrak_tle', name: 'CelesTrak', taskType: type, status, error: status === 'failed' ? `failure-${id}` : undefined, createdAt: 10, updatedAt: 20, completedAt: status === 'failed' ? 20 : undefined, }) test('a retry creates a new queue attempt and leaves every failed attempt untouched', () => { const history = [item(97), item(96), item(95)] let queue = upsertCollectionTask(history, item(98, 'queued')) queue = patchCollectionTask(queue, { taskId: '98', sourceId: '20', source: 'celestrak_tle', status: 'running', progress: 40 }, 100) expect(queue).toHaveLength(4) expect(queue[0].taskId).toBe('98') expect(queue[0].status).toBe('running') expect(queue.slice(1)).toEqual(history) queue = patchCollectionTask(queue, { taskId: 98, sourceId: '20', status: 'failed', error: 'new failure' }, 120) expect(queue.slice(1)).toEqual(history) expect(queue[0].completedAt).toBe(120) }) test('late websocket and upsert events cannot resurrect or reclassify a completed attempt', () => { const failed = item(97) expect(patchCollectionTask([failed], { taskId: 97, sourceId: '20', status: 'running' }, 200)).toEqual([failed]) expect(upsertCollectionTask([failed], item('97', 'queued'))).toEqual([failed]) expect(patchCollectionTask([failed], { taskId: 97, status: 'success' }, 200)).toEqual([failed]) expect(patchCollectionTask([failed], { taskId: 97, status: 'failed', error: 'more detail' }, 200)[0].completedAt).toBe(20) }) test('same-source concurrent attempts and different task types are independent', () => { const queue = upsertCollectionTask([item(98, 'running')], item(99, 'queued')) expect(queue).toHaveLength(2) expect(patchCollectionTask(queue, { taskId: 98, sourceId: '20', status: 'failed' })[0].status).toBe('queued') expect(patchCollectionTask([item(98, 'running')], { taskId: 98, taskType: 'clear_data', status: 'success' })[0].status).toBe('running') }) test('only an active ID-less placeholder binds by source; ID-less updates cannot touch real tasks', () => { const placeholder = item(null, 'queued') const bound = patchCollectionTask([placeholder, item(97)], { taskId: 98, sourceId: '20', status: 'running' }, 50) expect(bound[0].key).toBe('task:collect:98') expect(bound[0].createdAt).toBe(10) expect(bound[1]).toEqual(item(97)) expect(patchCollectionTask(bound, { sourceId: '20', status: 'failed' }, 60)).toEqual(bound) const differentSource = { ...placeholder, sourceId: '21' } expect(patchCollectionTask([differentSource], { taskId: 99, sourceId: '20', source: 'celestrak_tle', status: 'running' })).toEqual([differentSource]) }) test('old poll responses cannot replace the datasource row for a newer task', () => { expect(isStaleTaskUpdate(98, '97')).toBe(true) expect(isStaleTaskUpdate(98, null)).toBe(true) expect(isStaleTaskUpdate(98, '98')).toBe(false) expect(isStaleTaskUpdate(98, 99)).toBe(false) expect(isStaleTaskUpdate(null, 99)).toBe(false) }) test('late running updates for the same completed task do not reactivate the datasource row', () => { expect(isStaleTaskUpdate(98, '98', 'failed', 'running')).toBe(true) expect(isStaleTaskUpdate(98, '98', 'success', 'queued')).toBe(true) expect(isStaleTaskUpdate(98, '99', 'failed', 'queued')).toBe(false) })