test: share codex app-server setup helpers

This commit is contained in:
Peter Steinberger
2026-04-20 16:53:34 +01:00
parent eb4a9f2a2a
commit d2e2d971b6
3 changed files with 62 additions and 74 deletions

View File

@@ -17,17 +17,9 @@ describe("bridgeCodexAppServerStartOptions", () => {
crypto.createHash("sha256").update(profileId).digest("hex").slice(0, 16),
);
beforeAll(async () => {
({ bridgeCodexAppServerStartOptions } = await import("./auth-bridge.js"));
});
afterEach(async () => {
await Promise.all(
tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })),
);
});
it("bridges canonical OpenClaw oauth into an isolated CODEX_HOME", async () => {
async function createAgentDirWithDefaultProfile(
profile: Record<string, unknown> = {},
): Promise<string> {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
tempDirs.push(agentDir);
saveAuthProfileStore(
@@ -40,14 +32,31 @@ describe("bridgeCodexAppServerStartOptions", () => {
access: "access-token",
refresh: "refresh-token",
expires: Date.now() + 60_000,
accountId: "acct-123",
idToken: "id-token",
...profile,
},
},
},
agentDir,
{ filterExternalAuthProfiles: false },
);
return agentDir;
}
beforeAll(async () => {
({ bridgeCodexAppServerStartOptions } = await import("./auth-bridge.js"));
});
afterEach(async () => {
await Promise.all(
tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })),
);
});
it("bridges canonical OpenClaw oauth into an isolated CODEX_HOME", async () => {
const agentDir = await createAgentDirWithDefaultProfile({
accountId: "acct-123",
idToken: "id-token",
});
const result = await bridgeCodexAppServerStartOptions({
startOptions: {
@@ -110,24 +119,7 @@ describe("bridgeCodexAppServerStartOptions", () => {
});
it("refuses to overwrite a symlinked auth bridge file", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
tempDirs.push(agentDir);
saveAuthProfileStore(
{
version: 1,
profiles: {
"openai-codex:default": {
type: "oauth",
provider: "openai-codex",
access: "access-token",
refresh: "refresh-token",
expires: Date.now() + 60_000,
},
},
},
agentDir,
{ filterExternalAuthProfiles: false },
);
const agentDir = await createAgentDirWithDefaultProfile();
const codexHome = resolveHashedCodexHome(agentDir, "openai-codex:default");
await fs.mkdir(codexHome, { recursive: true });

View File

@@ -9,6 +9,26 @@ import { writeCodexAppServerBinding } from "./session-binding.js";
let tempDir: string;
async function writeTestBinding(options: { authProfileId?: string } = {}): Promise<string> {
const sessionFile = path.join(tempDir, "session.jsonl");
await writeCodexAppServerBinding(sessionFile, {
threadId: "thread-1",
cwd: tempDir,
...options,
});
return sessionFile;
}
function startCompaction(sessionFile: string, options: { currentTokenCount?: number } = {}) {
return maybeCompactCodexAppServerSession({
sessionId: "session-1",
sessionKey: "agent:main:session-1",
sessionFile,
workspaceDir: tempDir,
...options,
});
}
describe("maybeCompactCodexAppServerSession", () => {
beforeEach(async () => {
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-compact-"));
@@ -22,19 +42,9 @@ describe("maybeCompactCodexAppServerSession", () => {
it("waits for native app-server compaction before reporting success", async () => {
const fake = createFakeCodexClient();
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
const sessionFile = path.join(tempDir, "session.jsonl");
await writeCodexAppServerBinding(sessionFile, {
threadId: "thread-1",
cwd: tempDir,
});
const sessionFile = await writeTestBinding();
const pendingResult = maybeCompactCodexAppServerSession({
sessionId: "session-1",
sessionKey: "agent:main:session-1",
sessionFile,
workspaceDir: tempDir,
currentTokenCount: 123,
});
const pendingResult = startCompaction(sessionFile, { currentTokenCount: 123 });
await vi.waitFor(() => {
expect(fake.request).toHaveBeenCalledWith("thread/compact/start", { threadId: "thread-1" });
});
@@ -70,18 +80,9 @@ describe("maybeCompactCodexAppServerSession", () => {
it("accepts native context-compaction item completion as success", async () => {
const fake = createFakeCodexClient();
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
const sessionFile = path.join(tempDir, "session.jsonl");
await writeCodexAppServerBinding(sessionFile, {
threadId: "thread-1",
cwd: tempDir,
});
const sessionFile = await writeTestBinding();
const pendingResult = maybeCompactCodexAppServerSession({
sessionId: "session-1",
sessionKey: "agent:main:session-1",
sessionFile,
workspaceDir: tempDir,
});
const pendingResult = startCompaction(sessionFile);
await vi.waitFor(() => {
expect(fake.request).toHaveBeenCalledWith("thread/compact/start", { threadId: "thread-1" });
});
@@ -113,19 +114,9 @@ describe("maybeCompactCodexAppServerSession", () => {
seenAuthProfileId = authProfileId;
return fake.client;
});
const sessionFile = path.join(tempDir, "session.jsonl");
await writeCodexAppServerBinding(sessionFile, {
threadId: "thread-1",
cwd: tempDir,
authProfileId: "openai-codex:work",
});
const sessionFile = await writeTestBinding({ authProfileId: "openai-codex:work" });
const pendingResult = maybeCompactCodexAppServerSession({
sessionId: "session-1",
sessionKey: "agent:main:session-1",
sessionFile,
workspaceDir: tempDir,
});
const pendingResult = startCompaction(sessionFile);
await vi.waitFor(() => {
expect(fake.request).toHaveBeenCalledWith("thread/compact/start", { threadId: "thread-1" });
});

View File

@@ -4,25 +4,30 @@ import { listCodexAppServerModels } from "./models.js";
import { resetSharedCodexAppServerClientForTests } from "./shared-client.js";
import { createClientHarness } from "./test-support.js";
const mocks = vi.hoisted(() => ({
bridgeCodexAppServerStartOptions: vi.fn(async ({ startOptions }) => startOptions),
resolveOpenClawAgentDir: vi.fn(() => "/tmp/openclaw-agent"),
}));
const mocks = vi.hoisted(() => {
const authBridge = {
startOptions: vi.fn(async ({ startOptions }) => startOptions),
};
const providerAuth = {
agentDir: vi.fn(() => "/tmp/openclaw-agent"),
};
return { authBridge, providerAuth };
});
vi.mock("./auth-bridge.js", () => ({
bridgeCodexAppServerStartOptions: mocks.bridgeCodexAppServerStartOptions,
bridgeCodexAppServerStartOptions: mocks.authBridge.startOptions,
}));
vi.mock("openclaw/plugin-sdk/provider-auth", () => ({
resolveOpenClawAgentDir: mocks.resolveOpenClawAgentDir,
resolveOpenClawAgentDir: mocks.providerAuth.agentDir,
}));
describe("listCodexAppServerModels", () => {
afterEach(() => {
resetSharedCodexAppServerClientForTests();
vi.restoreAllMocks();
mocks.bridgeCodexAppServerStartOptions.mockClear();
mocks.resolveOpenClawAgentDir.mockClear();
mocks.authBridge.startOptions.mockClear();
mocks.providerAuth.agentDir.mockClear();
});
it("lists app-server models through the typed helper", async () => {