mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 12:41:23 +00:00
refactor(test): share sessions_spawn e2e harness
This commit is contained in:
@@ -1,62 +1,18 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
import { createOpenClawTools } from "./openclaw-tools.js";
|
import { createOpenClawTools } from "./openclaw-tools.js";
|
||||||
import "./test-helpers/fast-core-tools.js";
|
import "./test-helpers/fast-core-tools.js";
|
||||||
|
import {
|
||||||
|
getCallGatewayMock,
|
||||||
|
resetSessionsSpawnConfigOverride,
|
||||||
|
setSessionsSpawnConfigOverride,
|
||||||
|
} from "./openclaw-tools.subagents.sessions-spawn.test-harness.js";
|
||||||
import { resetSubagentRegistryForTests } from "./subagent-registry.js";
|
import { resetSubagentRegistryForTests } from "./subagent-registry.js";
|
||||||
|
|
||||||
type SessionsSpawnTestConfig = ReturnType<(typeof import("../config/config.js"))["loadConfig"]>;
|
const callGatewayMock = getCallGatewayMock();
|
||||||
|
|
||||||
const hoisted = vi.hoisted(() => {
|
|
||||||
const callGatewayMock = vi.fn();
|
|
||||||
const defaultConfigOverride = {
|
|
||||||
session: {
|
|
||||||
mainKey: "main",
|
|
||||||
scope: "per-sender",
|
|
||||||
},
|
|
||||||
} as SessionsSpawnTestConfig;
|
|
||||||
const state = { configOverride: defaultConfigOverride };
|
|
||||||
return { callGatewayMock, defaultConfigOverride, state };
|
|
||||||
});
|
|
||||||
|
|
||||||
const callGatewayMock = hoisted.callGatewayMock;
|
|
||||||
|
|
||||||
function resetConfigOverride() {
|
|
||||||
hoisted.state.configOverride = hoisted.defaultConfigOverride;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setConfigOverride(next: SessionsSpawnTestConfig) {
|
|
||||||
hoisted.state.configOverride = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi.mock("../gateway/call.js", () => ({
|
|
||||||
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
|
||||||
}));
|
|
||||||
// Some tools import callGateway via "../../gateway/call.js" (from nested folders). Mock that too.
|
|
||||||
vi.mock("../../gateway/call.js", () => ({
|
|
||||||
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig: () => hoisted.state.configOverride,
|
|
||||||
resolveGatewayPort: () => 18789,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Same module, different specifier (used by tools under src/agents/tools/*).
|
|
||||||
vi.mock("../../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig: () => hoisted.state.configOverride,
|
|
||||||
resolveGatewayPort: () => 18789,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("openclaw-tools: subagents (sessions_spawn allowlist)", () => {
|
describe("openclaw-tools: subagents (sessions_spawn allowlist)", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetConfigOverride();
|
resetSessionsSpawnConfigOverride();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sessions_spawn only allows same-agent by default", async () => {
|
it("sessions_spawn only allows same-agent by default", async () => {
|
||||||
@@ -84,7 +40,7 @@ describe("openclaw-tools: subagents (sessions_spawn allowlist)", () => {
|
|||||||
it("sessions_spawn forbids cross-agent spawning when not allowed", async () => {
|
it("sessions_spawn forbids cross-agent spawning when not allowed", async () => {
|
||||||
resetSubagentRegistryForTests();
|
resetSubagentRegistryForTests();
|
||||||
callGatewayMock.mockReset();
|
callGatewayMock.mockReset();
|
||||||
setConfigOverride({
|
setSessionsSpawnConfigOverride({
|
||||||
session: {
|
session: {
|
||||||
mainKey: "main",
|
mainKey: "main",
|
||||||
scope: "per-sender",
|
scope: "per-sender",
|
||||||
|
|||||||
@@ -1,60 +1,19 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
import { emitAgentEvent } from "../infra/agent-events.js";
|
import { emitAgentEvent } from "../infra/agent-events.js";
|
||||||
import { sleep } from "../utils.js";
|
import { sleep } from "../utils.js";
|
||||||
import { createOpenClawTools } from "./openclaw-tools.js";
|
import { createOpenClawTools } from "./openclaw-tools.js";
|
||||||
import "./test-helpers/fast-core-tools.js";
|
import "./test-helpers/fast-core-tools.js";
|
||||||
|
import {
|
||||||
|
getCallGatewayMock,
|
||||||
|
resetSessionsSpawnConfigOverride,
|
||||||
|
} from "./openclaw-tools.subagents.sessions-spawn.test-harness.js";
|
||||||
import { resetSubagentRegistryForTests } from "./subagent-registry.js";
|
import { resetSubagentRegistryForTests } from "./subagent-registry.js";
|
||||||
|
|
||||||
type SessionsSpawnTestConfig = ReturnType<(typeof import("../config/config.js"))["loadConfig"]>;
|
const callGatewayMock = getCallGatewayMock();
|
||||||
|
|
||||||
const hoisted = vi.hoisted(() => {
|
|
||||||
const callGatewayMock = vi.fn();
|
|
||||||
const defaultConfigOverride = {
|
|
||||||
session: {
|
|
||||||
mainKey: "main",
|
|
||||||
scope: "per-sender",
|
|
||||||
},
|
|
||||||
} as SessionsSpawnTestConfig;
|
|
||||||
const state = { configOverride: defaultConfigOverride };
|
|
||||||
return { callGatewayMock, defaultConfigOverride, state };
|
|
||||||
});
|
|
||||||
|
|
||||||
const callGatewayMock = hoisted.callGatewayMock;
|
|
||||||
|
|
||||||
function resetConfigOverride() {
|
|
||||||
hoisted.state.configOverride = hoisted.defaultConfigOverride;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi.mock("../gateway/call.js", () => ({
|
|
||||||
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
|
||||||
}));
|
|
||||||
// Some tools import callGateway via "../../gateway/call.js" (from nested folders). Mock that too.
|
|
||||||
vi.mock("../../gateway/call.js", () => ({
|
|
||||||
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig: () => hoisted.state.configOverride,
|
|
||||||
resolveGatewayPort: () => 18789,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Same module, different specifier (used by tools under src/agents/tools/*).
|
|
||||||
vi.mock("../../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig: () => hoisted.state.configOverride,
|
|
||||||
resolveGatewayPort: () => 18789,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetConfigOverride();
|
resetSessionsSpawnConfigOverride();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sessions_spawn runs cleanup flow after subagent completion", async () => {
|
it("sessions_spawn runs cleanup flow after subagent completion", async () => {
|
||||||
|
|||||||
@@ -1,63 +1,19 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
|
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
|
||||||
import "./test-helpers/fast-core-tools.js";
|
import "./test-helpers/fast-core-tools.js";
|
||||||
import { createOpenClawTools } from "./openclaw-tools.js";
|
import { createOpenClawTools } from "./openclaw-tools.js";
|
||||||
|
import {
|
||||||
|
getCallGatewayMock,
|
||||||
|
resetSessionsSpawnConfigOverride,
|
||||||
|
setSessionsSpawnConfigOverride,
|
||||||
|
} from "./openclaw-tools.subagents.sessions-spawn.test-harness.js";
|
||||||
import { resetSubagentRegistryForTests } from "./subagent-registry.js";
|
import { resetSubagentRegistryForTests } from "./subagent-registry.js";
|
||||||
|
|
||||||
type SessionsSpawnTestConfig = ReturnType<(typeof import("../config/config.js"))["loadConfig"]>;
|
const callGatewayMock = getCallGatewayMock();
|
||||||
|
|
||||||
const hoisted = vi.hoisted(() => {
|
|
||||||
const callGatewayMock = vi.fn();
|
|
||||||
const defaultConfigOverride = {
|
|
||||||
session: {
|
|
||||||
mainKey: "main",
|
|
||||||
scope: "per-sender",
|
|
||||||
},
|
|
||||||
} as SessionsSpawnTestConfig;
|
|
||||||
const state = { configOverride: defaultConfigOverride };
|
|
||||||
return { callGatewayMock, defaultConfigOverride, state };
|
|
||||||
});
|
|
||||||
|
|
||||||
const callGatewayMock = hoisted.callGatewayMock;
|
|
||||||
|
|
||||||
function resetConfigOverride() {
|
|
||||||
hoisted.state.configOverride = hoisted.defaultConfigOverride;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setConfigOverride(next: SessionsSpawnTestConfig) {
|
|
||||||
hoisted.state.configOverride = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi.mock("../gateway/call.js", () => ({
|
|
||||||
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
|
||||||
}));
|
|
||||||
// Some tools import callGateway via "../../gateway/call.js" (from nested folders). Mock that too.
|
|
||||||
vi.mock("../../gateway/call.js", () => ({
|
|
||||||
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig: () => hoisted.state.configOverride,
|
|
||||||
resolveGatewayPort: () => 18789,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Same module, different specifier (used by tools under src/agents/tools/*).
|
|
||||||
vi.mock("../../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig: () => hoisted.state.configOverride,
|
|
||||||
resolveGatewayPort: () => 18789,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => {
|
describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetConfigOverride();
|
resetSessionsSpawnConfigOverride();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sessions_spawn applies a model to the child session", async () => {
|
it("sessions_spawn applies a model to the child session", async () => {
|
||||||
@@ -192,7 +148,7 @@ describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => {
|
|||||||
it("sessions_spawn applies default subagent model from defaults config", async () => {
|
it("sessions_spawn applies default subagent model from defaults config", async () => {
|
||||||
resetSubagentRegistryForTests();
|
resetSubagentRegistryForTests();
|
||||||
callGatewayMock.mockReset();
|
callGatewayMock.mockReset();
|
||||||
setConfigOverride({
|
setSessionsSpawnConfigOverride({
|
||||||
session: { mainKey: "main", scope: "per-sender" },
|
session: { mainKey: "main", scope: "per-sender" },
|
||||||
agents: { defaults: { subagents: { model: "minimax/MiniMax-M2.1" } } },
|
agents: { defaults: { subagents: { model: "minimax/MiniMax-M2.1" } } },
|
||||||
});
|
});
|
||||||
@@ -278,7 +234,7 @@ describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => {
|
|||||||
it("sessions_spawn prefers per-agent subagent model over defaults", async () => {
|
it("sessions_spawn prefers per-agent subagent model over defaults", async () => {
|
||||||
resetSubagentRegistryForTests();
|
resetSubagentRegistryForTests();
|
||||||
callGatewayMock.mockReset();
|
callGatewayMock.mockReset();
|
||||||
setConfigOverride({
|
setSessionsSpawnConfigOverride({
|
||||||
session: { mainKey: "main", scope: "per-sender" },
|
session: { mainKey: "main", scope: "per-sender" },
|
||||||
agents: {
|
agents: {
|
||||||
defaults: { subagents: { model: "minimax/MiniMax-M2.1" } },
|
defaults: { subagents: { model: "minimax/MiniMax-M2.1" } },
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { vi } from "vitest";
|
||||||
|
|
||||||
|
type SessionsSpawnTestConfig = ReturnType<(typeof import("../config/config.js"))["loadConfig"]>;
|
||||||
|
|
||||||
|
// Avoid exporting vitest mock types (TS2742 under pnpm + d.ts emit).
|
||||||
|
// oxlint-disable-next-line typescript/no-explicit-any
|
||||||
|
type AnyMock = any;
|
||||||
|
|
||||||
|
const hoisted = vi.hoisted(() => {
|
||||||
|
const callGatewayMock = vi.fn();
|
||||||
|
const defaultConfigOverride = {
|
||||||
|
session: {
|
||||||
|
mainKey: "main",
|
||||||
|
scope: "per-sender",
|
||||||
|
},
|
||||||
|
} as SessionsSpawnTestConfig;
|
||||||
|
const state = { configOverride: defaultConfigOverride };
|
||||||
|
return { callGatewayMock, defaultConfigOverride, state };
|
||||||
|
});
|
||||||
|
|
||||||
|
export function getCallGatewayMock(): AnyMock {
|
||||||
|
return hoisted.callGatewayMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetSessionsSpawnConfigOverride(): void {
|
||||||
|
hoisted.state.configOverride = hoisted.defaultConfigOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSessionsSpawnConfigOverride(next: SessionsSpawnTestConfig): void {
|
||||||
|
hoisted.state.configOverride = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
vi.mock("../gateway/call.js", () => ({
|
||||||
|
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
||||||
|
}));
|
||||||
|
// Some tools import callGateway via "../../gateway/call.js" (from nested folders). Mock that too.
|
||||||
|
vi.mock("../../gateway/call.js", () => ({
|
||||||
|
callGateway: (opts: unknown) => hoisted.callGatewayMock(opts),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../config/config.js", async (importOriginal) => {
|
||||||
|
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
loadConfig: () => hoisted.state.configOverride,
|
||||||
|
resolveGatewayPort: () => 18789,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Same module, different specifier (used by tools under src/agents/tools/*).
|
||||||
|
vi.mock("../../config/config.js", async (importOriginal) => {
|
||||||
|
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
loadConfig: () => hoisted.state.configOverride,
|
||||||
|
resolveGatewayPort: () => 18789,
|
||||||
|
};
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user