Files
orca/src/main/active-view-persistence-boundary.test.ts
T
7386ef2857 perf(renderer): stop full durable-state save on every top-level view switch (#9002) (#9393)
* perf(renderer): stop full durable-state save on every top-level view switch (#9002)

Persist activeView in a tiny profile-scoped sidecar instead of mutating the monolithic recovery snapshot. Active-view-only updates now bypass the broad UI normalization and durable save scheduler, while a 100ms atomic writer coalesces rapid switches and a synchronous shutdown checkpoint closes the immediate-exit race. Legacy state remains a migration and downgrade fallback.

Coordinate renderer shutdown capture through one guarded checkpoint so workspace sessions and the active-view preference both survive graceful reloads, restarts, and quit cancellation.

Add a persistence-boundary test proving the sidecar stays below 64 bytes while orca-data.json remains byte-for-byte unchanged, plus repeated Windows Electron restart coverage and a path-normalization-safe restart fixture.

* harden active-view sidecar: prototype-safe validator, race-free async swap, independent shutdown flush

- isTopLevelView uses Object.hasOwn so a corrupt sidecar can't smuggle
  inherited keys (constructor/__proto__) through as a valid view.
- writeAsync guards the generation check and rename synchronously (renameSync)
  so a shutdown flushOrThrow can no longer interleave and let a stale async
  rename clobber the freshly-written view.
- shutdown checkpoint flushes the durable store and the active-view sidecar in
  independent try/catch blocks so one store's failure can't skip the other.
  Added regression tests for all three.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-20 01:14:17 -07:00

59 lines
2.1 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { getActiveViewPreferenceFile } from './active-view-preference'
const testState = { dir: '' }
vi.mock('electron', () => ({
app: { getPath: () => testState.dir },
safeStorage: {
isEncryptionAvailable: () => true,
encryptString: (plaintext: string) => Buffer.from(`encrypted:${plaintext}`, 'utf-8'),
decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').replace('encrypted:', '')
}
}))
vi.mock('./telemetry/client', () => ({ track: vi.fn() }))
vi.mock('./telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn() }))
vi.mock('./ssh/ssh-config-parser', () => ({
loadUserSshConfig: vi.fn(),
sshConfigHostsToTargets: vi.fn()
}))
describe('active-view persistence boundary', () => {
beforeEach(() => {
testState.dir = mkdtempSync(join(tmpdir(), 'orca-active-view-boundary-'))
})
afterEach(() => {
vi.useRealTimers()
rmSync(testState.dir, { recursive: true, force: true })
})
it('persists a view switch without changing the global durable snapshot', async () => {
vi.useFakeTimers()
vi.resetModules()
const { Store } = await import('./persistence')
const dataFile = join(testState.dir, 'orca-data.json')
const store = new Store({ dataFile })
store.flush()
const durableBefore = readFileSync(dataFile, 'utf-8')
store.updateUI({ activeView: 'settings' })
vi.advanceTimersByTime(1_000)
await store.waitForPendingWrite()
const preferenceFile = getActiveViewPreferenceFile(dataFile)
const preferencePayload = readFileSync(preferenceFile, 'utf-8')
expect(Buffer.byteLength(preferencePayload)).toBeLessThan(64)
expect(JSON.parse(preferencePayload)).toEqual({ activeView: 'settings' })
expect(readFileSync(dataFile, 'utf-8')).toBe(durableBefore)
expect(store.getUI().activeView).toBe('settings')
const reloaded = new Store({ dataFile })
expect(reloaded.getUI().activeView).toBe('settings')
})
})