Get your own Node server
const http = require('http');
const https = require('https');
const { URL } = require('url');

// Configuration
const CONFIG = {
  // Test server settings
  testServer: {
    port: 3008,
    // Delays for testing different timeout scenarios (in ms)
    responseDelays: {
      fast: 1000,    // 1s - should complete successfully
      slow: 5000,    // 5s - should trigger timeout
      verySlow: 10000 // 10s - should be aborted
    }
  },
  // Timeout settings (in ms)
  timeouts: {
    connection: 2000,  // Time to establish connection
    request: 3000,     // Time for the entire request
    socket: 1000       // Time of inactivity on the socket
  },
  // Target URL for external request test
  externalTestUrl: 'http://httpbin.org/delay/3'  // 3 second delay
};

// Create a test server with configurable response delay
function createTestServer() {
  const server = http.createServer((req, res) => {
    const url = new URL(req.url, `http://${req.headers.host}`);
    const delayType = url.searchParams.get('delay') || 'fast';
    const delay = CONFIG.testServer.responseDelays[delayType] || 0;
    
    console.log(`\n[${new Date().toISOString()}] Request received. Delay: ${delay}ms`);
    
    // Set a timeout to simulate a slow response
    setTimeout(() => {
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({
        status: 'success',
        message: 'Response after delay',
        delay: delay,
        timestamp: new Date().toISOString()
      }));
      console.log(`[${new Date().toISOString()}] Response sent after ${delay}ms`);
    }, delay);
  });
  
  return server;
}

// Function to make a request with timeouts
function makeRequest(url, options = {}) {
  const { protocol } = new URL(url);
  const client = protocol === 'https:' ? https : http;
  
  // Set default timeout options
  const timeoutOptions = {
    timeout: CONFIG.timeouts.request,
    ...options
  };
  
  console.log(`\n=== Making request to ${url} ===`);
  console.log('Timeout settings:', {
    request: timeoutOptions.timeout,
    connection: timeoutOptions.timeout,
    socket: CONFIG.timeouts.socket
  });
  
  const startTime = Date.now();
  const req = client.get(url, timeoutOptions, (res) => {
    console.log(`\n[${new Date().toISOString()}] Response received`);
    console.log(`Status: ${res.statusCode} ${res.statusMessage}`);
    console.log('Headers:', JSON.stringify(res.headers, null, 2));
    
    let data = '';
    res.on('data', (chunk) => {
      data += chunk;
    });
    
    res.on('end', () => {
      const endTime = Date.now();
      const duration = endTime - startTime;
      
      try {
        const jsonData = JSON.parse(data);
        console.log('Response body:', JSON.stringify(jsonData, null, 2));
      } catch (e) {
        console.log('Response body:', data);
      }
      
      console.log(`Request completed in ${duration}ms`);
    });
  });
  
  // Set socket timeout (time of inactivity)
  req.setTimeout(CONFIG.timeouts.socket, () => {
    console.error(`\n[${new Date().toISOString()}] Socket timeout after ${CONFIG.timeouts.socket}ms of inactivity`);
    req.abort(); // Abort the request
  });
  
  // Handle request timeout (entire request)
  req.on('timeout', () => {
    console.error(`\n[${new Date().toISOString()}] Request timeout after ${timeoutOptions.timeout}ms`);
    req.abort();
  });
  
  // Handle errors
  req.on('error', (err) => {
    const endTime = Date.now();
    console.error(`\n[${new Date().toISOString()}] Request error after ${endTime - startTime}ms:`, 
      err.code || err.message);
  });
  
  // Handle abort
  req.on('abort', () => {
    console.error(`[${new Date().toISOString()}] Request aborted`);
  });
  
  // Handle socket events
  req.on('socket', (socket) => {
    console.log(`[${new Date().toISOString()}] Socket assigned`);
    
    socket.setTimeout(CONFIG.timeouts.connection, () => {
      console.error(`[${new Date().toISOString()}] Connection timeout after ${CONFIG.timeouts.connection}ms`);
      req.abort();
    });
    
    socket.on('connect', () => {
      console.log(`[${new Date().toISOString()}] Socket connected`);
    });
    
    socket.on('error', (err) => {
      console.error(`[${new Date().toISOString()}] Socket error:`, err.message);
    });
  });
  
  return req;
}

