Skip to main content
Glama
tcp-transport.test.ts18.9 kB
import { describe, expect, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; import * as grpc from '@grpc/grpc-js'; import { rmSync, existsSync } from 'node:fs'; import { startServer } from '../server/index.js'; import { SandboxClient } from '../client/index.js'; // Helper to generate unique IDs for test isolation const uniqueId = () => `${Date.now()}-${Math.random().toString(36).slice(2)}`; // Hardcoded ports - src uses 51xxx, dist uses 51500+ const isDistBuild = import.meta.url.includes('/dist/'); const PORT_BASE = isDistBuild ? 51500 : 51000; describe('TCP Transport', () => { const testPort = PORT_BASE + 1; const testHost = '127.0.0.1'; const testCacheDir = `/tmp/prodisco-cache-tcp-${uniqueId()}`; let server: grpc.Server; let client: SandboxClient; beforeAll(async () => { // Start server with TCP transport server = await startServer({ useTcp: true, tcpHost: testHost, tcpPort: testPort, cacheDir: testCacheDir, }); // Create client with TCP transport client = new SandboxClient({ useTcp: true, tcpHost: testHost, tcpPort: testPort, }); // Wait for server to be healthy const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); }); afterAll(async () => { // Close client client.close(); // Shutdown server await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) { server.forceShutdown(); } resolve(); }); }); }); describe('Health Check over TCP', () => { it('returns healthy status', async () => { const result = await client.healthCheck(); expect(result.healthy).toBe(true); }); it('returns kubernetes context', async () => { const result = await client.healthCheck(); expect(result.kubernetesContext).toBeDefined(); expect(typeof result.kubernetesContext).toBe('string'); }); }); describe('Code Execution over TCP', () => { it('executes simple code', async () => { const result = await client.execute({ code: 'console.log("hello from TCP")', }); expect(result.success).toBe(true); expect(result.output).toBe('hello from TCP'); expect(result.error).toBeUndefined(); }); it('handles TypeScript code', async () => { const result = await client.execute({ code: ` interface User { name: string; } const user: User = { name: "TCP Test" }; console.log(user.name); `, }); expect(result.success).toBe(true); expect(result.output).toBe('TCP Test'); }); it('handles async code', async () => { const result = await client.execute({ code: ` await new Promise(r => setTimeout(r, 10)); console.log("async TCP complete"); `, }); expect(result.success).toBe(true); expect(result.output).toBe('async TCP complete'); }); it('handles execution errors', async () => { const result = await client.execute({ code: 'throw new Error("TCP error")', }); expect(result.success).toBe(false); expect(result.error).toBe('TCP error'); }); it('respects timeout', async () => { const result = await client.execute({ code: 'await new Promise(r => setTimeout(r, 10000))', timeoutMs: 100, }); expect(result.success).toBe(false); expect(result.error).toBe('Script execution timed out'); }); }); describe('Concurrent Requests over TCP', () => { it('handles multiple concurrent executions', async () => { const requests = Array.from({ length: 10 }, (_, i) => ({ code: `console.log("tcp concurrent ${i}")`, })); const results = await Promise.all( requests.map(req => client.execute(req)) ); expect(results.every(r => r.success)).toBe(true); results.forEach((result, i) => { expect(result.output).toBe(`tcp concurrent ${i}`); }); }); }); }); describe('TCP Transport with Environment Variables', () => { const testPort = PORT_BASE + 2; const testHost = '127.0.0.1'; const testCacheDir = `/tmp/prodisco-cache-tcp-env-${uniqueId()}`; let server: grpc.Server; let client: SandboxClient; let originalTcpHost: string | undefined; let originalTcpPort: string | undefined; let originalUseTcp: string | undefined; beforeAll(async () => { // Save original env vars originalTcpHost = process.env.SANDBOX_TCP_HOST; originalTcpPort = process.env.SANDBOX_TCP_PORT; originalUseTcp = process.env.SANDBOX_USE_TCP; // Set env vars process.env.SANDBOX_TCP_HOST = testHost; process.env.SANDBOX_TCP_PORT = String(testPort); process.env.SANDBOX_USE_TCP = 'true'; // Start server using env vars server = await startServer({ cacheDir: testCacheDir, }); // Create client using env vars client = new SandboxClient(); // Wait for server to be healthy const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); }); afterAll(async () => { // Close client client.close(); // Shutdown server await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) { server.forceShutdown(); } resolve(); }); }); // Restore original env vars if (originalTcpHost !== undefined) { process.env.SANDBOX_TCP_HOST = originalTcpHost; } else { delete process.env.SANDBOX_TCP_HOST; } if (originalTcpPort !== undefined) { process.env.SANDBOX_TCP_PORT = originalTcpPort; } else { delete process.env.SANDBOX_TCP_PORT; } if (originalUseTcp !== undefined) { process.env.SANDBOX_USE_TCP = originalUseTcp; } else { delete process.env.SANDBOX_USE_TCP; } }); it('connects using environment variables', async () => { const result = await client.healthCheck(); expect(result.healthy).toBe(true); }); it('executes code over TCP configured by env vars', async () => { const result = await client.execute({ code: 'console.log("env var TCP")', }); expect(result.success).toBe(true); expect(result.output).toBe('env var TCP'); }); }); describe('SandboxClient TCP Options', () => { it('uses TCP when useTcp is true', () => { const client = new SandboxClient({ useTcp: true }); expect(client).toBeInstanceOf(SandboxClient); client.close(); }); it('uses TCP when tcpHost is specified', () => { const client = new SandboxClient({ tcpHost: 'localhost' }); expect(client).toBeInstanceOf(SandboxClient); client.close(); }); it('uses TCP when tcpPort is specified', () => { const client = new SandboxClient({ tcpPort: 50051 }); expect(client).toBeInstanceOf(SandboxClient); client.close(); }); it('uses Unix socket by default', () => { const client = new SandboxClient({ socketPath: '/tmp/test.sock' }); expect(client).toBeInstanceOf(SandboxClient); client.close(); }); it('waitForHealthy returns false for non-existent TCP server', async () => { const client = new SandboxClient({ useTcp: true, tcpHost: 'localhost', tcpPort: 59999, // Unlikely to be in use }); const result = await client.waitForHealthy(100, 50); expect(result).toBe(false); client.close(); }); }); describe('TCP Transport - Script Caching', () => { const testPort = PORT_BASE + 3; const testHost = '127.0.0.1'; const testCacheDir = `/tmp/prodisco-cache-tcp-caching-${uniqueId()}`; let server: grpc.Server; let client: SandboxClient; beforeAll(async () => { server = await startServer({ useTcp: true, tcpHost: testHost, tcpPort: testPort, cacheDir: testCacheDir, }); client = new SandboxClient({ useTcp: true, tcpHost: testHost, tcpPort: testPort, }); await client.waitForHealthy(5000); }); afterAll(async () => { client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); it('caches successful executions over TCP', async () => { const code = `console.log("tcp cache test ${uniqueId()}")`; const result = await client.execute({ code }); expect(result.success).toBe(true); expect(result.cached).toBeDefined(); expect(result.cached!.name).toMatch(/^script-.*\.ts$/); }); it('can execute cached scripts over TCP', async () => { const uniqueValue = `tcp-cached-${uniqueId()}`; const code = `console.log("${uniqueValue}")`; // First execution - gets cached const firstResult = await client.execute({ code }); expect(firstResult.success).toBe(true); expect(firstResult.cached).toBeDefined(); // Execute from cache const cachedResult = await client.execute({ cached: firstResult.cached!.name, }); expect(cachedResult.success).toBe(true); expect(cachedResult.output).toBe(uniqueValue); }); it('returns error for non-existent cached script over TCP', async () => { const result = await client.execute({ cached: 'non-existent-tcp-script-12345', }); expect(result.success).toBe(false); expect(result.error).toContain('not found'); }); }); describe('TCP Transport - Server Binding Options', () => { it('binds to localhost', async () => { const testPort = PORT_BASE + 4; const testCacheDir = `/tmp/prodisco-cache-tcp-localhost-${uniqueId()}`; const server = await startServer({ useTcp: true, tcpHost: 'localhost', tcpPort: testPort, cacheDir: testCacheDir, }); const client = new SandboxClient({ useTcp: true, tcpHost: 'localhost', tcpPort: testPort, }); const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); const result = await client.execute({ code: 'console.log("localhost test")' }); expect(result.success).toBe(true); expect(result.output).toBe('localhost test'); client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); it('binds to 0.0.0.0', async () => { const testPort = PORT_BASE + 5; const testCacheDir = `/tmp/prodisco-cache-tcp-allif-${uniqueId()}`; const server = await startServer({ useTcp: true, tcpHost: '0.0.0.0', tcpPort: testPort, cacheDir: testCacheDir, }); // Connect via 127.0.0.1 (should work since server binds to all interfaces) const client = new SandboxClient({ useTcp: true, tcpHost: '127.0.0.1', tcpPort: testPort, }); const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); const result = await client.execute({ code: 'console.log("0.0.0.0 test")' }); expect(result.success).toBe(true); expect(result.output).toBe('0.0.0.0 test'); client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); }); describe('TCP Transport - Environment Variable Priority', () => { let originalSocketPath: string | undefined; let originalTcpHost: string | undefined; let originalTcpPort: string | undefined; let originalUseTcp: string | undefined; beforeEach(() => { // Save original env vars originalSocketPath = process.env.SANDBOX_SOCKET_PATH; originalTcpHost = process.env.SANDBOX_TCP_HOST; originalTcpPort = process.env.SANDBOX_TCP_PORT; originalUseTcp = process.env.SANDBOX_USE_TCP; // Clear all env vars delete process.env.SANDBOX_SOCKET_PATH; delete process.env.SANDBOX_TCP_HOST; delete process.env.SANDBOX_TCP_PORT; delete process.env.SANDBOX_USE_TCP; }); afterEach(() => { // Restore original env vars if (originalSocketPath !== undefined) { process.env.SANDBOX_SOCKET_PATH = originalSocketPath; } else { delete process.env.SANDBOX_SOCKET_PATH; } if (originalTcpHost !== undefined) { process.env.SANDBOX_TCP_HOST = originalTcpHost; } else { delete process.env.SANDBOX_TCP_HOST; } if (originalTcpPort !== undefined) { process.env.SANDBOX_TCP_PORT = originalTcpPort; } else { delete process.env.SANDBOX_TCP_PORT; } if (originalUseTcp !== undefined) { process.env.SANDBOX_USE_TCP = originalUseTcp; } else { delete process.env.SANDBOX_USE_TCP; } }); it('explicit useTcp=false overrides env vars', async () => { const testPort = PORT_BASE + 6; const id = uniqueId(); const testSocketPath = `/tmp/prodisco-test-priority-${id}.sock`; const testCacheDir = `/tmp/prodisco-cache-priority-${id}`; // Set env vars to use TCP process.env.SANDBOX_USE_TCP = 'true'; process.env.SANDBOX_TCP_HOST = '127.0.0.1'; process.env.SANDBOX_TCP_PORT = String(testPort); // But explicitly set useTcp=false - should use Unix socket const server = await startServer({ useTcp: false, socketPath: testSocketPath, cacheDir: testCacheDir, }); const client = new SandboxClient({ useTcp: false, socketPath: testSocketPath, }); const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); // Clean up socket file if (existsSync(testSocketPath)) { rmSync(testSocketPath); } if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); it('SANDBOX_USE_TCP=1 enables TCP', async () => { const testPort = PORT_BASE + 7; const testCacheDir = `/tmp/prodisco-cache-usetcp1-${uniqueId()}`; process.env.SANDBOX_USE_TCP = '1'; process.env.SANDBOX_TCP_HOST = '127.0.0.1'; process.env.SANDBOX_TCP_PORT = String(testPort); const server = await startServer({ cacheDir: testCacheDir }); const client = new SandboxClient(); const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); const result = await client.execute({ code: 'console.log("USE_TCP=1")' }); expect(result.success).toBe(true); client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); it('setting only SANDBOX_TCP_HOST implies TCP', async () => { const testPort = PORT_BASE + 8; const testCacheDir = `/tmp/prodisco-cache-hostimplies-${uniqueId()}`; // Only set host, not USE_TCP process.env.SANDBOX_TCP_HOST = '127.0.0.1'; process.env.SANDBOX_TCP_PORT = String(testPort); const server = await startServer({ cacheDir: testCacheDir }); const client = new SandboxClient(); const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); it('setting only SANDBOX_TCP_PORT implies TCP', async () => { const testPort = PORT_BASE + 9; const testCacheDir = `/tmp/prodisco-cache-portimplies-${uniqueId()}`; // Only set port, not USE_TCP or HOST process.env.SANDBOX_TCP_PORT = String(testPort); const server = await startServer({ cacheDir: testCacheDir }); // Client needs to know the port too const client = new SandboxClient(); const healthy = await client.waitForHealthy(5000); expect(healthy).toBe(true); client.close(); await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); }); describe('TCP Transport - Multiple Clients', () => { const testPort = PORT_BASE + 10; const testHost = '127.0.0.1'; const testCacheDir = `/tmp/prodisco-cache-tcp-multiclient-${uniqueId()}`; let server: grpc.Server; beforeAll(async () => { server = await startServer({ useTcp: true, tcpHost: testHost, tcpPort: testPort, cacheDir: testCacheDir, }); }); afterAll(async () => { await new Promise<void>((resolve) => { server.tryShutdown((err) => { if (err) server.forceShutdown(); resolve(); }); }); if (existsSync(testCacheDir)) { rmSync(testCacheDir, { recursive: true }); } }); it('handles multiple independent clients', async () => { const clients = Array.from({ length: 3 }, () => new SandboxClient({ useTcp: true, tcpHost: testHost, tcpPort: testPort, }) ); // Wait for all clients to be healthy const healthChecks = await Promise.all( clients.map(client => client.waitForHealthy(5000)) ); expect(healthChecks.every(h => h)).toBe(true); // Execute code from each client concurrently const results = await Promise.all( clients.map((client, i) => client.execute({ code: `console.log("client ${i}")` }) ) ); expect(results.every(r => r.success)).toBe(true); results.forEach((result, i) => { expect(result.output).toBe(`client ${i}`); }); // Close all clients clients.forEach(client => client.close()); }); it('handles client reconnection after close', async () => { const client1 = new SandboxClient({ useTcp: true, tcpHost: testHost, tcpPort: testPort, }); await client1.waitForHealthy(5000); const result1 = await client1.execute({ code: 'console.log("first")' }); expect(result1.success).toBe(true); client1.close(); // Create new client after closing the first one const client2 = new SandboxClient({ useTcp: true, tcpHost: testHost, tcpPort: testPort, }); await client2.waitForHealthy(5000); const result2 = await client2.execute({ code: 'console.log("second")' }); expect(result2.success).toBe(true); expect(result2.output).toBe('second'); client2.close(); }); });

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/harche/ProDisco'

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