Skip to main content
Glama
mkXultra
by mkXultra
StatsCollector.test.ts13.8 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { fs, vol } from 'memfs'; // Mock the fs module with memfs for testing vi.mock('fs', () => fs); vi.mock('fs/promises', () => fs.promises); describe('StatsCollector', () => { let statsCollector: any; beforeEach(async () => { // Set environment variable to use 'data' directory process.env.AGENT_COMM_DATA_DIR = 'data'; // Reset the virtual file system vol.reset(); // Create test directory structure with various data scenarios vol.fromJSON({ 'data/rooms.json': JSON.stringify({ rooms: { 'active-room': { name: 'active-room', createdAt: '2024-01-01T00:00:00Z', messageCount: 150 }, 'moderate-room': { name: 'moderate-room', createdAt: '2024-01-01T00:00:00Z', messageCount: 50 }, 'quiet-room': { name: 'quiet-room', createdAt: '2024-01-01T00:00:00Z', messageCount: 10 }, 'empty-room': { name: 'empty-room', createdAt: '2024-01-01T00:00:00Z', messageCount: 0 } } }), // Active room with lots of messages 'data/rooms/active-room/messages.jsonl': new Array(150).fill(0) .map((_, i) => `{"id":"msg-${i}","agentName":"agent${i % 5}","message":"Message ${i}","timestamp":"2024-01-01T${String(10 + Math.floor(i / 60)).padStart(2, '0')}:${String(i % 60).padStart(2, '0')}:00.000Z"}`) .join('\n'), 'data/rooms/active-room/presence.json': JSON.stringify({ users: { agent1: { status: 'online', lastSeen: '2024-01-01T15:00:00.000Z' }, agent2: { status: 'online', lastSeen: '2024-01-01T15:00:00.000Z' }, agent3: { status: 'offline', lastSeen: '2024-01-01T14:00:00.000Z' }, agent4: { status: 'online', lastSeen: '2024-01-01T15:00:00.000Z' }, agent5: { status: 'offline', lastSeen: '2024-01-01T13:00:00.000Z' } } }), // Moderate room 'data/rooms/moderate-room/messages.jsonl': new Array(45).fill(0) .map((_, i) => `{"id":"msg-${i}","agentName":"dev${i % 3}","message":"Development message ${i}","timestamp":"2024-01-02T10:${String(i).padStart(2, '0')}:00.000Z"}`) .join('\n'), 'data/rooms/moderate-room/presence.json': JSON.stringify({ users: { dev1: { status: 'online', lastSeen: '2024-01-02T12:00:00.000Z' }, dev2: { status: 'offline', lastSeen: '2024-01-02T11:00:00.000Z' }, dev3: { status: 'online', lastSeen: '2024-01-02T12:00:00.000Z' } } }), // Quiet room 'data/rooms/quiet-room/messages.jsonl': '{"id":"msg-1","agentName":"user1","message":"Hello","timestamp":"2024-01-03T10:00:00.000Z"}\n' + '{"id":"msg-2","agentName":"user2","message":"Hi","timestamp":"2024-01-03T10:01:00.000Z"}\n' + '{"id":"msg-3","agentName":"user1","message":"How are you?","timestamp":"2024-01-03T10:02:00.000Z"}\n' + '{"id":"msg-4","agentName":"user2","message":"Good, thanks!","timestamp":"2024-01-03T10:03:00.000Z"}\n' + '{"id":"msg-5","agentName":"user1","message":"Great!","timestamp":"2024-01-03T10:04:00.000Z"}', 'data/rooms/quiet-room/presence.json': JSON.stringify({ users: { user1: { status: 'offline', lastSeen: '2024-01-03T10:04:00.000Z' }, user2: { status: 'offline', lastSeen: '2024-01-03T10:03:00.000Z' } } }), // Empty room 'data/rooms/empty-room/messages.jsonl': '', 'data/rooms/empty-room/presence.json': JSON.stringify({ users: {} }) }); // Mock the StatsCollector const { StatsCollector } = await import('../../../src/features/management/StatsCollector'); statsCollector = new StatsCollector(); }); afterEach(() => { vi.clearAllMocks(); delete process.env.AGENT_COMM_DATA_DIR; }); describe('collectSystemStats', () => { it('should collect accurate system-wide statistics', async () => { const result = await statsCollector.collectSystemStatus(); expect(result).toMatchObject({ totalRooms: 4, totalOnlineUsers: 5, // 3 from active-room + 2 from moderate-room totalMessages: 200, // 150 + 45 + 5 + 0 totalStorageSize: expect.any(Number), rooms: expect.arrayContaining([ { name: 'active-room', onlineUsers: 3, totalMessages: 150, storageSize: expect.any(Number) }, { name: 'moderate-room', onlineUsers: 2, totalMessages: 45, storageSize: expect.any(Number) }, { name: 'quiet-room', onlineUsers: 0, totalMessages: 5, storageSize: expect.any(Number) }, { name: 'empty-room', onlineUsers: 0, totalMessages: 0, storageSize: 0 } ]) }); }); it('should calculate storage sizes correctly', async () => { const result = await statsCollector.collectSystemStatus(); // Verify that storage sizes are calculated correctly const activeRoomStats = result.rooms.find((r: any) => r.name === 'active-room'); const emptyRoomStats = result.rooms.find((r: any) => r.name === 'empty-room'); expect(activeRoomStats.storageSize).toBeGreaterThan(0); expect(emptyRoomStats.storageSize).toBe(0); // Total storage should be sum of all room storage const expectedTotalStorage = result.rooms.reduce((sum: number, room: any) => sum + room.storageSize, 0); expect(result.totalStorageSize).toBe(expectedTotalStorage); }); it('should handle rooms with missing files', async () => { // Create a new room without files to test robustness vol.reset(); vol.fromJSON({ 'data/rooms.json': JSON.stringify({ rooms: { 'missing-files-room': { name: 'missing-files-room', createdAt: '2024-01-01T00:00:00Z', messageCount: 0 } } }) // No messages.jsonl or presence.json files }); // Re-create StatsCollector with new filesystem const { StatsCollector } = await import('../../../src/features/management/StatsCollector'); const newStatsCollector = new StatsCollector(); const result = await newStatsCollector.collectSystemStatus(); const roomStats = result.rooms.find((r: any) => r.name === 'missing-files-room'); expect(roomStats).toMatchObject({ name: 'missing-files-room', onlineUsers: 0, // No presence file totalMessages: 0, // No messages file storageSize: 0 }); }); }); describe('collectRoomStats', () => { it('should collect detailed statistics for a specific room', async () => { const result = await statsCollector.getRoomStatistics('active-room'); expect(result).toMatchObject({ name: 'active-room', onlineUsers: 3, totalMessages: 150, storageSize: expect.any(Number) }); }); it('should handle empty room correctly', async () => { const result = await statsCollector.getRoomStatistics('empty-room'); expect(result).toMatchObject({ name: 'empty-room', onlineUsers: 0, totalMessages: 0, storageSize: 0 }); }); it('should count messages correctly', async () => { const result = await statsCollector.getRoomStatistics('quiet-room'); expect(result.totalMessages).toBe(5); }); it('should throw error for non-existent room', async () => { const result = await statsCollector.getRoomStatistics('non-existent-room'); expect(result).toMatchObject({ name: 'non-existent-room', onlineUsers: 0, totalMessages: 0, storageSize: 0 }); }); }); describe('collectMostActiveRoom', () => { it('should identify the most active room by message count', async () => { const result = await statsCollector.getMostActiveRoom(); expect(result).toMatchObject({ name: 'active-room', totalMessages: 150, onlineUsers: 3 }); }); it('should handle tie-breaking by online users', async () => { // Create two rooms with same message count vol.fromJSON({ 'data/rooms.json': JSON.stringify({ rooms: { 'room-a': { name: 'room-a', createdAt: '2024-01-01T00:00:00Z', messageCount: 100 }, 'room-b': { name: 'room-b', createdAt: '2024-01-01T00:00:00Z', messageCount: 100 } } }), 'data/rooms/room-a/messages.jsonl': new Array(100).fill('{"id":"msg","agentName":"agent","message":"test","timestamp":"2024-01-01T10:00:00.000Z"}').join('\n'), 'data/rooms/room-a/presence.json': JSON.stringify({ users: { agent1: { status: 'online', lastSeen: '2024-01-01T10:00:00.000Z' }, agent2: { status: 'offline', lastSeen: '2024-01-01T09:00:00.000Z' } } }), 'data/rooms/room-b/messages.jsonl': new Array(100).fill('{"id":"msg","agentName":"agent","message":"test","timestamp":"2024-01-02T10:00:00.000Z"}').join('\n'), 'data/rooms/room-b/presence.json': JSON.stringify({ users: { agent1: { status: 'online', lastSeen: '2024-01-02T10:00:00.000Z' }, agent2: { status: 'online', lastSeen: '2024-01-02T10:00:00.000Z' }, agent3: { status: 'online', lastSeen: '2024-01-02T10:00:00.000Z' } } }) }); const result = await statsCollector.getMostActiveRoom(); // getMostActiveRoom only considers message count, not online users for tie-breaking // Since both have same message count, it should return the first one found expect(result.name).toBe('room-a'); expect(result.totalMessages).toBe(100); }); it('should return null when no rooms exist', async () => { vol.fromJSON({ 'data/rooms.json': JSON.stringify({ rooms: {} }) }); const result = await statsCollector.getMostActiveRoom(); expect(result).toBeNull(); }); }); describe('performance and memory efficiency', () => { it('should handle large message files without loading everything into memory', async () => { // Create a very large message file (simulate 50,000 messages) const largeMessageFile = new Array(50000).fill(0) .map((_, i) => `{"id":"msg-${i}","agentName":"agent${i % 10}","message":"Large message content ${i} with some additional text to make it bigger","timestamp":"2024-01-01T${String(10 + Math.floor(i / 3600)).padStart(2, '0')}:${String(Math.floor((i % 3600) / 60)).padStart(2, '0')}:${String(i % 60).padStart(2, '0')}.000Z"}`) .join('\n'); vol.fromJSON({ 'data/rooms.json': JSON.stringify({ rooms: { 'huge-room': { name: 'huge-room', createdAt: '2024-01-01T00:00:00Z', messageCount: 50000 } } }), 'data/rooms/huge-room/messages.jsonl': largeMessageFile, 'data/rooms/huge-room/presence.json': JSON.stringify({ users: new Array(10).fill(0).reduce((acc, _, i) => { acc[`agent${i}`] = { status: i % 2 === 0 ? 'online' : 'offline', lastSeen: '2024-01-01T15:00:00.000Z' }; return acc; }, {}) }) }); const startTime = Date.now(); const result = await statsCollector.getRoomStatistics('huge-room'); const duration = Date.now() - startTime; expect(result.totalMessages).toBe(50000); expect(result.onlineUsers).toBe(5); // Half of 10 agents expect(duration).toBeLessThan(2000); // Should complete within 2 seconds // Verify total message count expect(result.totalMessages).toBe(50000); }); it('should handle large files efficiently', async () => { // Currently DataScanner uses readFile, not streaming // This test verifies it can handle large files without errors const startTime = Date.now(); const result = await statsCollector.getRoomStatistics('active-room'); const duration = Date.now() - startTime; expect(result.totalMessages).toBe(150); expect(duration).toBeLessThan(1000); // Should complete within 1 second }); }); describe('error handling', () => { it('should handle corrupted JSON files gracefully', async () => { vol.fromJSON({ 'data/rooms/active-room/presence.json': 'invalid json content' }); const result = await statsCollector.getRoomStatistics('active-room'); // Should default to empty presence data expect(result.onlineUsers).toBe(0); }); it('should handle permission errors', async () => { // Mock fs.stat to throw permission error vi.spyOn(fs.promises, 'stat').mockRejectedValueOnce( new Error('EACCES: permission denied') ); const result = await statsCollector.getRoomStatistics('active-room'); // Should return default values on error expect(result.totalMessages).toBe(0); expect(result.storageSize).toBe(0); }); it('should handle malformed message lines', async () => { vol.fromJSON({ 'data/rooms/active-room/messages.jsonl': '{"id":"msg-1","agentName":"agent1","message":"Valid message","timestamp":"2024-01-01T10:00:00.000Z"}\n' + 'invalid json line\n' + '{"id":"msg-2","agentName":"agent2","message":"Another valid message","timestamp":"2024-01-01T10:01:00.000Z"}' }); const result = await statsCollector.getRoomStatistics('active-room'); // Should count only valid JSON lines (2 valid out of 3 total) expect(result.totalMessages).toBe(2); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mkXultra/agent-communication-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server