@iota-big3/sdk-gateway
Version:
Universal API Gateway with protocol translation, intelligent routing, rate limiting, health checking, and caching
257 lines • 9.26 kB
JavaScript
;
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