Files
orca/config/scripts/orcad-artifact-version.test.mjs
T
Jinwoo Hong 776c791554 feat(orcad): ship the mobile web page so phones paired to orcad get it (#29882)
* feat(orcad): ship the mobile web page so phones paired to orcad get it

orcad never carried out/mobile-web, so it did not advertise
mobileWeb.bundle.v1 and phones paired directly to an orcad server fell
back to the app's built-in native screens.

The built page now ships in every orcad package at out/mobile-web, the
path getBundledMobileWebBundleRoot already probes under the install
root. Its manifest is a fixed artifact; its content-addressed assets
join the hashed artifact list from that manifest, as one shared copy in
the template's common files. build-orcad fails when the page is missing
or stale, and CI lanes that build orcad now build the page first.

* ci(orcad): check out mobile/ for the Windows host template build

* refactor(orcad): copy the page tree whole and build it once per CI run

The guard already refuses unlisted files, so staging copies the
bundle directory as native-chat-visuals is copied. The shipped template
takes the page the qualification lanes tested, the e2e build artifact
carries it, and the PR smoke builds it through install-mobile-dependencies
behind its own scope step. Drops tests that duplicated the guard's own.

* fix(orcad): refuse a template page asset name that escapes the slot
2026-10-16 19:29:41 -07:00

93 lines
4.0 KiB
JavaScript

import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import {
ORCAD_MOBILE_WEB_MANIFEST,
ORCAD_NODE_RUNTIME_MARKER_FILENAME,
ORCAD_SERVER_TARGET_FILENAME,
orcadArtifactFilenames,
orcadRipgrepArtifact
} from '../../src/shared/orcad-artifacts.ts'
import { SERVER_TARGETS } from '../../src/shared/node-runtime-pin.ts'
import { orcadAgentBrowserNativeName } from '../../src/shared/orcad-agent-browser-name.ts'
import { readOrcadArtifactIdentity } from '../../src/main/orcad/orcad-artifact-identity.ts'
import { computeOrcadFullVersion } from './orcad-artifact-version.mjs'
const directories = []
afterEach(() => {
for (const directory of directories.splice(0)) {
rmSync(directory, { recursive: true, force: true })
}
})
const PAGE_ASSET = 'out/mobile-web/index.html'
const PAGE_MANIFEST = JSON.stringify({ assets: [{ path: 'index.html' }] })
function createArtifactDirectory(target = 'linux-x64-glibc') {
const directory = mkdtempSync(join(tmpdir(), 'orcad-version-'))
directories.push(directory)
for (const filename of orcadArtifactFilenames(target, [PAGE_ASSET])) {
const path = join(directory, filename)
mkdirSync(dirname(path), { recursive: true })
writeFileSync(path, filename === ORCAD_MOBILE_WEB_MANIFEST ? PAGE_MANIFEST : filename)
}
writeFileSync(join(directory, ORCAD_SERVER_TARGET_FILENAME), `${target}\n`)
return directory
}
describe('standalone runtime version', () => {
it('changes when a shipped search binary changes and rejects a missing binary', () => {
const target = 'linux-x64-glibc'
const dir = createArtifactDirectory(target)
const before = computeOrcadFullVersion(dir, { target })
const binary = join(dir, orcadRipgrepArtifact(target))
writeFileSync(binary, 'updated binary')
expect(computeOrcadFullVersion(dir, { target })).not.toBe(before)
rmSync(binary)
expect(() => computeOrcadFullVersion(dir, { target })).toThrow(orcadRipgrepArtifact(target))
})
it('changes when a page asset changes and rejects a missing one', () => {
const target = 'linux-x64-glibc'
const dir = createArtifactDirectory(target)
const before = computeOrcadFullVersion(dir, { target })
writeFileSync(join(dir, PAGE_ASSET), 'updated page')
expect(computeOrcadFullVersion(dir, { target })).not.toBe(before)
rmSync(join(dir, PAGE_ASSET))
expect(() => computeOrcadFullVersion(dir, { target })).toThrow(PAGE_ASSET)
})
it('keys the version on the referenced runtime digest rather than its bytes', () => {
const target = 'darwin-arm64'
const dir = createArtifactDirectory(target)
writeFileSync(join(dir, ORCAD_NODE_RUNTIME_MARKER_FILENAME), `${'a'.repeat(64)}\n`)
const before = computeOrcadFullVersion(dir, { target })
writeFileSync(join(dir, ORCAD_NODE_RUNTIME_MARKER_FILENAME), `${'b'.repeat(64)}\n`)
expect(computeOrcadFullVersion(dir, { target })).not.toBe(before)
})
it.each(SERVER_TARGETS)(
'matches the installed %s identity with and without its optional browser',
async (target) => {
const dir = createArtifactDirectory(target)
const [platform, arch] = target.split('-')
const agentBrowserFilename = orcadAgentBrowserNativeName(
platform,
arch,
target.endsWith('-musl') ? 'musl' : 'glibc'
)
const options = { target, agentBrowserFilename }
const withoutBrowser = computeOrcadFullVersion(dir, options)
expect(withoutBrowser).toBe(await readOrcadArtifactIdentity(dir))
writeFileSync(join(dir, agentBrowserFilename), 'browser')
const withBrowser = computeOrcadFullVersion(dir, options)
expect(withBrowser).not.toBe(withoutBrowser)
expect(withBrowser).toBe(await readOrcadArtifactIdentity(dir))
writeFileSync(join(dir, agentBrowserFilename), 'updated-browser')
expect(computeOrcadFullVersion(dir, options)).not.toBe(withBrowser)
expect(computeOrcadFullVersion(dir, options)).toBe(await readOrcadArtifactIdentity(dir))
}
)
})