Files
orca/src/main/cli/linux-terminal-orca-cli-shim.test.ts
T

119 lines
4.7 KiB
TypeScript

import { chmodSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
vi.mock('electron', () => ({
app: { isPackaged: true }
}))
import { ensureLinuxTerminalOrcaCliShimDir } from './linux-terminal-orca-cli-shim'
const created: string[] = []
async function makeFixture(): Promise<{ userDataPath: string; resourcesPath: string }> {
const root = await mkdtemp(join(tmpdir(), 'orca-terminal-cli-shim-'))
created.push(root)
const resourcesPath = join(root, 'resources')
// The bundled orca-ide launcher must exist for the shim to be written.
mkdirSync(join(resourcesPath, 'bin'), { recursive: true })
writeFileSync(join(resourcesPath, 'bin', 'orca-ide'), '#!/usr/bin/env bash\n', 'utf8')
return { userDataPath: join(root, 'user-data'), resourcesPath }
}
afterEach(async () => {
await Promise.all(created.splice(0).map((dir) => rm(dir, { recursive: true, force: true })))
})
describe('ensureLinuxTerminalOrcaCliShimDir', () => {
it('writes an executable bare-orca shim that execs the bundled orca-ide launcher', async () => {
const { userDataPath, resourcesPath } = await makeFixture()
const shimDir = ensureLinuxTerminalOrcaCliShimDir({
userDataPath,
resourcesPath,
appImagePath: null
})
expect(shimDir).toBe(join(userDataPath, 'linux-orca-cli-shim'))
const content = readFileSync(join(shimDir!, 'orca'), 'utf8')
// Single-quoted so a resources path with shell metacharacters can't break out.
expect(content).toContain(`exec '${join(resourcesPath, 'bin', 'orca-ide')}' "$@"`)
const mode = statSync(join(shimDir!, 'orca')).mode & 0o777
expect(mode & 0o111).not.toBe(0)
})
it('memoizes per userDataPath and re-asserts the exec bit for a stale shim', async () => {
const { userDataPath, resourcesPath } = await makeFixture()
const options = { userDataPath, resourcesPath, appImagePath: null }
const first = ensureLinuxTerminalOrcaCliShimDir(options)
expect(first).not.toBeNull()
const shimPath = join(first!, 'orca')
chmodSync(shimPath, 0o644)
// A distinct userData path is not memoized, so ensure runs again and heals
// the exec bit lost above only when it actually processes that path.
const second = ensureLinuxTerminalOrcaCliShimDir(options)
expect(second).toBe(first)
const root = await mkdtemp(join(tmpdir(), 'orca-terminal-cli-shim-2-'))
created.push(root)
const otherUserData = join(root, 'user-data')
mkdirSync(join(otherUserData, 'linux-orca-cli-shim'), { recursive: true })
writeFileSync(join(otherUserData, 'linux-orca-cli-shim', 'orca'), 'stale contents', 'utf8')
chmodSync(join(otherUserData, 'linux-orca-cli-shim', 'orca'), 0o644)
const healed = ensureLinuxTerminalOrcaCliShimDir({
userDataPath: otherUserData,
resourcesPath,
appImagePath: null
})
expect(healed).not.toBeNull()
const healedPath = join(healed!, 'orca')
expect(readFileSync(healedPath, 'utf8')).toContain('orca-ide')
expect(statSync(healedPath).mode & 0o111).not.toBe(0)
})
it('execs the stable AppImage (not the ephemeral mount) when running from an AppImage', async () => {
const { userDataPath, resourcesPath } = await makeFixture()
const appImagePath = join(userDataPath, 'Applications', 'Orca.AppImage')
const shimDir = ensureLinuxTerminalOrcaCliShimDir({
userDataPath,
resourcesPath,
appImagePath
})
const content = readFileSync(join(shimDir!, 'orca'), 'utf8')
expect(content).toContain(appImagePath)
expect(content).not.toContain(resourcesPath)
})
it('returns null (and does not memoize) when the bundled launcher is missing', async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-terminal-cli-shim-missing-'))
created.push(root)
const userDataPath = join(root, 'user-data')
const missing = ensureLinuxTerminalOrcaCliShimDir({
userDataPath,
resourcesPath: join(root, 'resources'),
appImagePath: null
})
expect(missing).toBeNull()
// Once the launcher exists (e.g. later probe with real resources), the same
// userData path succeeds — proving failures are not cached.
const resourcesPath = join(root, 'resources')
mkdirSync(join(resourcesPath, 'bin'), { recursive: true })
writeFileSync(join(resourcesPath, 'bin', 'orca-ide'), '#!/usr/bin/env bash\n', 'utf8')
const recovered = ensureLinuxTerminalOrcaCliShimDir({
userDataPath,
resourcesPath,
appImagePath: null
})
expect(recovered).toBe(join(userDataPath, 'linux-orca-cli-shim'))
})
})