koa-classic-server 1.2.0 → 2.0.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,301 @@
1
+ /**
2
+ * Performance Benchmark Tests
3
+ *
4
+ * These tests measure current performance to establish a baseline.
5
+ * After optimizations, run these tests again to measure improvements.
6
+ *
7
+ * Usage:
8
+ * npm run test:performance
9
+ *
10
+ * To save results:
11
+ * npm run test:performance > benchmark-results-v1.2.0.txt
12
+ */
13
+
14
+ const Koa = require('koa');
15
+ const supertest = require('supertest');
16
+ const koaClassicServer = require('../index.cjs');
17
+ const path = require('path');
18
+ const fs = require('fs');
19
+
20
+ const BENCHMARK_DIR = path.join(__dirname, '../benchmark-data');
21
+
22
+ // Check if benchmark data exists
23
+ if (!fs.existsSync(BENCHMARK_DIR)) {
24
+ console.error('\nāŒ Benchmark data not found!');
25
+ console.error('Please run: node scripts/setup-benchmark.js\n');
26
+ process.exit(1);
27
+ }
28
+
29
+ // Helper to measure execution time
30
+ function measureTime(fn) {
31
+ const start = process.hrtime.bigint();
32
+ const result = fn();
33
+ const end = process.hrtime.bigint();
34
+ const durationMs = Number(end - start) / 1000000; // Convert to ms
35
+ return { result, durationMs };
36
+ }
37
+
38
+ async function measureTimeAsync(fn) {
39
+ const start = process.hrtime.bigint();
40
+ const result = await fn();
41
+ const end = process.hrtime.bigint();
42
+ const durationMs = Number(end - start) / 1000000;
43
+ return { result, durationMs };
44
+ }
45
+
46
+ // Helper to run multiple iterations and get statistics
47
+ async function benchmark(name, fn, iterations = 10) {
48
+ const times = [];
49
+
50
+ for (let i = 0; i < iterations; i++) {
51
+ const { durationMs } = await measureTimeAsync(fn);
52
+ times.push(durationMs);
53
+ }
54
+
55
+ const avg = times.reduce((a, b) => a + b, 0) / times.length;
56
+ const min = Math.min(...times);
57
+ const max = Math.max(...times);
58
+ const median = times.sort((a, b) => a - b)[Math.floor(times.length / 2)];
59
+
60
+ return { name, avg, min, max, median, times };
61
+ }
62
+
63
+ describe('Performance Benchmarks - BASELINE (v1.2.0)', () => {
64
+ let app;
65
+ let server;
66
+ let request;
67
+
68
+ beforeAll(() => {
69
+ app = new Koa();
70
+ app.use(koaClassicServer(BENCHMARK_DIR));
71
+ server = app.listen();
72
+ request = supertest(server);
73
+ });
74
+
75
+ afterAll(() => {
76
+ server.close();
77
+ });
78
+
79
+ describe('File Serving Performance', () => {
80
+ test('Benchmark: Small file (1KB) - 100 iterations', async () => {
81
+ const stats = await benchmark(
82
+ 'Small file (1KB)',
83
+ async () => {
84
+ const res = await request.get('/small-files/file-1.txt');
85
+ expect(res.status).toBe(200);
86
+ },
87
+ 100
88
+ );
89
+
90
+ console.log('\nšŸ“Š Small File (1KB) Benchmark:');
91
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
92
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
93
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
94
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
95
+
96
+ expect(stats.avg).toBeLessThan(50); // Should be fast
97
+ }, 30000);
98
+
99
+ test('Benchmark: Medium file (100KB) - 50 iterations', async () => {
100
+ const stats = await benchmark(
101
+ 'Medium file (100KB)',
102
+ async () => {
103
+ const res = await request.get('/medium-files/file-1.txt');
104
+ expect(res.status).toBe(200);
105
+ },
106
+ 50
107
+ );
108
+
109
+ console.log('\nšŸ“Š Medium File (100KB) Benchmark:');
110
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
111
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
112
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
113
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
114
+
115
+ expect(stats.avg).toBeLessThan(100);
116
+ }, 30000);
117
+
118
+ test('Benchmark: Large file (1MB) - 20 iterations', async () => {
119
+ const stats = await benchmark(
120
+ 'Large file (1MB)',
121
+ async () => {
122
+ const res = await request.get('/large-files/file-1.txt');
123
+ expect(res.status).toBe(200);
124
+ },
125
+ 20
126
+ );
127
+
128
+ console.log('\nšŸ“Š Large File (1MB) Benchmark:');
129
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
130
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
131
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
132
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
133
+
134
+ expect(stats.avg).toBeLessThan(500);
135
+ }, 30000);
136
+ });
137
+
138
+ describe('Directory Listing Performance', () => {
139
+ test('Benchmark: Small directory (100 files) - 50 iterations', async () => {
140
+ const stats = await benchmark(
141
+ 'Directory listing (100 files)',
142
+ async () => {
143
+ const res = await request.get('/small-files/');
144
+ expect(res.status).toBe(200);
145
+ expect(res.text).toContain('file-1.txt');
146
+ },
147
+ 50
148
+ );
149
+
150
+ console.log('\nšŸ“Š Small Directory (100 files) Benchmark:');
151
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
152
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
153
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
154
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
155
+ }, 30000);
156
+
157
+ test('Benchmark: Large directory (1,000 files) - 20 iterations', async () => {
158
+ const stats = await benchmark(
159
+ 'Directory listing (1,000 files)',
160
+ async () => {
161
+ const res = await request.get('/large-directory/');
162
+ expect(res.status).toBe(200);
163
+ expect(res.text).toContain('item-0001.txt');
164
+ },
165
+ 20
166
+ );
167
+
168
+ console.log('\nšŸ“Š Large Directory (1,000 files) Benchmark:');
169
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
170
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
171
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
172
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
173
+
174
+ // This is expected to be slow with current sync implementation
175
+ console.log(` āš ļø WARNING: This will be MUCH faster after async optimization`);
176
+ }, 60000);
177
+
178
+ test('Benchmark: Very large directory (10,000 files) - 5 iterations', async () => {
179
+ const stats = await benchmark(
180
+ 'Directory listing (10,000 files)',
181
+ async () => {
182
+ const res = await request.get('/very-large-directory/');
183
+ expect(res.status).toBe(200);
184
+ expect(res.text).toContain('item-00001.txt');
185
+ },
186
+ 5
187
+ );
188
+
189
+ console.log('\nšŸ“Š Very Large Directory (10,000 files) Benchmark:');
190
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
191
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
192
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
193
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
194
+ console.log(` āš ļø WARNING: Event loop BLOCKED during this operation!`);
195
+ console.log(` āš ļø Expected to drop to ~${(stats.avg * 0.3).toFixed(2)}ms after optimization`);
196
+ }, 120000);
197
+ });
198
+
199
+ describe('Concurrent Request Performance', () => {
200
+ test('Benchmark: 10 concurrent small file requests', async () => {
201
+ const start = process.hrtime.bigint();
202
+
203
+ const promises = Array.from({ length: 10 }, (_, i) =>
204
+ request.get(`/small-files/file-${i + 1}.txt`)
205
+ );
206
+
207
+ const results = await Promise.all(promises);
208
+
209
+ const end = process.hrtime.bigint();
210
+ const totalTime = Number(end - start) / 1000000;
211
+
212
+ console.log('\nšŸ“Š 10 Concurrent Small Files:');
213
+ console.log(` Total time: ${totalTime.toFixed(2)}ms`);
214
+ console.log(` Avg per request: ${(totalTime / 10).toFixed(2)}ms`);
215
+
216
+ results.forEach(res => expect(res.status).toBe(200));
217
+ }, 10000);
218
+
219
+ test('Benchmark: 5 concurrent directory listings (100 files each)', async () => {
220
+ const start = process.hrtime.bigint();
221
+
222
+ const promises = Array.from({ length: 5 }, () =>
223
+ request.get('/small-files/')
224
+ );
225
+
226
+ const results = await Promise.all(promises);
227
+
228
+ const end = process.hrtime.bigint();
229
+ const totalTime = Number(end - start) / 1000000;
230
+
231
+ console.log('\nšŸ“Š 5 Concurrent Directory Listings (100 files):');
232
+ console.log(` Total time: ${totalTime.toFixed(2)}ms`);
233
+ console.log(` Avg per request: ${(totalTime / 5).toFixed(2)}ms`);
234
+ console.log(` āš ļø With current sync code, these run SEQUENTIALLY`);
235
+ console.log(` āš ļø After async optimization, will run in PARALLEL`);
236
+
237
+ results.forEach(res => expect(res.status).toBe(200));
238
+ }, 30000);
239
+ });
240
+
241
+ describe('404 Not Found Performance', () => {
242
+ test('Benchmark: Non-existent file - 50 iterations', async () => {
243
+ const stats = await benchmark(
244
+ '404 Not Found',
245
+ async () => {
246
+ const res = await request.get('/does-not-exist-12345.txt');
247
+ expect(res.status).toBe(404);
248
+ },
249
+ 50
250
+ );
251
+
252
+ console.log('\nšŸ“Š 404 Not Found Benchmark:');
253
+ console.log(` Average: ${stats.avg.toFixed(2)}ms`);
254
+ console.log(` Median: ${stats.median.toFixed(2)}ms`);
255
+ console.log(` Min: ${stats.min.toFixed(2)}ms`);
256
+ console.log(` Max: ${stats.max.toFixed(2)}ms`);
257
+ }, 10000);
258
+ });
259
+
260
+ describe('Memory Usage (Informational)', () => {
261
+ test('Memory usage during large directory listing', async () => {
262
+ // Force garbage collection if available
263
+ if (global.gc) {
264
+ global.gc();
265
+ }
266
+
267
+ const memBefore = process.memoryUsage();
268
+
269
+ // Request large directory
270
+ const res = await request.get('/very-large-directory/');
271
+ expect(res.status).toBe(200);
272
+
273
+ const memAfter = process.memoryUsage();
274
+
275
+ const heapUsedDiff = (memAfter.heapUsed - memBefore.heapUsed) / 1024 / 1024;
276
+ const externalDiff = (memAfter.external - memBefore.external) / 1024 / 1024;
277
+
278
+ console.log('\nšŸ“Š Memory Usage (10,000 files directory):');
279
+ console.log(` Heap used increase: ${heapUsedDiff.toFixed(2)} MB`);
280
+ console.log(` External increase: ${externalDiff.toFixed(2)} MB`);
281
+ console.log(` Response size: ${(res.text.length / 1024 / 1024).toFixed(2)} MB`);
282
+ console.log(` āš ļø Expected to reduce by ~30-40% after optimization`);
283
+ }, 30000);
284
+ });
285
+ });
286
+
287
+ // Summary report
288
+ afterAll(() => {
289
+ console.log('\n' + '='.repeat(70));
290
+ console.log('šŸ“‹ BASELINE BENCHMARK SUMMARY');
291
+ console.log('='.repeat(70));
292
+ console.log('\nThese results represent the CURRENT performance (v1.2.0)');
293
+ console.log('After implementing optimizations, run this test again to see improvements.\n');
294
+ console.log('Expected improvements after optimization:');
295
+ console.log(' āœ“ Small files: 10-20% faster (async operations)');
296
+ console.log(' āœ“ Large directories: 50-70% faster (async + array join)');
297
+ console.log(' āœ“ Concurrent requests: 5-10x faster (non-blocking event loop)');
298
+ console.log(' āœ“ Memory usage: 30-40% reduction (array join vs concatenation)');
299
+ console.log(' āœ“ With HTTP caching: 80-95% faster (304 responses)');
300
+ console.log('='.repeat(70) + '\n');
301
+ });
@@ -0,0 +1,354 @@
1
+
2
+ > koa-classic-server@1.2.0 test:performance
3
+ > jest __tests__/performance.test.js --runInBand
4
+
5
+ console.log
6
+
7
+ šŸ“Š Small File (1KB) Benchmark:
8
+
9
+ at Object.log (__tests__/performance.test.js:90:21)
10
+
11
+ console.log
12
+ Average: 2.93ms
13
+
14
+ at Object.log (__tests__/performance.test.js:91:21)
15
+
16
+ console.log
17
+ Median: 2.54ms
18
+
19
+ at Object.log (__tests__/performance.test.js:92:21)
20
+
21
+ console.log
22
+ Min: 1.99ms
23
+
24
+ at Object.log (__tests__/performance.test.js:93:21)
25
+
26
+ console.log
27
+ Max: 26.87ms
28
+
29
+ at Object.log (__tests__/performance.test.js:94:21)
30
+
31
+ console.log
32
+
33
+ šŸ“Š Medium File (100KB) Benchmark:
34
+
35
+ at Object.log (__tests__/performance.test.js:109:21)
36
+
37
+ console.log
38
+ Average: 3.59ms
39
+
40
+ at Object.log (__tests__/performance.test.js:110:21)
41
+
42
+ console.log
43
+ Median: 3.51ms
44
+
45
+ at Object.log (__tests__/performance.test.js:111:21)
46
+
47
+ console.log
48
+ Min: 2.46ms
49
+
50
+ at Object.log (__tests__/performance.test.js:112:21)
51
+
52
+ console.log
53
+ Max: 8.36ms
54
+
55
+ at Object.log (__tests__/performance.test.js:113:21)
56
+
57
+ console.log
58
+
59
+ šŸ“Š Large File (1MB) Benchmark:
60
+
61
+ at Object.log (__tests__/performance.test.js:128:21)
62
+
63
+ console.log
64
+ Average: 9.03ms
65
+
66
+ at Object.log (__tests__/performance.test.js:129:21)
67
+
68
+ console.log
69
+ Median: 8.35ms
70
+
71
+ at Object.log (__tests__/performance.test.js:130:21)
72
+
73
+ console.log
74
+ Min: 5.46ms
75
+
76
+ at Object.log (__tests__/performance.test.js:131:21)
77
+
78
+ console.log
79
+ Max: 13.81ms
80
+
81
+ at Object.log (__tests__/performance.test.js:132:21)
82
+
83
+ console.log
84
+
85
+ šŸ“Š Small Directory (100 files) Benchmark:
86
+
87
+ at Object.log (__tests__/performance.test.js:150:21)
88
+
89
+ console.log
90
+ Average: 2.65ms
91
+
92
+ at Object.log (__tests__/performance.test.js:151:21)
93
+
94
+ console.log
95
+ Median: 2.54ms
96
+
97
+ at Object.log (__tests__/performance.test.js:152:21)
98
+
99
+ console.log
100
+ Min: 2.22ms
101
+
102
+ at Object.log (__tests__/performance.test.js:153:21)
103
+
104
+ console.log
105
+ Max: 4.69ms
106
+
107
+ at Object.log (__tests__/performance.test.js:154:21)
108
+
109
+ console.log
110
+
111
+ šŸ“Š Large Directory (1,000 files) Benchmark:
112
+
113
+ at Object.log (__tests__/performance.test.js:168:21)
114
+
115
+ console.log
116
+ Average: 9.23ms
117
+
118
+ at Object.log (__tests__/performance.test.js:169:21)
119
+
120
+ console.log
121
+ Median: 9.14ms
122
+
123
+ at Object.log (__tests__/performance.test.js:170:21)
124
+
125
+ console.log
126
+ Min: 8.26ms
127
+
128
+ at Object.log (__tests__/performance.test.js:171:21)
129
+
130
+ console.log
131
+ Max: 11.64ms
132
+
133
+ at Object.log (__tests__/performance.test.js:172:21)
134
+
135
+ console.log
136
+ āš ļø WARNING: This will be MUCH faster after async optimization
137
+
138
+ at Object.log (__tests__/performance.test.js:175:21)
139
+
140
+ console.log
141
+
142
+ šŸ“Š Very Large Directory (10,000 files) Benchmark:
143
+
144
+ at Object.log (__tests__/performance.test.js:189:21)
145
+
146
+ console.log
147
+ Average: 102.37ms
148
+
149
+ at Object.log (__tests__/performance.test.js:190:21)
150
+
151
+ console.log
152
+ Median: 95.13ms
153
+
154
+ at Object.log (__tests__/performance.test.js:191:21)
155
+
156
+ console.log
157
+ Min: 90.91ms
158
+
159
+ at Object.log (__tests__/performance.test.js:192:21)
160
+
161
+ console.log
162
+ Max: 120.85ms
163
+
164
+ at Object.log (__tests__/performance.test.js:193:21)
165
+
166
+ console.log
167
+ āš ļø WARNING: Event loop BLOCKED during this operation!
168
+
169
+ at Object.log (__tests__/performance.test.js:194:21)
170
+
171
+ console.log
172
+ āš ļø Expected to drop to ~30.71ms after optimization
173
+
174
+ at Object.log (__tests__/performance.test.js:195:21)
175
+
176
+ console.log
177
+
178
+ šŸ“Š 10 Concurrent Small Files:
179
+
180
+ at Object.log (__tests__/performance.test.js:212:21)
181
+
182
+ console.log
183
+ Total time: 15.50ms
184
+
185
+ at Object.log (__tests__/performance.test.js:213:21)
186
+
187
+ console.log
188
+ Avg per request: 1.55ms
189
+
190
+ at Object.log (__tests__/performance.test.js:214:21)
191
+
192
+ console.log
193
+
194
+ šŸ“Š 5 Concurrent Directory Listings (100 files):
195
+
196
+ at Object.log (__tests__/performance.test.js:231:21)
197
+
198
+ console.log
199
+ Total time: 11.30ms
200
+
201
+ at Object.log (__tests__/performance.test.js:232:21)
202
+
203
+ console.log
204
+ Avg per request: 2.26ms
205
+
206
+ at Object.log (__tests__/performance.test.js:233:21)
207
+
208
+ console.log
209
+ āš ļø With current sync code, these run SEQUENTIALLY
210
+
211
+ at Object.log (__tests__/performance.test.js:234:21)
212
+
213
+ console.log
214
+ āš ļø After async optimization, will run in PARALLEL
215
+
216
+ at Object.log (__tests__/performance.test.js:235:21)
217
+
218
+ console.log
219
+
220
+ šŸ“Š 404 Not Found Benchmark:
221
+
222
+ at Object.log (__tests__/performance.test.js:252:21)
223
+
224
+ console.log
225
+ Average: 1.26ms
226
+
227
+ at Object.log (__tests__/performance.test.js:253:21)
228
+
229
+ console.log
230
+ Median: 1.24ms
231
+
232
+ at Object.log (__tests__/performance.test.js:254:21)
233
+
234
+ console.log
235
+ Min: 1.05ms
236
+
237
+ at Object.log (__tests__/performance.test.js:255:21)
238
+
239
+ console.log
240
+ Max: 2.17ms
241
+
242
+ at Object.log (__tests__/performance.test.js:256:21)
243
+
244
+ console.log
245
+
246
+ šŸ“Š Memory Usage (10,000 files directory):
247
+
248
+ at Object.log (__tests__/performance.test.js:278:21)
249
+
250
+ console.log
251
+ Heap used increase: 1.16 MB
252
+
253
+ at Object.log (__tests__/performance.test.js:279:21)
254
+
255
+ console.log
256
+ External increase: 2.57 MB
257
+
258
+ at Object.log (__tests__/performance.test.js:280:21)
259
+
260
+ console.log
261
+ Response size: 1.29 MB
262
+
263
+ at Object.log (__tests__/performance.test.js:281:21)
264
+
265
+ console.log
266
+ āš ļø Expected to reduce by ~30-40% after optimization
267
+
268
+ at Object.log (__tests__/performance.test.js:282:21)
269
+
270
+ console.log
271
+
272
+ ======================================================================
273
+
274
+ at Object.log (__tests__/performance.test.js:289:13)
275
+
276
+ console.log
277
+ šŸ“‹ BASELINE BENCHMARK SUMMARY
278
+
279
+ at Object.log (__tests__/performance.test.js:290:13)
280
+
281
+ console.log
282
+ ======================================================================
283
+
284
+ at Object.log (__tests__/performance.test.js:291:13)
285
+
286
+ console.log
287
+
288
+ These results represent the CURRENT performance (v1.2.0)
289
+
290
+ at Object.log (__tests__/performance.test.js:292:13)
291
+
292
+ console.log
293
+ After implementing optimizations, run this test again to see improvements.
294
+
295
+ at Object.log (__tests__/performance.test.js:293:13)
296
+
297
+ console.log
298
+ Expected improvements after optimization:
299
+
300
+ at Object.log (__tests__/performance.test.js:294:13)
301
+
302
+ console.log
303
+ āœ“ Small files: 10-20% faster (async operations)
304
+
305
+ at Object.log (__tests__/performance.test.js:295:13)
306
+
307
+ console.log
308
+ āœ“ Large directories: 50-70% faster (async + array join)
309
+
310
+ at Object.log (__tests__/performance.test.js:296:13)
311
+
312
+ console.log
313
+ āœ“ Concurrent requests: 5-10x faster (non-blocking event loop)
314
+
315
+ at Object.log (__tests__/performance.test.js:297:13)
316
+
317
+ console.log
318
+ āœ“ Memory usage: 30-40% reduction (array join vs concatenation)
319
+
320
+ at Object.log (__tests__/performance.test.js:298:13)
321
+
322
+ console.log
323
+ āœ“ With HTTP caching: 80-95% faster (304 responses)
324
+
325
+ at Object.log (__tests__/performance.test.js:299:13)
326
+
327
+ console.log
328
+ ======================================================================
329
+
330
+ at Object.log (__tests__/performance.test.js:300:13)
331
+
332
+ PASS __tests__/performance.test.js
333
+ Performance Benchmarks - BASELINE (v1.2.0)
334
+ File Serving Performance
335
+ āœ“ Benchmark: Small file (1KB) - 100 iterations (318 ms)
336
+ āœ“ Benchmark: Medium file (100KB) - 50 iterations (184 ms)
337
+ āœ“ Benchmark: Large file (1MB) - 20 iterations (183 ms)
338
+ Directory Listing Performance
339
+ āœ“ Benchmark: Small directory (100 files) - 50 iterations (135 ms)
340
+ āœ“ Benchmark: Large directory (1,000 files) - 20 iterations (188 ms)
341
+ āœ“ Benchmark: Very large directory (10,000 files) - 5 iterations (515 ms)
342
+ Concurrent Request Performance
343
+ āœ“ Benchmark: 10 concurrent small file requests (18 ms)
344
+ āœ“ Benchmark: 5 concurrent directory listings (100 files each) (14 ms)
345
+ 404 Not Found Performance
346
+ āœ“ Benchmark: Non-existent file - 50 iterations (66 ms)
347
+ Memory Usage (Informational)
348
+ āœ“ Memory usage during large directory listing (88 ms)
349
+
350
+ Test Suites: 1 passed, 1 total
351
+ Tests: 10 passed, 10 total
352
+ Snapshots: 0 total
353
+ Time: 3.227 s, estimated 4 s
354
+ Ran all test suites matching /__tests__\/performance.test.js/i.