refactor(test): share gateway onboarding state-dir lifecycle
This commit is contained in:
@@ -100,6 +100,21 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
||||
delete process.env.OPENCLAW_CONFIG_PATH;
|
||||
return stateDir;
|
||||
};
|
||||
const withStateDir = async (
|
||||
prefix: string,
|
||||
run: (stateDir: string) => Promise<void>,
|
||||
): Promise<void> => {
|
||||
const stateDir = await initStateDir(prefix);
|
||||
try {
|
||||
await run(stateDir);
|
||||
} finally {
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
}
|
||||
};
|
||||
const runOnboarding = async (options: Record<string, unknown>) => {
|
||||
const { runNonInteractiveOnboarding } = await import("./onboard-non-interactive.js");
|
||||
await runNonInteractiveOnboarding(options, runtime);
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
process.env.OPENCLAW_SKIP_CHANNELS = "1";
|
||||
@@ -131,13 +146,11 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
||||
});
|
||||
|
||||
it("writes gateway token auth into config and gateway enforces it", async () => {
|
||||
const stateDir = await initStateDir("state-noninteractive-");
|
||||
const token = "tok_test_123";
|
||||
const workspace = path.join(stateDir, "openclaw");
|
||||
await withStateDir("state-noninteractive-", async (stateDir) => {
|
||||
const token = "tok_test_123";
|
||||
const workspace = path.join(stateDir, "openclaw");
|
||||
|
||||
const { runNonInteractiveOnboarding } = await import("./onboard-non-interactive.js");
|
||||
await runNonInteractiveOnboarding(
|
||||
{
|
||||
await runOnboarding({
|
||||
nonInteractive: true,
|
||||
mode: "local",
|
||||
workspace,
|
||||
@@ -148,65 +161,57 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
||||
gatewayBind: "loopback",
|
||||
gatewayAuth: "token",
|
||||
gatewayToken: token,
|
||||
},
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
const { resolveConfigPath } = await import("../config/paths.js");
|
||||
const configPath = resolveConfigPath(process.env, stateDir);
|
||||
const cfg = JSON.parse(await fs.readFile(configPath, "utf8")) as {
|
||||
gateway?: { auth?: { mode?: string; token?: string } };
|
||||
agents?: { defaults?: { workspace?: string } };
|
||||
};
|
||||
const { resolveConfigPath } = await import("../config/paths.js");
|
||||
const configPath = resolveConfigPath(process.env, stateDir);
|
||||
const cfg = JSON.parse(await fs.readFile(configPath, "utf8")) as {
|
||||
gateway?: { auth?: { mode?: string; token?: string } };
|
||||
agents?: { defaults?: { workspace?: string } };
|
||||
};
|
||||
|
||||
expect(cfg?.agents?.defaults?.workspace).toBe(workspace);
|
||||
expect(cfg?.gateway?.auth?.mode).toBe("token");
|
||||
expect(cfg?.gateway?.auth?.token).toBe(token);
|
||||
expect(cfg?.agents?.defaults?.workspace).toBe(workspace);
|
||||
expect(cfg?.gateway?.auth?.mode).toBe("token");
|
||||
expect(cfg?.gateway?.auth?.token).toBe(token);
|
||||
|
||||
await expectGatewayTokenAuth({
|
||||
authConfig: cfg.gateway?.auth,
|
||||
token,
|
||||
env: process.env,
|
||||
await expectGatewayTokenAuth({
|
||||
authConfig: cfg.gateway?.auth,
|
||||
token,
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
}, 60_000);
|
||||
|
||||
it("writes gateway.remote url/token and callGateway uses them", async () => {
|
||||
const stateDir = await initStateDir("state-remote-");
|
||||
const port = await getFreePort();
|
||||
const token = "tok_remote_123";
|
||||
const { runNonInteractiveOnboarding } = await import("./onboard-non-interactive.js");
|
||||
await runNonInteractiveOnboarding(
|
||||
{
|
||||
await withStateDir("state-remote-", async () => {
|
||||
const port = await getFreePort();
|
||||
const token = "tok_remote_123";
|
||||
await runOnboarding({
|
||||
nonInteractive: true,
|
||||
mode: "remote",
|
||||
remoteUrl: `ws://127.0.0.1:${port}`,
|
||||
remoteToken: token,
|
||||
authChoice: "skip",
|
||||
json: true,
|
||||
},
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
const { resolveConfigPath } = await import("../config/config.js");
|
||||
const cfg = JSON.parse(await fs.readFile(resolveConfigPath(), "utf8")) as {
|
||||
gateway?: { mode?: string; remote?: { url?: string; token?: string } };
|
||||
};
|
||||
const { resolveConfigPath } = await import("../config/config.js");
|
||||
const cfg = JSON.parse(await fs.readFile(resolveConfigPath(), "utf8")) as {
|
||||
gateway?: { mode?: string; remote?: { url?: string; token?: string } };
|
||||
};
|
||||
|
||||
expect(cfg.gateway?.mode).toBe("remote");
|
||||
expect(cfg.gateway?.remote?.url).toBe(`ws://127.0.0.1:${port}`);
|
||||
expect(cfg.gateway?.remote?.token).toBe(token);
|
||||
expect(cfg.gateway?.mode).toBe("remote");
|
||||
expect(cfg.gateway?.remote?.url).toBe(`ws://127.0.0.1:${port}`);
|
||||
expect(cfg.gateway?.remote?.token).toBe(token);
|
||||
|
||||
gatewayClientCalls.length = 0;
|
||||
const { callGateway } = await import("../gateway/call.js");
|
||||
const health = await callGateway<{ ok?: boolean }>({ method: "health" });
|
||||
expect(health?.ok).toBe(true);
|
||||
const lastCall = gatewayClientCalls[gatewayClientCalls.length - 1];
|
||||
expect(lastCall?.url).toBe(`ws://127.0.0.1:${port}`);
|
||||
expect(lastCall?.token).toBe(token);
|
||||
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
gatewayClientCalls.length = 0;
|
||||
const { callGateway } = await import("../gateway/call.js");
|
||||
const health = await callGateway<{ ok?: boolean }>({ method: "health" });
|
||||
expect(health?.ok).toBe(true);
|
||||
const lastCall = gatewayClientCalls[gatewayClientCalls.length - 1];
|
||||
expect(lastCall?.url).toBe(`ws://127.0.0.1:${port}`);
|
||||
expect(lastCall?.token).toBe(token);
|
||||
});
|
||||
}, 60_000);
|
||||
|
||||
it("auto-generates token auth when binding LAN and persists the token", async () => {
|
||||
@@ -214,16 +219,14 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
||||
// Windows runner occasionally drops the temp config write in this flow; skip to keep CI green.
|
||||
return;
|
||||
}
|
||||
const stateDir = await initStateDir("state-lan-");
|
||||
process.env.OPENCLAW_STATE_DIR = stateDir;
|
||||
process.env.OPENCLAW_CONFIG_PATH = path.join(stateDir, "openclaw.json");
|
||||
await withStateDir("state-lan-", async (stateDir) => {
|
||||
process.env.OPENCLAW_STATE_DIR = stateDir;
|
||||
process.env.OPENCLAW_CONFIG_PATH = path.join(stateDir, "openclaw.json");
|
||||
|
||||
const port = await getFreeGatewayPort();
|
||||
const workspace = path.join(stateDir, "openclaw");
|
||||
const port = await getFreeGatewayPort();
|
||||
const workspace = path.join(stateDir, "openclaw");
|
||||
|
||||
const { runNonInteractiveOnboarding } = await import("./onboard-non-interactive.js");
|
||||
await runNonInteractiveOnboarding(
|
||||
{
|
||||
await runOnboarding({
|
||||
nonInteractive: true,
|
||||
mode: "local",
|
||||
workspace,
|
||||
@@ -233,32 +236,29 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
||||
installDaemon: false,
|
||||
gatewayPort: port,
|
||||
gatewayBind: "lan",
|
||||
},
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
const { resolveConfigPath } = await import("../config/paths.js");
|
||||
const configPath = resolveConfigPath(process.env, stateDir);
|
||||
const cfg = JSON.parse(await fs.readFile(configPath, "utf8")) as {
|
||||
gateway?: {
|
||||
bind?: string;
|
||||
port?: number;
|
||||
auth?: { mode?: string; token?: string };
|
||||
const { resolveConfigPath } = await import("../config/paths.js");
|
||||
const configPath = resolveConfigPath(process.env, stateDir);
|
||||
const cfg = JSON.parse(await fs.readFile(configPath, "utf8")) as {
|
||||
gateway?: {
|
||||
bind?: string;
|
||||
port?: number;
|
||||
auth?: { mode?: string; token?: string };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
expect(cfg.gateway?.bind).toBe("lan");
|
||||
expect(cfg.gateway?.port).toBe(port);
|
||||
expect(cfg.gateway?.auth?.mode).toBe("token");
|
||||
const token = cfg.gateway?.auth?.token ?? "";
|
||||
expect(token.length).toBeGreaterThan(8);
|
||||
expect(cfg.gateway?.bind).toBe("lan");
|
||||
expect(cfg.gateway?.port).toBe(port);
|
||||
expect(cfg.gateway?.auth?.mode).toBe("token");
|
||||
const token = cfg.gateway?.auth?.token ?? "";
|
||||
expect(token.length).toBeGreaterThan(8);
|
||||
|
||||
await expectGatewayTokenAuth({
|
||||
authConfig: cfg.gateway?.auth,
|
||||
token,
|
||||
env: process.env,
|
||||
await expectGatewayTokenAuth({
|
||||
authConfig: cfg.gateway?.auth,
|
||||
token,
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user