mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-29 16:54:30 +00:00
test: snapshot ci timeout investigation
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { clearRuntimeAuthProfileStoreSnapshots } from "../agents/auth-profiles.js";
|
||||
import { NON_ENV_SECRETREF_MARKER } from "../agents/model-auth-markers.js";
|
||||
import { clearConfigCache, type OpenClawConfig } from "../config/config.js";
|
||||
|
||||
const resolveProviderUsageAuthWithPluginMock = vi.fn(async (..._args: unknown[]) => null);
|
||||
|
||||
@@ -10,6 +12,12 @@ vi.mock("../plugins/provider-runtime.js", () => ({
|
||||
resolveProviderUsageAuthWithPlugin: resolveProviderUsageAuthWithPluginMock,
|
||||
}));
|
||||
|
||||
vi.mock("../agents/cli-credentials.js", () => ({
|
||||
readCodexCliCredentialsCached: () => null,
|
||||
readMiniMaxCliCredentialsCached: () => null,
|
||||
readQwenCliCredentialsCached: () => null,
|
||||
}));
|
||||
|
||||
let resolveProviderAuths: typeof import("./provider-usage.auth.js").resolveProviderAuths;
|
||||
type ProviderAuth = import("./provider-usage.auth.js").ProviderAuth;
|
||||
|
||||
@@ -36,65 +44,59 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
clearConfigCache();
|
||||
clearRuntimeAuthProfileStoreSnapshots();
|
||||
resolveProviderUsageAuthWithPluginMock.mockReset();
|
||||
resolveProviderUsageAuthWithPluginMock.mockResolvedValue(null);
|
||||
});
|
||||
|
||||
async function withSuiteHome<T>(
|
||||
fn: (home: string) => Promise<T>,
|
||||
env: Record<string, string | undefined>,
|
||||
): Promise<T> {
|
||||
afterEach(() => {
|
||||
clearConfigCache();
|
||||
clearRuntimeAuthProfileStoreSnapshots();
|
||||
});
|
||||
|
||||
async function withSuiteHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
const base = path.join(suiteRoot, `case-${++suiteCase}`);
|
||||
await fs.mkdir(base, { recursive: true });
|
||||
await fs.mkdir(path.join(base, ".openclaw", "agents", "main", "sessions"), { recursive: true });
|
||||
return await fn(base);
|
||||
}
|
||||
|
||||
const keysToRestore = new Set<string>([
|
||||
"HOME",
|
||||
"USERPROFILE",
|
||||
"HOMEDRIVE",
|
||||
"HOMEPATH",
|
||||
"OPENCLAW_HOME",
|
||||
"OPENCLAW_STATE_DIR",
|
||||
...Object.keys(env),
|
||||
]);
|
||||
const snapshot: Record<string, string | undefined> = {};
|
||||
for (const key of keysToRestore) {
|
||||
snapshot[key] = process.env[key];
|
||||
}
|
||||
function agentDirForHome(home: string): string {
|
||||
return path.join(home, ".openclaw", "agents", "main", "agent");
|
||||
}
|
||||
|
||||
process.env.HOME = base;
|
||||
process.env.USERPROFILE = base;
|
||||
if (process.platform === "win32") {
|
||||
const match = base.match(/^([A-Za-z]:)(.*)$/);
|
||||
if (match) {
|
||||
process.env.HOMEDRIVE = match[1];
|
||||
process.env.HOMEPATH = match[2] || "\\";
|
||||
}
|
||||
}
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
process.env.OPENCLAW_STATE_DIR = path.join(base, ".openclaw");
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
function buildSuiteEnv(
|
||||
home: string,
|
||||
env: Record<string, string | undefined> = {},
|
||||
): NodeJS.ProcessEnv {
|
||||
const suiteEnv: NodeJS.ProcessEnv = {
|
||||
...EMPTY_PROVIDER_ENV,
|
||||
HOME: home,
|
||||
USERPROFILE: home,
|
||||
OPENCLAW_STATE_DIR: path.join(home, ".openclaw"),
|
||||
...env,
|
||||
};
|
||||
const match = home.match(/^([A-Za-z]:)(.*)$/);
|
||||
if (match) {
|
||||
suiteEnv.HOMEDRIVE = match[1];
|
||||
suiteEnv.HOMEPATH = match[2] || "\\";
|
||||
}
|
||||
return suiteEnv;
|
||||
}
|
||||
|
||||
async function readConfigForHome(home: string): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
return await fn(base);
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(snapshot)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
return JSON.parse(
|
||||
await fs.readFile(path.join(home, ".openclaw", "openclaw.json"), "utf8"),
|
||||
) as Record<string, unknown>;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async function writeAuthProfiles(home: string, profiles: Record<string, unknown>) {
|
||||
const agentDir = path.join(home, ".openclaw", "agents", "main", "agent");
|
||||
const agentDir = agentDirForHome(home);
|
||||
await fs.mkdir(agentDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(agentDir, "auth-profiles.json"),
|
||||
@@ -114,7 +116,7 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
}
|
||||
|
||||
async function writeProfileOrder(home: string, provider: string, profileIds: string[]) {
|
||||
const agentDir = path.join(home, ".openclaw", "agents", "main", "agent");
|
||||
const agentDir = agentDirForHome(home);
|
||||
const parsed = JSON.parse(
|
||||
await fs.readFile(path.join(agentDir, "auth-profiles.json"), "utf8"),
|
||||
) as Record<string, unknown>;
|
||||
@@ -149,28 +151,26 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
}
|
||||
|
||||
async function resolveMinimaxAuthFromConfiguredKey(apiKey: string) {
|
||||
return await withSuiteHome(
|
||||
async (home) => {
|
||||
await writeConfig(home, {
|
||||
models: {
|
||||
providers: {
|
||||
minimax: {
|
||||
baseUrl: "https://api.minimaxi.com",
|
||||
models: [createTestModelDefinition()],
|
||||
apiKey,
|
||||
},
|
||||
return await withSuiteHome(async (home) => {
|
||||
await writeConfig(home, {
|
||||
models: {
|
||||
providers: {
|
||||
minimax: {
|
||||
baseUrl: "https://api.minimaxi.com",
|
||||
models: [createTestModelDefinition()],
|
||||
apiKey,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return await resolveProviderAuths({
|
||||
providers: ["minimax"],
|
||||
});
|
||||
},
|
||||
{
|
||||
...EMPTY_PROVIDER_ENV,
|
||||
},
|
||||
);
|
||||
return await resolveProviderAuths({
|
||||
providers: ["minimax"],
|
||||
agentDir: agentDirForHome(home),
|
||||
config: (await readConfigForHome(home)) as OpenClawConfig,
|
||||
env: buildSuiteEnv(home),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function expectResolvedAuthsFromSuiteHome(params: {
|
||||
@@ -179,19 +179,16 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
env?: Record<string, string | undefined>;
|
||||
setup?: (home: string) => Promise<void>;
|
||||
}) {
|
||||
await withSuiteHome(
|
||||
async (home) => {
|
||||
await params.setup?.(home);
|
||||
const auths = await resolveProviderAuths({
|
||||
providers: params.providers,
|
||||
});
|
||||
expect(auths).toEqual(params.expected);
|
||||
},
|
||||
{
|
||||
...EMPTY_PROVIDER_ENV,
|
||||
...params.env,
|
||||
},
|
||||
);
|
||||
await withSuiteHome(async (home) => {
|
||||
await params.setup?.(home);
|
||||
const auths = await resolveProviderAuths({
|
||||
providers: params.providers,
|
||||
agentDir: agentDirForHome(home),
|
||||
config: (await readConfigForHome(home)) as OpenClawConfig,
|
||||
env: buildSuiteEnv(home, params.env),
|
||||
});
|
||||
expect(auths).toEqual(params.expected);
|
||||
});
|
||||
}
|
||||
|
||||
it.each([
|
||||
@@ -401,18 +398,24 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
|
||||
const auths = await resolveProviderAuths({
|
||||
providers: ["anthropic"],
|
||||
agentDir: agentDirForHome(home),
|
||||
config: (await readConfigForHome(home)) as OpenClawConfig,
|
||||
env: buildSuiteEnv(home),
|
||||
});
|
||||
expect(auths).toEqual([]);
|
||||
}, {});
|
||||
});
|
||||
});
|
||||
|
||||
it("skips providers without oauth-compatible profiles", async () => {
|
||||
await withSuiteHome(async () => {
|
||||
await withSuiteHome(async (home) => {
|
||||
const auths = await resolveProviderAuths({
|
||||
providers: ["anthropic"],
|
||||
agentDir: agentDirForHome(home),
|
||||
config: (await readConfigForHome(home)) as OpenClawConfig,
|
||||
env: buildSuiteEnv(home),
|
||||
});
|
||||
expect(auths).toEqual([]);
|
||||
}, {});
|
||||
});
|
||||
});
|
||||
|
||||
it("skips oauth profiles that resolve without an api key and uses later profiles", async () => {
|
||||
@@ -430,9 +433,12 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
|
||||
const auths = await resolveProviderAuths({
|
||||
providers: ["anthropic"],
|
||||
agentDir: agentDirForHome(home),
|
||||
config: (await readConfigForHome(home)) as OpenClawConfig,
|
||||
env: buildSuiteEnv(home),
|
||||
});
|
||||
expect(auths).toEqual([{ provider: "anthropic", token: "anthropic-token" }]);
|
||||
}, {});
|
||||
});
|
||||
});
|
||||
|
||||
it("skips api_key entries in oauth token resolution order", async () => {
|
||||
@@ -445,9 +451,12 @@ describe("resolveProviderAuths key normalization", () => {
|
||||
|
||||
const auths = await resolveProviderAuths({
|
||||
providers: ["anthropic"],
|
||||
agentDir: agentDirForHome(home),
|
||||
config: (await readConfigForHome(home)) as OpenClawConfig,
|
||||
env: buildSuiteEnv(home),
|
||||
});
|
||||
expect(auths).toEqual([{ provider: "anthropic", token: "token-1" }]);
|
||||
}, {});
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores marker-backed config keys for provider usage auth resolution", async () => {
|
||||
|
||||
@@ -66,8 +66,16 @@ describe("memory search async sync", () => {
|
||||
const cfg = buildConfig();
|
||||
manager = await createMemoryManagerOrThrow(cfg);
|
||||
|
||||
const pending = new Promise<void>(() => {});
|
||||
const syncMock = vi.fn(async () => pending);
|
||||
let releaseSync = () => {};
|
||||
const pending = new Promise<void>((resolve) => {
|
||||
releaseSync = () => resolve();
|
||||
}).finally(() => {
|
||||
(manager as unknown as { syncing: Promise<void> | null }).syncing = null;
|
||||
});
|
||||
const syncMock = vi.fn(async () => {
|
||||
(manager as unknown as { syncing: Promise<void> | null }).syncing = pending;
|
||||
return pending;
|
||||
});
|
||||
(manager as unknown as { sync: () => Promise<void> }).sync = syncMock;
|
||||
|
||||
const activeManager = manager;
|
||||
@@ -76,6 +84,10 @@ describe("memory search async sync", () => {
|
||||
}
|
||||
await activeManager.search("hello");
|
||||
expect(syncMock).toHaveBeenCalledTimes(1);
|
||||
releaseSync();
|
||||
await vi.waitFor(() => {
|
||||
expect((manager as unknown as { syncing: Promise<void> | null }).syncing).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("waits for in-flight search sync during close", async () => {
|
||||
|
||||
Reference in New Issue
Block a user