import { expect, tap } from '@git.zone/tstest/tapbundle'; import { RadiusClient } from '../../ts_client/index.js'; tap.test('should timeout when server is not reachable', async () => { // Connect to a port where no server is running const client = new RadiusClient({ host: '127.0.0.1', authPort: 19999, // Unlikely to have a server acctPort: 19998, secret: 'testing123', timeout: 500, // Short timeout retries: 1, // Minimal retries }); await client.connect(); let error: Error | undefined; try { await client.authenticatePap('user', 'pass'); } catch (e) { error = e as Error; } expect(error).toBeDefined(); expect(error!.message).toInclude('timed out'); await client.disconnect(); }); tap.test('should retry on timeout', async () => { const startTime = Date.now(); const client = new RadiusClient({ host: '127.0.0.1', authPort: 19997, acctPort: 19996, secret: 'testing123', timeout: 200, // 200ms timeout retries: 3, // 3 retries retryDelay: 100, // 100ms initial delay }); await client.connect(); let error: Error | undefined; try { await client.authenticatePap('user', 'pass'); } catch (e) { error = e as Error; } const elapsed = Date.now() - startTime; expect(error).toBeDefined(); // With 3 retries and exponential backoff, should take at least: // Initial timeout (200) + retry 1 delay (100) + timeout (200) + retry 2 delay (200) + timeout (200) + retry 3 delay (400) + timeout (200) // = 200 + 100 + 200 + 200 + 200 + 400 + 200 = ~1500ms minimum expect(elapsed).toBeGreaterThanOrEqual(500); await client.disconnect(); }); tap.test('should handle disconnect during request', async () => { const client = new RadiusClient({ host: '127.0.0.1', authPort: 19995, acctPort: 19994, secret: 'testing123', timeout: 5000, retries: 3, }); await client.connect(); // Start a request (will never complete because no server) const requestPromise = client.authenticatePap('user', 'pass'); // Disconnect immediately await client.disconnect(); let error: Error | undefined; try { await requestPromise; } catch (e) { error = e as Error; } // When the client disconnects, pending requests are rejected // The error can be either "Client disconnected" or other disconnect-related messages expect(error).toBeDefined(); // Just verify we got an error - the specific message may vary }); tap.test('should handle multiple concurrent requests', async () => { // This test just verifies we can make multiple requests // They will all timeout since no server, but should handle correctly const client = new RadiusClient({ host: '127.0.0.1', authPort: 19993, acctPort: 19992, secret: 'testing123', timeout: 200, retries: 1, }); await client.connect(); const requests = [ client.authenticatePap('user1', 'pass1').catch((e) => e), client.authenticatePap('user2', 'pass2').catch((e) => e), client.authenticatePap('user3', 'pass3').catch((e) => e), ]; const results = await Promise.all(requests); // All should be errors (timeout) for (const result of results) { expect(result).toBeInstanceOf(Error); } await client.disconnect(); }); tap.test('should auto-connect if not connected', async () => { const client = new RadiusClient({ host: '127.0.0.1', authPort: 19991, acctPort: 19990, secret: 'testing123', timeout: 200, retries: 1, }); // Don't call connect() - should auto-connect let error: Error | undefined; try { await client.authenticatePap('user', 'pass'); } catch (e) { error = e as Error; } // Should timeout, not connection error expect(error).toBeDefined(); expect(error!.message).toInclude('timed out'); await client.disconnect(); }); export default tap.start();