Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/opencode-runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ jobs:
node "$PNPM_SCRIPT" install --frozen-lockfile
node "$PNPM_SCRIPT" --filter "@sapiom/harness..." build
- name: Execute the installed runtime with the production context plugin
run: node "$PNPM_SCRIPT" --filter @sapiom/opencode exec vitest run src/assistant-context.native.test.ts src/startup-dependencies.native.test.ts src/runtime-identity.test.ts src/desktop-runtime-identity.test.ts
# Keep unrelated native work out of the strict fresh-start deadline test.
# That test still keeps two independent runtimes alive together.
run: node "$PNPM_SCRIPT" --filter @sapiom/opencode exec vitest run --no-file-parallelism src/assistant-context.native.test.ts src/startup-dependencies.native.test.ts src/runtime-identity.test.ts src/desktop-runtime-identity.test.ts
- name: Verify desktop signing boundaries
run: node --test packages/harness-desktop/scripts/opencode-after-pack.check.cjs
- name: Verify accepted-source retention on the target filesystem
Expand Down
74 changes: 71 additions & 3 deletions packages/opencode/src/startup-dependencies.native.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,22 @@ import {
import { tmpdir } from "node:os";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { expect, it } from "vitest";
import { startOpenCodeServer, type OpenCodeServer } from "./server.js";
import { expect, it, vi } from "vitest";
import {
OpenCodeStartupError,
startOpenCodeServer,
type OpenCodeServer,
} from "./server.js";

interface StartupTiming {
attempt: string;
beforeLaunchMs?: number;
healthOkMs?: number;
configResponseMs?: number;
readyMs?: number;
settledMs?: number;
outcome?: string;
}

it("opens two fresh native sessions within the default deadline without a package registry", async () => {
const root = await mkdtemp(join(tmpdir(), "opencode-startup-dependencies-"));
Expand All @@ -28,13 +42,36 @@ it("opens two fresh native sessions within the default deadline without a packag
if (!address || typeof address === "string")
throw new Error("registry unavailable");
const starts: number[] = [];
const timings: StartupTiming[] = [];
let active: { timing: StartupTiming; startedAt: number } | undefined;
const nativeFetch = globalThis.fetch;
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockImplementation(async (input, init) => {
const current = active;
const response = await nativeFetch(input, init);
if (current) {
const path =
input instanceof URL
? input.pathname
: new URL(typeof input === "string" ? input : input.url).pathname;
const elapsed = Math.round(performance.now() - current.startedAt);
if (path === "/global/health" && response.ok)
current.timing.healthOkMs ??= elapsed;
if (path === "/config") current.timing.configResponseMs ??= elapsed;
}
return response;
});
let cleanup: PromiseSettledResult<void>[] = [];
try {
const conversations: string[] = [];
for (const name of ["first", "second"]) {
const stateRoot = join(root, name);
let configDirectory = "";
const startedAt = performance.now();
const timing: StartupTiming = { attempt: name };
timings.push(timing);
active = { timing, startedAt };
const runtime = await startOpenCodeServer({
command: process.env.SAPIOM_OPENCODE_CONTEXT_TEST_BINARY
? { executable: process.env.SAPIOM_OPENCODE_CONTEXT_TEST_BINARY }
Expand All @@ -54,8 +91,27 @@ it("opens two fresh native sessions within the default deadline without a packag
join(configDirectory, ".npmrc"),
`registry=http://127.0.0.1:${address.port}\n`,
);
timing.beforeLaunchMs = Math.round(performance.now() - startedAt);
},
});
})
.then(
(runtime) => {
timing.readyMs = Math.round(performance.now() - startedAt);
timing.outcome = "ready";
return runtime;
},
(error: unknown) => {
timing.outcome =
error instanceof OpenCodeStartupError
? error.code
: "other-error";
throw error;
},
)
.finally(() => {
timing.settledMs = Math.round(performance.now() - startedAt);
active = undefined;
});
starts.push(performance.now() - startedAt);
runtimes.push(runtime);
// The installer fast path must be backed by the real shipped dependency.
Expand Down Expand Up @@ -92,6 +148,18 @@ it("opens two fresh native sessions within the default deadline without a packag
expect(registryRequests).toEqual([]);
expect(starts.every((elapsed) => elapsed < 15_000)).toBe(true);
} finally {
fetchSpy.mockRestore();
// Only bounded phase names/timings: no headers, URLs, config, or native logs.
// Failed settledMs includes the existing bounded cleanup after the deadline.
console.info(
"Native startup timing",
JSON.stringify({
platform: process.platform,
arch: process.arch,
deadlineMs: 15_000,
timings,
}),
);
cleanup = await Promise.allSettled(
runtimes.map((runtime) => runtime.close()),
);
Expand Down
Loading