Skip to main content
Glama
flexible-command-configuration.test.ts13 kB
/** * Story 7: Flexible Command Configuration Unit Tests * * Unit tests for FlexibleCommandConfiguration class that supports JSON-based * command configuration with validation and error handling. * * Tests follow TDD red-green-refactor cycle: * 1. Write failing test (red) * 2. Implement minimal code to pass (green) * 3. Refactor for clean code * * CRITICAL: No mocks in production code - tests use real configuration validation */ import { FlexibleCommandConfiguration, ConfigurationValidationError } from './flexible-command-configuration'; describe('FlexibleCommandConfiguration', () => { describe('constructor validation', () => { test('should throw error for invalid workflowTimeout', () => { const invalidConfig = { preWebSocketCommands: [], postWebSocketCommands: [], workflowTimeout: -1000 }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('workflowTimeout must be positive'); }); test('should throw error for zero workflowTimeout', () => { const invalidConfig = { preWebSocketCommands: [], postWebSocketCommands: [], workflowTimeout: 0 }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('workflowTimeout must be positive'); }); test('should throw error for empty sessionName', () => { const invalidConfig = { preWebSocketCommands: [], postWebSocketCommands: [], sessionName: '' }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('sessionName cannot be empty'); }); test('should throw error for whitespace-only sessionName', () => { const invalidConfig = { preWebSocketCommands: [], postWebSocketCommands: [], sessionName: ' ' }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('sessionName cannot be empty'); }); test('should accept valid minimal configuration', () => { const validConfig = { preWebSocketCommands: [], postWebSocketCommands: [] }; expect(() => new FlexibleCommandConfiguration(validConfig)) .not.toThrow(); }); test('should accept valid full configuration', () => { const validConfig = { preWebSocketCommands: [ 'ssh_connect {"host": "localhost", "username": "test_user"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"command": "whoami"}'} ], workflowTimeout: 30000, sessionName: 'test-session' }; expect(() => new FlexibleCommandConfiguration(validConfig)) .not.toThrow(); }); }); describe('command syntax validation', () => { test('should reject malformed JSON in preWebSocketCommands', () => { const invalidConfig = { preWebSocketCommands: [ 'ssh_connect {invalid json}' ], postWebSocketCommands: [] }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('Invalid JSON in preWebSocketCommand at index 0: ssh_connect {invalid json}'); }); test('should reject malformed JSON in postWebSocketCommands', () => { const invalidConfig = { preWebSocketCommands: [], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {malformed: json'} ] }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('Invalid JSON in postWebSocketCommand at index 0: ssh_exec {malformed: json'); }); test('should reject commands without JSON parameters', () => { const invalidConfig = { preWebSocketCommands: [ 'ssh_connect' ], postWebSocketCommands: [] }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('Command must have JSON parameters: ssh_connect'); }); test('should reject commands with only tool name', () => { const invalidConfig = { preWebSocketCommands: [], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec'} ] }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('Command must have JSON parameters: ssh_exec'); }); test('should accept valid MCP tool commands', () => { const validConfig = { preWebSocketCommands: [ 'ssh_connect {"host": "localhost", "username": "test_user"}', 'ssh_exec {"command": "pwd"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"command": "whoami"}'}, {initiator: 'mcp-client', command: 'ssh_disconnect {}'} ] }; expect(() => new FlexibleCommandConfiguration(validConfig)) .not.toThrow(); }); test('should accept commands with empty JSON object', () => { const validConfig = { preWebSocketCommands: [ 'ssh_disconnect {}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_status {}'} ] }; expect(() => new FlexibleCommandConfiguration(validConfig)) .not.toThrow(); }); }); describe('configuration conversion', () => { test('should convert JSON string commands to PreWebSocketCommand objects', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [ 'ssh_connect {"host": "localhost", "username": "test_user"}', 'ssh_exec {"command": "pwd"}' ], postWebSocketCommands: [] }); const preCommands = config.getPreWebSocketCommands(); expect(preCommands).toHaveLength(2); expect(preCommands[0]).toEqual({ tool: 'ssh_connect', args: { host: 'localhost', username: 'test_user' } }); expect(preCommands[1]).toEqual({ tool: 'ssh_exec', args: { command: 'pwd' } }); }); test('should convert JSON string commands with empty objects', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [ 'ssh_disconnect {}' ], postWebSocketCommands: [] }); const preCommands = config.getPreWebSocketCommands(); expect(preCommands).toHaveLength(1); expect(preCommands[0]).toEqual({ tool: 'ssh_disconnect', args: {} }); }); test('should handle empty command arrays', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [], postWebSocketCommands: [] }); expect(config.getPreWebSocketCommands()).toHaveLength(0); expect(config.getPostWebSocketCommands()).toHaveLength(0); }); test('should preserve postWebSocketCommands as strings', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"command": "whoami"}'}, {initiator: 'mcp-client', command: 'ssh_disconnect {}'} ] }); const postCommands = config.getPostWebSocketCommands(); expect(postCommands).toHaveLength(2); expect(postCommands[0]).toBe('ssh_exec {"command": "whoami"}'); expect(postCommands[1]).toBe('ssh_disconnect {}'); }); }); describe('configuration properties', () => { test('should provide default values for optional properties', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [], postWebSocketCommands: [] }); expect(config.getWorkflowTimeout()).toBe(10000); expect(config.getSessionName()).toBe('flexible-config-session'); }); test('should use provided values for optional properties', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [], postWebSocketCommands: [], workflowTimeout: 25000, sessionName: 'custom-session' }); expect(config.getWorkflowTimeout()).toBe(25000); expect(config.getSessionName()).toBe('custom-session'); }); test('should provide comprehensive response collector config', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [ 'ssh_connect {"host": "localhost", "username": "test_user"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"command": "whoami"}'} ], workflowTimeout: 20000, sessionName: 'integration-test' }); const collectorConfig = config.getComprehensiveResponseCollectorConfig(); expect(collectorConfig.workflowTimeout).toBe(20000); expect(collectorConfig.sessionName).toBe('integration-test'); expect(collectorConfig.preWebSocketCommands).toHaveLength(1); expect(collectorConfig.preWebSocketCommands![0]).toEqual({ tool: 'ssh_connect', args: { host: 'localhost', username: 'test_user' } }); expect(collectorConfig.postWebSocketCommands).toHaveLength(1); expect(collectorConfig.postWebSocketCommands![0]).toBe('ssh_exec {"command": "whoami"}'); }); }); describe('complex scenarios', () => { test('should handle multiple SSH session commands', () => { const config = new FlexibleCommandConfiguration({ preWebSocketCommands: [ 'ssh_create_session {"sessionName": "session1"}', 'ssh_connect {"host": "host1", "username": "user1"}', 'ssh_exec {"command": "pwd"}', 'ssh_create_session {"sessionName": "session2"}', 'ssh_connect {"host": "host2", "username": "user2"}', 'ssh_exec {"command": "ls -la"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"command": "whoami"}'}, {initiator: 'mcp-client', command: 'ssh_disconnect {}'}, {initiator: 'mcp-client', command: 'ssh_switch_session {"sessionName": "session1"}'}, {initiator: 'mcp-client', command: 'ssh_exec {"command": "date"}'}, {initiator: 'mcp-client', command: 'ssh_disconnect {}'} ], workflowTimeout: 45000, sessionName: 'multi-session-test' }); const preCommands = config.getPreWebSocketCommands(); const postCommands = config.getPostWebSocketCommands(); expect(preCommands).toHaveLength(6); expect(postCommands).toHaveLength(5); // Verify first session commands expect(preCommands[0]).toEqual({ tool: 'ssh_create_session', args: { sessionName: 'session1' } }); expect(preCommands[1]).toEqual({ tool: 'ssh_connect', args: { host: 'host1', username: 'user1' } }); // Verify second session commands expect(preCommands[3]).toEqual({ tool: 'ssh_create_session', args: { sessionName: 'session2' } }); expect(preCommands[4]).toEqual({ tool: 'ssh_connect', args: { host: 'host2', username: 'user2' } }); // Verify post commands expect(postCommands[2]).toBe('ssh_switch_session {"sessionName": "session1"}'); }); test('should validate all commands in complex scenarios', () => { const invalidConfig = { preWebSocketCommands: [ 'ssh_create_session {"sessionName": "session1"}', 'ssh_connect {invalid json}', // Invalid JSON 'ssh_exec {"command": "pwd"}' ], postWebSocketCommands: [ 'ssh_exec {"command": "whoami"}', 'ssh_disconnect' // Missing JSON parameters ] }; expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow(ConfigurationValidationError); expect(() => new FlexibleCommandConfiguration(invalidConfig)) .toThrow('Invalid JSON in preWebSocketCommand at index 1: ssh_connect {invalid json}'); }); }); });

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/LightspeedDMS/ssh-mcp'

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