Skip to main content
Glama
lsp-client-lifecycle.test.ts5.13 kB
import { describe, it, beforeEach } from 'node:test'; import assert from 'node:assert'; import { LSPClient } from '../src/lsp-client.js'; import { EventEmitter } from 'events'; describe('LSPClient Lifecycle', () => { describe('shutdown behavior', () => { it('should set shutdown flag when disconnect is called', () => { const client = new LSPClient(); assert.strictEqual(client.shouldReconnect(), true, 'should allow reconnect initially'); client.disconnect(); assert.strictEqual(client.shouldReconnect(), false, 'should not allow reconnect after disconnect'); }); it('should prevent reconnection after shutdown', () => { const client = new LSPClient(); client.disconnect(); // shouldReconnect should return false assert.strictEqual(client.shouldReconnect(), false); }); it('should clear diagnostics cache on disconnect', () => { const client = new LSPClient(); // Verify cache is cleared (getAllDiagnostics returns empty object) client.disconnect(); const diagnostics = client.getAllDiagnostics(); assert.deepStrictEqual(diagnostics, {}); }); }); describe('reconnection guard', () => { it('shouldReconnect returns true before disconnect', () => { const client = new LSPClient(); assert.strictEqual(client.shouldReconnect(), true); }); it('shouldReconnect returns false after disconnect', () => { const client = new LSPClient(); client.disconnect(); assert.strictEqual(client.shouldReconnect(), false); }); it('shouldReconnect is idempotent', () => { const client = new LSPClient(); client.disconnect(); assert.strictEqual(client.shouldReconnect(), false); assert.strictEqual(client.shouldReconnect(), false); assert.strictEqual(client.shouldReconnect(), false); }); }); describe('socket cleanup', () => { it('should set socket to null after disconnect', () => { const client = new LSPClient(); // Disconnect should set socket to null client.disconnect(); // We can't directly test private socket property, but we can verify // that disconnect doesn't throw and cache is cleared const diagnostics = client.getAllDiagnostics(); assert.deepStrictEqual(diagnostics, {}); }); it('disconnect should be safe to call multiple times', () => { const client = new LSPClient(); assert.doesNotThrow(() => { client.disconnect(); client.disconnect(); client.disconnect(); }); }); }); describe('event emission', () => { it('should be an EventEmitter', () => { const client = new LSPClient(); assert.ok(client instanceof EventEmitter); }); it('should support event listeners', () => { const client = new LSPClient(); let eventFired = false; client.on('test-event', () => { eventFired = true; }); client.emit('test-event'); assert.strictEqual(eventFired, true); }); }); describe('port validation', () => { it('should reject invalid port numbers', () => { process.env.GODOT_LSP_PORT = '99999'; const client = new LSPClient(); assert.rejects( client.connect(), /Invalid GODOT_LSP_PORT/ ); delete process.env.GODOT_LSP_PORT; }); it('should reject negative ports', () => { process.env.GODOT_LSP_PORT = '-1'; const client = new LSPClient(); assert.rejects( client.connect(), /Invalid GODOT_LSP_PORT/ ); delete process.env.GODOT_LSP_PORT; }); it('should reject zero port', () => { process.env.GODOT_LSP_PORT = '0'; const client = new LSPClient(); assert.rejects( client.connect(), /Invalid GODOT_LSP_PORT/ ); delete process.env.GODOT_LSP_PORT; }); it('should reject non-numeric ports', () => { process.env.GODOT_LSP_PORT = 'abc'; const client = new LSPClient(); assert.rejects( client.connect(), /Invalid GODOT_LSP_PORT/ ); delete process.env.GODOT_LSP_PORT; }); }); describe('buffer limits', () => { it('should have 10MB max buffer size', () => { const client = new LSPClient(); const maxSize = (client as any).MAX_BUFFER_SIZE; assert.strictEqual(maxSize, 10 * 1024 * 1024); }); }); describe('message parsing', () => { it('should handle malformed JSON without crashing', () => { const client = new LSPClient(); const handleData = (client as any).handleData.bind(client); const malformedMessage = Buffer.from('Content-Length: 5\r\n\r\n{bad}'); assert.doesNotThrow(() => handleData(malformedMessage)); }); it('should continue processing after JSON error', () => { const client = new LSPClient(); const handleData = (client as any).handleData.bind(client); const badMessage = Buffer.from('Content-Length: 5\r\n\r\n{bad}'); handleData(badMessage); assert.strictEqual(client.shouldReconnect(), true); }); }); });

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/ryanmazzolini/minimal-godot-mcp'

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