191 lines
6.2 KiB
JavaScript
191 lines
6.2 KiB
JavaScript
const { describe, test, expect, beforeEach, afterEach } = require('@jest/globals');
|
|
const BMADMessageQueue = require('../../core/message-queue');
|
|
const path = require('path');
|
|
|
|
describe('BMADMessageQueue', () => {
|
|
let queue;
|
|
let tempDir;
|
|
|
|
beforeEach(async () => {
|
|
tempDir = await global.testUtils.createTempDir();
|
|
queue = new BMADMessageQueue({ basePath: tempDir });
|
|
await queue.initialize();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await global.testUtils.cleanupTempDir(tempDir);
|
|
});
|
|
|
|
describe('Message Operations', () => {
|
|
test('should send and retrieve a message', async () => {
|
|
const messageData = {
|
|
agent: 'test-agent',
|
|
type: 'test',
|
|
data: { foo: 'bar' }
|
|
};
|
|
|
|
const messageId = await queue.sendMessage(messageData);
|
|
expect(messageId).toMatch(/^msg-\d+-[a-f0-9]+$/);
|
|
|
|
const retrieved = await queue.getMessage(messageId);
|
|
expect(retrieved.agent).toBe('test-agent');
|
|
expect(retrieved.type).toBe('test');
|
|
expect(retrieved.data).toEqual({ foo: 'bar' });
|
|
expect(retrieved.status).toBe('pending');
|
|
});
|
|
|
|
test('should update message status', async () => {
|
|
const messageId = await queue.sendMessage({
|
|
agent: 'test',
|
|
type: 'update-test'
|
|
});
|
|
|
|
const updated = await queue.updateMessage(messageId, {
|
|
status: 'processing',
|
|
progress: 50
|
|
});
|
|
|
|
expect(updated.status).toBe('processing');
|
|
expect(updated.progress).toBe(50);
|
|
expect(updated.version).toBe(2);
|
|
});
|
|
|
|
test('should mark message as complete', async () => {
|
|
const messageId = await queue.sendMessage({
|
|
agent: 'test',
|
|
type: 'complete-test'
|
|
});
|
|
|
|
await queue.markComplete(messageId, { result: 'success' });
|
|
|
|
const completed = await queue.getMessage(messageId);
|
|
expect(completed.status).toBe('completed');
|
|
expect(completed.result).toEqual({ result: 'success' });
|
|
expect(completed.completedAt).toBeDefined();
|
|
});
|
|
|
|
test('should mark message as failed', async () => {
|
|
const messageId = await queue.sendMessage({
|
|
agent: 'test',
|
|
type: 'fail-test'
|
|
});
|
|
|
|
await queue.markFailed(messageId, new Error('Test error'));
|
|
|
|
const failed = await queue.getMessage(messageId);
|
|
expect(failed.status).toBe('failed');
|
|
expect(failed.error).toBe('Test error');
|
|
expect(failed.failedAt).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Retry Logic', () => {
|
|
test('should retry a message', async () => {
|
|
const messageId = await queue.sendMessage({
|
|
agent: 'test',
|
|
type: 'retry-test'
|
|
});
|
|
|
|
const retried = await queue.retry(messageId);
|
|
expect(retried.retries).toBe(1);
|
|
expect(retried.status).toBe('retrying');
|
|
expect(retried.lastRetry).toBeDefined();
|
|
});
|
|
|
|
test('should respect max retries', async () => {
|
|
const messageId = await queue.sendMessage({
|
|
agent: 'test',
|
|
type: 'max-retry-test'
|
|
});
|
|
|
|
// Simulate max retries
|
|
for (let i = 0; i < queue.maxRetries; i++) {
|
|
await queue.retry(messageId);
|
|
}
|
|
|
|
const message = await queue.getMessage(messageId);
|
|
expect(message.retries).toBe(queue.maxRetries);
|
|
});
|
|
});
|
|
|
|
describe('Queue Management', () => {
|
|
test('should list messages by status', async () => {
|
|
// Create messages with different statuses
|
|
const activeId = await queue.sendMessage({ agent: 'test', type: 'active' });
|
|
const completedId = await queue.sendMessage({ agent: 'test', type: 'completed' });
|
|
await queue.markComplete(completedId, {});
|
|
|
|
const activeMessages = await queue.listMessages('active');
|
|
const completedMessages = await queue.listMessages('completed');
|
|
|
|
expect(activeMessages.length).toBe(1);
|
|
expect(activeMessages[0].id).toBe(activeId);
|
|
expect(completedMessages.length).toBe(1);
|
|
expect(completedMessages[0].id).toBe(completedId);
|
|
});
|
|
|
|
test('should get queue metrics', async () => {
|
|
// Create test messages
|
|
await queue.sendMessage({ agent: 'test1', type: 'test' });
|
|
await queue.sendMessage({ agent: 'test2', type: 'test' });
|
|
|
|
const completedId = await queue.sendMessage({ agent: 'test3', type: 'test' });
|
|
await queue.markComplete(completedId, {});
|
|
|
|
const metrics = await queue.getMetrics();
|
|
expect(metrics.queueDepth).toBe(2);
|
|
expect(metrics.completedCount).toBe(1);
|
|
expect(metrics.failedCount).toBe(0);
|
|
expect(metrics.avgProcessingTime).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
test('should cleanup old messages', async () => {
|
|
// Create an old message
|
|
const oldMessageId = await queue.sendMessage({ agent: 'test', type: 'old' });
|
|
const message = await queue.getMessage(oldMessageId);
|
|
|
|
// Manually set timestamp to old value
|
|
message.timestamp = Date.now() - (queue.ttl + 1000);
|
|
const messagePath = path.join(tempDir, 'queue', 'active', `${oldMessageId}.json`);
|
|
const fs = require('fs').promises;
|
|
await fs.writeFile(messagePath, JSON.stringify(message));
|
|
|
|
// Create a new message
|
|
await queue.sendMessage({ agent: 'test', type: 'new' });
|
|
|
|
// Run cleanup
|
|
await queue.cleanup();
|
|
|
|
// Check that old message is gone
|
|
await expect(queue.getMessage(oldMessageId)).rejects.toThrow();
|
|
|
|
// New message should still exist
|
|
const activeMessages = await queue.listMessages('active');
|
|
expect(activeMessages.length).toBe(1);
|
|
expect(activeMessages[0].type).toBe('new');
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', () => {
|
|
test('should throw error for non-existent message', async () => {
|
|
await expect(queue.getMessage('non-existent-id')).rejects.toThrow('Message non-existent-id not found');
|
|
});
|
|
|
|
test('should handle concurrent operations', async () => {
|
|
const operations = [];
|
|
|
|
// Send multiple messages concurrently
|
|
for (let i = 0; i < 10; i++) {
|
|
operations.push(queue.sendMessage({
|
|
agent: `agent-${i}`,
|
|
type: 'concurrent',
|
|
index: i
|
|
}));
|
|
}
|
|
|
|
const messageIds = await Promise.all(operations);
|
|
expect(messageIds.length).toBe(10);
|
|
expect(new Set(messageIds).size).toBe(10); // All IDs should be unique
|
|
});
|
|
});
|
|
}); |