Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
This commit is contained in:
161
scripts/k6-load-test.js
Normal file
161
scripts/k6-load-test.js
Normal file
@@ -0,0 +1,161 @@
|
||||
// k6 Load Testing Configuration
|
||||
// Comprehensive load test for Sankofa Phoenix API
|
||||
// Usage: k6 run k6-load-test.js
|
||||
|
||||
import http from 'k6/http';
|
||||
import { check, sleep } from 'k6';
|
||||
import { Rate, Trend, Counter } from 'k6/metrics';
|
||||
|
||||
// Custom metrics
|
||||
const errorRate = new Rate('errors');
|
||||
const apiLatency = new Trend('api_latency');
|
||||
const graphqlLatency = new Trend('graphql_latency');
|
||||
const requestCount = new Counter('requests_total');
|
||||
|
||||
// Configuration
|
||||
const API_URL = __ENV.API_URL || 'https://api.sankofa.nexus';
|
||||
const TEST_DURATION = __ENV.TEST_DURATION || '5m';
|
||||
const VUS = parseInt(__ENV.VUS || '10');
|
||||
|
||||
export const options = {
|
||||
stages: [
|
||||
// Ramp up to 10 VUs over 1 minute
|
||||
{ duration: '1m', target: 10 },
|
||||
// Stay at 10 VUs for 2 minutes
|
||||
{ duration: '2m', target: 10 },
|
||||
// Ramp up to 50 VUs over 2 minutes
|
||||
{ duration: '2m', target: 50 },
|
||||
// Stay at 50 VUs for 2 minutes
|
||||
{ duration: '2m', target: 50 },
|
||||
// Ramp up to 100 VUs over 2 minutes
|
||||
{ duration: '2m', target: 100 },
|
||||
// Stay at 100 VUs for 2 minutes
|
||||
{ duration: '2m', target: 100 },
|
||||
// Ramp down to 0 VUs over 2 minutes
|
||||
{ duration: '2m', target: 0 },
|
||||
],
|
||||
thresholds: {
|
||||
// 95% of requests should be below 200ms
|
||||
'http_req_duration': ['p(95)<200', 'p(99)<500'],
|
||||
// Error rate should be less than 1%
|
||||
'http_req_failed': ['rate<0.01'],
|
||||
'errors': ['rate<0.01'],
|
||||
// API latency should be below 200ms
|
||||
'api_latency': ['p(95)<200'],
|
||||
// GraphQL latency should be below 300ms
|
||||
'graphql_latency': ['p(95)<300'],
|
||||
},
|
||||
};
|
||||
|
||||
// Test data
|
||||
const graphqlQueries = [
|
||||
{
|
||||
query: '{ __typename }',
|
||||
},
|
||||
{
|
||||
query: `
|
||||
query {
|
||||
me {
|
||||
id
|
||||
email
|
||||
name
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
query: `
|
||||
query {
|
||||
sites {
|
||||
id
|
||||
name
|
||||
region
|
||||
status
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
// Helper function to get random query
|
||||
function getRandomQuery() {
|
||||
return graphqlQueries[Math.floor(Math.random() * graphqlQueries.length)];
|
||||
}
|
||||
|
||||
export default function () {
|
||||
// Test 1: Health endpoint
|
||||
const healthStart = Date.now();
|
||||
const healthRes = http.get(`${API_URL}/health`, {
|
||||
tags: { name: 'HealthCheck' },
|
||||
});
|
||||
const healthDuration = Date.now() - healthStart;
|
||||
|
||||
const healthCheck = check(healthRes, {
|
||||
'health status is 200': (r) => r.status === 200,
|
||||
'health response time < 100ms': (r) => r.timings.duration < 100,
|
||||
});
|
||||
|
||||
errorRate.add(!healthCheck);
|
||||
apiLatency.add(healthDuration);
|
||||
requestCount.add(1, { endpoint: 'health' });
|
||||
|
||||
sleep(0.5);
|
||||
|
||||
// Test 2: GraphQL endpoint
|
||||
const graphqlQuery = getRandomQuery();
|
||||
const graphqlStart = Date.now();
|
||||
const graphqlRes = http.post(
|
||||
`${API_URL}/graphql`,
|
||||
JSON.stringify(graphqlQuery),
|
||||
{
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
tags: { name: 'GraphQL' },
|
||||
}
|
||||
);
|
||||
const graphqlDuration = Date.now() - graphqlStart;
|
||||
|
||||
const graphqlCheck = check(graphqlRes, {
|
||||
'graphql status is 200': (r) => r.status === 200,
|
||||
'graphql response time < 300ms': (r) => r.timings.duration < 300,
|
||||
'graphql has data': (r) => {
|
||||
try {
|
||||
const body = JSON.parse(r.body);
|
||||
return body.data !== undefined || body.errors === undefined;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
errorRate.add(!graphqlCheck);
|
||||
graphqlLatency.add(graphqlDuration);
|
||||
requestCount.add(1, { endpoint: 'graphql' });
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
export function handleSummary(data) {
|
||||
return {
|
||||
'stdout': textSummary(data, { indent: ' ', enableColors: true }),
|
||||
'summary.json': JSON.stringify(data),
|
||||
};
|
||||
}
|
||||
|
||||
function textSummary(data, options) {
|
||||
const indent = options.indent || '';
|
||||
const enableColors = options.enableColors || false;
|
||||
|
||||
let summary = '';
|
||||
summary += `${indent}Test Summary\n`;
|
||||
summary += `${indent}============\n\n`;
|
||||
|
||||
// Metrics summary
|
||||
summary += `${indent}Metrics:\n`;
|
||||
summary += `${indent} - Total Requests: ${data.metrics.requests_total.values.count}\n`;
|
||||
summary += `${indent} - Failed Requests: ${data.metrics.http_req_failed.values.rate * 100}%\n`;
|
||||
summary += `${indent} - p95 Latency: ${data.metrics.http_req_duration.values['p(95)']}ms\n`;
|
||||
summary += `${indent} - p99 Latency: ${data.metrics.http_req_duration.values['p(99)']}ms\n`;
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user