UNPKG

@electric-sql/pglite-socket

Version:

A socket implementation for PGlite enabling remote connections

214 lines (182 loc) 5.91 kB
import { describe, it, expect, afterEach } from 'vitest' import { spawn, ChildProcess } from 'node:child_process' import { createConnection } from 'net' import path from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const serverScript = path.resolve(__dirname, '../src/scripts/server.ts') // Helper to wait for a port to be available async function waitForPort(port: number, timeout = 5000): Promise<boolean> { const start = Date.now() while (Date.now() - start < timeout) { try { const socket = createConnection({ port, host: '127.0.0.1' }) await new Promise<void>((resolve, reject) => { socket.on('connect', () => { socket.end() resolve() }) socket.on('error', reject) }) return true } catch { await new Promise((resolve) => setTimeout(resolve, 100)) } } return false } describe('Server Script Tests', () => { const TEST_PORT_BASE = 15500 let currentTestPort = TEST_PORT_BASE // Get a unique port for each test function getTestPort(): number { return ++currentTestPort } describe('Help and Basic Functionality', () => { it('should show help when --help flag is used', async () => { const serverProcess = spawn('tsx', [serverScript, '--help'], { stdio: ['pipe', 'pipe', 'pipe'], }) let output = '' serverProcess.stdout?.on('data', (data) => { output += data.toString() }) await new Promise<void>((resolve) => { serverProcess.on('exit', (code) => { expect(code).toBe(0) expect(output).toContain('PGlite Socket Server') expect(output).toContain('Usage:') expect(output).toContain('Options:') expect(output).toContain('--db') expect(output).toContain('--port') expect(output).toContain('--host') resolve() }) }) }, 10000) it('should accept and use debug level parameter', async () => { const testPort = getTestPort() const serverProcess = spawn( 'tsx', [serverScript, '--port', testPort.toString(), '--debug', '2'], { stdio: ['pipe', 'pipe', 'pipe'], }, ) let output = '' serverProcess.stdout?.on('data', (data) => { output += data.toString() }) // Wait for server to start await waitForPort(testPort) // Kill the server serverProcess.kill('SIGTERM') await new Promise<void>((resolve) => { serverProcess.on('exit', () => { expect(output).toContain('Debug level: 2') resolve() }) }) }, 10000) }) describe('Server Startup and Connectivity', () => { let serverProcess: ChildProcess | null = null afterEach(async () => { if (serverProcess) { serverProcess.kill('SIGTERM') await new Promise<void>((resolve) => { if (serverProcess) { serverProcess.on('exit', () => resolve()) } else { resolve() } }) serverProcess = null } }) it('should start server on TCP port and accept connections', async () => { const testPort = getTestPort() serverProcess = spawn( 'tsx', [serverScript, '--port', testPort.toString()], { stdio: ['pipe', 'pipe', 'pipe'], }, ) let output = '' serverProcess.stdout?.on('data', (data) => { output += data.toString() }) // Wait for server to be ready const isReady = await waitForPort(testPort) expect(isReady).toBe(true) // Check that we can connect const socket = createConnection({ port: testPort, host: '127.0.0.1' }) await new Promise<void>((resolve, reject) => { socket.on('connect', resolve) socket.on('error', reject) setTimeout(() => reject(new Error('Connection timeout')), 3000) }) socket.end() expect(output).toContain('PGlite database initialized') expect(output).toContain(`"port":${testPort}`) }, 10000) it('should work with memory database', async () => { const testPort = getTestPort() serverProcess = spawn( 'tsx', [serverScript, '--port', testPort.toString(), '--db', 'memory://'], { stdio: ['pipe', 'pipe', 'pipe'], }, ) let output = '' serverProcess.stdout?.on('data', (data) => { output += data.toString() }) const isReady = await waitForPort(testPort) expect(isReady).toBe(true) expect(output).toContain('Initializing PGLite with database: memory://') }, 10000) }) describe('Configuration Options', () => { let serverProcess: ChildProcess | null = null afterEach(async () => { if (serverProcess) { serverProcess.kill('SIGTERM') await new Promise<void>((resolve) => { if (serverProcess) { serverProcess.on('exit', () => resolve()) } else { resolve() } }) serverProcess = null } }) it('should handle different hosts', async () => { const testPort = getTestPort() serverProcess = spawn( 'tsx', [serverScript, '--port', testPort.toString(), '--host', '0.0.0.0'], { stdio: ['pipe', 'pipe', 'pipe'], }, ) let output = '' serverProcess.stdout?.on('data', (data) => { output += data.toString() }) const isReady = await waitForPort(testPort) expect(isReady).toBe(true) serverProcess.kill() await new Promise<void>((resolve) => { serverProcess.on('exit', () => { expect(output).toContain(`"host":"0.0.0.0"`) serverProcess = null resolve() }) }) }, 10000) }) })