mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 18:44:02 +00:00
fix: stabilize full-suite regressions
This commit is contained in:
@@ -3218,7 +3218,7 @@ describe("active-memory plugin", () => {
|
||||
testing.setSetupGraceTimeoutMsForTests(0);
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
timeoutMs: 100,
|
||||
timeoutMs: 1_000,
|
||||
};
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
hoisted.sessionStore["agent:main:memory-get-miss"] = {
|
||||
|
||||
@@ -25,12 +25,14 @@ describe("mantis visual task runtime", () => {
|
||||
let repoRoot: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), "mantis-visual-task-"));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(repoRoot, { force: true, recursive: true });
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
|
||||
@@ -520,9 +520,12 @@ export async function runMantisVisualDriver(
|
||||
runner,
|
||||
stdio: "inherit",
|
||||
});
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, opts.settleMs ?? DEFAULT_SETTLE_MS);
|
||||
});
|
||||
const settleMs = opts.settleMs ?? DEFAULT_SETTLE_MS;
|
||||
if (settleMs > 0) {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, settleMs);
|
||||
});
|
||||
}
|
||||
await runCommandWithExternalOutput({
|
||||
command: crabboxBin,
|
||||
outputPath: screenshotPath,
|
||||
|
||||
@@ -16,6 +16,7 @@ function createFetchFixture(payload: unknown): typeof fetch {
|
||||
|
||||
describe("scanOpenRouterModels", () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
@@ -113,6 +114,7 @@ describe("scanOpenRouterModels", () => {
|
||||
});
|
||||
|
||||
it("applies the scan timeout to the OpenRouter catalog request", async () => {
|
||||
vi.useFakeTimers();
|
||||
const fetchImpl: typeof fetch = async (_input, init) =>
|
||||
await new Promise<Response>((_resolve, reject) => {
|
||||
const signal = typeof init === "object" && init ? init.signal : undefined;
|
||||
@@ -125,13 +127,16 @@ describe("scanOpenRouterModels", () => {
|
||||
});
|
||||
});
|
||||
|
||||
await expect(
|
||||
const scan = expect(
|
||||
scanOpenRouterModels({
|
||||
fetchImpl,
|
||||
probe: false,
|
||||
timeoutMs: 1,
|
||||
}),
|
||||
).rejects.toThrow(/catalog aborted/);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
await scan;
|
||||
});
|
||||
|
||||
it("caps oversized scan timeouts before scheduling catalog aborts", async () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ const pluginRegistryMocks = vi.hoisted(() => {
|
||||
loadPluginManifestRegistryForInstalledIndex: loadManifestRegistry,
|
||||
loadPluginManifestRegistryForPluginRegistry: loadManifestRegistry,
|
||||
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
|
||||
resolveInstalledManifestRegistryIndexFingerprint: vi.fn(() => "test-index"),
|
||||
loadPluginMetadataSnapshot: vi.fn((params: unknown) => {
|
||||
const registry = loadManifestRegistry(params) ?? { plugins: [], diagnostics: [] };
|
||||
return {
|
||||
@@ -26,6 +27,8 @@ const pluginRegistryMocks = vi.hoisted(() => {
|
||||
vi.mock("../plugins/manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex:
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex,
|
||||
resolveInstalledManifestRegistryIndexFingerprint:
|
||||
pluginRegistryMocks.resolveInstalledManifestRegistryIndexFingerprint,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
@@ -38,12 +41,68 @@ vi.mock("../plugins/plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot: pluginRegistryMocks.loadPluginMetadataSnapshot,
|
||||
}));
|
||||
|
||||
import { clearCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js";
|
||||
import {
|
||||
clearCurrentPluginMetadataSnapshot,
|
||||
setCurrentPluginMetadataSnapshot,
|
||||
} from "../plugins/current-plugin-metadata-snapshot.js";
|
||||
import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
|
||||
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
|
||||
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.types.js";
|
||||
import {
|
||||
resetProviderAuthAliasMapCacheForTest,
|
||||
resolveProviderIdForAuth,
|
||||
} from "./provider-auth-aliases.js";
|
||||
|
||||
function createPluginMetadataSnapshot(params: {
|
||||
config?: Parameters<typeof resolveInstalledPluginIndexPolicyHash>[0];
|
||||
plugins: readonly PluginManifestRecord[];
|
||||
}): PluginMetadataSnapshot {
|
||||
const policyHash = resolveInstalledPluginIndexPolicyHash(params.config);
|
||||
return {
|
||||
policyHash,
|
||||
index: {
|
||||
version: 1,
|
||||
hostContractVersion: "test",
|
||||
compatRegistryVersion: "test",
|
||||
migrationVersion: 1,
|
||||
policyHash,
|
||||
generatedAtMs: 1,
|
||||
installRecords: {},
|
||||
plugins: params.plugins.map((plugin) => ({
|
||||
pluginId: plugin.id,
|
||||
origin: plugin.origin ?? "global",
|
||||
enabled: true,
|
||||
enabledByDefault: true,
|
||||
})),
|
||||
diagnostics: [],
|
||||
},
|
||||
registryDiagnostics: [],
|
||||
manifestRegistry: { plugins: params.plugins, diagnostics: [] },
|
||||
plugins: params.plugins,
|
||||
diagnostics: [],
|
||||
byPluginId: new Map(params.plugins.map((plugin) => [plugin.id, plugin])),
|
||||
normalizePluginId: (pluginId) => pluginId,
|
||||
owners: {
|
||||
channels: new Map(),
|
||||
channelConfigs: new Map(),
|
||||
providers: new Map(),
|
||||
modelCatalogProviders: new Map(),
|
||||
cliBackends: new Map(),
|
||||
setupProviders: new Map(),
|
||||
commandAliases: new Map(),
|
||||
contracts: new Map(),
|
||||
},
|
||||
metrics: {
|
||||
registrySnapshotMs: 0,
|
||||
manifestRegistryMs: 0,
|
||||
ownerMapsMs: 0,
|
||||
totalMs: 0,
|
||||
indexPluginCount: params.plugins.length,
|
||||
manifestPluginCount: params.plugins.length,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("provider auth aliases", () => {
|
||||
beforeEach(() => {
|
||||
clearCurrentPluginMetadataSnapshot();
|
||||
@@ -56,7 +115,7 @@ describe("provider auth aliases", () => {
|
||||
});
|
||||
|
||||
it("treats deprecated auth choice ids as provider auth aliases", () => {
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
const metadataSnapshot = createPluginMetadataSnapshot({
|
||||
plugins: [
|
||||
{
|
||||
id: "openai",
|
||||
@@ -71,21 +130,22 @@ describe("provider auth aliases", () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
expect(resolveProviderIdForAuth("codex-cli")).toBe("openai");
|
||||
expect(resolveProviderIdForAuth("openai-chatgpt-import")).toBe("openai");
|
||||
expect(resolveProviderIdForAuth("openai")).toBe("openai");
|
||||
expect(resolveProviderIdForAuth("codex-cli", { metadataSnapshot })).toBe("openai");
|
||||
expect(resolveProviderIdForAuth("openai-chatgpt-import", { metadataSnapshot })).toBe("openai");
|
||||
expect(resolveProviderIdForAuth("openai", { metadataSnapshot })).toBe("openai");
|
||||
});
|
||||
|
||||
it("does not reuse aliases across env-resolved plugin roots", () => {
|
||||
const config = {};
|
||||
const env = {
|
||||
HOME: "/home/one",
|
||||
OPENCLAW_HOME: undefined,
|
||||
} as NodeJS.ProcessEnv;
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForPluginRegistry
|
||||
.mockReturnValueOnce({
|
||||
setCurrentPluginMetadataSnapshot(
|
||||
createPluginMetadataSnapshot({
|
||||
config,
|
||||
plugins: [
|
||||
{
|
||||
id: "one",
|
||||
@@ -93,9 +153,15 @@ describe("provider auth aliases", () => {
|
||||
providerAuthAliases: { fixture: "provider-one" },
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
}),
|
||||
{ config, env },
|
||||
);
|
||||
|
||||
expect(resolveProviderIdForAuth("fixture", { config, env })).toBe("provider-one");
|
||||
env.HOME = "/home/two";
|
||||
setCurrentPluginMetadataSnapshot(
|
||||
createPluginMetadataSnapshot({
|
||||
config,
|
||||
plugins: [
|
||||
{
|
||||
id: "two",
|
||||
@@ -103,15 +169,11 @@ describe("provider auth aliases", () => {
|
||||
providerAuthAliases: { fixture: "provider-two" },
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
expect(resolveProviderIdForAuth("fixture", { config: {}, env })).toBe("provider-one");
|
||||
env.HOME = "/home/two";
|
||||
expect(resolveProviderIdForAuth("fixture", { config: {}, env })).toBe("provider-two");
|
||||
expect(pluginRegistryMocks.loadPluginManifestRegistryForPluginRegistry).toHaveBeenCalledTimes(
|
||||
2,
|
||||
}),
|
||||
{ config, env },
|
||||
);
|
||||
|
||||
expect(resolveProviderIdForAuth("fixture", { config, env })).toBe("provider-two");
|
||||
});
|
||||
|
||||
it("uses caller-provided metadata snapshots without loading plugin metadata", () => {
|
||||
|
||||
@@ -827,7 +827,6 @@ describe("Tool Search", () => {
|
||||
}, 5_000);
|
||||
|
||||
it("aborts already-started bridged calls when code mode times out", async () => {
|
||||
testing.setToolSearchMinCodeTimeoutMsForTest(100);
|
||||
const codeTool = fakeTool(TOOL_SEARCH_CODE_MODE_TOOL_NAME, "code mode");
|
||||
const target = pluginTool("fake_abort_on_timeout", "Long-running target tool");
|
||||
let observedSignal: AbortSignal | undefined;
|
||||
@@ -860,7 +859,7 @@ describe("Tool Search", () => {
|
||||
|
||||
const config = {
|
||||
tools: {
|
||||
toolSearch: { enabled: true, mode: "code", codeTimeoutMs: 100 },
|
||||
toolSearch: { enabled: true, mode: "code", codeTimeoutMs: 1_000 },
|
||||
},
|
||||
} as never;
|
||||
applyToolSearchCatalog({
|
||||
|
||||
@@ -115,6 +115,8 @@ describe("startProxy", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetProxyLifecycleForTests();
|
||||
resetActiveManagedProxyStateForTests();
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ describe("run-oxlint", () => {
|
||||
" ...process.env,",
|
||||
" OPENCLAW_OXLINT_SHARD_HEARTBEAT_MS: '0',",
|
||||
" OPENCLAW_OXLINT_SHARD_TIMEOUT_MS: '0',",
|
||||
" OPENCLAW_OXLINT_SHARD_KILL_GRACE_MS: '25',",
|
||||
" OPENCLAW_OXLINT_SHARD_KILL_GRACE_MS: '250',",
|
||||
" },",
|
||||
" extraArgs: [],",
|
||||
" runner: process.env.RUNNER_FILE,",
|
||||
|
||||
@@ -182,23 +182,35 @@ setInterval(() => {}, 1000);
|
||||
args: [scriptPath, grandchildPidPath],
|
||||
command: process.execPath,
|
||||
cwd: root,
|
||||
timeoutKillGraceMs: 25,
|
||||
timeoutMs: 100,
|
||||
timeoutKillGraceMs: 100,
|
||||
timeoutMs: 500,
|
||||
});
|
||||
const runResult = runPromise.then(
|
||||
() => ({ ok: true as const }),
|
||||
(error: unknown) => ({ error, ok: false as const }),
|
||||
);
|
||||
|
||||
try {
|
||||
await waitFor(() => fs.existsSync(grandchildPidPath));
|
||||
grandchildPid = Number.parseInt(fs.readFileSync(grandchildPidPath, "utf8"), 10);
|
||||
await waitFor(() => {
|
||||
if (!fs.existsSync(grandchildPidPath)) {
|
||||
return false;
|
||||
}
|
||||
grandchildPid = Number.parseInt(fs.readFileSync(grandchildPidPath, "utf8"), 10);
|
||||
return Number.isInteger(grandchildPid) && isProcessAlive(grandchildPid);
|
||||
});
|
||||
expect(Number.isInteger(grandchildPid)).toBe(true);
|
||||
expect(isProcessAlive(grandchildPid)).toBe(true);
|
||||
|
||||
await expect(runPromise).rejects.toMatchObject({
|
||||
code: "ETIMEDOUT",
|
||||
message: expect.stringContaining("timed out after 100ms"),
|
||||
const result = await runResult;
|
||||
expect(result).toMatchObject({
|
||||
error: {
|
||||
code: "ETIMEDOUT",
|
||||
message: expect.stringContaining("timed out after 500ms"),
|
||||
},
|
||||
ok: false,
|
||||
});
|
||||
await waitFor(() => !isProcessAlive(grandchildPid));
|
||||
} finally {
|
||||
await runPromise.catch(() => {});
|
||||
await runResult.catch(() => {});
|
||||
if (grandchildPid && isProcessAlive(grandchildPid)) {
|
||||
process.kill(grandchildPid, "SIGKILL");
|
||||
}
|
||||
|
||||
@@ -1602,12 +1602,13 @@ describe("grouped chat rendering", () => {
|
||||
},
|
||||
{ interval: 1, timeout: 100 },
|
||||
);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
const [fetchUrl, fetchInit] = requireFetchCall(fetchMock);
|
||||
expect(fetchUrl).toBe(
|
||||
"/api/chat/media/outgoing/agent%3Amain%3Amain/00000000-0000-4000-8000-000000000000/full",
|
||||
);
|
||||
expectSameOriginGet(fetchInit);
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
for (const [fetchUrl, fetchInit] of fetchMock.mock.calls as [string, RequestInit?][]) {
|
||||
expect(fetchUrl).toBe(
|
||||
"/api/chat/media/outgoing/agent%3Amain%3Amain/00000000-0000-4000-8000-000000000000/full",
|
||||
);
|
||||
expectSameOriginGet(fetchInit);
|
||||
}
|
||||
});
|
||||
|
||||
it("does not send auth to cross-origin managed-image-looking URLs", () => {
|
||||
|
||||
Reference in New Issue
Block a user