test: reduce agents test hotspots

This commit is contained in:
Peter Steinberger
2026-04-18 20:28:43 +01:00
parent d1fb2d25ea
commit ab1e091e39
5 changed files with 269 additions and 392 deletions

View File

@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resetFileLockStateForTest } from "../../infra/file-lock.js";
import { captureEnv } from "../../test-utils/env.js";
import { resolveApiKeyForProfile, resetOAuthRefreshQueuesForTest } from "./oauth.js";
@@ -110,8 +110,13 @@ describe("OAuth credential adoption is identity-gated", () => {
"PI_CODING_AGENT_DIR",
]);
let tempRoot = "";
let caseIndex = 0;
let mainAgentDir = "";
beforeAll(async () => {
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-adopt-identity-"));
});
beforeEach(async () => {
resetFileLockStateForTest();
refreshProviderOAuthCredentialWithPluginMock.mockReset();
@@ -119,9 +124,10 @@ describe("OAuth credential adoption is identity-gated", () => {
formatProviderAuthProfileApiKeyWithPluginMock.mockReset();
formatProviderAuthProfileApiKeyWithPluginMock.mockReturnValue(undefined);
clearRuntimeAuthProfileStoreSnapshots();
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-adopt-identity-"));
process.env.OPENCLAW_STATE_DIR = tempRoot;
mainAgentDir = path.join(tempRoot, "agents", "main", "agent");
caseIndex += 1;
const caseRoot = path.join(tempRoot, `case-${caseIndex}`);
process.env.OPENCLAW_STATE_DIR = caseRoot;
mainAgentDir = path.join(caseRoot, "agents", "main", "agent");
process.env.OPENCLAW_AGENT_DIR = mainAgentDir;
process.env.PI_CODING_AGENT_DIR = mainAgentDir;
await fs.mkdir(mainAgentDir, { recursive: true });
@@ -133,6 +139,9 @@ describe("OAuth credential adoption is identity-gated", () => {
resetFileLockStateForTest();
clearRuntimeAuthProfileStoreSnapshots();
resetOAuthRefreshQueuesForTest();
});
afterAll(async () => {
if (tempRoot) {
await fs.rm(tempRoot, { recursive: true, force: true });
}

View File

@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resetFileLockStateForTest } from "../../infra/file-lock.js";
import { captureEnv } from "../../test-utils/env.js";
import { __testing as externalAuthTesting } from "./external-auth.js";
@@ -116,8 +116,13 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
"PI_CODING_AGENT_DIR",
]);
let tempRoot = "";
let caseIndex = 0;
let mainAgentDir = "";
beforeAll(async () => {
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-mirror-"));
});
beforeEach(async () => {
resetFileLockStateForTest();
refreshProviderOAuthCredentialWithPluginMock.mockReset();
@@ -126,9 +131,10 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
formatProviderAuthProfileApiKeyWithPluginMock.mockReturnValue(undefined);
externalAuthTesting.setResolveExternalAuthProfilesForTest(() => []);
clearRuntimeAuthProfileStoreSnapshots();
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-mirror-"));
process.env.OPENCLAW_STATE_DIR = tempRoot;
mainAgentDir = path.join(tempRoot, "agents", "main", "agent");
caseIndex += 1;
const caseRoot = path.join(tempRoot, `case-${caseIndex}`);
process.env.OPENCLAW_STATE_DIR = caseRoot;
mainAgentDir = path.join(caseRoot, "agents", "main", "agent");
process.env.OPENCLAW_AGENT_DIR = mainAgentDir;
process.env.PI_CODING_AGENT_DIR = mainAgentDir;
await fs.mkdir(mainAgentDir, { recursive: true });
@@ -141,6 +147,9 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
externalAuthTesting.resetResolveExternalAuthProfilesForTest();
clearRuntimeAuthProfileStoreSnapshots();
resetOAuthRefreshQueuesForTest();
});
afterAll(async () => {
if (tempRoot) {
await fs.rm(tempRoot, { recursive: true, force: true });
}

View File

@@ -460,338 +460,6 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
).toBe("bot-alpha");
});
it("sessions_spawn prefers peer-specific binding over channel-only binding", async () => {
const targetRoom = "!roomA:example.org";
expect(
await executeBoundAccountSpawn({
callId: "call-peer-specific",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "matrix",
agentAccountId: "bot-beta",
agentTo: targetRoom,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: targetRoom },
accountId: "bot-alpha-room-a",
},
},
],
}),
).toBe("bot-alpha-room-a");
});
it("sessions_spawn falls back to channel-only binding when peer does not match", async () => {
const otherRoom = "!roomB:example.org";
expect(
await executeBoundAccountSpawn({
callId: "call-fallback",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "matrix",
agentAccountId: "bot-beta",
agentTo: otherRoom,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "!roomA:example.org" },
accountId: "bot-alpha-room-a",
},
},
],
}),
).toBe("bot-alpha-default");
});
it("sessions_spawn treats a wildcard peer binding as match-any and beats channel-only", async () => {
const callerRoom = "!anyRoom:example.org";
expect(
await executeBoundAccountSpawn({
callId: "call-wildcard-peer",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "matrix",
agentAccountId: "bot-beta",
agentTo: callerRoom,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "*" },
accountId: "bot-alpha-wildcard",
},
},
],
}),
).toBe("bot-alpha-wildcard");
});
it("sessions_spawn prefers exact peer binding over wildcard peer binding", async () => {
const exactRoom = "!roomA:example.org";
expect(
await executeBoundAccountSpawn({
callId: "call-exact-over-wildcard",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "matrix",
agentAccountId: "bot-beta",
agentTo: exactRoom,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "*" },
accountId: "bot-alpha-wildcard",
},
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: exactRoom },
accountId: "bot-alpha-room-a",
},
},
],
}),
).toBe("bot-alpha-room-a");
});
it("sessions_spawn uses requester roles for role-scoped target-agent accounts", async () => {
expect(
await executeBoundAccountSpawn({
callId: "call-role-scoped-account",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "discord",
agentAccountId: "bot-beta",
agentTo: "channel:ops",
agentGroupSpace: "guild-current",
agentMemberRoleIds: ["admin"],
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "discord", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "discord",
guildId: "guild-current",
roles: ["admin"],
peer: { kind: "channel", id: "channel:ops" },
accountId: "bot-alpha-admin",
},
},
],
}),
).toBe("bot-alpha-admin");
});
it("sessions_spawn strips channel-side prefixes from agentTo before bound-account lookup", async () => {
const rawRoomId = "!exampleRoomId:example.org";
// agentTo arrives in delivery-target format (room:<id>), while the binding
// stores the raw id. Without prefix normalization the exact peer match
// would silently fail and the caller account would leak to the child.
expect(
await executeBoundAccountSpawn({
callId: "call-prefixed-to",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "matrix",
agentAccountId: "bot-beta",
agentTo: `room:${rawRoomId}`,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: rawRoomId },
accountId: "bot-alpha",
},
},
],
}),
).toBe("bot-alpha");
});
it("sessions_spawn peels channel prefix then kind prefix for <channel>:<kind>:<id> targets", async () => {
const rawGroupId = "U123example";
// LINE emits its originatingTo as `line:group:<id>`. Without peeling the
// channel prefix first and looping, a naive strip would leave `group:<id>`
// (or `line:<id>`) and the exact peer-id binding would not match.
expect(
await executeBoundAccountSpawn({
callId: "call-line-nested-prefix",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "line",
agentAccountId: "bot-beta",
agentTo: `line:group:${rawGroupId}`,
},
bindings: [
// Wildcard peer binding with a conflicting kind (direct) must be
// skipped because the inferred kind is `group`.
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "line",
peer: { kind: "direct", id: "*" },
accountId: "bot-alpha-line-dm",
},
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "line",
peer: { kind: "group", id: rawGroupId },
accountId: "bot-alpha-line",
},
},
],
}),
).toBe("bot-alpha-line");
});
it("sessions_spawn classifies Matrix room:@user targets as direct, not channel", async () => {
const rawUserId = "@other-user:example.org";
// Matrix thread delivery encodes per-user DM targets as `room:@user:server`.
// The `room:` prefix must not override the embedded `@` direct-peer marker.
expect(
await executeBoundAccountSpawn({
callId: "call-room-at-user",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "matrix",
agentAccountId: "bot-beta",
agentTo: `room:${rawUserId}`,
},
bindings: [
// A conflicting channel-kinded binding on the same peer id must not
// match because the embedded `@` marker identifies a direct peer.
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: rawUserId },
accountId: "bot-alpha-wrong-kind",
},
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "direct", id: rawUserId },
accountId: "bot-alpha-dm",
},
},
],
}),
).toBe("bot-alpha-dm");
});
it("sessions_spawn strips only the Teams conversation: wrapper", async () => {
const rawConversationId = "a:1:example-conversation@thread.v2";
// Teams inbound context sets OriginatingTo to `conversation:<id>`. The
// Teams id itself may start with another token-colon segment, so extraction
// must stop after the known wrapper instead of peeling arbitrary prefixes.
expect(
await executeBoundAccountSpawn({
callId: "call-teams-conversation",
agentId: "bot-alpha",
context: {
agentSessionKey: "main",
agentChannel: "msteams",
agentAccountId: "bot-beta",
agentTo: `conversation:${rawConversationId}`,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "msteams",
peer: { kind: "channel", id: rawConversationId },
accountId: "bot-alpha-teams",
},
},
],
}),
).toBe("bot-alpha-teams");
});
it("sessions_spawn preserves the caller's account for same-agent subagent spawns", async () => {
const room = "!someRoom:example.org";
// Spawn a child of the same agent (no explicit agentId), so the caller's
// active account must win over any configured binding for that same agent.
expect(
await executeBoundAccountSpawn({
callId: "call-same-agent",
context: {
agentSessionKey: "agent:bot-alpha:session:main",
agentChannel: "matrix",
agentAccountId: "bot-alpha-adhoc",
agentTo: room,
},
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
],
}),
).toBe("bot-alpha-adhoc");
});
it("sessions_spawn announces with requester accountId", async () => {
const ctx = setupSessionsSpawnGatewayMock({});

View File

@@ -29,9 +29,12 @@ async function createWorkspaceBundle(params: {
}
describe("loadEnabledBundlePiSettingsSnapshot", () => {
it("loads sanitized settings from enabled bundle plugins", async () => {
it("loads sanitized settings and MCP defaults from enabled bundle plugins", async () => {
const workspaceDir = await tempDirs.make("openclaw-workspace-");
const pluginRoot = await createWorkspaceBundle({ workspaceDir });
const resolvedPluginRoot = await fs.realpath(pluginRoot);
await fs.mkdir(path.join(pluginRoot, "servers"), { recursive: true });
const resolvedServerPath = await fs.realpath(path.join(pluginRoot, "servers"));
await fs.writeFile(
path.join(pluginRoot, "settings.json"),
JSON.stringify({
@@ -41,6 +44,22 @@ describe("loadEnabledBundlePiSettingsSnapshot", () => {
}),
"utf-8",
);
await fs.writeFile(
path.join(pluginRoot, ".mcp.json"),
JSON.stringify({
mcpServers: {
bundleProbe: {
command: "node",
args: ["./servers/probe.mjs"],
},
sharedServer: {
command: "node",
args: ["./servers/bundle.mjs"],
},
},
}),
"utf-8",
);
const snapshot = loadEnabledBundlePiSettingsSnapshot({
cwd: workspaceDir,
@@ -56,64 +75,20 @@ describe("loadEnabledBundlePiSettingsSnapshot", () => {
expect(snapshot.hideThinkingBlock).toBe(true);
expect(snapshot.shellPath).toBeUndefined();
expect(snapshot.compaction?.keepRecentTokens).toBe(64_000);
});
it("loads enabled bundle MCP servers into the Pi settings snapshot", async () => {
const workspaceDir = await tempDirs.make("openclaw-workspace-");
const pluginRoot = await createWorkspaceBundle({ workspaceDir });
const resolvedPluginRoot = await fs.realpath(pluginRoot);
await fs.mkdir(path.join(pluginRoot, "servers"), { recursive: true });
const resolvedServerPath = await fs.realpath(path.join(pluginRoot, "servers"));
await fs.writeFile(
path.join(pluginRoot, ".mcp.json"),
JSON.stringify({
mcpServers: {
bundleProbe: {
command: "node",
args: ["./servers/probe.mjs"],
},
},
}),
"utf-8",
);
const snapshot = loadEnabledBundlePiSettingsSnapshot({
cwd: workspaceDir,
cfg: {
plugins: {
entries: {
"claude-bundle": { enabled: true },
},
},
},
});
expect((snapshot as Record<string, unknown>).mcpServers).toEqual({
bundleProbe: {
command: "node",
args: [path.join(resolvedServerPath, "probe.mjs")],
cwd: resolvedPluginRoot,
},
sharedServer: {
command: "node",
args: [path.join(resolvedServerPath, "bundle.mjs")],
cwd: resolvedPluginRoot,
},
});
});
it("lets top-level MCP config override bundle MCP defaults", async () => {
const workspaceDir = await tempDirs.make("openclaw-workspace-");
const pluginRoot = await createWorkspaceBundle({ workspaceDir });
await fs.writeFile(
path.join(pluginRoot, ".mcp.json"),
JSON.stringify({
mcpServers: {
sharedServer: {
command: "node",
args: ["./servers/bundle.mjs"],
},
},
}),
"utf-8",
);
const snapshot = loadEnabledBundlePiSettingsSnapshot({
const overridden = loadEnabledBundlePiSettingsSnapshot({
cwd: workspaceDir,
cfg: {
mcp: {
@@ -131,7 +106,12 @@ describe("loadEnabledBundlePiSettingsSnapshot", () => {
},
});
expect((snapshot as Record<string, unknown>).mcpServers).toEqual({
expect((overridden as Record<string, unknown>).mcpServers).toEqual({
bundleProbe: {
command: "node",
args: [path.join(resolvedServerPath, "probe.mjs")],
cwd: resolvedPluginRoot,
},
sharedServer: {
url: "https://example.com/mcp",
},

View File

@@ -3,6 +3,24 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveRequesterOriginForChild } from "./spawn-requester-origin.js";
describe("resolveRequesterOriginForChild", () => {
function resolveAccount(params: {
cfg: OpenClawConfig;
targetAgentId?: string;
requesterAgentId?: string;
requesterChannel: string;
requesterAccountId?: string;
requesterTo: string;
requesterGroupSpace?: string | null;
requesterMemberRoleIds?: string[];
}) {
return resolveRequesterOriginForChild({
requesterAccountId: "bot-beta",
...params,
targetAgentId: params.targetAgentId ?? "bot-alpha",
requesterAgentId: params.requesterAgentId ?? "main",
})?.accountId;
}
it.each([
["channel:conversation-a", "channel:conversation-a", "channel"],
["dm:conversation-a", "dm:conversation-a", "direct"],
@@ -44,6 +62,199 @@ describe("resolveRequesterOriginForChild", () => {
},
);
it.each([
{
name: "prefers peer-specific binding over channel-only binding",
requesterChannel: "matrix",
requesterTo: "!roomA:example.org",
expected: "bot-alpha-room-a",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "!roomA:example.org" },
accountId: "bot-alpha-room-a",
},
},
],
},
{
name: "falls back to channel-only binding when peer does not match",
requesterChannel: "matrix",
requesterTo: "!roomB:example.org",
expected: "bot-alpha-default",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "!roomA:example.org" },
accountId: "bot-alpha-room-a",
},
},
],
},
{
name: "treats wildcard peer binding as match-any and beats channel-only",
requesterChannel: "matrix",
requesterTo: "!anyRoom:example.org",
expected: "bot-alpha-wildcard",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "*" },
accountId: "bot-alpha-wildcard",
},
},
],
},
{
name: "prefers exact peer binding over wildcard peer binding",
requesterChannel: "matrix",
requesterTo: "!roomA:example.org",
expected: "bot-alpha-room-a",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "*" },
accountId: "bot-alpha-wildcard",
},
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "!roomA:example.org" },
accountId: "bot-alpha-room-a",
},
},
],
},
{
name: "uses requester roles for role-scoped target-agent accounts",
requesterChannel: "discord",
requesterTo: "channel:ops",
requesterGroupSpace: "guild-current",
requesterMemberRoleIds: ["admin"],
expected: "bot-alpha-admin",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "discord", accountId: "bot-alpha-default" },
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "discord",
guildId: "guild-current",
roles: ["admin"],
peer: { kind: "channel", id: "channel:ops" },
accountId: "bot-alpha-admin",
},
},
],
},
{
name: "strips channel-side prefixes before bound-account lookup",
requesterChannel: "matrix",
requesterTo: "room:!exampleRoomId:example.org",
expected: "bot-alpha",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "!exampleRoomId:example.org" },
accountId: "bot-alpha",
},
},
],
},
{
name: "classifies Matrix room:@user targets as direct, not channel",
requesterChannel: "matrix",
requesterTo: "room:@other-user:example.org",
expected: "bot-alpha-dm",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "channel", id: "@other-user:example.org" },
accountId: "bot-alpha-wrong-kind",
},
},
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "matrix",
peer: { kind: "direct", id: "@other-user:example.org" },
accountId: "bot-alpha-dm",
},
},
],
},
{
name: "preserves the caller account for same-agent subagent spawns",
requesterChannel: "matrix",
requesterAccountId: "bot-alpha-adhoc",
requesterAgentId: "bot-alpha",
requesterTo: "!someRoom:example.org",
expected: "bot-alpha-adhoc",
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: { channel: "matrix", accountId: "bot-alpha-default" },
},
],
},
] as const)("selects target account: $name", (scenario) => {
expect(
resolveAccount({
cfg: { bindings: [...scenario.bindings] } as OpenClawConfig,
requesterChannel: scenario.requesterChannel,
requesterAccountId: scenario.requesterAccountId,
requesterAgentId: scenario.requesterAgentId,
requesterTo: scenario.requesterTo,
requesterGroupSpace: scenario.requesterGroupSpace,
requesterMemberRoleIds: scenario.requesterMemberRoleIds
? [...scenario.requesterMemberRoleIds]
: undefined,
}),
).toBe(scenario.expected);
});
it("preserves canonical peer ids that start with token-colon after a known wrapper", () => {
const to = "conversation:a:1:team-thread";
const cfg = {