mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 02:57:36 +00:00
test: remove browser capability inventories and mock receipts (#36032)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -1,16 +1,9 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
OrcaRuntimeService,
|
||||
RuntimeBrowserCommands,
|
||||
setRuntimeBrowserCommandsFactory,
|
||||
setRuntimeBrowserUnavailableCause
|
||||
} from '../orca-runtime-test-mocks.spec'
|
||||
import { runtimeAdvertisesBrowserClientHosting } from '../../../shared/browser-client-hosting-eligibility'
|
||||
import { OrcaRuntimeService } from '../orca-runtime-test-mocks.spec'
|
||||
import {
|
||||
TEST_REPO_ID,
|
||||
TEST_WORKTREE_ID,
|
||||
TEST_WORKTREE_PATH,
|
||||
createRuntime,
|
||||
store
|
||||
} from '../orca-runtime-test-fixtures.spec'
|
||||
|
||||
@@ -42,22 +35,4 @@ describe('OrcaRuntimeService', () => {
|
||||
).rejects.toThrow('selector_not_found')
|
||||
expect(internals.listResolvedWorktrees).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
// #30731: engine-free orcad can host client-rendered pages while reporting its local engine failure.
|
||||
it('advertises client hosting from an engine-free factory while reporting the engine cause', () => {
|
||||
setRuntimeBrowserCommandsFactory((host) => new RuntimeBrowserCommands(host), {
|
||||
headless: true,
|
||||
clientHostingWithoutEngine: true,
|
||||
isAvailable: () => false
|
||||
})
|
||||
setRuntimeBrowserUnavailableCause({ reason: 'unconfigured' })
|
||||
const status = createRuntime().getStatus()
|
||||
expect(runtimeAdvertisesBrowserClientHosting(status.capabilities)).toBe(true)
|
||||
expect(status.capabilities).toContain('browser.tab-create-known-id.v1')
|
||||
expect(status.capabilities).not.toContain('browser.headless.v1')
|
||||
expect(status.degradations).toContainEqual(
|
||||
expect.objectContaining({ code: 'browser_unavailable', reason: 'unconfigured' })
|
||||
)
|
||||
setRuntimeBrowserUnavailableCause(null)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
OrcaRuntimeService,
|
||||
RuntimeBrowserCommands,
|
||||
deleteWorktreeHistoryDirMock,
|
||||
electronMocks,
|
||||
getBrowserHostLeaseRegistry,
|
||||
getRuntimeBrowserPageRegistry,
|
||||
headlessBrowserTabsUnchanged,
|
||||
setRuntimeBrowserCommandsFactory,
|
||||
setRuntimeBrowserUnavailableCause,
|
||||
setRuntimeTerminalUnavailableCause
|
||||
getRuntimeBrowserPageRegistry
|
||||
} from '../orca-runtime-test-mocks.spec'
|
||||
import type { RuntimeMobileSessionTabsResult } from '../orca-runtime-test-mocks.spec'
|
||||
import {
|
||||
TEST_REPO_ID,
|
||||
TEST_WINDOW_ID,
|
||||
TEST_WORKTREE_ID,
|
||||
createRuntime,
|
||||
store
|
||||
@@ -23,276 +15,9 @@ import {
|
||||
attachClientBrowserHost,
|
||||
publishClientHostedPage
|
||||
} from '../orca-runtime-test-scenario-builders.spec'
|
||||
import { mkdtempSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import {
|
||||
initializeBrowserIdentityModeStore,
|
||||
resetBrowserIdentityModeStoreForTests
|
||||
} from '../../browser/browser-identity-mode-store'
|
||||
import { runtimeAdvertisesBrowserClientHosting } from '../../../shared/browser-client-hosting-eligibility'
|
||||
import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity'
|
||||
|
||||
describe('OrcaRuntimeService', () => {
|
||||
it('advertises Google clear only for a live supporting executor, independently of client hosting', async () => {
|
||||
for (const supported of [undefined, false, true]) {
|
||||
let available = true
|
||||
setRuntimeBrowserCommandsFactory((host) => new RuntimeBrowserCommands(host), {
|
||||
headless: true,
|
||||
clientHostingWithoutEngine: true,
|
||||
isAvailable: () => available,
|
||||
supportsGoogleCookieClear: supported === undefined ? undefined : () => supported
|
||||
})
|
||||
const runtime = createRuntime()
|
||||
const capabilities = runtime.getStatus().capabilities ?? []
|
||||
expect(capabilities.includes('browser.google-cookie-clear.v1')).toBe(supported === true)
|
||||
available = false
|
||||
expect(runtime.getStatus().capabilities).not.toContain('browser.google-cookie-clear.v1')
|
||||
expect(runtimeAdvertisesBrowserClientHosting(runtime.getStatus().capabilities)).toBe(true)
|
||||
}
|
||||
const { installElectronBrowserCommands } = await import('../../host/electron-browser-commands')
|
||||
installElectronBrowserCommands()
|
||||
expect(createRuntime().getStatus().capabilities).toContain('browser.google-cookie-clear.v1')
|
||||
setRuntimeBrowserCommandsFactory(null)
|
||||
expect(createRuntime().getStatus().capabilities).not.toContain('browser.google-cookie-clear.v1')
|
||||
})
|
||||
|
||||
it('advertises client hosting when its factory implements client page creation', () => {
|
||||
const capabilities = createRuntime().getStatus().capabilities
|
||||
expect(runtimeAdvertisesBrowserClientHosting(capabilities)).toBe(true)
|
||||
expect(capabilities).toContain('browser.tab-create-known-id.v1')
|
||||
})
|
||||
|
||||
it('does not offer client placement through a server-only external browser provider', () => {
|
||||
setRuntimeBrowserCommandsFactory((host) => new RuntimeBrowserCommands(host), {
|
||||
headless: true
|
||||
})
|
||||
const capabilities = createRuntime().getStatus().capabilities
|
||||
expect(capabilities).toContain('browser.headless.v1')
|
||||
expect(capabilities).toContain('browser.tab-create-known-id.v1')
|
||||
expect(capabilities).not.toContain('browser.clientHost.v1')
|
||||
expect(runtimeAdvertisesBrowserClientHosting(capabilities)).toBe(false)
|
||||
expect(capabilities).toContain('network.browserTunnel.v1')
|
||||
})
|
||||
|
||||
it('withdraws client hosting when its factory health probe fails', () => {
|
||||
let available = true
|
||||
setRuntimeBrowserCommandsFactory((host) => new RuntimeBrowserCommands(host), {
|
||||
clientHosting: true,
|
||||
isAvailable: () => available
|
||||
})
|
||||
const runtime = createRuntime()
|
||||
expect(runtimeAdvertisesBrowserClientHosting(runtime.getStatus().capabilities)).toBe(true)
|
||||
available = false
|
||||
expect(runtimeAdvertisesBrowserClientHosting(runtime.getStatus().capabilities)).toBe(false)
|
||||
})
|
||||
// Uninitialized stores cannot serve identity methods; never advertise them to mixed-version clients.
|
||||
it('advertises the browser identity capability only where an identity store exists', () => {
|
||||
resetBrowserIdentityModeStoreForTests()
|
||||
expect(createRuntime().getStatus().capabilities).not.toContain('browser.identity.v1')
|
||||
|
||||
initializeBrowserIdentityModeStore(mkdtempSync(join(tmpdir(), 'orca-identity-capability-')))
|
||||
try {
|
||||
expect(createRuntime().getStatus().capabilities).toContain('browser.identity.v1')
|
||||
} finally {
|
||||
resetBrowserIdentityModeStoreForTests()
|
||||
}
|
||||
})
|
||||
|
||||
it('advertises headless browser capability when an offscreen backend backs a windowless host', () => {
|
||||
const runtime = createRuntime()
|
||||
runtime.setOffscreenBrowserBackend({
|
||||
createTab: vi.fn(),
|
||||
closeTab: vi.fn(),
|
||||
ownsTab: () => true
|
||||
})
|
||||
|
||||
const capabilities = runtime.getStatus().capabilities
|
||||
expect(capabilities).toContain('browser.screencast.v1')
|
||||
expect(capabilities).toContain('browser.headless.v1')
|
||||
expect(capabilities).toContain('browser.certificate-trust.v1')
|
||||
})
|
||||
|
||||
it('advertises only while headless browser commands remain live', () => {
|
||||
let available = true
|
||||
setRuntimeBrowserCommandsFactory((host) => new RuntimeBrowserCommands(host), {
|
||||
headless: true,
|
||||
isAvailable: () => available
|
||||
})
|
||||
const status = createRuntime().getStatus()
|
||||
|
||||
expect(status.capabilities).toContain('browser.headless.v1')
|
||||
expect(status.capabilities).not.toContain('browser.screencast.v1')
|
||||
expect(status.capabilities).not.toContain('browser.clientHost.v1')
|
||||
expect(status.capabilities).toContain('browser.tab-create-known-id.v1')
|
||||
expect(runtimeAdvertisesBrowserClientHosting(status.capabilities)).toBe(false)
|
||||
expect(status.capabilities).not.toContain('browser.certificate-trust.v1')
|
||||
expect(status.degradations).toBeUndefined()
|
||||
|
||||
available = false
|
||||
const degraded = createRuntime().getStatus()
|
||||
expect(degraded.capabilities).not.toContain('browser.headless.v1')
|
||||
// Previously resolved provider death is health failure, not misconfiguration.
|
||||
expect(degraded.degradations).toEqual([
|
||||
{
|
||||
code: 'browser_unavailable',
|
||||
capability: 'browser.headless.v1',
|
||||
reason: 'provider_unhealthy',
|
||||
message: 'The browser provider started but is no longer answering health checks.'
|
||||
}
|
||||
])
|
||||
})
|
||||
it('surfaces live offscreen load failures in headless browser snapshots', () => {
|
||||
const runtime = createRuntime()
|
||||
runtime.setOffscreenBrowserBackend({
|
||||
createTab: vi.fn(),
|
||||
closeTab: vi.fn(),
|
||||
ownsTab: () => true
|
||||
})
|
||||
runtime.setAgentBrowserBridge({
|
||||
tabList: vi.fn(() => ({
|
||||
tabs: [
|
||||
{
|
||||
browserPageId: 'page-certificate-error',
|
||||
index: 0,
|
||||
url: 'https://localhost:3443/',
|
||||
title: 'Local HTTPS',
|
||||
active: true,
|
||||
loadError: {
|
||||
code: -202,
|
||||
description: 'ERR_CERT_AUTHORITY_INVALID',
|
||||
validatedUrl: 'https://localhost:3443/'
|
||||
},
|
||||
certificateFailure: {
|
||||
challengeId: 'challenge-1',
|
||||
browserPageId: 'page-certificate-error',
|
||||
errorCode: -202,
|
||||
error: 'ERR_CERT_AUTHORITY_INVALID',
|
||||
origin: 'https://localhost:3443',
|
||||
displayHost: 'localhost:3443',
|
||||
canProceed: true,
|
||||
observedAt: 123
|
||||
}
|
||||
}
|
||||
]
|
||||
}))
|
||||
} as never)
|
||||
const browserTabs = runtime['buildHeadlessMobileSessionBrowserTabs'](TEST_WORKTREE_ID)
|
||||
expect(browserTabs).toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: 'browser',
|
||||
browserPageId: 'page-certificate-error',
|
||||
loadError: {
|
||||
code: -202,
|
||||
description: 'ERR_CERT_AUTHORITY_INVALID',
|
||||
validatedUrl: 'https://localhost:3443/'
|
||||
},
|
||||
certificateFailure: {
|
||||
challengeId: 'challenge-1',
|
||||
browserPageId: 'page-certificate-error',
|
||||
errorCode: -202,
|
||||
error: 'ERR_CERT_AUTHORITY_INVALID',
|
||||
origin: 'https://localhost:3443',
|
||||
displayHost: 'localhost:3443',
|
||||
canProceed: true,
|
||||
observedAt: 123
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('synthesizes runtime-owned client pages without a server browser backend', () => {
|
||||
const runtime = createRuntime()
|
||||
getRuntimeBrowserPageRegistry(runtime).publishClientPage({
|
||||
browserPageId: 'page-client',
|
||||
workspaceId: TEST_WORKTREE_ID,
|
||||
browserProfileId: 'profile-a',
|
||||
executionHostKey: 'execution-a',
|
||||
placement: {
|
||||
kind: 'client',
|
||||
browserHostClientId: 'host-a',
|
||||
browserHostGeneration: 3,
|
||||
pageHostGeneration: 9
|
||||
},
|
||||
url: 'https://remote.internal/',
|
||||
title: 'Remote app',
|
||||
loading: false,
|
||||
canGoBack: true,
|
||||
canGoForward: false,
|
||||
active: true
|
||||
})
|
||||
|
||||
expect(runtime['buildHeadlessMobileSessionBrowserTabs'](TEST_WORKTREE_ID)).toEqual([
|
||||
{
|
||||
type: 'browser',
|
||||
id: 'page-client',
|
||||
title: 'Remote app',
|
||||
browserWorkspaceId: 'page-client',
|
||||
browserPageId: 'page-client',
|
||||
browserProfileId: 'profile-a',
|
||||
executionHostKey: 'execution-a',
|
||||
placement: {
|
||||
kind: 'client',
|
||||
browserHostClientId: 'host-a',
|
||||
browserHostGeneration: 3,
|
||||
pageHostGeneration: 9
|
||||
},
|
||||
url: 'https://remote.internal/',
|
||||
loading: false,
|
||||
canGoBack: true,
|
||||
canGoForward: false,
|
||||
isActive: true
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
it('publishes a runtime-owned client page through the session-tab listener', () => {
|
||||
const runtime = createRuntime()
|
||||
runtime['mobileSessionTabsByWorktree'].set(TEST_WORKTREE_ID, {
|
||||
worktree: TEST_WORKTREE_ID,
|
||||
publicationEpoch: 'renderer:1',
|
||||
snapshotVersion: 1,
|
||||
activeGroupId: 'group-1',
|
||||
activeTabId: null,
|
||||
activeTabType: null,
|
||||
tabGroups: [{ id: 'group-1', activeTabId: null, tabOrder: [] }],
|
||||
tabs: []
|
||||
})
|
||||
const snapshots: RuntimeMobileSessionTabsResult[] = []
|
||||
const unsubscribe = runtime.onMobileSessionTabsChanged((snapshot) => snapshots.push(snapshot))
|
||||
getRuntimeBrowserPageRegistry(runtime).publishClientPage({
|
||||
browserPageId: 'page-client',
|
||||
workspaceId: TEST_WORKTREE_ID,
|
||||
browserProfileId: 'profile-a',
|
||||
executionHostKey: 'execution-a',
|
||||
placement: {
|
||||
kind: 'client',
|
||||
browserHostClientId: 'host-a',
|
||||
browserHostGeneration: 3,
|
||||
pageHostGeneration: 9
|
||||
},
|
||||
url: 'about:blank',
|
||||
loading: true,
|
||||
active: true
|
||||
})
|
||||
|
||||
runtime.notifyMobileSessionTabsChanged(TEST_WORKTREE_ID)
|
||||
|
||||
expect(snapshots.at(-1)?.tabs).toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: 'browser',
|
||||
browserPageId: 'page-client',
|
||||
loading: true,
|
||||
placement: expect.objectContaining({
|
||||
kind: 'client',
|
||||
browserHostClientId: 'host-a',
|
||||
pageHostGeneration: 9
|
||||
})
|
||||
})
|
||||
)
|
||||
unsubscribe()
|
||||
})
|
||||
|
||||
it('preserves a live client page across headed renderer graph updates and prunes it after retirement', async () => {
|
||||
const runtime = createRuntime()
|
||||
const pages = getRuntimeBrowserPageRegistry(runtime)
|
||||
@@ -361,241 +86,6 @@ describe('OrcaRuntimeService', () => {
|
||||
expect((await runtime.listMobileSessionTabs(`id:${TEST_WORKTREE_ID}`)).tabs).toEqual([])
|
||||
})
|
||||
|
||||
it('detects headless browser-tab changes by field, treating absent and null loadError alike', () => {
|
||||
const base = {
|
||||
type: 'browser' as const,
|
||||
id: 'page-1',
|
||||
title: 'Local',
|
||||
browserWorkspaceId: 'page-1',
|
||||
browserPageId: 'page-1',
|
||||
url: 'https://localhost:3443/',
|
||||
loading: false,
|
||||
canGoBack: false,
|
||||
canGoForward: false,
|
||||
isActive: true
|
||||
}
|
||||
const err = {
|
||||
code: -202,
|
||||
description: 'ERR_CERT_AUTHORITY_INVALID',
|
||||
validatedUrl: 'https://localhost:3443/'
|
||||
}
|
||||
const certificateFailure = {
|
||||
challengeId: 'challenge-1',
|
||||
browserPageId: 'page-1',
|
||||
errorCode: -202,
|
||||
error: 'ERR_CERT_AUTHORITY_INVALID',
|
||||
origin: 'https://localhost:3443',
|
||||
displayHost: 'localhost:3443',
|
||||
canProceed: true,
|
||||
observedAt: 123
|
||||
}
|
||||
const unchanged = (a: unknown[], b: unknown[]): boolean =>
|
||||
headlessBrowserTabsUnchanged(a as never, b as never)
|
||||
|
||||
// Missing/null loadError are equivalent despite differing JSON representations.
|
||||
expect(unchanged([{ ...base }], [{ ...base, loadError: null }])).toBe(true)
|
||||
expect(unchanged([{ ...base, loadError: err }], [{ ...base, loadError: { ...err } }])).toBe(
|
||||
true
|
||||
)
|
||||
expect(unchanged([{ ...base }], [{ ...base, loadError: err }])).toBe(false)
|
||||
expect(
|
||||
unchanged([{ ...base, loadError: err }], [{ ...base, loadError: { ...err, code: -200 } }])
|
||||
).toBe(false)
|
||||
expect(
|
||||
unchanged(
|
||||
[{ ...base, certificateFailure }],
|
||||
[{ ...base, certificateFailure: { ...certificateFailure } }]
|
||||
)
|
||||
).toBe(true)
|
||||
expect(unchanged([{ ...base }], [{ ...base, certificateFailure }])).toBe(false)
|
||||
expect(
|
||||
unchanged(
|
||||
[{ ...base, certificateFailure }],
|
||||
[{ ...base, certificateFailure: { ...certificateFailure, challengeId: 'challenge-2' } }]
|
||||
)
|
||||
).toBe(false)
|
||||
expect(unchanged([{ ...base }], [{ ...base, title: 'Changed' }])).toBe(false)
|
||||
expect(unchanged([{ ...base }], [{ ...base, isActive: false }])).toBe(false)
|
||||
expect(unchanged([{ ...base }], [{ ...base }, { ...base, id: 'page-2' }])).toBe(false)
|
||||
})
|
||||
|
||||
it('does not advertise headless browser capability when a renderer window exists', () => {
|
||||
const runtime = createRuntime()
|
||||
electronMocks.BrowserWindow.fromId.mockReturnValue({ isDestroyed: () => false } as never)
|
||||
runtime.attachWindow(TEST_WINDOW_ID)
|
||||
runtime.setOffscreenBrowserBackend({
|
||||
createTab: vi.fn(),
|
||||
closeTab: vi.fn(),
|
||||
ownsTab: () => true
|
||||
})
|
||||
|
||||
expect(runtime.getStatus().capabilities).not.toContain('browser.headless.v1')
|
||||
// Remote certificate proceed also applies to desktop webviews.
|
||||
expect(runtime.getStatus().capabilities).toContain('browser.certificate-trust.v1')
|
||||
})
|
||||
|
||||
it('declares browser unavailability when no browser provider resolves', async () => {
|
||||
setRuntimeBrowserCommandsFactory(null)
|
||||
const runtime = createRuntime()
|
||||
const status = runtime.getStatus()
|
||||
|
||||
expect(status.capabilities).not.toContain('browser.headless.v1')
|
||||
expect(status.capabilities).not.toContain('browser.certificate-trust.v1')
|
||||
expect(status.capabilities).not.toContain('browser.screencast.v1')
|
||||
expect(status.capabilities).not.toContain('browser.clientHost.v1')
|
||||
expect(status.capabilities).not.toContain('browser.tab-create-known-id.v1')
|
||||
expect(runtimeAdvertisesBrowserClientHosting(status.capabilities)).toBe(false)
|
||||
expect(status.degradations).toEqual([
|
||||
{
|
||||
code: 'browser_unavailable',
|
||||
capability: 'browser.headless.v1',
|
||||
reason: 'unknown',
|
||||
message:
|
||||
'Browser automation is unavailable on this host, and the cause could not be determined.'
|
||||
}
|
||||
])
|
||||
await expect(
|
||||
Promise.resolve().then(() => runtime.browserGoto({ url: 'https://example.com' }))
|
||||
).rejects.toMatchObject({ code: 'browser_unavailable' })
|
||||
await expect(
|
||||
Promise.resolve().then(() =>
|
||||
runtime.browserScreencast(
|
||||
{ format: 'jpeg' },
|
||||
{ sendBinary: () => true, emit: () => undefined }
|
||||
)
|
||||
)
|
||||
).rejects.toMatchObject({ code: 'browser_unavailable' })
|
||||
})
|
||||
|
||||
it('reports the driver as missing instead of telling a configured operator to configure it', () => {
|
||||
setRuntimeBrowserCommandsFactory(null)
|
||||
setRuntimeBrowserUnavailableCause({ reason: 'driver_missing' })
|
||||
|
||||
const [degradation] = createRuntime().getStatus().degradations ?? []
|
||||
|
||||
expect(degradation).toEqual({
|
||||
code: 'browser_unavailable',
|
||||
capability: 'browser.headless.v1',
|
||||
reason: 'driver_missing',
|
||||
message:
|
||||
'ORCA_BROWSER_EXECUTABLE is set, but the bundled agent-browser driver is missing or not executable on this host, so Chromium cannot be driven.'
|
||||
})
|
||||
expect(degradation?.message).not.toMatch(/set ORCA_BROWSER_EXECUTABLE/)
|
||||
})
|
||||
|
||||
it('carries the underlying error to the client when a provider failed to start', () => {
|
||||
setRuntimeBrowserCommandsFactory(null)
|
||||
setRuntimeBrowserUnavailableCause({
|
||||
reason: 'electron_start_failed',
|
||||
detail: 'sidecar exited with code 1'
|
||||
})
|
||||
|
||||
const [degradation] = createRuntime().getStatus().degradations ?? []
|
||||
|
||||
expect(degradation).toEqual({
|
||||
code: 'browser_unavailable',
|
||||
capability: 'browser.headless.v1',
|
||||
reason: 'electron_start_failed',
|
||||
detail: 'sidecar exited with code 1',
|
||||
message:
|
||||
'The installed Electron browser provider failed to start. (sidecar exited with code 1)'
|
||||
})
|
||||
})
|
||||
|
||||
it('blames the missing desktop window when a renderer-backed factory is installed', () => {
|
||||
const [degradation] = createRuntime().getStatus().degradations ?? []
|
||||
|
||||
expect(degradation).toMatchObject({
|
||||
reason: 'desktop_window_unavailable',
|
||||
message: 'Browser automation on this host needs a desktop window, and none is available.'
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps the degradation wire-safe for peers that predate structured causes', () => {
|
||||
setRuntimeBrowserCommandsFactory(null)
|
||||
setRuntimeBrowserUnavailableCause({ reason: 'executable_not_found', detail: '/nope/chromium' })
|
||||
|
||||
const [degradation] = createRuntime().getStatus().degradations ?? []
|
||||
|
||||
// Older clients require stable code/capability and a self-contained sentence without optional fields.
|
||||
expect(degradation?.code).toBe('browser_unavailable')
|
||||
expect(degradation?.capability).toBe('browser.headless.v1')
|
||||
expect(degradation?.message).toBe(
|
||||
'ORCA_BROWSER_EXECUTABLE points at a path that does not exist. (/nope/chromium)'
|
||||
)
|
||||
})
|
||||
|
||||
it('reports a host that cannot load node-pty, instead of that host never answering', () => {
|
||||
// Loader crashes otherwise reach clients as unexplained dropped connections.
|
||||
setRuntimeTerminalUnavailableCause({
|
||||
reason: 'libc_floor',
|
||||
detail: 'the binary requires GLIBC_2.34'
|
||||
})
|
||||
|
||||
const degradations = createRuntime().getStatus().degradations ?? []
|
||||
|
||||
expect(degradations).toContainEqual({
|
||||
code: 'terminal_unavailable',
|
||||
capability: 'terminal.pty.v1',
|
||||
reason: 'libc_floor',
|
||||
detail: 'the binary requires GLIBC_2.34',
|
||||
message:
|
||||
"This host's node-pty binary was built against a newer C library than the host provides, so the dynamic loader refuses it. Rebuild node-pty on this host, or deploy a build whose prebuilt binary matches this platform's libc. (the binary requires GLIBC_2.34)"
|
||||
})
|
||||
})
|
||||
|
||||
it('reports browser and terminal loss together, because they fail independently', () => {
|
||||
setRuntimeBrowserCommandsFactory(null)
|
||||
setRuntimeBrowserUnavailableCause({ reason: 'unconfigured' })
|
||||
setRuntimeTerminalUnavailableCause({ reason: 'dependency_missing' })
|
||||
|
||||
const codes = (createRuntime().getStatus().degradations ?? []).map((entry) => entry.code)
|
||||
|
||||
expect(codes).toEqual(['browser_unavailable', 'terminal_unavailable'])
|
||||
})
|
||||
|
||||
it('says nothing about terminals when no precondition proved them broken', () => {
|
||||
// Unprobed hosts cannot claim proven health or failure; silence means no verdict.
|
||||
const degradations = createRuntime().getStatus().degradations ?? []
|
||||
expect(degradations.map((entry) => entry.code)).not.toContain('terminal_unavailable')
|
||||
})
|
||||
|
||||
it('closes a worktree’s offscreen browser pages when its metadata is removed (leak fix)', () => {
|
||||
const runtime = createRuntime()
|
||||
const closeTab = vi.fn().mockResolvedValue(undefined)
|
||||
runtime.setOffscreenBrowserBackend({ createTab: vi.fn(), closeTab, ownsTab: () => true })
|
||||
runtime.setAgentBrowserBridge({
|
||||
tabList: vi.fn((worktreeId: string) =>
|
||||
worktreeId === TEST_WORKTREE_ID
|
||||
? { tabs: [{ browserPageId: 'page-a' }, { browserPageId: 'page-b' }] }
|
||||
: { tabs: [] }
|
||||
)
|
||||
} as never)
|
||||
|
||||
runtime['removeWorktreeMetadataAndHistory'](store as never, TEST_WORKTREE_ID)
|
||||
|
||||
expect(closeTab).toHaveBeenCalledWith('page-a')
|
||||
expect(closeTab).toHaveBeenCalledWith('page-b')
|
||||
expect(closeTab).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('does not rescue a paired renderer PTY into a recreated worktree', () => {
|
||||
const runtime = createRuntime()
|
||||
const ptyId = 'paired-pty-deleted-worktree'
|
||||
runtime.registerPty(ptyId, TEST_WORKTREE_ID, null, {
|
||||
tabId: 'tab-deleted-worktree',
|
||||
leafId: 'leaf-deleted-worktree'
|
||||
})
|
||||
const internals = runtime as unknown as {
|
||||
pairedRendererSessionOwnedPtyIds: Set<string>
|
||||
}
|
||||
internals.pairedRendererSessionOwnedPtyIds.add(ptyId)
|
||||
|
||||
runtime['removeWorktreeMetadataAndHistory'](store as never, TEST_WORKTREE_ID)
|
||||
|
||||
expect(internals.pairedRendererSessionOwnedPtyIds.has(ptyId)).toBe(false)
|
||||
})
|
||||
|
||||
it('closes a worktree’s client-hosted browser pages when its metadata is removed (leak fix)', async () => {
|
||||
const runtime = createRuntime()
|
||||
const host = attachClientBrowserHost(runtime)
|
||||
@@ -631,17 +121,6 @@ describe('OrcaRuntimeService', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('does not republish a removed worktree’s client tabs to a same-id recreate', async () => {
|
||||
const runtime = createRuntime()
|
||||
const host = attachClientBrowserHost(runtime)
|
||||
await publishClientHostedPage(runtime, host, 'page-removed', TEST_WORKTREE_ID)
|
||||
|
||||
runtime['removeWorktreeMetadataAndHistory'](store as never, TEST_WORKTREE_ID)
|
||||
|
||||
expect(runtime['buildHeadlessMobileSessionBrowserTabs'](TEST_WORKTREE_ID)).toEqual([])
|
||||
expect((await runtime.listMobileSessionTabs(`id:${TEST_WORKTREE_ID}`)).tabs).toEqual([])
|
||||
})
|
||||
|
||||
it('drops a client page record even when its close command cannot be issued', async () => {
|
||||
const runtime = createRuntime()
|
||||
const host = attachClientBrowserHost(runtime)
|
||||
|
||||
Reference in New Issue
Block a user