UNPKG

@iota-big3/sdk-gateway

Version:

Universal API Gateway with protocol translation, intelligent routing, rate limiting, health checking, and caching

257 lines 9.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.criticalPaths = void 0; exports.runSmokeTests = runSmokeTests; exports.generateReport = generateReport; /** * Critical path smoke tests for production validation */ exports.criticalPaths = [ { name: 'Health Check Endpoint', critical: true, timeout: 5000, test: async (gateway) => { const start = Date.now(); const response = await fetch(`${gateway}/health`); const duration = Date.now() - start; if (response.status !== 200) { throw new Error(`Health check returned ${response.status}`); } if (duration > 100) { throw new Error(`Health check too slow: ${duration}ms`); } const data = await response.json(); if (data.status !== 'healthy') { throw new Error(`Gateway unhealthy: ${data.status}`); } } }, { name: 'Service Discovery', critical: true, timeout: 10000, test: async (gateway) => { const response = await fetch(`${gateway}/api/services`); if (response.status !== 200) { throw new Error(`Service discovery returned ${response.status}`); } const services = await response.json(); if (!Array.isArray(services) || services.length === 0) { throw new Error('No services discovered'); } const unhealthy = services.filter(s => !s.healthy); if (unhealthy.length > 0) { throw new Error(`${unhealthy.length} unhealthy services found`); } } }, { name: 'Request Routing', timeout: 5000, test: async (gateway) => { const testPath = '/api/test/smoke'; const response = await fetch(`${gateway}${testPath}`, { headers: { 'x-smoke-test': 'true' } }); if (response.status >= 500) { throw new Error(`Routing test returned ${response.status}`); } const routedTo = response.headers.get('x-routed-to'); if (!routedTo) { throw new Error('No routing header found'); } const latency = parseInt(response.headers.get('x-gateway-latency') || '0'); if (latency > 200) { throw new Error(`Routing too slow: ${latency}ms`); } } }, { name: 'Rate Limiting', timeout: 10000, test: async (gateway) => { const endpoint = `${gateway}/api/rate-limit-test`; const requests = []; // Make 10 rapid requests for (let i = 0; i < 10; i++) { requests.push(fetch(endpoint, { headers: { 'x-client-id': 'smoke-test' } })); } const responses = await Promise.all(requests); const rateLimited = responses.filter(r => r.status === 429); if (rateLimited.length === 0) { throw new Error('Rate limiting not working - no 429 responses'); } // Check retry-after header const retryAfter = rateLimited[0]?.headers.get('retry-after'); if (!retryAfter) { throw new Error('Rate limit response missing retry-after header'); } } }, { name: 'Circuit Breaker', timeout: 15000, test: async (gateway) => { const endpoint = `${gateway}/api/circuit-test`; // Force circuit to open by causing failures const failures = []; for (let i = 0; i < 5; i++) { failures.push(fetch(endpoint, { headers: { 'x-force-failure': 'true' } }).catch(() => null)); } await Promise.all(failures); // Circuit should be open now const response = await fetch(endpoint); if (response.status !== 503) { throw new Error(`Expected 503 (circuit open), got ${response.status}`); } const circuitState = response.headers.get('x-circuit-state'); if (circuitState !== 'OPEN') { throw new Error(`Circuit breaker not open: ${circuitState}`); } } }, { name: 'Cache Functionality', timeout: 8000, test: async (gateway) => { const endpoint = `${gateway}/api/cache-test`; const cacheKey = `smoke-test-${Date.now()}`; // First request - should miss cache const response1 = await fetch(endpoint, { headers: { 'x-cache-key': cacheKey } }); if (response1.headers.get('x-cache') !== 'MISS') { throw new Error('First request should be cache miss'); } // Second request - should hit cache const response2 = await fetch(endpoint, { headers: { 'x-cache-key': cacheKey } }); if (response2.headers.get('x-cache') !== 'HIT') { throw new Error('Second request should be cache hit'); } // Verify same content const body1 = await response1.text(); const body2 = await response2.text(); if (body1 !== body2) { throw new Error('Cached response content mismatch'); } } }, { name: 'Authentication', timeout: 5000, test: async (gateway) => { // Test without auth const response1 = await fetch(`${gateway}/api/protected`); if (response1.status !== 401) { throw new Error(`Expected 401 without auth, got ${response1.status}`); } // Test with invalid auth const response2 = await fetch(`${gateway}/api/protected`, { headers: { 'Authorization': 'Bearer invalid-token' } }); if (response2.status !== 403) { throw new Error(`Expected 403 with invalid auth, got ${response2.status}`); } } }, { name: 'Metrics Endpoint', timeout: 5000, test: async (gateway) => { const response = await fetch(`${gateway}/metrics`); if (response.status !== 200) { throw new Error(`Metrics endpoint returned ${response.status}`); } const metrics = await response.json(); if (!metrics.requests || typeof metrics.requests.total !== 'number') { throw new Error('Invalid metrics format'); } if (!metrics.latency || typeof metrics.latency.p95 !== 'number') { throw new Error('Missing latency metrics'); } } } ]; /** * Run all smoke tests */ async function runSmokeTests(gatewayUrl, options) { const tests = options?.filter ? exports.criticalPaths.filter(options.filter) : exports.criticalPaths; const results = []; if (options?.parallel) { // Run tests in parallel const promises = tests.map(test => runSingleTest(gatewayUrl, test)); const parallelResults = await Promise.all(promises); results.push(...parallelResults); } else { // Run tests sequentially for (const test of tests) { const result = await runSingleTest(gatewayUrl, test); results.push(result); if (!result.passed && (test.critical || options?.stopOnFailure)) { break; } } } return results; } /** * Run a single smoke test */ async function runSingleTest(gatewayUrl, test) { const start = Date.now(); try { // Apply timeout if specified const timeout = test.timeout || 30000; const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Test timeout')), timeout); }); await Promise.race([ test.test(gatewayUrl), timeoutPromise ]); return { name: test.name, passed: true, duration: Date.now() - start }; } catch (error) { return { name: test.name, passed: false, duration: Date.now() - start, error: error instanceof Error ? error.message : String(error) }; } } /** * Generate smoke test report */ function generateReport(results) { const failures = results.filter(r => !r.passed); const slowTests = results.filter(r => r.duration > 1000); const totalDuration = results.reduce((sum, r) => sum + r.duration, 0); return { summary: { total: results.length, passed: results.filter(r => r.passed).length, failed: failures.length, duration: totalDuration, passRate: (results.filter(r => r.passed).length / results.length) * 100 }, failures, slowTests }; } //# sourceMappingURL=critical-paths.js.map