chore: remove stale test files for deleted modules (council, container)
council.test.ts and container.test.ts reference modules that were removed in a previous commit (b65e9d6). These files cannot run and cause test suite failures.
Made-with: Cursor
This commit is contained in:
@@ -1,131 +0,0 @@
|
||||
import { describe, expect, jest, test } from 'bun:test';
|
||||
import { buildContainersFromEvents } from './container.js';
|
||||
import type { PulseStore } from './store.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('buildContainersFromEvents', () => {
|
||||
test('registers a single container', () => {
|
||||
const store = makeMockStore([
|
||||
{
|
||||
id: 1,
|
||||
occurredAt: 1000,
|
||||
kind: 'container-registered',
|
||||
meta: JSON.stringify({
|
||||
containerId: 'openclaw-neko',
|
||||
type: 'openclaw',
|
||||
host: 'neko-vm',
|
||||
tools: ['exec', 'browser'],
|
||||
}),
|
||||
},
|
||||
]);
|
||||
const containers = buildContainersFromEvents(store);
|
||||
expect(containers.size).toBe(1);
|
||||
const c = containers.get('openclaw-neko')!;
|
||||
expect(c.containerId).toBe('openclaw-neko');
|
||||
expect(c.type).toBe('openclaw');
|
||||
expect(c.host).toBe('neko-vm');
|
||||
expect(c.status).toBe('online');
|
||||
expect(c.tools).toEqual(['exec', 'browser']);
|
||||
expect(c.registeredAt).toBe(1000);
|
||||
});
|
||||
|
||||
test('registers multiple containers', () => {
|
||||
const store = makeMockStore([
|
||||
{
|
||||
id: 1,
|
||||
occurredAt: 1000,
|
||||
kind: 'container-registered',
|
||||
meta: JSON.stringify({
|
||||
containerId: 'openclaw-neko',
|
||||
type: 'openclaw',
|
||||
host: 'neko-vm',
|
||||
tools: ['exec'],
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
occurredAt: 2000,
|
||||
kind: 'container-registered',
|
||||
meta: JSON.stringify({
|
||||
containerId: 'cursor-neko',
|
||||
type: 'cursor',
|
||||
host: 'neko-vm',
|
||||
tools: ['code-edit'],
|
||||
}),
|
||||
},
|
||||
]);
|
||||
const containers = buildContainersFromEvents(store);
|
||||
expect(containers.size).toBe(2);
|
||||
expect(containers.get('openclaw-neko')!.type).toBe('openclaw');
|
||||
expect(containers.get('cursor-neko')!.type).toBe('cursor');
|
||||
});
|
||||
|
||||
test('status changes (online → busy → offline)', () => {
|
||||
const store = makeMockStore([
|
||||
{
|
||||
id: 1,
|
||||
occurredAt: 1000,
|
||||
kind: 'container-registered',
|
||||
meta: JSON.stringify({
|
||||
containerId: 'openclaw-neko',
|
||||
type: 'openclaw',
|
||||
host: 'neko-vm',
|
||||
tools: [],
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
occurredAt: 2000,
|
||||
kind: 'container-status-changed',
|
||||
meta: JSON.stringify({ containerId: 'openclaw-neko', status: 'busy' }),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
occurredAt: 3000,
|
||||
kind: 'container-status-changed',
|
||||
meta: JSON.stringify({
|
||||
containerId: 'openclaw-neko',
|
||||
status: 'offline',
|
||||
}),
|
||||
},
|
||||
]);
|
||||
const containers = buildContainersFromEvents(store);
|
||||
const c = containers.get('openclaw-neko')!;
|
||||
expect(c.status).toBe('offline');
|
||||
expect(c.updatedAt).toBe(3000);
|
||||
});
|
||||
|
||||
test('empty event stream', () => {
|
||||
const store = makeMockStore([]);
|
||||
const containers = buildContainersFromEvents(store);
|
||||
expect(containers.size).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,219 +0,0 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { runCouncil } from './council.js';
|
||||
import type { CouncilMessage, ModeratorFn } from './moderator.js';
|
||||
import { createRoundRobinModerator } from './moderators/round-robin.js';
|
||||
import type { PersonaState } from './task-events.js';
|
||||
|
||||
function makePersona(id: string): PersonaState {
|
||||
return {
|
||||
personaId: id,
|
||||
name: id,
|
||||
container: 'openclaw',
|
||||
capabilities: [],
|
||||
registeredAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
describe('runCouncil', () => {
|
||||
test('round-robin with 3 participants', async () => {
|
||||
const speeches: string[] = [];
|
||||
const result = await runCouncil({
|
||||
moderator: createRoundRobinModerator(),
|
||||
participants: [makePersona('a'), makePersona('b'), makePersona('c')],
|
||||
onSpeak: async (id) => {
|
||||
const msg = `${id} says hello`;
|
||||
speeches.push(msg);
|
||||
return msg;
|
||||
},
|
||||
});
|
||||
|
||||
expect(speeches).toEqual(['a says hello', 'b says hello', 'c says hello']);
|
||||
expect(result.history).toHaveLength(3);
|
||||
expect(result.history[0]!.personaId).toBe('a');
|
||||
expect(result.history[1]!.personaId).toBe('b');
|
||||
expect(result.history[2]!.personaId).toBe('c');
|
||||
expect(result.summary).toBe('All participants have spoken');
|
||||
// 3 speak rounds + 1 close round = 4
|
||||
expect(result.rounds).toBe(4);
|
||||
});
|
||||
|
||||
test('maxRounds limits execution', async () => {
|
||||
// A moderator that always says speak 'a' (never closes)
|
||||
const infiniteMod: ModeratorFn = async () => ({
|
||||
action: 'speak',
|
||||
personaId: 'a',
|
||||
});
|
||||
|
||||
const result = await runCouncil({
|
||||
moderator: infiniteMod,
|
||||
participants: [makePersona('a')],
|
||||
onSpeak: async () => 'loop',
|
||||
maxRounds: 3,
|
||||
});
|
||||
|
||||
expect(result.history).toHaveLength(3);
|
||||
expect(result.rounds).toBe(3);
|
||||
expect(result.summary).toBe('Max rounds exceeded');
|
||||
});
|
||||
|
||||
test('add member mid-council', async () => {
|
||||
let callCount = 0;
|
||||
const addingMod: ModeratorFn = async (_participants, _history) => {
|
||||
callCount++;
|
||||
if (callCount === 1) {
|
||||
return { action: 'speak', personaId: 'a' };
|
||||
}
|
||||
if (callCount === 2) {
|
||||
return {
|
||||
action: 'add',
|
||||
persona: makePersona('newcomer'),
|
||||
};
|
||||
}
|
||||
if (callCount === 3) {
|
||||
return { action: 'speak', personaId: 'newcomer' };
|
||||
}
|
||||
return { action: 'close', summary: 'done' };
|
||||
};
|
||||
|
||||
const added: string[] = [];
|
||||
const result = await runCouncil({
|
||||
moderator: addingMod,
|
||||
participants: [makePersona('a')],
|
||||
onSpeak: async (id) => `${id} speaks`,
|
||||
onAddMember: async (p) => {
|
||||
added.push(p.personaId);
|
||||
},
|
||||
});
|
||||
|
||||
expect(added).toEqual(['newcomer']);
|
||||
expect(result.history).toHaveLength(2);
|
||||
expect(result.history[0]!.personaId).toBe('a');
|
||||
expect(result.history[1]!.personaId).toBe('newcomer');
|
||||
expect(result.summary).toBe('done');
|
||||
});
|
||||
|
||||
test('continues from existing history', async () => {
|
||||
const existingHistory: CouncilMessage[] = [
|
||||
{ personaId: 'a', content: 'earlier', timestamp: 1 },
|
||||
];
|
||||
|
||||
const result = await runCouncil({
|
||||
moderator: createRoundRobinModerator(),
|
||||
participants: [makePersona('a'), makePersona('b')],
|
||||
history: existingHistory,
|
||||
onSpeak: async (id) => `${id} continues`,
|
||||
});
|
||||
|
||||
// 'a' already spoke, so only 'b' speaks, then close
|
||||
expect(result.history).toHaveLength(2);
|
||||
expect(result.history[0]!.personaId).toBe('a');
|
||||
expect(result.history[0]!.content).toBe('earlier');
|
||||
expect(result.history[1]!.personaId).toBe('b');
|
||||
expect(result.rounds).toBe(2); // 1 speak + 1 close
|
||||
});
|
||||
|
||||
test('empty history start', async () => {
|
||||
const result = await runCouncil({
|
||||
moderator: createRoundRobinModerator(),
|
||||
participants: [makePersona('solo')],
|
||||
onSpeak: async () => 'only one',
|
||||
});
|
||||
|
||||
expect(result.history).toHaveLength(1);
|
||||
expect(result.history[0]!.personaId).toBe('solo');
|
||||
});
|
||||
|
||||
test('spawn sub-council via onSpawn', async () => {
|
||||
let callCount = 0;
|
||||
const spawnMod: ModeratorFn = async () => {
|
||||
callCount++;
|
||||
if (callCount === 1) {
|
||||
return { action: 'speak', personaId: 'a' };
|
||||
}
|
||||
if (callCount === 2) {
|
||||
return {
|
||||
action: 'spawn',
|
||||
topicId: 'sub-1',
|
||||
title: 'Sub task',
|
||||
participants: [makePersona('a'), makePersona('b')],
|
||||
};
|
||||
}
|
||||
return { action: 'close', summary: 'parent done' };
|
||||
};
|
||||
|
||||
const spawnCalls: { topicId: string; title: string }[] = [];
|
||||
const result = await runCouncil({
|
||||
moderator: spawnMod,
|
||||
participants: [makePersona('a'), makePersona('b')],
|
||||
onSpeak: async (id) => `${id} speaks`,
|
||||
onSpawn: async (topicId, title, _participants) => {
|
||||
spawnCalls.push({ topicId, title });
|
||||
return { history: [], summary: 'sub-council resolved', rounds: 2 };
|
||||
},
|
||||
});
|
||||
|
||||
expect(spawnCalls).toEqual([{ topicId: 'sub-1', title: 'Sub task' }]);
|
||||
// history: a speaks + sub-council message + (no more speak before close)
|
||||
expect(result.history).toHaveLength(2);
|
||||
expect(result.history[1]!.personaId).toBe('sub-council:sub-1');
|
||||
expect(result.history[1]!.content).toBe('sub-council resolved');
|
||||
expect(result.summary).toBe('parent done');
|
||||
});
|
||||
|
||||
test('nested spawn (sub-council spawns grandchild)', async () => {
|
||||
let parentCall = 0;
|
||||
const parentMod: ModeratorFn = async () => {
|
||||
parentCall++;
|
||||
if (parentCall === 1) {
|
||||
return {
|
||||
action: 'spawn',
|
||||
topicId: 'child',
|
||||
title: 'Child topic',
|
||||
participants: [makePersona('a')],
|
||||
};
|
||||
}
|
||||
return { action: 'close', summary: 'parent done' };
|
||||
};
|
||||
|
||||
const result = await runCouncil({
|
||||
moderator: parentMod,
|
||||
participants: [makePersona('a')],
|
||||
onSpeak: async (id) => `${id} speaks`,
|
||||
onSpawn: async (topicId, _title, participants) => {
|
||||
// Child council that itself spawns a grandchild
|
||||
let childCall = 0;
|
||||
const childMod: ModeratorFn = async () => {
|
||||
childCall++;
|
||||
if (childCall === 1) {
|
||||
return {
|
||||
action: 'spawn',
|
||||
topicId: 'grandchild',
|
||||
title: 'Grandchild topic',
|
||||
participants,
|
||||
};
|
||||
}
|
||||
return { action: 'close', summary: `child ${topicId} done` };
|
||||
};
|
||||
|
||||
return runCouncil({
|
||||
moderator: childMod,
|
||||
participants,
|
||||
onSpeak: async (id) => `${id} in child`,
|
||||
onSpawn: async (gcTopicId) => {
|
||||
return {
|
||||
history: [],
|
||||
summary: `grandchild ${gcTopicId} resolved`,
|
||||
rounds: 1,
|
||||
};
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.history).toHaveLength(1);
|
||||
expect(result.history[0]!.personaId).toBe('sub-council:child');
|
||||
expect(result.history[0]!.content).toBe('child child done');
|
||||
expect(result.summary).toBe('parent done');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user