|
|
@@ -210,7 +210,7 @@ describe('SessionProjectionCache write policy', () => {
|
|
|
// The mark is throttled, so the creation cut has no marks folded.
|
|
|
await created
|
|
|
expect((await storedRows(root, session.id))?.['cache-test/marks']?.seq).toBe(-1)
|
|
|
- const written = whenWritten(ctx, session.id)
|
|
|
+ const written = whenWritten(ctx, id)
|
|
|
const end = endTurn(session)
|
|
|
await written
|
|
|
expect((await storedRows(root, session.id))?.['cache-test/marks'])
|
|
|
@@ -222,44 +222,50 @@ describe('SessionProjectionCache write policy', () => {
|
|
|
// A forked child seeded with its ancestor's title-like event: no
|
|
|
// conversation follows, yet the creation write must capture the fold so
|
|
|
// a crash or a live-held fork still lists the derived value.
|
|
|
- const session = ctx.sessions.create(SessionId('seeded'), {
|
|
|
+ const id = SessionId('seeded')
|
|
|
+ const created = whenWritten(ctx, id)
|
|
|
+ const session = ctx.sessions.create(id, {
|
|
|
seed: [{ type: 'cache-test/mark', seq: 0, time: 1, data: { marks: ['seed'] } }] as SessionEvent[],
|
|
|
})
|
|
|
- await vi.waitFor(async () => {
|
|
|
- expect((await storedRows(root, session.id))?.['cache-test/marks']?.val)
|
|
|
- .toEqual({ marks: ['seed'] })
|
|
|
- }, { timeout: 5_000 })
|
|
|
+ await created
|
|
|
+ expect((await storedRows(root, session.id))?.['cache-test/marks']?.val)
|
|
|
+ .toEqual({ marks: ['seed'] })
|
|
|
})
|
|
|
|
|
|
it('writes at session disposal (detach, the live-to-cold moment)', async () => {
|
|
|
const { ctx, root } = await harness()
|
|
|
+ vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] })
|
|
|
+ const id = SessionId('detach')
|
|
|
+ const created = whenWritten(ctx, id)
|
|
|
// Sessions dispose with their owning fiber: create in a child plugin.
|
|
|
let session: Session | undefined
|
|
|
const owner = await ctx.plugin(Object.assign((inner: Context) => {
|
|
|
- session = inner.sessions.create(SessionId('detach'))
|
|
|
+ session = inner.sessions.create(id)
|
|
|
}, { inject: ['sessions'] }))
|
|
|
if (session === undefined) throw new Error('session was not created')
|
|
|
+ await created
|
|
|
mark(session, ['live'])
|
|
|
+ const written = whenWritten(ctx, id)
|
|
|
await owner.dispose()
|
|
|
- const detached = session
|
|
|
- await vi.waitFor(async () => {
|
|
|
- expect((await storedRows(root, detached.id))?.['cache-test/marks']?.val).toEqual({ marks: ['live'] })
|
|
|
- }, { timeout: 5_000 })
|
|
|
+ await written
|
|
|
+ expect((await storedRows(root, id))?.['cache-test/marks']?.val).toEqual({ marks: ['live'] })
|
|
|
})
|
|
|
|
|
|
it('flushes when the in-turn event count reaches the configured threshold', async () => {
|
|
|
const { ctx, root } = await harness({ config: { writeEveryEvents: 3, writeIntervalMs: 60_000 } })
|
|
|
- const session = ctx.sessions.create(SessionId('count'))
|
|
|
+ vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] })
|
|
|
+ const id = SessionId('count')
|
|
|
+ const created = whenWritten(ctx, id)
|
|
|
+ const session = ctx.sessions.create(id)
|
|
|
mark(session, ['1'])
|
|
|
mark(session, ['2'])
|
|
|
- await vi.waitFor(async () => {
|
|
|
- expect((await storedRows(root, session.id))?.['cache-test/marks'])
|
|
|
- .toEqual({ ver: 1, seq: -1, val: null }) // still the creation cut
|
|
|
- }, { timeout: 5_000 })
|
|
|
+ await created
|
|
|
+ expect((await storedRows(root, id))?.['cache-test/marks'])
|
|
|
+ .toEqual({ ver: 1, seq: -1, val: null }) // still the creation cut
|
|
|
+ const written = whenWritten(ctx, id)
|
|
|
mark(session, ['3'])
|
|
|
- await vi.waitFor(async () => {
|
|
|
- expect((await storedRows(root, session.id))?.['cache-test/marks']?.val).toEqual({ marks: ['3'] })
|
|
|
- }, { timeout: 5_000 })
|
|
|
+ await written
|
|
|
+ expect((await storedRows(root, id))?.['cache-test/marks']?.val).toEqual({ marks: ['3'] })
|
|
|
})
|
|
|
|
|
|
it('flushes on the configured interval when the count threshold is not reached', async () => {
|
|
|
@@ -334,16 +340,15 @@ describe('SessionProjectionCache write policy', () => {
|
|
|
await vi.waitFor(() => {
|
|
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('turn/end write for "fail-soft" failed'))
|
|
|
}, { timeout: 5_000 })
|
|
|
- await vi.waitFor(async () => {
|
|
|
- expect(await storedRows(root, session.id)).toBeUndefined()
|
|
|
- }, { timeout: 5_000 })
|
|
|
+ expect(await storedRows(root, session.id)).toBeUndefined()
|
|
|
// Self-heal: once the blocker clears, the next mandatory point writes.
|
|
|
await rm(recordPath(root, session.id), { recursive: true })
|
|
|
+ vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] })
|
|
|
mark(session, ['y'])
|
|
|
+ const written = whenWritten(ctx, session.id)
|
|
|
endTurn(session)
|
|
|
- await vi.waitFor(async () => {
|
|
|
- expect((await storedRows(root, session.id))?.['cache-test/marks']?.val).toEqual({ marks: ['y'] })
|
|
|
- }, { timeout: 5_000 })
|
|
|
+ await written
|
|
|
+ expect((await storedRows(root, session.id))?.['cache-test/marks']?.val).toEqual({ marks: ['y'] })
|
|
|
})
|
|
|
})
|
|
|
|