test: fix full ci suite follow-ups

This commit is contained in:
Peter Steinberger
2026-04-27 01:10:28 +01:00
parent 3b514ad5f3
commit b825c8d34b
3 changed files with 82 additions and 12 deletions

View File

@@ -25,6 +25,7 @@ const serviceLoaded = vi.fn();
const prepareRestartScript = vi.fn();
const runRestartScript = vi.fn();
const mockedRunDaemonInstall = vi.fn();
const serviceReadCommand = vi.fn();
const serviceReadRuntime = vi.fn();
const inspectPortUsage = vi.fn();
const classifyPortListener = vi.fn();
@@ -164,8 +165,27 @@ vi.mock("../plugins/installed-plugin-index-records.js", async (importOriginal) =
});
vi.mock("../daemon/service.js", () => ({
readGatewayServiceState: async () => {
const command = await serviceReadCommand();
const env = {
...process.env,
...(command && typeof command === "object" && "environment" in command
? (command.environment as NodeJS.ProcessEnv | undefined)
: undefined),
};
const [loaded, runtime] = await Promise.all([serviceLoaded({ env }), serviceReadRuntime(env)]);
return {
installed: command !== null,
loaded,
running: runtime?.status === "running",
env,
command,
runtime,
};
},
resolveGatewayService: vi.fn(() => ({
isLoaded: (...args: unknown[]) => serviceLoaded(...args),
readCommand: (...args: unknown[]) => serviceReadCommand(...args),
readRuntime: (...args: unknown[]) => serviceReadRuntime(...args),
})),
}));
@@ -451,6 +471,9 @@ describe("update-cli", () => {
readPackageVersion.mockResolvedValue("1.0.0");
resolveGlobalManager.mockResolvedValue("npm");
serviceLoaded.mockResolvedValue(false);
serviceReadCommand.mockImplementation(async () =>
(await serviceLoaded()) ? { programArguments: ["openclaw", "gateway", "run"] } : null,
);
serviceReadRuntime.mockResolvedValue({
status: "running",
pid: 4242,
@@ -543,11 +566,12 @@ describe("update-cli", () => {
});
it("keeps downgrade post-update work in the current process", async () => {
const downgradedRoot = createCaseDir("openclaw-downgraded-root");
setupUpdatedRootRefresh({
gatewayUpdateImpl: async () =>
makeOkUpdateResult({
mode: "npm",
root: createCaseDir("openclaw-downgraded-root"),
root: downgradedRoot,
before: { version: "2026.4.14" },
after: { version: "2026.4.10" },
}),
@@ -574,13 +598,13 @@ describe("update-cli", () => {
url: "ws://127.0.0.1:18789",
});
await updateCommand({ yes: true, tag: "2026.4.10" });
await updateCommand({ yes: true, tag: "2026.4.10", restart: false });
expect(spawn).not.toHaveBeenCalled();
expect(syncPluginsForUpdateChannel).toHaveBeenCalled();
expect(updateNpmInstalledPlugins).toHaveBeenCalled();
expect(runDaemonInstall).toHaveBeenCalled();
expect(probeGateway).toHaveBeenCalled();
expect(runDaemonInstall).not.toHaveBeenCalled();
expect(probeGateway).not.toHaveBeenCalled();
expect(defaultRuntime.exit).not.toHaveBeenCalledWith(1);
});
@@ -1872,25 +1896,32 @@ describe("update-cli", () => {
await updateCommand({ yes: true });
expect(runDaemonInstall).toHaveBeenCalledWith({
force: true,
json: undefined,
});
expect(runDaemonInstall).not.toHaveBeenCalled();
expect(runRestartScript).not.toHaveBeenCalled();
expect(defaultRuntime.exit).toHaveBeenCalledWith(1);
expect(
vi
.mocked(defaultRuntime.log)
.mock.calls.map((call) => String(call[0]))
.join("\n"),
).toContain("updated install entrypoint not found");
});
it("fails a JSON package update when fallback restart leaves the old gateway running", async () => {
const updatedRoot = createCaseDir("openclaw-updated-root");
const updatedEntrypoint = path.join(updatedRoot, "dist", "entry.js");
setupUpdatedRootRefresh({
entrypoints: [updatedEntrypoint],
gatewayUpdateImpl: async () =>
makeOkUpdateResult({
mode: "npm",
root: createCaseDir("openclaw-updated-root"),
root: updatedRoot,
before: { version: "2026.4.23" },
after: { version: "2026.4.24" },
}),
});
prepareRestartScript.mockResolvedValue(null);
serviceLoaded.mockResolvedValue(true);
probeGateway.mockResolvedValue({
ok: true,
close: null,
@@ -1911,7 +1942,11 @@ describe("update-cli", () => {
await updateCommand({ yes: true, json: true });
expect(runRestartScript).not.toHaveBeenCalled();
expect(runDaemonRestart).toHaveBeenCalled();
expect(runDaemonRestart).not.toHaveBeenCalled();
expect(runCommandWithTimeout).toHaveBeenCalledWith(
[expect.stringMatching(/node/), updatedEntrypoint, "gateway", "restart", "--json"],
expect.objectContaining({ cwd: updatedRoot, timeoutMs: 60_000 }),
);
expect(probeGateway).toHaveBeenCalledWith(expect.objectContaining({ includeDetails: true }));
expect(defaultRuntime.exit).toHaveBeenCalledWith(1);
expect(defaultRuntime.writeJson).not.toHaveBeenCalled();
@@ -1927,11 +1962,14 @@ describe("update-cli", () => {
});
it("fails a package update when the restarted gateway reports activated plugin load errors", async () => {
const updatedRoot = createCaseDir("openclaw-updated-root");
const updatedEntrypoint = path.join(updatedRoot, "dist", "entry.js");
setupUpdatedRootRefresh({
entrypoints: [updatedEntrypoint],
gatewayUpdateImpl: async () =>
makeOkUpdateResult({
mode: "npm",
root: createCaseDir("openclaw-updated-root"),
root: updatedRoot,
before: { version: "2026.4.23" },
after: { version: "2026.4.24" },
}),

View File

@@ -69,6 +69,12 @@ import { createUtilsVitestConfig } from "./vitest/vitest.utils.config.ts";
import { createWizardVitestConfig } from "./vitest/vitest.wizard.config.ts";
const EXTENSIONS_CHANNEL_GLOB = ["extensions", "channel", "**"].join("/");
const PRIVATE_PLUGIN_SDK_SUBPATHS = [
"qa-channel",
"qa-channel-protocol",
"qa-lab",
"qa-runtime",
] as const;
function bundledExcludePatternCouldMatchFile(pattern: string, file: string): boolean {
if (pattern === file) {
@@ -82,6 +88,28 @@ function bundledExcludePatternCouldMatchFile(pattern: string, file: string): boo
}
describe("resolveVitestIsolation", () => {
it("aliases private QA plugin SDK subpaths for source tests only", () => {
expect(sharedVitestConfig.resolve.alias).toEqual(
expect.arrayContaining(
PRIVATE_PLUGIN_SDK_SUBPATHS.map((subpath) =>
expect.objectContaining({
find: `openclaw/plugin-sdk/${subpath}`,
replacement: path.join(process.cwd(), "src", "plugin-sdk", `${subpath}.ts`),
}),
),
),
);
expect(sharedVitestConfig.resolve.alias).not.toEqual(
expect.arrayContaining(
PRIVATE_PLUGIN_SDK_SUBPATHS.map((subpath) =>
expect.objectContaining({
find: `@openclaw/plugin-sdk/${subpath}`,
}),
),
),
);
});
it("defaults shared scoped configs to the non-isolated runner", () => {
expect(resolveVitestIsolation({})).toBe(false);
});

View File

@@ -1,6 +1,7 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import { pluginSdkSubpaths } from "../../scripts/lib/plugin-sdk-entries.mjs";
import privateLocalOnlyPluginSdkSubpaths from "../../scripts/lib/plugin-sdk-private-local-only-subpaths.json" with { type: "json" };
import {
detectVitestHostInfo as detectVitestHostInfoImpl,
isCiLikeEnv,
@@ -113,6 +114,9 @@ const workerConfig = resolveSharedVitestWorkerConfig({
isWindows,
localScheduling,
});
const sourcePluginSdkSubpaths = [
...new Set([...pluginSdkSubpaths, ...privateLocalOnlyPluginSdkSubpaths]),
].toSorted((left, right) => left.localeCompare(right));
if (!isCI && localScheduling.throttledBySystem && shouldPrintVitestThrottle(process.env)) {
console.error(
@@ -131,7 +135,7 @@ export const sharedVitestConfig = {
find: "openclaw/extension-api",
replacement: path.join(repoRoot, "src", "extensionAPI.ts"),
},
...pluginSdkSubpaths.map((subpath) => ({
...sourcePluginSdkSubpaths.map((subpath) => ({
find: `openclaw/plugin-sdk/${subpath}`,
replacement: path.join(repoRoot, "src", "plugin-sdk", `${subpath}.ts`),
})),