chore: remove obsolete binding and broker tests
CI / test (push) Has been cancelled

These tests reference modules (binding.js/broker.js) that no longer exist.

Signed-off-by: Xiaonuo <xiaonuo@git.shazhou.work>
This commit is contained in:
2026-04-17 20:47:06 +08:00
parent 3cdd9aeba6
commit c703befcdc
2 changed files with 0 additions and 583 deletions
-170
View File
@@ -1,170 +0,0 @@
import { describe, expect, jest, test } from 'bun:test';
import { buildBindingsFromEvents, resolveRole } from './binding.js';
import type { Container } from './container.js';
import type { PulseStore } from './store.js';
import type { PersonaState } from './task-events.js';
function makeMockStore(
events: Array<{ id: number; occurredAt: number; kind: string; meta: string }>,
): PulseStore {
return {
appendEvent: jest.fn(() => ({
id: 1,
occurredAt: Date.now(),
kind: 'mock',
})),
appendEvents: jest.fn(() => []),
getLatest: jest.fn(() => null),
getLatestWhere: jest.fn(() => null),
getRecent: jest.fn(() => []),
queryByKind: jest.fn((kind: string) =>
events.filter((e) => e.kind === kind),
),
getAfter: jest.fn(() => []),
hasEvents: jest.fn(() => false),
putObject: jest.fn(() => 'hash'),
getObject: jest.fn(() => null),
close: jest.fn(),
createObject: jest.fn(() => 1),
getObjectInstance: jest.fn(() => null),
queryObjectsByType: jest.fn(() => []),
archiveEvents: jest.fn(() => 0),
downsampleEvents: jest.fn(() => 0),
};
}
describe('buildBindingsFromEvents', () => {
test('bind persona to container', () => {
const store = makeMockStore([
{
id: 1,
occurredAt: 1000,
kind: 'persona-bound',
meta: JSON.stringify({
personaId: 'xiaoju',
containerId: 'openclaw-neko',
}),
},
]);
const bindings = buildBindingsFromEvents(store);
expect(bindings.size).toBe(1);
const b = bindings.get('xiaoju')!;
expect(b.personaId).toBe('xiaoju');
expect(b.containerId).toBe('openclaw-neko');
expect(b.boundAt).toBe(1000);
});
test('rebind (migration) — new bind overwrites old', () => {
const store = makeMockStore([
{
id: 1,
occurredAt: 1000,
kind: 'persona-bound',
meta: JSON.stringify({
personaId: 'xiaoju',
containerId: 'openclaw-neko',
}),
},
{
id: 2,
occurredAt: 2000,
kind: 'persona-bound',
meta: JSON.stringify({
personaId: 'xiaoju',
containerId: 'hermes-neko',
}),
},
]);
const bindings = buildBindingsFromEvents(store);
expect(bindings.size).toBe(1);
expect(bindings.get('xiaoju')!.containerId).toBe('hermes-neko');
expect(bindings.get('xiaoju')!.boundAt).toBe(2000);
});
test('unbind removes binding', () => {
const store = makeMockStore([
{
id: 1,
occurredAt: 1000,
kind: 'persona-bound',
meta: JSON.stringify({
personaId: 'xiaoju',
containerId: 'openclaw-neko',
}),
},
{
id: 2,
occurredAt: 2000,
kind: 'persona-unbound',
meta: JSON.stringify({
personaId: 'xiaoju',
containerId: 'openclaw-neko',
reason: 'manual',
}),
},
]);
const bindings = buildBindingsFromEvents(store);
expect(bindings.size).toBe(0);
});
});
describe('resolveRole', () => {
const personas = new Map<string, PersonaState>([
[
'xiaoju',
{
personaId: 'xiaoju',
name: '小橘',
container: 'openclaw',
capabilities: ['coding', 'ops'],
registeredAt: 1000,
updatedAt: 1000,
},
],
]);
const containers = new Map<string, Container>([
[
'openclaw-neko',
{
containerId: 'openclaw-neko',
type: 'openclaw',
host: 'neko-vm',
status: 'online',
tools: ['exec', 'browser'],
registeredAt: 1000,
updatedAt: 1000,
},
],
]);
test('resolves role successfully', () => {
const bindings = new Map([
[
'xiaoju',
{ personaId: 'xiaoju', containerId: 'openclaw-neko', boundAt: 1000 },
],
]);
const role = resolveRole('xiaoju', personas, bindings, containers);
expect(role).not.toBeNull();
expect(role!.persona.name).toBe('小橘');
expect(role!.container.containerId).toBe('openclaw-neko');
});
test('returns null when persona not bound', () => {
const bindings = new Map();
const role = resolveRole('xiaoju', personas, bindings, containers);
expect(role).toBeNull();
});
test('returns null when container does not exist', () => {
const bindings = new Map([
[
'xiaoju',
{ personaId: 'xiaoju', containerId: 'nonexistent', boundAt: 1000 },
],
]);
const role = resolveRole('xiaoju', personas, bindings, containers);
expect(role).toBeNull();
});
});
-413
View File
@@ -1,413 +0,0 @@
import { beforeEach, describe, expect, jest, test } from 'bun:test';
import type { LlmClient, LlmResponse } from '../llm-client.js';
import type { BrokerEffect } from '../rules/task-rule.js';
import type { PulseStore } from '../store.js';
import { createBrokerExecutor } from './broker.js';
function makeMockLlmClient(response: LlmResponse): LlmClient {
return {
chat: jest.fn(async () => response),
};
}
function makeMockRoutineStore(): PulseStore {
return {
appendEvent: jest.fn(() => ({
id: 1,
occurredAt: Date.now(),
kind: 'mock',
})),
appendEvents: jest.fn(() => []),
getLatest: jest.fn(() => null),
getLatestWhere: jest.fn(() => null),
getRecent: jest.fn(() => []),
queryByKind: jest.fn(() => []),
getAfter: jest.fn(() => []),
hasEvents: jest.fn(() => false),
putObject: jest.fn(() => 'hash'),
getObject: jest.fn(() => null),
close: jest.fn(),
createObject: jest.fn(() => 1),
getObjectInstance: jest.fn(() => null),
queryObjectsByType: jest.fn(() => []),
archiveEvents: jest.fn(() => 0),
downsampleEvents: jest.fn(() => 0),
};
}
describe('createBrokerExecutor', () => {
let workflowStore: PulseStore;
beforeEach(() => {
workflowStore = makeMockRoutineStore();
});
test('assigns tasks via LLM tool calls', async () => {
(
workflowStore.queryByKind as ReturnType<typeof jest.fn>
).mockImplementation((kind: string) => {
if (kind === 'task-created') {
return [
{
id: 1,
occurredAt: 1000,
kind: 'task-created',
meta: JSON.stringify({
taskId: 't1',
projectId: 'proj-1',
title: 'Fix bug',
description: 'fix it',
type: 'bug',
priority: 5,
creatorId: 'user-1',
}),
},
];
}
return [];
});
const llmResponse: LlmResponse = {
tool_calls: [
{
id: 'call-1',
function: {
name: 'assign_task',
arguments: JSON.stringify({
taskId: 't1',
assigneeId: 'cursor',
}),
},
},
],
};
const llmClient = makeMockLlmClient(llmResponse);
const executor = createBrokerExecutor({ llmClient, workflowStore });
const effect: BrokerEffect = { kind: 'broker', taskIds: ['t1'] };
await executor(effect);
const appendCalls = (
workflowStore.appendEvent as ReturnType<typeof jest.fn>
).mock.calls;
const routingCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-routing',
);
expect(routingCalls).toHaveLength(1);
const routingMeta = JSON.parse(routingCalls[0][0].meta);
expect(routingMeta.taskId).toBe('t1');
expect(routingMeta.brokerSessionId).toBeDefined();
const assignedCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-assigned',
);
expect(assignedCalls).toHaveLength(1);
const meta = JSON.parse(assignedCalls[0][0].meta);
expect(meta.taskId).toBe('t1');
expect(meta.assigneeId).toBe('cursor');
expect(meta.assignedBy).toBe('broker');
});
test('writes task-responded on LLM failure', async () => {
(
workflowStore.queryByKind as ReturnType<typeof jest.fn>
).mockImplementation((kind: string) => {
if (kind === 'task-created') {
return [
{
id: 1,
occurredAt: 1000,
kind: 'task-created',
meta: JSON.stringify({
taskId: 't1',
projectId: 'proj-1',
title: 'Fix bug',
description: 'fix it',
type: 'bug',
priority: 5,
creatorId: 'user-1',
}),
},
];
}
return [];
});
const llmClient: LlmClient = {
chat: jest.fn(async () => {
throw new Error('LLM unavailable');
}),
};
const executor = createBrokerExecutor({ llmClient, workflowStore });
const effect: BrokerEffect = { kind: 'broker', taskIds: ['t1'] };
await executor(effect);
const appendCalls = (
workflowStore.appendEvent as ReturnType<typeof jest.fn>
).mock.calls;
const routingCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-routing',
);
expect(routingCalls).toHaveLength(1);
const respondedCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-responded',
);
expect(respondedCalls).toHaveLength(1);
const meta = JSON.parse(respondedCalls[0][0].meta);
expect(meta.taskId).toBe('t1');
expect(meta.result).toContain('Routing failed');
});
test('skips if no matching tasks found', async () => {
(workflowStore.queryByKind as ReturnType<typeof jest.fn>).mockReturnValue(
[],
);
const llmClient = makeMockLlmClient({ content: 'ok' });
const executor = createBrokerExecutor({ llmClient, workflowStore });
const effect: BrokerEffect = { kind: 'broker', taskIds: ['nonexistent'] };
await executor(effect);
expect(llmClient.chat).not.toHaveBeenCalled();
});
test('skips if effect kind is not broker', async () => {
const llmClient = makeMockLlmClient({ content: 'ok' });
const executor = createBrokerExecutor({ llmClient, workflowStore });
await executor({ kind: 'other', taskIds: [] } as unknown as BrokerEffect);
expect(llmClient.chat).not.toHaveBeenCalled();
});
test('handles LLM response without tool_calls', async () => {
(
workflowStore.queryByKind as ReturnType<typeof jest.fn>
).mockImplementation((kind: string) => {
if (kind === 'task-created') {
return [
{
id: 1,
occurredAt: 1000,
kind: 'task-created',
meta: JSON.stringify({
taskId: 't1',
projectId: 'proj-1',
title: 'Fix',
description: 'fix',
type: 'bug',
priority: 0,
creatorId: 'user-1',
}),
},
];
}
return [];
});
const llmClient = makeMockLlmClient({ content: 'ok' });
const executor = createBrokerExecutor({ llmClient, workflowStore });
const effect: BrokerEffect = { kind: 'broker', taskIds: ['t1'] };
await executor(effect);
const appendCalls = (
workflowStore.appendEvent as ReturnType<typeof jest.fn>
).mock.calls;
const assignedCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-assigned',
);
expect(assignedCalls).toHaveLength(0);
});
test('uses dynamic personas when getPersonas is provided', async () => {
(
workflowStore.queryByKind as ReturnType<typeof jest.fn>
).mockImplementation((kind: string) => {
if (kind === 'task-created') {
return [
{
id: 1,
occurredAt: 1000,
kind: 'task-created',
meta: JSON.stringify({
taskId: 't1',
projectId: 'proj-1',
title: 'Fix bug',
description: 'fix it',
type: 'bug',
priority: 5,
creatorId: 'user-1',
}),
},
];
}
return [];
});
const llmResponse: LlmResponse = {
tool_calls: [
{
id: 'call-1',
function: {
name: 'assign_task',
arguments: JSON.stringify({
taskId: 't1',
assigneeId: 'xiaoju',
}),
},
},
],
};
const llmClient = makeMockLlmClient(llmResponse);
const personas = new Map([
[
'xiaoju',
{
personaId: 'xiaoju',
name: '小橘',
container: 'openclaw' as const,
capabilities: ['coding', 'ops'],
registeredAt: 1000,
updatedAt: 1000,
},
],
[
'claude',
{
personaId: 'claude',
name: 'Claude',
container: 'claude-code' as const,
capabilities: ['coding', 'review'],
registeredAt: 1000,
updatedAt: 1000,
},
],
]);
const executor = createBrokerExecutor({
llmClient,
workflowStore,
getPersonas: () => personas,
});
await executor({ kind: 'broker', taskIds: ['t1'] });
// Verify LLM was called with dynamic prompt containing persona info
const chatCall = (llmClient.chat as ReturnType<typeof jest.fn>).mock
.calls[0][0];
expect(chatCall.messages[0].content).toContain('xiaoju');
expect(chatCall.messages[0].content).toContain('claude');
expect(chatCall.messages[0].content).toContain('capabilities');
// Verify tools enum contains dynamic agent ids
const assigneeProp =
chatCall.tools[0].function.parameters.properties.assigneeId;
expect(assigneeProp.enum).toContain('xiaoju');
expect(assigneeProp.enum).toContain('claude');
expect(assigneeProp.enum).not.toContain('cursor');
// Verify assignment went through
const appendCalls = (
workflowStore.appendEvent as ReturnType<typeof jest.fn>
).mock.calls;
const assignedCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-assigned',
);
expect(assignedCalls).toHaveLength(1);
const meta = JSON.parse(assignedCalls[0][0].meta);
expect(meta.assigneeId).toBe('xiaoju');
});
test('handles multiple task assignments', async () => {
(
workflowStore.queryByKind as ReturnType<typeof jest.fn>
).mockImplementation((kind: string) => {
if (kind === 'task-created') {
return [
{
id: 1,
occurredAt: 1000,
kind: 'task-created',
meta: JSON.stringify({
taskId: 't1',
projectId: 'proj-1',
title: 'Task 1',
description: 'desc 1',
type: 'bug',
priority: 5,
creatorId: 'user-1',
}),
},
{
id: 2,
occurredAt: 1001,
kind: 'task-created',
meta: JSON.stringify({
taskId: 't2',
projectId: 'proj-1',
title: 'Task 2',
description: 'desc 2',
type: 'rfc',
priority: 3,
creatorId: 'user-1',
}),
},
];
}
return [];
});
const llmResponse: LlmResponse = {
tool_calls: [
{
id: 'call-1',
function: {
name: 'assign_task',
arguments: JSON.stringify({
taskId: 't1',
assigneeId: 'cursor',
}),
},
},
{
id: 'call-2',
function: {
name: 'assign_task',
arguments: JSON.stringify({
taskId: 't2',
assigneeId: 'cursor',
}),
},
},
],
};
const llmClient = makeMockLlmClient(llmResponse);
const executor = createBrokerExecutor({ llmClient, workflowStore });
await executor({ kind: 'broker', taskIds: ['t1', 't2'] });
const appendCalls = (
workflowStore.appendEvent as ReturnType<typeof jest.fn>
).mock.calls;
const assignedCalls = appendCalls.filter(
(call: unknown[]) =>
(call[0] as { kind: string }).kind === 'task-assigned',
);
expect(assignedCalls).toHaveLength(2);
});
});