Files
stack/packages/agent/src/runtime-provider-parity.test.ts
jason.woltje 6345dbfcf2
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
feat(agent): add Matrix native runtime provider (#744)
2026-07-13 15:29:37 +00:00

177 lines
5.2 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import type { AgentRuntimeProvider, RuntimeScope } from '@mosaicstack/types';
import {
MatrixNativeRuntimeProvider,
type MatrixRuntimeTransport,
} from './matrix-native-runtime-provider.js';
import {
TmuxFleetRuntimeProvider,
type FleetRuntimeTransport,
} from './tmux-fleet-runtime-provider.js';
const scope: RuntimeScope = {
actorId: 'operator-1',
tenantId: 'tenant-a',
channelId: 'cli',
correlationId: 'corr-1',
};
interface ProviderFixture {
name: string;
provider: AgentRuntimeProvider;
providerId: string;
verifySession: unknown;
send: unknown;
}
function fixtures(): ProviderFixture[] {
const fleetTransport: FleetRuntimeTransport = {
verifySession: vi.fn(async () => ({
id: 'session-1',
runtimeId: 'native-1',
socketName: 'fleet',
})),
listSessions: vi.fn(async () => [
{ id: 'session-1', runtimeId: 'native-1', socketName: 'fleet' },
]),
sendMessage: vi.fn(async () => undefined),
terminate: vi.fn(async () => undefined),
};
const fleet = new TmuxFleetRuntimeProvider({
transport: fleetTransport,
readAuthority: { canRead: vi.fn(async () => true) },
writeAuthority: {
canWrite: vi.fn(async () => true),
assertAuthorized: vi.fn(async () => undefined),
},
attachmentIdFactory: () => 'attachment-1',
now: () => new Date('2026-07-13T00:00:00.000Z'),
});
const matrixTransport: MatrixRuntimeTransport = {
health: vi.fn(async () => ({
status: 'healthy' as const,
checkedAt: '2026-07-13T00:00:00.000Z',
})),
verifySession: vi.fn(async () => ({
id: 'session-1',
runtimeId: 'native-1',
state: 'active' as const,
createdAt: '2026-07-13T00:00:00.000Z',
updatedAt: '2026-07-13T00:00:00.000Z',
})),
listSessions: vi.fn(async () => [
{
id: 'session-1',
runtimeId: 'native-1',
state: 'active' as const,
createdAt: '2026-07-13T00:00:00.000Z',
updatedAt: '2026-07-13T00:00:00.000Z',
},
]),
stream: async function* () {},
send: vi.fn(async () => undefined),
terminate: vi.fn(async () => undefined),
};
const matrix = new MatrixNativeRuntimeProvider({
transport: matrixTransport,
readAuthority: { canRead: vi.fn(async () => true) },
writeAuthority: {
canWrite: vi.fn(async () => true),
assertAuthorized: vi.fn(async () => undefined),
},
attachmentIdFactory: () => 'attachment-1',
now: () => new Date('2026-07-13T00:00:00.000Z'),
});
return [
{
name: 'tmux/fleet',
provider: fleet,
providerId: 'fleet.tmux',
verifySession: fleetTransport.verifySession,
send: fleetTransport.sendMessage,
},
{
name: 'Matrix/native',
provider: matrix,
providerId: 'runtime.matrix',
verifySession: matrixTransport.verifySession,
send: matrixTransport.send,
},
];
}
/** Shared contract tests for the migration-safe provider intersection. */
describe('tmux/fleet and Matrix/native provider parity', (): void => {
it.each(fixtures())(
'%s exposes the shared runtime operations',
async (fixture): Promise<void> => {
await expect(fixture.provider.capabilities(scope)).resolves.toEqual(
expect.objectContaining({
supported: expect.arrayContaining([
'session.list',
'session.tree',
'session.send',
'session.attach',
'session.terminate',
]),
}),
);
await expect(fixture.provider.listSessions(scope)).resolves.toEqual([
expect.objectContaining({
id: 'session-1',
providerId: fixture.providerId,
runtimeId: 'native-1',
}),
]);
},
);
it.each(fixtures())(
'%s rejects empty messages before touching its transport',
async (fixture): Promise<void> => {
await expect(
fixture.provider.sendMessage(
'session-1',
{ content: '', idempotencyKey: 'message-1' },
scope,
),
).rejects.toMatchObject({ code: 'invalid_request' });
expect(fixture.verifySession).not.toHaveBeenCalled();
expect(fixture.send).not.toHaveBeenCalled();
},
);
it.each(fixtures())(
'%s rejects an empty termination approval before touching its transport',
async (fixture): Promise<void> => {
await expect(fixture.provider.terminate('session-1', '', scope)).rejects.toMatchObject({
code: 'invalid_request',
});
expect(fixture.verifySession).not.toHaveBeenCalled();
},
);
it.each(fixtures())(
'%s creates a read-only handle bound to immutable scope',
async (fixture): Promise<void> => {
await expect(fixture.provider.attach('session-1', 'control', scope)).rejects.toMatchObject({
code: 'forbidden',
});
expect(fixture.verifySession).not.toHaveBeenCalled();
await expect(fixture.provider.attach('session-1', 'read', scope)).resolves.toEqual(
expect.objectContaining({
attachmentId: 'attachment-1',
sessionId: 'session-1',
mode: 'read',
}),
);
await expect(
fixture.provider.detach('attachment-1', { ...scope, actorId: 'operator-2' }),
).rejects.toMatchObject({ code: 'forbidden' });
},
);
});