// Main function to run the demo
async function runDemo() {
  // Start the test server
  const server = createTestServer();
  
  server.listen(CONFIG.testServer.port, () => {
    console.log(`Test server running at http://localhost:${CONFIG.testServer.port}`);
    console.log('Available test endpoints:');
    console.log(`- Fast response:   http://localhost:${CONFIG.testServer.port}/?delay=fast`);
    console.log(`- Slow response:   http://localhost:${CONFIG.testServer.port}/?delay=slow`);
    console.log(`- Very slow response: http://localhost:${CONFIG.testServer.port}/?delay=verySlow`);
    console.log('\n=== Starting timeout demo ===\n');
    
    // Run test cases with different timeouts
    const testCases = [
      {
        name: 'Fast response (should succeed)',
        url: `http://localhost:${CONFIG.testServer.port}/?delay=fast`,
        options: { timeout: 5000 }
      },
      {
        name: 'Slow response (should timeout)',
        url: `http://localhost:${CONFIG.testServer.port}/?delay=slow`,
        options: { timeout: 3000 }
      },
      {
        name: 'External request with timeout',
        url: CONFIG.externalTestUrl,
        options: { timeout: 2000 },
        skip: false // Set to true to skip external requests
      }
    ];
    
    // Run test cases sequentially
    (async function runTests(index = 0) {
      if (index >= testCases.length) {
        console.log('\n=== All tests completed ===');
        console.log('The test server is still running. Press Ctrl+C to stop it.');
        console.log(`Visit http://localhost:${CONFIG.testServer.port} in your browser for more testing.`);
        return;
      }
      
      const test = testCases[index];
      
      if (test.skip) {
        console.log(`\n=== Skipping: ${test.name} ===`);
        runTests(index + 1);
        return;
      }
      
      console.log(`\n=== Test ${index + 1}: ${test.name} ===`);
      console.log(`URL: ${test.url}`);
      
      await new Promise((resolve) => {
        const req = makeRequest(test.url, test.options);
        
        req.on('close', () => {
          // Add a small delay between tests
          setTimeout(resolve, 2000);
        });
      });
      
      // Run next test
      runTests(index + 1);
    })();
  });
  
  // Handle server errors
  server.on('error', (err) => {
    console.error('Server error:', err);
  });
  
  // Handle process termination
  process.on('SIGINT', () => {
    console.log('\nShutting down server...');
    server.close(() => {
      console.log('Server closed');
      process.exit(0);
    });
  });
}

// Run the demo
runDemo().catch(console.error);

              
Test server running at http://localhost:3008
Available test endpoints:
- Fast response:   http://localhost:3008/?delay=fast
- Slow response:   http://localhost:3008/?delay=slow
- Very slow response: http://localhost:3008/?delay=verySlow

=== Starting timeout demo ===

=== Test 1: Fast response (should succeed) ===
URL: http://localhost:3008/?delay=fast

=== Making request to http://localhost:3008/?delay=fast ===
Timeout settings: { request: 5000, connection: 2000, socket: 1000 }
[2025-06-18T06:40:38.123Z] Socket assigned
[2025-06-18T06:40:38.125Z] Socket connected
[2025-06-18T06:40:38.126Z] Request received. Delay: 1000ms
[2025-06-18T06:40:39.126Z] Response sent after 1000ms

[2025-06-18T06:40:39.127Z] Response received
Status: 200 OK
Headers: {
  "content-type": "application/json",
  "date": "Wed, 18 Jun 2025 06:40:38 GMT",
  "connection": "close",
  "transfer-encoding": "chunked"
}
Response body: {
  "status": "success",
  "message": "Response after delay",
  "delay": 1000,
  "timestamp": "2025-06-18T06:40:39.126Z"
}
Request completed in 1003ms

=== Test 2: Slow response (should timeout) ===
URL: http://localhost:3008/?delay=slow

=== Making request to http://localhost:3008/?delay=slow ===
Timeout settings: { request: 3000, connection: 2000, socket: 1000 }
[2025-06-18T06:40:41.127Z] Socket assigned
[2025-06-18T06:40:41.128Z] Socket connected
[2025-06-18T06:40:41.129Z] Request received. Delay: 5000ms
[2025-06-18T06:40:44.130Z] Request timeout after 3000ms
[2025-06-18T06:40:44.130Z] Request aborted
[2025-06-18T06:40:44.130Z] Request error after 3003ms: ECONNRESET

=== Test 3: External request with timeout ===
URL: http://httpbin.org/delay/3

=== Making request to http://httpbin.org/delay/3 ===
Timeout settings: { request: 2000, connection: 2000, socket: 1000 }
[2025-06-18T06:40:46.131Z] Socket assigned
[2025-06-18T06:40:46.132Z] Socket connected
[2025-06-18T06:40:48.132Z] Request timeout after 2000ms
[2025-06-18T06:40:48.132Z] Request aborted
[2025-06-18T06:40:48.132Z] Request error after 2001ms: ECONNRESET

=== All tests completed ===
The test server is still running. Press Ctrl+C to stop it.
Visit http://localhost:3008 in your browser for more testing.

Shutting down server...
Server closed