omgkit 2.21.7 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,389 @@
1
+ ---
2
+ name: testing/chaos-testing
3
+ description: Chaos engineering and fault injection patterns for testing system resilience, failure recovery, and graceful degradation
4
+ category: testing
5
+ tags:
6
+ - testing
7
+ - chaos
8
+ - resilience
9
+ - fault-injection
10
+ - reliability
11
+ related_skills:
12
+ - testing/comprehensive-testing
13
+ - devops/observability
14
+ - backend/event-driven-architecture
15
+ ---
16
+
17
+ # Chaos Testing
18
+
19
+ Build resilient systems by intentionally introducing failures and verifying recovery.
20
+
21
+ ## Quick Start
22
+
23
+ ```bash
24
+ # Run chaos tests
25
+ npm test -- tests/chaos/
26
+
27
+ # Run with chaos monkey enabled
28
+ CHAOS_ENABLED=true npm start
29
+
30
+ # Simulate network failures
31
+ npm run chaos:network
32
+ ```
33
+
34
+ ## Core Principles
35
+
36
+ 1. **Hypothesis-Driven**: Define expected behavior before experiments
37
+ 2. **Minimize Blast Radius**: Start small, expand gradually
38
+ 3. **Automate Rollback**: Always have a kill switch
39
+ 4. **Monitor Everything**: Observe system behavior during chaos
40
+
41
+ ## Fault Injection Patterns
42
+
43
+ ### 1. Network Failures
44
+
45
+ ```javascript
46
+ describe('Network Resilience', () => {
47
+ it('handles API timeout gracefully', async () => {
48
+ // Simulate slow API
49
+ server.delay('/api/users', 10000);
50
+
51
+ const start = Date.now();
52
+ const result = await fetchWithTimeout('/api/users', 3000);
53
+ const duration = Date.now() - start;
54
+
55
+ expect(duration).toBeLessThan(4000);
56
+ expect(result.fallback).toBe(true);
57
+ });
58
+
59
+ it('retries on network failure', async () => {
60
+ let attempts = 0;
61
+
62
+ server.intercept('/api/data', () => {
63
+ attempts++;
64
+ if (attempts < 3) throw new Error('Network error');
65
+ return { data: 'success' };
66
+ });
67
+
68
+ const result = await fetchWithRetry('/api/data');
69
+
70
+ expect(attempts).toBe(3);
71
+ expect(result.data).toBe('success');
72
+ });
73
+
74
+ it('handles partial responses', async () => {
75
+ server.intercept('/api/large', (req, res) => {
76
+ res.write('{\"data\":');
77
+ res.destroy(); // Simulate connection drop
78
+ });
79
+
80
+ const result = await fetchWithRecovery('/api/large');
81
+ expect(result.error).toBe('incomplete_response');
82
+ });
83
+ });
84
+ ```
85
+
86
+ ### 2. Service Failures
87
+
88
+ ```javascript
89
+ describe('Service Resilience', () => {
90
+ it('falls back when primary service fails', async () => {
91
+ // Kill primary service
92
+ await killService('payment-primary');
93
+
94
+ const result = await processPayment({ amount: 100 });
95
+
96
+ expect(result.provider).toBe('fallback');
97
+ expect(result.success).toBe(true);
98
+ });
99
+
100
+ it('circuit breaker opens after failures', async () => {
101
+ const breaker = new CircuitBreaker(unreliableService, {
102
+ failureThreshold: 3,
103
+ resetTimeout: 1000,
104
+ });
105
+
106
+ // Trigger failures
107
+ for (let i = 0; i < 5; i++) {
108
+ await breaker.call().catch(() => {});
109
+ }
110
+
111
+ expect(breaker.state).toBe('open');
112
+
113
+ // Fast fail while open
114
+ const start = Date.now();
115
+ await breaker.call().catch(() => {});
116
+ expect(Date.now() - start).toBeLessThan(10);
117
+ });
118
+
119
+ it('recovers after circuit breaker resets', async () => {
120
+ const breaker = new CircuitBreaker(service, { resetTimeout: 100 });
121
+
122
+ // Open the breaker
123
+ await triggerCircuitOpen(breaker);
124
+ expect(breaker.state).toBe('open');
125
+
126
+ // Wait for reset
127
+ await sleep(150);
128
+
129
+ // Should be half-open, allowing a test request
130
+ service.mockImplementation(() => ({ success: true }));
131
+ const result = await breaker.call();
132
+
133
+ expect(breaker.state).toBe('closed');
134
+ expect(result.success).toBe(true);
135
+ });
136
+ });
137
+ ```
138
+
139
+ ### 3. Database Failures
140
+
141
+ ```javascript
142
+ describe('Database Resilience', () => {
143
+ it('handles connection pool exhaustion', async () => {
144
+ // Exhaust connection pool
145
+ const connections = [];
146
+ for (let i = 0; i < db.maxConnections; i++) {
147
+ connections.push(await db.getConnection());
148
+ }
149
+
150
+ // New request should wait or fail gracefully
151
+ const start = Date.now();
152
+ const result = await db.query('SELECT 1').catch(e => e);
153
+
154
+ expect(result.message).toMatch(/timeout|pool exhausted/);
155
+ expect(Date.now() - start).toBeLessThan(6000);
156
+
157
+ // Cleanup
158
+ await Promise.all(connections.map(c => c.release()));
159
+ });
160
+
161
+ it('handles replica lag', async () => {
162
+ // Write to primary
163
+ await db.primary.insert('users', { name: 'test' });
164
+
165
+ // Read from replica immediately (may not have replicated)
166
+ const result = await db.replica.query('SELECT * FROM users WHERE name = ?', ['test']);
167
+
168
+ // System should handle missing data
169
+ if (result.length === 0) {
170
+ // Fallback to primary read
171
+ const fallback = await db.primary.query('SELECT * FROM users WHERE name = ?', ['test']);
172
+ expect(fallback.length).toBe(1);
173
+ }
174
+ });
175
+
176
+ it('handles deadlocks', async () => {
177
+ const ops = [
178
+ async () => {
179
+ await db.transaction(async (tx) => {
180
+ await tx.update('accounts', { id: 1 }, { balance: 100 });
181
+ await sleep(50);
182
+ await tx.update('accounts', { id: 2 }, { balance: 200 });
183
+ });
184
+ },
185
+ async () => {
186
+ await db.transaction(async (tx) => {
187
+ await tx.update('accounts', { id: 2 }, { balance: 300 });
188
+ await sleep(50);
189
+ await tx.update('accounts', { id: 1 }, { balance: 400 });
190
+ });
191
+ },
192
+ ];
193
+
194
+ const results = await Promise.allSettled(ops.map(op => op()));
195
+ const retried = results.filter(r =>
196
+ r.status === 'fulfilled' || r.reason.retried
197
+ );
198
+
199
+ expect(retried.length).toBeGreaterThan(0);
200
+ });
201
+ });
202
+ ```
203
+
204
+ ### 4. Resource Exhaustion
205
+
206
+ ```javascript
207
+ describe('Resource Exhaustion', () => {
208
+ it('handles disk full', async () => {
209
+ // Simulate disk full
210
+ fs.mockImplementation('writeFile', () => {
211
+ throw new Error('ENOSPC: no space left on device');
212
+ });
213
+
214
+ const result = await saveData({ large: 'data' });
215
+
216
+ expect(result.error).toBe('storage_full');
217
+ expect(result.cached).toBe(true);
218
+ });
219
+
220
+ it('handles memory pressure', async () => {
221
+ const originalHeap = process.memoryUsage().heapUsed;
222
+
223
+ // Allocate significant memory
224
+ const allocations = [];
225
+ for (let i = 0; i < 10; i++) {
226
+ allocations.push(new Array(10000000).fill('x'));
227
+ }
228
+
229
+ // System should still respond
230
+ const result = await healthCheck();
231
+ expect(result.status).toBe('degraded');
232
+
233
+ // Cleanup
234
+ allocations.length = 0;
235
+ if (global.gc) global.gc();
236
+ });
237
+
238
+ it('handles CPU saturation', async () => {
239
+ // Saturate CPU
240
+ const workers = [];
241
+ for (let i = 0; i < 4; i++) {
242
+ workers.push(cpuIntensiveTask());
243
+ }
244
+
245
+ // Critical endpoint should still respond
246
+ const start = Date.now();
247
+ const result = await api.get('/health');
248
+ const duration = Date.now() - start;
249
+
250
+ expect(result.status).toBe(200);
251
+ expect(duration).toBeLessThan(5000);
252
+
253
+ await Promise.all(workers);
254
+ });
255
+ });
256
+ ```
257
+
258
+ ### 5. Clock Skew
259
+
260
+ ```javascript
261
+ describe('Clock Resilience', () => {
262
+ it('handles clock skew between services', () => {
263
+ // Simulate 5-minute clock difference
264
+ const serverTime = Date.now() - 5 * 60 * 1000;
265
+
266
+ const token = jwt.sign({ exp: serverTime + 3600000 }, secret);
267
+ const result = validateToken(token, { clockTolerance: 300 });
268
+
269
+ expect(result.valid).toBe(true);
270
+ });
271
+
272
+ it('handles leap seconds', () => {
273
+ // Simulate time going backward
274
+ MockDate.set(new Date('2024-06-30T23:59:60Z'));
275
+
276
+ const result = processScheduledTask();
277
+
278
+ expect(result.error).toBeUndefined();
279
+ MockDate.reset();
280
+ });
281
+ });
282
+ ```
283
+
284
+ ## Chaos Monkey Implementation
285
+
286
+ ```javascript
287
+ class ChaosMonkey {
288
+ constructor(options = {}) {
289
+ this.enabled = options.enabled ?? false;
290
+ this.probability = options.probability ?? 0.1;
291
+ this.faults = options.faults ?? ['latency', 'error', 'timeout'];
292
+ }
293
+
294
+ maybeInjectFault() {
295
+ if (!this.enabled) return null;
296
+ if (Math.random() > this.probability) return null;
297
+
298
+ const fault = this.faults[Math.floor(Math.random() * this.faults.length)];
299
+
300
+ switch (fault) {
301
+ case 'latency':
302
+ return { type: 'latency', delay: 1000 + Math.random() * 4000 };
303
+ case 'error':
304
+ return { type: 'error', code: 500, message: 'Chaos error' };
305
+ case 'timeout':
306
+ return { type: 'timeout', duration: 30000 };
307
+ default:
308
+ return null;
309
+ }
310
+ }
311
+
312
+ wrap(fn) {
313
+ return async (...args) => {
314
+ const fault = this.maybeInjectFault();
315
+
316
+ if (fault) {
317
+ switch (fault.type) {
318
+ case 'latency':
319
+ await new Promise(r => setTimeout(r, fault.delay));
320
+ break;
321
+ case 'error':
322
+ throw new Error(fault.message);
323
+ case 'timeout':
324
+ await new Promise(() => {}); // Never resolves
325
+ }
326
+ }
327
+
328
+ return fn(...args);
329
+ };
330
+ }
331
+ }
332
+
333
+ // Usage
334
+ const chaos = new ChaosMonkey({
335
+ enabled: process.env.CHAOS_ENABLED === 'true',
336
+ probability: 0.05,
337
+ });
338
+
339
+ const fetchUsers = chaos.wrap(async () => {
340
+ return api.get('/users');
341
+ });
342
+ ```
343
+
344
+ ## Game Day Scenarios
345
+
346
+ ```javascript
347
+ describe('Game Day: Total Service Failure', () => {
348
+ it('survives primary database failure', async () => {
349
+ // Kill primary database
350
+ await killDatabase('primary');
351
+
352
+ // Application should failover
353
+ const result = await api.get('/users');
354
+ expect(result.status).toBe(200);
355
+ expect(result.headers['x-database']).toBe('replica');
356
+
357
+ // Restore
358
+ await restoreDatabase('primary');
359
+ });
360
+
361
+ it('survives region failure', async () => {
362
+ // Simulate region failure
363
+ await disableRegion('us-east-1');
364
+
365
+ // Traffic should route to backup region
366
+ const result = await api.get('/health');
367
+ expect(result.region).toBe('us-west-2');
368
+
369
+ // Restore
370
+ await enableRegion('us-east-1');
371
+ });
372
+ });
373
+ ```
374
+
375
+ ## When to Use
376
+
377
+ - Before major deployments
378
+ - After significant architecture changes
379
+ - Periodically in production (carefully!)
380
+ - During reliability engineering efforts
381
+ - When building distributed systems
382
+
383
+ ## Anti-Patterns
384
+
385
+ 1. **No Kill Switch**: Always have rollback mechanism
386
+ 2. **Testing in Production Without Prep**: Start in staging
387
+ 3. **No Observability**: Monitor during experiments
388
+ 4. **Large Blast Radius**: Start small
389
+ 5. **No Hypothesis**: Define expected behavior first
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: testing/comprehensive-testing
3
+ description: Comprehensive 4D testing methodology covering Accuracy, Performance, Security, and Accessibility for production-ready quality assurance
4
+ category: testing
5
+ tags:
6
+ - testing
7
+ - quality
8
+ - omega
9
+ - comprehensive
10
+ - methodology
11
+ related_skills:
12
+ - testing/vitest
13
+ - testing/property-testing
14
+ - testing/security-testing
15
+ - testing/performance-testing
16
+ - methodology/omega
17
+ ---
18
+
19
+ # Omega Testing
20
+
21
+ Comprehensive 4-Dimensional testing methodology for production-ready quality assurance.
22
+
23
+ ## Quick Start
24
+
25
+ ```javascript
26
+ // Run comprehensive Omega tests
27
+ npm run test:omega
28
+
29
+ // Or run individual dimensions
30
+ npm run test:accuracy // Unit, integration, E2E
31
+ npm run test:performance // Load, stress, benchmarks
32
+ npm run test:security // Vulnerability, injection, auth
33
+ npm run test:a11y // WCAG, keyboard, screen reader
34
+ ```
35
+
36
+ ## The 4 Dimensions
37
+
38
+ ### 1. Accuracy Testing
39
+ Ensures correctness of functionality.
40
+
41
+ ```javascript
42
+ // Unit Tests - Isolated function testing
43
+ describe('calculateTotal', () => {
44
+ it('calculates sum correctly', () => {
45
+ expect(calculateTotal([10, 20, 30])).toBe(60);
46
+ });
47
+
48
+ it('handles empty array', () => {
49
+ expect(calculateTotal([])).toBe(0);
50
+ });
51
+
52
+ it('handles negative numbers', () => {
53
+ expect(calculateTotal([-10, 20])).toBe(10);
54
+ });
55
+ });
56
+
57
+ // Integration Tests - Component interaction
58
+ describe('OrderService', () => {
59
+ it('creates order with payment', async () => {
60
+ const order = await orderService.create(cart, payment);
61
+ expect(order.status).toBe('confirmed');
62
+ expect(paymentService.charge).toHaveBeenCalled();
63
+ });
64
+ });
65
+
66
+ // E2E Tests - Full user flows
67
+ test('user can complete checkout', async ({ page }) => {
68
+ await page.goto('/products');
69
+ await page.click('[data-testid="add-to-cart"]');
70
+ await page.click('[data-testid="checkout"]');
71
+ await page.fill('#email', 'user@example.com');
72
+ await page.click('[data-testid="place-order"]');
73
+ await expect(page.locator('.order-confirmation')).toBeVisible();
74
+ });
75
+ ```
76
+
77
+ ### 2. Performance Testing
78
+ Ensures speed and resource efficiency.
79
+
80
+ ```javascript
81
+ // Benchmark Tests
82
+ describe('Performance Benchmarks', () => {
83
+ it('responds under 100ms', async () => {
84
+ const start = performance.now();
85
+ await api.fetch('/users');
86
+ const duration = performance.now() - start;
87
+ expect(duration).toBeLessThan(100);
88
+ });
89
+
90
+ it('handles 1000 concurrent requests', async () => {
91
+ const requests = Array(1000).fill().map(() => api.fetch('/users'));
92
+ const results = await Promise.all(requests);
93
+ expect(results.every(r => r.status === 200)).toBe(true);
94
+ });
95
+ });
96
+
97
+ // Memory Tests
98
+ it('does not leak memory', async () => {
99
+ const before = process.memoryUsage().heapUsed;
100
+ for (let i = 0; i < 1000; i++) {
101
+ await processData(largeDataset);
102
+ }
103
+ global.gc();
104
+ const after = process.memoryUsage().heapUsed;
105
+ expect(after - before).toBeLessThan(10 * 1024 * 1024); // 10MB
106
+ });
107
+ ```
108
+
109
+ ### 3. Security Testing
110
+ Ensures protection against vulnerabilities.
111
+
112
+ ```javascript
113
+ // Injection Tests
114
+ describe('SQL Injection Prevention', () => {
115
+ const maliciousInputs = [
116
+ "'; DROP TABLE users; --",
117
+ "1' OR '1'='1",
118
+ "admin'--",
119
+ ];
120
+
121
+ maliciousInputs.forEach(input => {
122
+ it(`blocks injection: ${input.slice(0, 20)}...`, async () => {
123
+ const result = await db.query(
124
+ 'SELECT * FROM users WHERE name = ?',
125
+ [input]
126
+ );
127
+ expect(result).toEqual([]);
128
+ });
129
+ });
130
+ });
131
+
132
+ // Authentication Tests
133
+ describe('Authentication', () => {
134
+ it('rejects expired tokens', async () => {
135
+ const expiredToken = generateToken({ exp: Date.now() - 1000 });
136
+ const response = await api.get('/protected', {
137
+ headers: { Authorization: `Bearer ${expiredToken}` },
138
+ });
139
+ expect(response.status).toBe(401);
140
+ });
141
+
142
+ it('prevents brute force', async () => {
143
+ for (let i = 0; i < 10; i++) {
144
+ await api.post('/login', { password: 'wrong' });
145
+ }
146
+ const response = await api.post('/login', { password: 'correct' });
147
+ expect(response.status).toBe(429); // Rate limited
148
+ });
149
+ });
150
+ ```
151
+
152
+ ### 4. Accessibility Testing
153
+ Ensures usability for all users.
154
+
155
+ ```javascript
156
+ // WCAG Compliance
157
+ describe('Accessibility', () => {
158
+ it('has proper heading hierarchy', async () => {
159
+ const headings = await page.$$eval('h1, h2, h3, h4, h5, h6', els =>
160
+ els.map(el => ({ level: parseInt(el.tagName[1]), text: el.textContent }))
161
+ );
162
+
163
+ for (let i = 1; i < headings.length; i++) {
164
+ const skip = headings[i].level - headings[i-1].level;
165
+ expect(skip).toBeLessThanOrEqual(1);
166
+ }
167
+ });
168
+
169
+ it('images have alt text', async () => {
170
+ const images = await page.$$('img');
171
+ for (const img of images) {
172
+ const alt = await img.getAttribute('alt');
173
+ expect(alt).toBeTruthy();
174
+ }
175
+ });
176
+
177
+ it('is keyboard navigable', async () => {
178
+ await page.keyboard.press('Tab');
179
+ const focused = await page.evaluate(() => document.activeElement.tagName);
180
+ expect(['A', 'BUTTON', 'INPUT']).toContain(focused);
181
+ });
182
+ });
183
+
184
+ // Screen Reader Testing
185
+ it('announces dynamic content', async () => {
186
+ await page.click('#load-more');
187
+ const liveRegion = await page.$('[aria-live="polite"]');
188
+ expect(await liveRegion.textContent()).toContain('Loaded');
189
+ });
190
+ ```
191
+
192
+ ## Coverage Requirements
193
+
194
+ | Dimension | Minimum | Target | Excellent |
195
+ |-----------|---------|--------|-----------|
196
+ | Accuracy (Unit) | 80% | 90% | 95% |
197
+ | Accuracy (Integration) | 60% | 75% | 85% |
198
+ | Performance | Pass SLAs | <100ms p95 | <50ms p95 |
199
+ | Security | No critical | No high | No medium |
200
+ | Accessibility | AA | AAA | Full AAA |
201
+
202
+ ## Test Organization
203
+
204
+ ```
205
+ tests/
206
+ ├── accuracy/
207
+ │ ├── unit/ # Isolated unit tests
208
+ │ ├── integration/ # Component integration
209
+ │ └── e2e/ # End-to-end flows
210
+ ├── performance/
211
+ │ ├── benchmarks/ # Speed benchmarks
212
+ │ ├── load/ # Load testing
213
+ │ └── stress/ # Stress testing
214
+ ├── security/
215
+ │ ├── injection/ # Injection tests
216
+ │ ├── auth/ # Authentication
217
+ │ └── vulnerabilities/# Known vulns
218
+ └── accessibility/
219
+ ├── wcag/ # WCAG compliance
220
+ ├── keyboard/ # Keyboard nav
221
+ └── screen-reader/ # SR compatibility
222
+ ```
223
+
224
+ ## F.I.R.S.T. Principles
225
+
226
+ - **Fast**: Tests run quickly (< 1ms for unit, < 100ms for integration)
227
+ - **Independent**: Tests don't depend on each other
228
+ - **Repeatable**: Same results every time
229
+ - **Self-Validating**: Pass or fail, no manual inspection
230
+ - **Timely**: Write tests before or with code
231
+
232
+ ## Anti-Patterns to Avoid
233
+
234
+ 1. **Testing Implementation**: Test behavior, not internals
235
+ 2. **Flaky Tests**: Eliminate randomness and timing issues
236
+ 3. **Over-Mocking**: Don't mock everything
237
+ 4. **Ignoring Edge Cases**: Test boundaries and errors
238
+ 5. **Copy-Paste Tests**: Use parameterized tests
239
+ 6. **No Assertions**: Every test must assert something
240
+ 7. **Testing Third-Party Code**: Focus on your code
241
+
242
+ ## When to Use
243
+
244
+ - Starting a new project with quality focus
245
+ - Improving existing test coverage
246
+ - Preparing for production deployment
247
+ - Meeting compliance requirements (SOC2, GDPR)
248
+ - Building critical infrastructure