test(queue): cover atomic ownership and MCP tool schemas (MQ-007)

This commit is contained in:
2026-03-06 09:37:21 -06:00
parent 869f9b49df
commit 119fbdf801
2 changed files with 119 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
import { describe, expect, it } from 'vitest';
import {
queueClaimToolInputSchema,
queueCompleteToolInputSchema,
queueFailToolInputSchema,
queueGetToolInputSchema,
queueHeartbeatToolInputSchema,
queueListToolInputSchema,
queueReleaseToolInputSchema,
queueStatusToolInputSchema,
} from '../src/mcp-tool-schemas.js';
describe('MCP tool schemas', () => {
it('validates queue_list filters', () => {
const parsed = queueListToolInputSchema.parse({
project: 'queue',
mission: 'phase1',
status: 'pending',
});
expect(parsed).toEqual({
project: 'queue',
mission: 'phase1',
status: 'pending',
});
});
it('requires a taskId for queue_get', () => {
expect(() => queueGetToolInputSchema.parse({})).toThrowError();
});
it('requires positive ttlSeconds for queue_claim', () => {
expect(() =>
queueClaimToolInputSchema.parse({
taskId: 'MQ-007',
agentId: 'agent-a',
ttlSeconds: 0,
}),
).toThrowError();
});
it('accepts optional fields for queue_heartbeat and queue_release', () => {
const heartbeat = queueHeartbeatToolInputSchema.parse({
taskId: 'MQ-007',
ttlSeconds: 30,
});
const release = queueReleaseToolInputSchema.parse({
taskId: 'MQ-007',
});
expect(heartbeat).toEqual({
taskId: 'MQ-007',
ttlSeconds: 30,
});
expect(release).toEqual({
taskId: 'MQ-007',
});
});
it('validates queue_complete and queue_fail payloads', () => {
const complete = queueCompleteToolInputSchema.parse({
taskId: 'MQ-007',
agentId: 'agent-a',
summary: 'done',
});
const fail = queueFailToolInputSchema.parse({
taskId: 'MQ-007',
reason: 'boom',
});
expect(complete).toEqual({
taskId: 'MQ-007',
agentId: 'agent-a',
summary: 'done',
});
expect(fail).toEqual({
taskId: 'MQ-007',
reason: 'boom',
});
});
it('accepts an empty payload for queue_status', () => {
const parsed = queueStatusToolInputSchema.parse({});
expect(parsed).toEqual({});
});
});

View File

@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest';
import {
RedisTaskRepository,
TaskOwnershipError,
TaskTransitionError,
type RedisTaskClient,
type RedisTaskTransaction,
@@ -327,4 +328,32 @@ describe('RedisTaskRepository atomic transitions', () => {
}),
).rejects.toBeInstanceOf(TaskTransitionError);
});
it('enforces claim ownership for release and complete', async () => {
const [repository] = createRepositoryPair(() => 1_700_000_000_000);
await repository.create({
project: 'queue',
mission: 'phase1',
taskId: 'MQ-004-OWN',
title: 'Ownership checks',
});
await repository.claim('MQ-004-OWN', {
agentId: 'agent-a',
ttlSeconds: 60,
});
await expect(
repository.release('MQ-004-OWN', {
agentId: 'agent-b',
}),
).rejects.toBeInstanceOf(TaskOwnershipError);
await expect(
repository.complete('MQ-004-OWN', {
agentId: 'agent-b',
}),
).rejects.toBeInstanceOf(TaskOwnershipError);
});
});