mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test: strengthen routing, scheduling, and session assertions (#33189)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -32,7 +32,9 @@ describe('mobile E2EE v2 key schedule', () => {
|
||||
|
||||
it('derives unique direction keys and session IDs across fresh client nonces', () => {
|
||||
const { hello, ready, sharedSecret } = createMobileE2EEV2Fixture()
|
||||
const fingerprints = new Set<string>()
|
||||
const mobileToDesktopKeys = new Set<string>()
|
||||
const desktopToMobileKeys = new Set<string>()
|
||||
const sessionIds = new Set<string>()
|
||||
for (let index = 0; index < 128; index++) {
|
||||
const nonce = new Uint8Array(32)
|
||||
new DataView(nonce.buffer).setUint32(28, index, false)
|
||||
@@ -47,12 +49,12 @@ describe('mobile E2EE v2 key schedule', () => {
|
||||
clientNonce: handshake.clientNonce,
|
||||
desktopNonce: handshake.desktopNonce
|
||||
})
|
||||
fingerprints.add(
|
||||
[schedule.mobileToDesktopKey, schedule.desktopToMobileKey, schedule.sessionId]
|
||||
.map(hex)
|
||||
.join(':')
|
||||
)
|
||||
mobileToDesktopKeys.add(hex(schedule.mobileToDesktopKey))
|
||||
desktopToMobileKeys.add(hex(schedule.desktopToMobileKey))
|
||||
sessionIds.add(hex(schedule.sessionId))
|
||||
}
|
||||
expect(fingerprints.size).toBe(128)
|
||||
expect(mobileToDesktopKeys.size).toBe(128)
|
||||
expect(desktopToMobileKeys.size).toBe(128)
|
||||
expect(sessionIds.size).toBe(128)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -56,7 +56,7 @@ function logicalClient(initial: ConnectionState) {
|
||||
}
|
||||
|
||||
describe('direct pairing upgrade controller', () => {
|
||||
it('upgrades immediately after an authenticated direct connection', async () => {
|
||||
it('forwards a completed upgrade for an already connected client', async () => {
|
||||
const logical = logicalClient('connected')
|
||||
const upgrade = vi.fn(async () => upgraded)
|
||||
const onUpgraded = vi.fn(async () => {})
|
||||
@@ -83,7 +83,9 @@ describe('direct pairing upgrade controller', () => {
|
||||
await controller.start()
|
||||
controller.setForeground(false)
|
||||
controller.setForeground(true)
|
||||
await vi.waitFor(() => expect(onUpgraded).toHaveBeenCalledOnce())
|
||||
await Promise.resolve()
|
||||
|
||||
expect(onUpgraded).toHaveBeenCalledOnce()
|
||||
|
||||
expect(upgrade).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { scheduleOrphanedMobileRelayCleanup } from './mobile-relay-orphan-cleanup'
|
||||
|
||||
describe('mobile relay orphan cleanup', () => {
|
||||
it('durably schedules credential deletion before removing an orphan overlay pointer', async () => {
|
||||
it('schedules each orphan credential cleanup before removing its overlay pointer', async () => {
|
||||
const order: string[] = []
|
||||
const deleteCredential = vi.fn(async () => {})
|
||||
const scheduleCleanup = vi.fn(async (hostId: string) => {
|
||||
@@ -23,7 +23,7 @@ describe('mobile relay orphan cleanup', () => {
|
||||
expect(scheduleCleanup).toHaveBeenCalledWith('host-1', deleteCredential)
|
||||
})
|
||||
|
||||
it('retains the overlay pointer when durable cleanup scheduling fails', async () => {
|
||||
it('retains the overlay pointer when the cleanup scheduler rejects', async () => {
|
||||
const removeOverlay = vi.fn(async () => {})
|
||||
await scheduleOrphanedMobileRelayCleanup({
|
||||
hostIds: ['host-1'],
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createRelayRecoveryLog } from './mobile-relay-recovery-log'
|
||||
import type { ConnectionLogEntry } from './types'
|
||||
|
||||
afterEach(() => vi.restoreAllMocks())
|
||||
|
||||
describe('createRelayRecoveryLog', () => {
|
||||
it('uses distinct ids across logger instances', () => {
|
||||
vi.spyOn(Date, 'now').mockReturnValue(1)
|
||||
const entries: ConnectionLogEntry[] = []
|
||||
const sink = vi.fn((entry: ConnectionLogEntry) => entries.push(entry))
|
||||
createRelayRecoveryLog(() => 1, sink)('first')
|
||||
createRelayRecoveryLog(() => 1, sink)('second')
|
||||
|
||||
expect(entries).toHaveLength(2)
|
||||
expect(entries[0]?.id).not.toBe(entries[1]?.id)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomBytes } from 'node:crypto'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { gunzipSync } from 'fflate'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { encodeMobileWebBundleRange } from '../../../src/main/runtime/rpc/methods/mobile-web-bundle-range-encoding'
|
||||
@@ -29,7 +29,11 @@ describe('a host-encoded range decoded by the phone', () => {
|
||||
})
|
||||
|
||||
it('leaves incompressible bytes as identity, which needs no decoder', async () => {
|
||||
const raw = randomBytes(4096)
|
||||
const raw = Buffer.concat(
|
||||
Array.from({ length: 128 }, (_, index) =>
|
||||
createHash('sha256').update(`range-${index}`).digest()
|
||||
)
|
||||
)
|
||||
const encoded = await encodeMobileWebBundleRange(raw)
|
||||
|
||||
expect(encoded.encoding).toBe('identity')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { runRpcOperation } from './rpc-operation'
|
||||
import {
|
||||
MOBILE_WEB_BUNDLE_CHUNK_BYTES,
|
||||
MOBILE_WEB_BUNDLE_RANGE_BYTES,
|
||||
@@ -69,10 +70,18 @@ describe('mobile web bundle range reply reader', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('is a require-result read of the range method', () => {
|
||||
expect(mobileWebBundleRangeRead.method).toBe(MOBILE_WEB_BUNDLE_RANGE_METHOD)
|
||||
expect(mobileWebBundleRangeRead.acceptance).toBe('require-result-or-throw')
|
||||
expect(mobileWebBundleRangeRead.barrier).toBe('on-settle')
|
||||
it('requests a range and surfaces the host refusal', async () => {
|
||||
const params = { buildId: 'a'.repeat(64), path: 'index.html', offset: 0 }
|
||||
const sendRequest = vi.fn(async () => ({
|
||||
id: 'range-1',
|
||||
ok: false as const,
|
||||
error: { code: 'forbidden', message: 'no' }
|
||||
}))
|
||||
|
||||
await expect(
|
||||
runRpcOperation({ sendRequest }, mobileWebBundleRangeRead, params)
|
||||
).rejects.toThrow('forbidden: no')
|
||||
expect(sendRequest).toHaveBeenCalledWith(MOBILE_WEB_BUNDLE_RANGE_METHOD, params, undefined)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -8,12 +8,20 @@ import {
|
||||
|
||||
describe('app menu selection actions', () => {
|
||||
it.each(['copy', 'select-all'] as const)('reports whether %s has an owned target', (action) => {
|
||||
const handler = (event: Event): void => event.preventDefault()
|
||||
let receivedAction: unknown
|
||||
const handler = (event: Event): void => {
|
||||
if (event instanceof CustomEvent) {
|
||||
receivedAction = event.detail
|
||||
}
|
||||
event.preventDefault()
|
||||
}
|
||||
window.addEventListener(APP_MENU_SELECTION_ACTION_EVENT, handler)
|
||||
|
||||
expect(dispatchAppMenuSelectionAction(action)).toBe(true)
|
||||
const claimed = dispatchAppMenuSelectionAction(action)
|
||||
|
||||
window.removeEventListener(APP_MENU_SELECTION_ACTION_EVENT, handler)
|
||||
expect(claimed).toBe(true)
|
||||
expect(receivedAction).toBe(action)
|
||||
})
|
||||
|
||||
it('leaves unowned actions available for native fallback', () => {
|
||||
|
||||
@@ -37,13 +37,19 @@ function find(
|
||||
} = {}
|
||||
): string | null {
|
||||
const livePtyIds = new Set(options.livePtyIds ?? runs.map((entry) => entry.terminalPtyId))
|
||||
const statusesByPaneKey = new Map(
|
||||
runs.map((entry) => [
|
||||
entry.terminalPaneKey,
|
||||
options.status ?? { state: 'done', agentType: 'claude' }
|
||||
])
|
||||
)
|
||||
return findReusableAutomationRun({
|
||||
automationId: 'auto-1',
|
||||
agentId: 'claude',
|
||||
worktreeId: 'wt-1',
|
||||
currentRunId: 'run-current',
|
||||
runs,
|
||||
agentStatusForPane: () => options.status ?? { state: 'done', agentType: 'claude' },
|
||||
agentStatusForPane: (paneKey) => statusesByPaneKey.get(paneKey),
|
||||
liveSession: (candidate) => (livePtyIds.has(candidate.terminalPtyId) ? candidate.id : null)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,6 +33,23 @@ describe('stepCalmStatusReveal', () => {
|
||||
|
||||
it('says an outage that outlasts the delay, and holds it long enough to read', () => {
|
||||
const shownAt = CALM_STATUS_REVEAL_DELAY_MS
|
||||
const pending = stepCalmStatusReveal(CALM_STATUS_IDLE, {
|
||||
down: true,
|
||||
immediate: false,
|
||||
now: 0
|
||||
})
|
||||
expect(pending.recheckInMs).toBe(CALM_STATUS_REVEAL_DELAY_MS)
|
||||
const shown = stepCalmStatusReveal(pending.next, {
|
||||
down: true,
|
||||
immediate: false,
|
||||
now: shownAt
|
||||
})
|
||||
const recovering = stepCalmStatusReveal(shown.next, {
|
||||
down: false,
|
||||
immediate: false,
|
||||
now: shownAt + 100
|
||||
})
|
||||
expect(recovering.recheckInMs).toBe(CALM_STATUS_MIN_VISIBLE_MS - 100)
|
||||
expect(
|
||||
run([
|
||||
{ at: 0, down: true },
|
||||
|
||||
Reference in New Issue
Block a user