- Resume persisted outbox jobs at startup without dropping writes when credentials are unavailable - Serialize IndexedDB revisions and guard sync completion against concurrent saves - Reconcile tombstones without reviving deleted documents and bound S3 metadata requests - Require explicit CORS configuration instead of overwriting bucket rules during connection tests - Keep ACP agents exclusive to the Design role and normalize invalid model limits
69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
|
|
import { nextSyncWakeDelay } from '@/app/storage/sync/engine'
|
|
import { createMemoryOutbox } from '@/app/storage/sync/outbox'
|
|
import { supersedePutCanvasJobs, type OutboxJob } from '@/app/storage/sync/types'
|
|
|
|
describe('supersedePutCanvasJobs', () => {
|
|
test('drops older putCanvas jobs for same canvas', () => {
|
|
const jobs: OutboxJob[] = [
|
|
{
|
|
id: 'a',
|
|
canvasId: 'c1',
|
|
type: 'putCanvas',
|
|
revision: 1,
|
|
createdAt: 1,
|
|
attempts: 0,
|
|
nextAttemptAt: 1
|
|
},
|
|
{
|
|
id: 'b',
|
|
canvasId: 'c1',
|
|
type: 'putThumb',
|
|
revision: 1,
|
|
createdAt: 2,
|
|
attempts: 0,
|
|
nextAttemptAt: 2
|
|
},
|
|
{
|
|
id: 'c',
|
|
canvasId: 'c2',
|
|
type: 'putCanvas',
|
|
revision: 3,
|
|
createdAt: 3,
|
|
attempts: 0,
|
|
nextAttemptAt: 3
|
|
}
|
|
]
|
|
const next = supersedePutCanvasJobs(jobs, 'c1', 5)
|
|
expect(next.map((j) => j.id).sort()).toEqual(['b', 'c'])
|
|
})
|
|
})
|
|
|
|
describe('sync wake scheduling', () => {
|
|
test('does not poll jobs parked for repaired configuration', () => {
|
|
const parked: OutboxJob = {
|
|
id: 'parked',
|
|
canvasId: 'c1',
|
|
type: 'putCanvas',
|
|
revision: 1,
|
|
createdAt: 1,
|
|
attempts: 0,
|
|
nextAttemptAt: Number.MAX_SAFE_INTEGER
|
|
}
|
|
expect(nextSyncWakeDelay([parked], 100)).toBeNull()
|
|
expect(nextSyncWakeDelay([{ ...parked, nextAttemptAt: 500 }], 100)).toBe(400)
|
|
})
|
|
})
|
|
|
|
describe('memory outbox', () => {
|
|
test('enqueues and supersedes putCanvas', async () => {
|
|
const outbox = createMemoryOutbox()
|
|
await outbox.enqueue({ canvasId: 'c1', type: 'putCanvas', revision: 1 })
|
|
await outbox.enqueue({ canvasId: 'c1', type: 'putCanvas', revision: 2 })
|
|
const list = await outbox.list()
|
|
expect(list.filter((j) => j.type === 'putCanvas')).toHaveLength(1)
|
|
expect(list[0]?.revision).toBe(2)
|
|
})
|
|
})
|