Files
orca/src/main/app-relaunch.test.ts
T
Neil 3f81541188 Support restarting Windows Orca as administrator (#28073)
* feat(windows): add administrator PowerShell terminal setting

* fix(settings): localize administrator terminal search keywords

* fix(windows): restrict elevated terminal host to Orca's runtime and requesting account

* fix(windows): harden administrator terminal routing, inventory and restore

* fix(build): build the Windows agent hook when electron-builder packages Windows

* fix(build): build the packaged Windows agent hook for the target architecture

* fix(windows): accept the development terminal runtime and test real elevation in CI

* feat(windows): show administrator status and restart instructions

* fix(settings): localize administrator mode search keywords

* test(settings): isolate the desktop permission section in shell picker tests

* Add Windows administrator restart and simplify Terminal settings

* Keep administrator restart silent and settings actions within narrow panes

* Keep Windows shell choices and permission guides usable at minimum width

* Prevent later restarts from replaying administrator terminal reset

* Fix CI route resolution and transient Windows fixture cleanup
2026-10-13 18:06:05 -07:00

114 lines
4.4 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const { appRelaunchMock, hasSwitchMock, recordDurableCrashBreadcrumbMock } = vi.hoisted(() => ({
appRelaunchMock: vi.fn(),
hasSwitchMock: vi.fn<(name: string) => boolean>(() => false),
recordDurableCrashBreadcrumbMock: vi.fn()
}))
vi.mock('electron', () => ({
app: { relaunch: appRelaunchMock, commandLine: { hasSwitch: hasSwitchMock } }
}))
vi.mock('./windows/windows-administrator-status', () => ({
getWindowsAdministratorStatus: vi.fn(async () => true)
}))
vi.mock('./daemon/daemon-provider-restart', () => ({ restartDaemon: vi.fn(async () => {}) }))
vi.mock('./crash-reporting/durable-crash-breadcrumb', () => ({
recordDurableCrashBreadcrumb: recordDurableCrashBreadcrumbMock
}))
import { relaunchApp } from './app-relaunch'
import { restartLocalTerminalsAfterElevation } from './windows/windows-administrator-restart'
import { _resetHydrateShellPathCache, _setLaunchPathForTests } from './startup/hydrate-shell-path'
beforeEach(() => {
appRelaunchMock.mockReset()
hasSwitchMock.mockReset().mockReturnValue(false)
recordDurableCrashBreadcrumbMock.mockReset()
})
const originalPath = process.env.PATH
const originalArgv = process.argv
afterEach(() => {
process.argv = originalArgv
vi.restoreAllMocks()
_resetHydrateShellPathCache()
if (originalPath === undefined) {
delete process.env.PATH
} else {
process.env.PATH = originalPath
}
})
describe('relaunchApp', () => {
it('does not replay native administrator restart arguments before or after consumption', async () => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
const flag = '--orca-restart-local-terminals-as-administrator'
const nativeArgv = ['Orca.exe', '--user-data-dir=C:\\Orca profile', flag]
process.argv = [...nativeArgv]
hasSwitchMock.mockImplementation((name: string) => nativeArgv.includes(`--${name}`))
let nextArgs: string[] | undefined
appRelaunchMock.mockImplementation((options?: Electron.RelaunchOptions) => {
nextArgs = options?.args ?? nativeArgv.slice(1)
})
relaunchApp('renderer-request')
expect(nextArgs).toEqual(['--user-data-dir=C:\\Orca profile'])
await restartLocalTerminalsAfterElevation(new AbortController().signal)
expect(process.argv).not.toContain(flag)
expect(nativeArgv).toContain(flag)
relaunchApp('profile-switch')
expect(nextArgs).toEqual(['--user-data-dir=C:\\Orca profile'])
const custom = { execPath: 'administrator-launcher.exe', args: ['restart', flag] }
relaunchApp('windows-administrator', undefined, custom)
expect(appRelaunchMock).toHaveBeenLastCalledWith(custom)
})
it.each(['win32', 'darwin', 'linux'] as const)(
'preserves default relaunch arguments for ordinary %s launches',
(platform) => {
vi.spyOn(process, 'platform', 'get').mockReturnValue(platform)
relaunchApp('renderer-request')
expect(appRelaunchMock).toHaveBeenCalledWith(undefined)
}
)
it('passes the native restart target to Electron after recording the reason', () => {
const options = { execPath: 'C:\\Orca\\resources\\bin\\orca.exe', args: ['restart'] }
relaunchApp('windows-administrator', undefined, options)
expect(appRelaunchMock).toHaveBeenCalledWith(options)
expect(recordDurableCrashBreadcrumbMock.mock.invocationCallOrder[0]).toBeLessThan(
appRelaunchMock.mock.invocationCallOrder[0]
)
})
it('durably records the reason before scheduling the replacement process', () => {
relaunchApp('gpu-fallback', { processReason: 'crashed', exitCode: 5 })
expect(recordDurableCrashBreadcrumbMock).toHaveBeenCalledOnce()
expect(recordDurableCrashBreadcrumbMock).toHaveBeenCalledWith('app_relaunch_requested', {
processReason: 'crashed',
exitCode: 5,
reason: 'gpu-fallback'
})
expect(appRelaunchMock).toHaveBeenCalledOnce()
expect(recordDurableCrashBreadcrumbMock.mock.invocationCallOrder[0]).toBeLessThan(
appRelaunchMock.mock.invocationCallOrder[0]
)
})
it('does not carry Orca PATH seeds into the replacement process', () => {
process.env.PATH = '/seeded/newest-nvm/bin:/usr/bin'
_setLaunchPathForTests('/usr/bin')
let inheritedPath: string | undefined
appRelaunchMock.mockImplementation(() => {
inheritedPath = process.env.PATH
})
relaunchApp('renderer-request')
expect(inheritedPath).toBe('/usr/bin')
expect(process.env.PATH).toBe('/seeded/newest-nvm/bin:/usr/bin')
})
})