mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 16:02:50 +00:00
* fix(runtime): terminate renderer graph reload generations * fix(runtime): harden renderer reload teardown * fix(runtime): fence renderer graph publication ownership * test(runtime): register renderer graph reload gate * test(runtime): record live reload validation * fix(runtime): ignore cancelled renderer navigations * chore: preserve main formatting during branch sync * chore: satisfy changed-code quality gate * fix(runtime): restore cancelled renderer reloads * fix(runtime): preserve committed reload fencing * test(runtime): prove cancelled reload timeout * docs(reliability): record reload cancellation oracle --------- Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
105 lines
3.7 KiB
TypeScript
105 lines
3.7 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
import {
|
|
RuntimeGraphReloadLifecycle,
|
|
type RuntimeGraphReloadSettlement
|
|
} from './runtime-graph-reload-lifecycle'
|
|
|
|
describe('RuntimeGraphReloadLifecycle', () => {
|
|
afterEach(() => {
|
|
vi.useRealTimers()
|
|
})
|
|
|
|
it('records success, failure, cancellation, and timeout as terminal outcomes', async () => {
|
|
vi.useFakeTimers()
|
|
const settlements: RuntimeGraphReloadSettlement[] = []
|
|
const timeouts: number[] = []
|
|
const lifecycle = new RuntimeGraphReloadLifecycle({
|
|
timeoutMs: 100,
|
|
onSettled: (settlement) => settlements.push(settlement),
|
|
onTimeout: (revision) => timeouts.push(revision)
|
|
})
|
|
|
|
const success = lifecycle.begin(1)
|
|
expect(lifecycle.settle(success, 'success')).toBe(true)
|
|
const failure = lifecycle.begin(1)
|
|
expect(lifecycle.settle(failure, 'failure')).toBe(true)
|
|
const cancelled = lifecycle.begin(1)
|
|
expect(lifecycle.settle(cancelled, 'cancelled')).toBe(true)
|
|
const timeout = lifecycle.begin(1)
|
|
await vi.advanceTimersByTimeAsync(100)
|
|
|
|
expect(settlements.map(({ revision, outcome }) => ({ revision, outcome }))).toEqual([
|
|
{ revision: success, outcome: 'success' },
|
|
{ revision: failure, outcome: 'failure' },
|
|
{ revision: cancelled, outcome: 'cancelled' },
|
|
{ revision: timeout, outcome: 'timeout' }
|
|
])
|
|
expect(timeouts).toEqual([timeout])
|
|
expect(lifecycle.getActiveRevision()).toBeNull()
|
|
})
|
|
|
|
it('cancels a superseded generation and ignores its stale completion and timeout', async () => {
|
|
vi.useFakeTimers()
|
|
const settlements: RuntimeGraphReloadSettlement[] = []
|
|
const timeouts: number[] = []
|
|
const lifecycle = new RuntimeGraphReloadLifecycle({
|
|
timeoutMs: 100,
|
|
onSettled: (settlement) => settlements.push(settlement),
|
|
onTimeout: (revision) => timeouts.push(revision)
|
|
})
|
|
|
|
const first = lifecycle.begin(1)
|
|
await vi.advanceTimersByTimeAsync(60)
|
|
const second = lifecycle.begin(1)
|
|
|
|
expect(lifecycle.settle(first, 'success')).toBe(false)
|
|
await vi.advanceTimersByTimeAsync(40)
|
|
expect(timeouts).toEqual([])
|
|
expect(lifecycle.getActiveRevision()).toBe(second)
|
|
|
|
await vi.advanceTimersByTimeAsync(60)
|
|
expect(timeouts).toEqual([second])
|
|
expect(settlements.map(({ revision, outcome }) => ({ revision, outcome }))).toEqual([
|
|
{ revision: first, outcome: 'cancelled' },
|
|
{ revision: second, outcome: 'timeout' }
|
|
])
|
|
})
|
|
|
|
it('keeps a generation started by a cancellation observer active', async () => {
|
|
vi.useFakeTimers()
|
|
const settlements: RuntimeGraphReloadSettlement[] = []
|
|
const timeouts: number[] = []
|
|
let nestedRevision: number | null = null
|
|
let didReenter = false
|
|
let lifecycle!: RuntimeGraphReloadLifecycle
|
|
lifecycle = new RuntimeGraphReloadLifecycle({
|
|
timeoutMs: 100,
|
|
onSettled: (settlement) => {
|
|
settlements.push(settlement)
|
|
if (settlement.outcome === 'cancelled' && !didReenter) {
|
|
didReenter = true
|
|
nestedRevision = lifecycle.begin(3)
|
|
}
|
|
},
|
|
onTimeout: (revision) => timeouts.push(revision)
|
|
})
|
|
|
|
const first = lifecycle.begin(1)
|
|
const replacement = lifecycle.begin(2)
|
|
|
|
expect(replacement).toBe(2)
|
|
expect(nestedRevision).toBe(3)
|
|
expect(lifecycle.getActiveRevision()).toBe(nestedRevision)
|
|
expect(lifecycle.settle(replacement, 'success')).toBe(false)
|
|
|
|
await vi.advanceTimersByTimeAsync(100)
|
|
|
|
expect(timeouts).toEqual([nestedRevision])
|
|
expect(settlements.map(({ revision, outcome }) => ({ revision, outcome }))).toEqual([
|
|
{ revision: first, outcome: 'cancelled' },
|
|
{ revision: replacement, outcome: 'cancelled' },
|
|
{ revision: nestedRevision, outcome: 'timeout' }
|
|
])
|
|
})
|
|
})
|