UNPKG

osc-mcp-server

Version:

Model Context Protocol server for OSC (Open Sound Control) endpoint management

434 lines 18.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const manager_1 = require("./manager"); const index_1 = require("../types/index"); jest.mock('./endpoint'); describe('OSCManager', () => { let manager; let mockEndpoint; beforeEach(() => { mockEndpoint = { getId: jest.fn(), getPort: jest.fn(), getStatus: jest.fn(), getMessageBuffer: jest.fn(), isActive: jest.fn(), startListening: jest.fn(), stopListening: jest.fn(), on: jest.fn(), emit: jest.fn(), removeAllListeners: jest.fn(), }; require('./endpoint').createOSCEndpoint.mockReturnValue(mockEndpoint); manager = (0, manager_1.createOSCManager)(); }); afterEach(() => { jest.clearAllMocks(); }); describe('createEndpoint', () => { const testConfig = { port: 8000, bufferSize: 100, addressFilters: ['/test/*'], }; beforeEach(() => { mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: ['/test/*'], createdAt: new Date(), messageCount: 0, }); mockEndpoint.startListening.mockResolvedValue(); }); it('should create endpoint successfully', async () => { const endpointCreatedHandler = jest.fn(); manager.on('endpointCreated', endpointCreatedHandler); const response = await manager.createEndpoint(testConfig); expect(response).toEqual({ endpointId: 'endpoint-1', port: 8000, status: 'active', message: 'OSC endpoint created successfully on port 8000', }); expect(mockEndpoint.startListening).toHaveBeenCalled(); expect(endpointCreatedHandler).toHaveBeenCalledWith(expect.objectContaining({ id: 'endpoint-1', port: 8000, status: 'active', })); }); it('should set up event handlers for endpoint', async () => { await manager.createEndpoint(testConfig); expect(mockEndpoint.on).toHaveBeenCalledWith('message', expect.any(Function)); expect(mockEndpoint.on).toHaveBeenCalledWith('error', expect.any(Function)); expect(mockEndpoint.on).toHaveBeenCalledWith('statusChange', expect.any(Function)); }); it('should prevent creating endpoint on port already in use', async () => { await manager.createEndpoint(testConfig); const response = await manager.createEndpoint(testConfig); expect(response).toEqual({ endpointId: '', port: 8000, status: 'error', message: 'Port 8000 is already in use. Please try a different port.', }); }); it('should handle endpoint creation errors', async () => { mockEndpoint.startListening.mockRejectedValue(new Error('Port in use')); const response = await manager.createEndpoint(testConfig); expect(response).toEqual({ endpointId: '', port: 8000, status: 'error', message: "Operation 'createEndpoint' failed: Port in use", }); }); it('should generate unique endpoint IDs', async () => { const config1 = { port: 8001 }; const config2 = { port: 8002 }; mockEndpoint.getId.mockReturnValueOnce('endpoint-1').mockReturnValueOnce('endpoint-2'); mockEndpoint.getPort.mockReturnValueOnce(8001).mockReturnValueOnce(8002); const response1 = await manager.createEndpoint(config1); const response2 = await manager.createEndpoint(config2); expect(response1.endpointId).toBe('endpoint-1'); expect(response2.endpointId).toBe('endpoint-2'); }); }); describe('stopEndpoint', () => { beforeEach(async () => { mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.startListening.mockResolvedValue(); mockEndpoint.stopListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); }); it('should stop endpoint successfully', async () => { const endpointStoppedHandler = jest.fn(); manager.on('endpointStopped', endpointStoppedHandler); const response = await manager.stopEndpoint('endpoint-1'); expect(response).toEqual({ endpointId: 'endpoint-1', message: 'Endpoint endpoint-1 stopped successfully', }); expect(mockEndpoint.stopListening).toHaveBeenCalled(); expect(endpointStoppedHandler).toHaveBeenCalledWith('endpoint-1'); }); it('should handle stopping non-existent endpoint', async () => { const response = await manager.stopEndpoint('non-existent'); expect(response).toEqual({ endpointId: 'non-existent', message: "Endpoint 'non-existent' not found. Please check the endpoint ID and try again.", }); }); it('should handle errors during endpoint stop', async () => { mockEndpoint.stopListening.mockRejectedValue(new Error('Stop failed')); const response = await manager.stopEndpoint('endpoint-1'); expect(response).toEqual({ endpointId: 'endpoint-1', message: "Operation 'stopEndpoint' failed: Stop failed", }); }); it('should remove endpoint from registry after stopping', async () => { await manager.stopEndpoint('endpoint-1'); const status = manager.getEndpointStatus('endpoint-1'); expect(status.endpoints).toHaveLength(0); }); }); describe('getEndpointStatus', () => { beforeEach(async () => { mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.startListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); }); it('should return status for specific endpoint', () => { const response = manager.getEndpointStatus('endpoint-1'); expect(response.endpoints).toHaveLength(1); expect(response.endpoints[0]).toEqual(expect.objectContaining({ id: 'endpoint-1', port: 8000, status: 'active', })); }); it('should return empty array for non-existent endpoint', () => { const response = manager.getEndpointStatus('non-existent'); expect(response.endpoints).toHaveLength(0); }); it('should return all endpoints when no ID specified', () => { const response = manager.getEndpointStatus(); expect(response.endpoints).toHaveLength(1); expect(response.endpoints[0]?.id).toBe('endpoint-1'); }); }); describe('getMessages', () => { let mockBuffer; beforeEach(async () => { mockBuffer = { getMessages: jest.fn(), getMessageCount: jest.fn(), }; mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.getMessageBuffer.mockReturnValue(mockBuffer); mockEndpoint.startListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); }); it('should get messages from specific endpoint', () => { const testMessages = [ { timestamp: new Date(), address: '/test', typeTags: 'f', arguments: [440.0], sourceIp: '192.168.1.100', sourcePort: 57120, }, ]; mockBuffer.getMessages.mockReturnValue(testMessages); mockBuffer.getMessageCount.mockReturnValue(1); const response = manager.getMessages('endpoint-1'); expect(response).toEqual({ messages: testMessages, totalCount: 1, filteredCount: 1, }); expect(mockBuffer.getMessages).toHaveBeenCalledWith({}); }); it('should get messages from all endpoints', () => { const testMessages = [ { timestamp: new Date(), address: '/test', typeTags: 'f', arguments: [440.0], sourceIp: '192.168.1.100', sourcePort: 57120, }, ]; mockBuffer.getMessages.mockReturnValue(testMessages); mockBuffer.getMessageCount.mockReturnValue(1); const response = manager.getMessages(); expect(response).toEqual({ messages: testMessages, totalCount: 1, filteredCount: 1, }); }); it('should pass query parameters to buffer', () => { const query = { addressPattern: '/synth/*', limit: 10 }; mockBuffer.getMessages.mockReturnValue([]); mockBuffer.getMessageCount.mockReturnValue(0); manager.getMessages('endpoint-1', query); expect(mockBuffer.getMessages).toHaveBeenCalledWith(query); }); it('should handle non-existent endpoint', () => { const response = manager.getMessages('non-existent'); expect(response).toEqual({ messages: [], totalCount: 0, filteredCount: 0, }); }); }); describe('getRecentMessages', () => { let mockBuffer; beforeEach(async () => { mockBuffer = { getMessages: jest.fn(), getMessageCount: jest.fn(), }; mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.getMessageBuffer.mockReturnValue(mockBuffer); mockEndpoint.startListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); }); it('should get recent messages with time window', () => { const testMessages = [ { timestamp: new Date(), address: '/test', typeTags: 'f', arguments: [440.0], sourceIp: '192.168.1.100', sourcePort: 57120, }, ]; mockBuffer.getMessages.mockReturnValue(testMessages); mockBuffer.getMessageCount.mockReturnValue(1); const messages = manager.getRecentMessages(60, 'endpoint-1', 10); expect(messages).toEqual(testMessages); expect(mockBuffer.getMessages).toHaveBeenCalledWith(expect.objectContaining({ since: expect.any(Date), limit: 10, })); }); }); describe('shutdown', () => { beforeEach(async () => { mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.startListening.mockResolvedValue(); mockEndpoint.stopListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); }); it('should stop all endpoints', async () => { await manager.shutdown(); expect(mockEndpoint.stopListening).toHaveBeenCalled(); expect(manager.getTotalEndpointCount()).toBe(0); }); it('should handle errors during shutdown gracefully', async () => { mockEndpoint.stopListening.mockRejectedValue(new Error('Stop failed')); const consoleSpy = jest.spyOn(console, 'error').mockImplementation(); await manager.shutdown(); expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Error stopping endpoint'), expect.any(Error)); consoleSpy.mockRestore(); }); }); describe('utility methods', () => { beforeEach(async () => { mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.startListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); }); it('should return correct active endpoint count', () => { expect(manager.getActiveEndpointCount()).toBe(1); }); it('should return correct total endpoint count', () => { expect(manager.getTotalEndpointCount()).toBe(1); }); it('should check if port is in use', () => { expect(manager.isPortInUse(8000)).toBe(true); expect(manager.isPortInUse(8001)).toBe(false); }); it('should return used ports', () => { const usedPorts = manager.getUsedPorts(); expect(usedPorts).toEqual([8000]); }); it('should handle inactive endpoints in port checks', () => { mockEndpoint.isActive.mockReturnValue(false); expect(manager.isPortInUse(8000)).toBe(false); expect(manager.getUsedPorts()).toEqual([]); expect(manager.getActiveEndpointCount()).toBe(0); }); }); describe('event forwarding', () => { let messageHandler; let errorHandler; beforeEach(async () => { mockEndpoint.getId.mockReturnValue('endpoint-1'); mockEndpoint.getPort.mockReturnValue(8000); mockEndpoint.isActive.mockReturnValue(true); mockEndpoint.getStatus.mockReturnValue({ id: 'endpoint-1', port: 8000, status: 'active', bufferSize: 100, addressFilters: [], createdAt: new Date(), messageCount: 0, }); mockEndpoint.startListening.mockResolvedValue(); await manager.createEndpoint({ port: 8000 }); const onCalls = mockEndpoint.on.mock.calls; messageHandler = onCalls.find((call) => call[0] === 'message')?.[1]; errorHandler = onCalls.find((call) => call[0] === 'error')?.[1]; }); it('should forward message events', () => { const messageReceivedHandler = jest.fn(); manager.on('messageReceived', messageReceivedHandler); const testMessage = { timestamp: new Date(), address: '/test', typeTags: 'f', arguments: [440.0], sourceIp: '192.168.1.100', sourcePort: 57120, }; if (messageHandler) { messageHandler(testMessage); } expect(messageReceivedHandler).toHaveBeenCalledWith('endpoint-1', testMessage); }); it('should forward error events', () => { const endpointErrorHandler = jest.fn(); manager.on('endpointError', endpointErrorHandler); const testError = { code: index_1.ErrorCode.NETWORK_ERROR, message: 'Test error', }; if (errorHandler) { errorHandler(testError); } expect(endpointErrorHandler).toHaveBeenCalledWith('endpoint-1', testError); }); }); }); //# sourceMappingURL=manager.test.js.map