mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 00:33:31 +00:00
refactor(test): share auth test env/profile helpers
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
|
||||||
import path from "node:path";
|
|
||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
import { captureEnv } from "../test-utils/env.js";
|
import { captureEnv } from "../test-utils/env.js";
|
||||||
import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js";
|
import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js";
|
||||||
import { createExitThrowingRuntime, createWizardPrompter } from "./test-wizard-helpers.js";
|
import {
|
||||||
|
createExitThrowingRuntime,
|
||||||
const authProfilePathFor = (agentDir: string) => path.join(agentDir, "auth-profiles.json");
|
createWizardPrompter,
|
||||||
|
readAuthProfilesForAgent,
|
||||||
|
setupAuthTestEnv,
|
||||||
|
} from "./test-wizard-helpers.js";
|
||||||
|
|
||||||
function createHuggingfacePrompter(params: {
|
function createHuggingfacePrompter(params: {
|
||||||
text: WizardPrompter["text"];
|
text: WizardPrompter["text"];
|
||||||
@@ -25,9 +26,27 @@ function createHuggingfacePrompter(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("applyAuthChoiceHuggingface", () => {
|
describe("applyAuthChoiceHuggingface", () => {
|
||||||
const envSnapshot = captureEnv(["OPENCLAW_AGENT_DIR", "HF_TOKEN", "HUGGINGFACE_HUB_TOKEN"]);
|
const envSnapshot = captureEnv([
|
||||||
|
"OPENCLAW_STATE_DIR",
|
||||||
|
"OPENCLAW_AGENT_DIR",
|
||||||
|
"PI_CODING_AGENT_DIR",
|
||||||
|
"HF_TOKEN",
|
||||||
|
"HUGGINGFACE_HUB_TOKEN",
|
||||||
|
]);
|
||||||
let tempStateDir: string | null = null;
|
let tempStateDir: string | null = null;
|
||||||
|
|
||||||
|
async function setupTempState() {
|
||||||
|
const env = await setupAuthTestEnv("openclaw-hf-");
|
||||||
|
tempStateDir = env.stateDir;
|
||||||
|
return env.agentDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readAuthProfiles(agentDir: string) {
|
||||||
|
return await readAuthProfilesForAgent<{
|
||||||
|
profiles?: Record<string, { key?: string }>;
|
||||||
|
}>(agentDir);
|
||||||
|
}
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
if (tempStateDir) {
|
if (tempStateDir) {
|
||||||
await fs.rm(tempStateDir, { recursive: true, force: true });
|
await fs.rm(tempStateDir, { recursive: true, force: true });
|
||||||
@@ -41,17 +60,14 @@ describe("applyAuthChoiceHuggingface", () => {
|
|||||||
authChoice: "openrouter-api-key",
|
authChoice: "openrouter-api-key",
|
||||||
config: {},
|
config: {},
|
||||||
prompter: {} as WizardPrompter,
|
prompter: {} as WizardPrompter,
|
||||||
runtime: {} as RuntimeEnv,
|
runtime: createExitThrowingRuntime(),
|
||||||
setDefaultModel: false,
|
setDefaultModel: false,
|
||||||
});
|
});
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prompts for key and model, then writes config and auth profile", async () => {
|
it("prompts for key and model, then writes config and auth profile", async () => {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hf-"));
|
const agentDir = await setupTempState();
|
||||||
const agentDir = path.join(tempStateDir, "agent");
|
|
||||||
process.env.OPENCLAW_AGENT_DIR = agentDir;
|
|
||||||
await fs.mkdir(agentDir, { recursive: true });
|
|
||||||
|
|
||||||
const text = vi.fn().mockResolvedValue("hf-test-token");
|
const text = vi.fn().mockResolvedValue("hf-test-token");
|
||||||
const select: WizardPrompter["select"] = vi.fn(
|
const select: WizardPrompter["select"] = vi.fn(
|
||||||
@@ -81,21 +97,14 @@ describe("applyAuthChoiceHuggingface", () => {
|
|||||||
expect.objectContaining({ message: "Default Hugging Face model" }),
|
expect.objectContaining({ message: "Default Hugging Face model" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const authProfilePath = authProfilePathFor(agentDir);
|
const parsed = await readAuthProfiles(agentDir);
|
||||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
|
||||||
const parsed = JSON.parse(raw) as {
|
|
||||||
profiles?: Record<string, { key?: string }>;
|
|
||||||
};
|
|
||||||
expect(parsed.profiles?.["huggingface:default"]?.key).toBe("hf-test-token");
|
expect(parsed.profiles?.["huggingface:default"]?.key).toBe("hf-test-token");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not prompt to reuse env token when opts.token already provided", async () => {
|
it("does not prompt to reuse env token when opts.token already provided", async () => {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hf-"));
|
const agentDir = await setupTempState();
|
||||||
const agentDir = path.join(tempStateDir, "agent");
|
|
||||||
process.env.OPENCLAW_AGENT_DIR = agentDir;
|
|
||||||
process.env.HF_TOKEN = "hf-env-token";
|
process.env.HF_TOKEN = "hf-env-token";
|
||||||
delete process.env.HUGGINGFACE_HUB_TOKEN;
|
delete process.env.HUGGINGFACE_HUB_TOKEN;
|
||||||
await fs.mkdir(agentDir, { recursive: true });
|
|
||||||
|
|
||||||
const text = vi.fn().mockResolvedValue("hf-text-token");
|
const text = vi.fn().mockResolvedValue("hf-text-token");
|
||||||
const select: WizardPrompter["select"] = vi.fn(
|
const select: WizardPrompter["select"] = vi.fn(
|
||||||
@@ -121,11 +130,7 @@ describe("applyAuthChoiceHuggingface", () => {
|
|||||||
expect(confirm).not.toHaveBeenCalled();
|
expect(confirm).not.toHaveBeenCalled();
|
||||||
expect(text).not.toHaveBeenCalled();
|
expect(text).not.toHaveBeenCalled();
|
||||||
|
|
||||||
const authProfilePath = authProfilePathFor(agentDir);
|
const parsed = await readAuthProfiles(agentDir);
|
||||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
|
||||||
const parsed = JSON.parse(raw) as {
|
|
||||||
profiles?: Record<string, { key?: string }>;
|
|
||||||
};
|
|
||||||
expect(parsed.profiles?.["huggingface:default"]?.key).toBe("hf-opts-token");
|
expect(parsed.profiles?.["huggingface:default"]?.key).toBe("hf-opts-token");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
|
||||||
import path from "node:path";
|
|
||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
import { captureEnv } from "../test-utils/env.js";
|
import { captureEnv } from "../test-utils/env.js";
|
||||||
import { applyAuthChoice } from "./auth-choice.js";
|
import { applyAuthChoice } from "./auth-choice.js";
|
||||||
import { createExitThrowingRuntime, createWizardPrompter } from "./test-wizard-helpers.js";
|
import {
|
||||||
|
createExitThrowingRuntime,
|
||||||
|
createWizardPrompter,
|
||||||
|
readAuthProfilesForAgent,
|
||||||
|
setupAuthTestEnv,
|
||||||
|
} from "./test-wizard-helpers.js";
|
||||||
|
|
||||||
const authProfilePathFor = (agentDir: string) => path.join(agentDir, "auth-profiles.json");
|
|
||||||
const requireAgentDir = () => {
|
const requireAgentDir = () => {
|
||||||
const agentDir = process.env.OPENCLAW_AGENT_DIR;
|
const agentDir = process.env.OPENCLAW_AGENT_DIR;
|
||||||
if (!agentDir) {
|
if (!agentDir) {
|
||||||
@@ -30,13 +32,17 @@ describe("applyAuthChoice (moonshot)", () => {
|
|||||||
let tempStateDir: string | null = null;
|
let tempStateDir: string | null = null;
|
||||||
|
|
||||||
async function setupTempState() {
|
async function setupTempState() {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
const env = await setupAuthTestEnv("openclaw-auth-");
|
||||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
tempStateDir = env.stateDir;
|
||||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
|
||||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
|
||||||
delete process.env.MOONSHOT_API_KEY;
|
delete process.env.MOONSHOT_API_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function readAuthProfiles() {
|
||||||
|
return await readAuthProfilesForAgent<{
|
||||||
|
profiles?: Record<string, { key?: string }>;
|
||||||
|
}>(requireAgentDir());
|
||||||
|
}
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
if (tempStateDir) {
|
if (tempStateDir) {
|
||||||
await fs.rm(tempStateDir, { recursive: true, force: true });
|
await fs.rm(tempStateDir, { recursive: true, force: true });
|
||||||
@@ -73,11 +79,7 @@ describe("applyAuthChoice (moonshot)", () => {
|
|||||||
expect(result.config.models?.providers?.moonshot?.baseUrl).toBe("https://api.moonshot.cn/v1");
|
expect(result.config.models?.providers?.moonshot?.baseUrl).toBe("https://api.moonshot.cn/v1");
|
||||||
expect(result.agentModelOverride).toBe("moonshot/kimi-k2.5");
|
expect(result.agentModelOverride).toBe("moonshot/kimi-k2.5");
|
||||||
|
|
||||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
const parsed = await readAuthProfiles();
|
||||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
|
||||||
const parsed = JSON.parse(raw) as {
|
|
||||||
profiles?: Record<string, { key?: string }>;
|
|
||||||
};
|
|
||||||
expect(parsed.profiles?.["moonshot:default"]?.key).toBe("sk-moonshot-cn-test");
|
expect(parsed.profiles?.["moonshot:default"]?.key).toBe("sk-moonshot-cn-test");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -100,11 +102,7 @@ describe("applyAuthChoice (moonshot)", () => {
|
|||||||
expect(result.config.models?.providers?.moonshot?.baseUrl).toBe("https://api.moonshot.cn/v1");
|
expect(result.config.models?.providers?.moonshot?.baseUrl).toBe("https://api.moonshot.cn/v1");
|
||||||
expect(result.agentModelOverride).toBeUndefined();
|
expect(result.agentModelOverride).toBeUndefined();
|
||||||
|
|
||||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
const parsed = await readAuthProfiles();
|
||||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
|
||||||
const parsed = JSON.parse(raw) as {
|
|
||||||
profiles?: Record<string, { key?: string }>;
|
|
||||||
};
|
|
||||||
expect(parsed.profiles?.["moonshot:default"]?.key).toBe("sk-moonshot-cn-test");
|
expect(parsed.profiles?.["moonshot:default"]?.key).toBe("sk-moonshot-cn-test");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { OAuthCredentials } from "@mariozechner/pi-ai";
|
import type { OAuthCredentials } from "@mariozechner/pi-ai";
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { afterEach, describe, expect, it } from "vitest";
|
import { afterEach, describe, expect, it } from "vitest";
|
||||||
import { captureEnv } from "../test-utils/env.js";
|
import { captureEnv } from "../test-utils/env.js";
|
||||||
@@ -30,15 +29,7 @@ import {
|
|||||||
ZAI_CODING_CN_BASE_URL,
|
ZAI_CODING_CN_BASE_URL,
|
||||||
ZAI_GLOBAL_BASE_URL,
|
ZAI_GLOBAL_BASE_URL,
|
||||||
} from "./onboard-auth.js";
|
} from "./onboard-auth.js";
|
||||||
|
import { readAuthProfilesForAgent, setupAuthTestEnv } from "./test-wizard-helpers.js";
|
||||||
const authProfilePathFor = (agentDir: string) => path.join(agentDir, "auth-profiles.json");
|
|
||||||
const requireAgentDir = () => {
|
|
||||||
const agentDir = process.env.OPENCLAW_AGENT_DIR;
|
|
||||||
if (!agentDir) {
|
|
||||||
throw new Error("OPENCLAW_AGENT_DIR not set");
|
|
||||||
}
|
|
||||||
return agentDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
function createLegacyProviderConfig(params: {
|
function createLegacyProviderConfig(params: {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
@@ -88,10 +79,8 @@ describe("writeOAuthCredentials", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("writes auth-profiles.json under OPENCLAW_AGENT_DIR when set", async () => {
|
it("writes auth-profiles.json under OPENCLAW_AGENT_DIR when set", async () => {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-"));
|
const env = await setupAuthTestEnv("openclaw-oauth-");
|
||||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
tempStateDir = env.stateDir;
|
||||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
|
||||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
|
||||||
|
|
||||||
const creds = {
|
const creds = {
|
||||||
refresh: "refresh-token",
|
refresh: "refresh-token",
|
||||||
@@ -101,11 +90,9 @@ describe("writeOAuthCredentials", () => {
|
|||||||
|
|
||||||
await writeOAuthCredentials("openai-codex", creds);
|
await writeOAuthCredentials("openai-codex", creds);
|
||||||
|
|
||||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
const parsed = await readAuthProfilesForAgent<{
|
||||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
|
||||||
const parsed = JSON.parse(raw) as {
|
|
||||||
profiles?: Record<string, OAuthCredentials & { type?: string }>;
|
profiles?: Record<string, OAuthCredentials & { type?: string }>;
|
||||||
};
|
}>(env.agentDir);
|
||||||
expect(parsed.profiles?.["openai-codex:default"]).toMatchObject({
|
expect(parsed.profiles?.["openai-codex:default"]).toMatchObject({
|
||||||
refresh: "refresh-token",
|
refresh: "refresh-token",
|
||||||
access: "access-token",
|
access: "access-token",
|
||||||
@@ -135,18 +122,14 @@ describe("setMinimaxApiKey", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("writes to OPENCLAW_AGENT_DIR when set", async () => {
|
it("writes to OPENCLAW_AGENT_DIR when set", async () => {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-minimax-"));
|
const env = await setupAuthTestEnv("openclaw-minimax-", { agentSubdir: "custom-agent" });
|
||||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
tempStateDir = env.stateDir;
|
||||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "custom-agent");
|
|
||||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
|
||||||
|
|
||||||
await setMinimaxApiKey("sk-minimax-test");
|
await setMinimaxApiKey("sk-minimax-test");
|
||||||
|
|
||||||
const customAuthPath = authProfilePathFor(requireAgentDir());
|
const parsed = await readAuthProfilesForAgent<{
|
||||||
const raw = await fs.readFile(customAuthPath, "utf8");
|
|
||||||
const parsed = JSON.parse(raw) as {
|
|
||||||
profiles?: Record<string, { type?: string; provider?: string; key?: string }>;
|
profiles?: Record<string, { type?: string; provider?: string; key?: string }>;
|
||||||
};
|
}>(env.agentDir);
|
||||||
expect(parsed.profiles?.["minimax:default"]).toMatchObject({
|
expect(parsed.profiles?.["minimax:default"]).toMatchObject({
|
||||||
type: "api_key",
|
type: "api_key",
|
||||||
provider: "minimax",
|
provider: "minimax",
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import fs from "node:fs/promises";
|
||||||
|
import path from "node:path";
|
||||||
import { vi } from "vitest";
|
import { vi } from "vitest";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
|
import { makeTempWorkspace } from "../test-helpers/workspace.js";
|
||||||
|
|
||||||
export const noopAsync = async () => {};
|
export const noopAsync = async () => {};
|
||||||
export const noop = () => {};
|
export const noop = () => {};
|
||||||
@@ -31,3 +34,24 @@ export function createWizardPrompter(
|
|||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function setupAuthTestEnv(
|
||||||
|
prefix = "openclaw-auth-",
|
||||||
|
options?: { agentSubdir?: string },
|
||||||
|
): Promise<{
|
||||||
|
stateDir: string;
|
||||||
|
agentDir: string;
|
||||||
|
}> {
|
||||||
|
const stateDir = await makeTempWorkspace(prefix);
|
||||||
|
const agentDir = path.join(stateDir, options?.agentSubdir ?? "agent");
|
||||||
|
process.env.OPENCLAW_STATE_DIR = stateDir;
|
||||||
|
process.env.OPENCLAW_AGENT_DIR = agentDir;
|
||||||
|
process.env.PI_CODING_AGENT_DIR = agentDir;
|
||||||
|
await fs.mkdir(agentDir, { recursive: true });
|
||||||
|
return { stateDir, agentDir };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function readAuthProfilesForAgent<T>(agentDir: string): Promise<T> {
|
||||||
|
const raw = await fs.readFile(path.join(agentDir, "auth-profiles.json"), "utf8");
|
||||||
|
return JSON.parse(raw) as T;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user