/** * Unit tests for remote-proxy-client module */ import { describe, it, expect } from 'bun:test'; import { type RemoteProxyClientConfig, type RemoteProxyStatus, } from '../../../src/cliproxy/remote-proxy-client'; // We test the module's type exports and error handling logic // Actual HTTP calls are not mocked in this unit test - use integration tests for that describe('remote-proxy-client', () => { describe('type exports', () => { it('should export RemoteProxyClientConfig interface', () => { // Type-level test - ensure the interface shape is correct const config: RemoteProxyClientConfig = { host: 'localhost', port: 8317, protocol: 'http', authToken: 'test-token', timeout: 2000, allowSelfSigned: false, }; expect(config.host).toBe('localhost'); expect(config.port).toBe(8317); expect(config.protocol).toBe('http'); }); it('should export RemoteProxyStatus interface', () => { // Success case const successStatus: RemoteProxyStatus = { reachable: true, latencyMs: 50, }; expect(successStatus.reachable).toBe(true); expect(successStatus.latencyMs).toBe(50); // Error case const errorStatus: RemoteProxyStatus = { reachable: false, error: 'Connection refused', errorCode: 'CONNECTION_REFUSED', }; expect(errorStatus.reachable).toBe(false); expect(errorStatus.error).toBe('Connection refused'); expect(errorStatus.errorCode).toBe('CONNECTION_REFUSED'); }); }); describe('RemoteProxyErrorCode', () => { it('should define expected error codes', () => { const validCodes = [ 'CONNECTION_REFUSED', 'TIMEOUT', 'AUTH_FAILED', 'DNS_FAILED', 'NETWORK_UNREACHABLE', 'UNKNOWN', ]; // Type-level test - ensure error codes can be used const status1: RemoteProxyStatus = { reachable: false, errorCode: 'CONNECTION_REFUSED' }; const status2: RemoteProxyStatus = { reachable: false, errorCode: 'TIMEOUT' }; const status3: RemoteProxyStatus = { reachable: false, errorCode: 'AUTH_FAILED' }; const status4: RemoteProxyStatus = { reachable: false, errorCode: 'UNKNOWN' }; const status5: RemoteProxyStatus = { reachable: false, errorCode: 'DNS_FAILED' }; const status6: RemoteProxyStatus = { reachable: false, errorCode: 'NETWORK_UNREACHABLE' }; expect(validCodes).toContain(status1.errorCode); expect(validCodes).toContain(status2.errorCode); expect(validCodes).toContain(status3.errorCode); expect(validCodes).toContain(status4.errorCode); expect(validCodes).toContain(status5.errorCode); expect(validCodes).toContain(status6.errorCode); }); }); describe('config validation', () => { it('should require host and port', () => { const minimalConfig: RemoteProxyClientConfig = { host: '127.0.0.1', port: 8317, protocol: 'http', }; expect(minimalConfig.host).toBeDefined(); expect(minimalConfig.port).toBeDefined(); expect(minimalConfig.protocol).toBeDefined(); }); it('should allow optional fields', () => { const config: RemoteProxyClientConfig = { host: '127.0.0.1', port: 8317, protocol: 'https', authToken: 'secret', timeout: 5000, allowSelfSigned: true, }; expect(config.authToken).toBe('secret'); expect(config.timeout).toBe(5000); expect(config.allowSelfSigned).toBe(true); }); it('should accept http and https protocols', () => { const httpConfig: RemoteProxyClientConfig = { host: 'localhost', port: 8317, protocol: 'http', }; const httpsConfig: RemoteProxyClientConfig = { host: 'localhost', port: 8317, protocol: 'https', }; expect(httpConfig.protocol).toBe('http'); expect(httpsConfig.protocol).toBe('https'); }); }); describe('health check URL construction', () => { // CLIProxyAPI uses root endpoint for liveness checks (no /health endpoint) it('should construct correct health check URL pattern using /', () => { const config: RemoteProxyClientConfig = { host: '192.168.1.100', port: 8317, protocol: 'http', }; const expectedUrl = `${config.protocol}://${config.host}:${config.port}/`; expect(expectedUrl).toBe('http://192.168.1.100:8317/'); }); it('should construct HTTPS URL when protocol is https', () => { const config: RemoteProxyClientConfig = { host: 'secure.example.com', port: 443, protocol: 'https', }; const expectedUrl = `${config.protocol}://${config.host}:${config.port}/`; expect(expectedUrl).toBe('https://secure.example.com:443/'); }); }); describe('port defaults by protocol', () => { // Document expected default ports based on protocol // HTTP: 8317 (CLIProxyAPI default for local/dev scenarios) // HTTPS: 443 (standard SSL port for production remote servers) it('should document HTTP default port as 8317', () => { // HTTP connections default to CLIProxyAPI port 8317 // This matches local development scenarios const expectedHttpDefault = 8317; expect(expectedHttpDefault).toBe(8317); }); it('should document HTTPS default port as 443', () => { // HTTPS connections default to standard SSL port 443 // This matches production remote server scenarios const expectedHttpsDefault = 443; expect(expectedHttpsDefault).toBe(443); }); it('should allow port to be optional in config', () => { // Port is optional - when undefined, defaults based on protocol const configWithoutPort: RemoteProxyClientConfig = { host: 'example.com', protocol: 'https', // port is intentionally undefined }; expect(configWithoutPort.port).toBeUndefined(); expect(configWithoutPort.protocol).toBe('https'); }); }); });