Files
xget/test/features/performance.test.js
xixu-me 81e810ec9a Add type declarations and improve test typings
Introduces src/types.d.ts and test/types.d.ts for Cloudflare Workers and test utilities. Enhances JSDoc comments and type annotations across test files for better type safety and clarity. Updates tsconfig.json to use bundler module resolution and include additional type sources. Minor test logic and assertion improvements for robustness.
2025-12-08 19:57:48 +08:00

241 lines
6.9 KiB
JavaScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
// Mock PerformanceMonitor class for testing
class MockPerformanceMonitor {
constructor() {
this.startTime = Date.now();
this.marks = new Map();
}
/**
* Mark a performance measurement
* @param {string} name - Name of the mark
*/
mark(name) {
if (this.marks.has(name)) {
console.warn(`Mark with name ${name} already exists.`);
}
this.marks.set(name, Date.now() - this.startTime);
}
getMetrics() {
return Object.fromEntries(this.marks.entries());
}
}
describe('Performance Monitoring', () => {
/** @type {MockPerformanceMonitor} */
let monitor;
beforeEach(() => {
monitor = new MockPerformanceMonitor();
});
describe('PerformanceMonitor Class', () => {
it('should initialize with start time', () => {
expect(monitor.startTime).toBeDefined();
expect(typeof monitor.startTime).toBe('number');
});
it('should create timing marks', () => {
monitor.mark('test-mark');
const metrics = monitor.getMetrics();
expect(metrics).toHaveProperty('test-mark');
expect(typeof metrics['test-mark']).toBe('number');
});
it('should handle multiple marks', () => {
monitor.mark('mark1');
monitor.mark('mark2');
monitor.mark('mark3');
const metrics = monitor.getMetrics();
expect(Object.keys(metrics)).toHaveLength(3);
expect(metrics).toHaveProperty('mark1');
expect(metrics).toHaveProperty('mark2');
expect(metrics).toHaveProperty('mark3');
});
it('should warn on duplicate mark names', () => {
// Mock console.warn for this test
const originalWarn = console.warn;
const mockWarn = vi.fn();
console.warn = mockWarn;
monitor.mark('duplicate');
monitor.mark('duplicate');
expect(mockWarn).toHaveBeenCalledWith('Mark with name duplicate already exists.');
// Restore original console.warn
console.warn = originalWarn;
});
it('should return metrics as plain object', () => {
monitor.mark('test');
const metrics = monitor.getMetrics();
expect(metrics).toBeTypeOf('object');
expect(Array.isArray(metrics)).toBe(false);
});
it('should track elapsed time correctly', async () => {
monitor.mark('start');
// Wait a small amount of time
await new Promise(resolve => setTimeout(resolve, 10));
monitor.mark('end');
const metrics = monitor.getMetrics();
expect(metrics.end).toBeGreaterThan(metrics.start);
});
});
describe('Performance Metrics Validation', () => {
it('should produce serializable metrics', () => {
monitor.mark('request-start');
monitor.mark('proxy-start');
monitor.mark('proxy-end');
monitor.mark('request-end');
const metrics = monitor.getMetrics();
expect(() => JSON.stringify(metrics)).not.toThrow();
});
it('should have reasonable timing values', () => {
monitor.mark('test-mark');
const metrics = monitor.getMetrics();
const timing = metrics['test-mark'];
// Should be a positive number and reasonable (less than 1 second for this test)
expect(timing).toBeGreaterThanOrEqual(0);
expect(timing).toBeLessThan(1000);
});
it('should maintain chronological order', async () => {
monitor.mark('first');
await new Promise(resolve => setTimeout(resolve, 5));
monitor.mark('second');
await new Promise(resolve => setTimeout(resolve, 5));
monitor.mark('third');
const metrics = monitor.getMetrics();
expect(metrics.first).toBeLessThan(metrics.second);
expect(metrics.second).toBeLessThan(metrics.third);
});
});
describe('Common Performance Scenarios', () => {
it('should track request lifecycle', () => {
// Simulate typical request flow
monitor.mark('request-received');
monitor.mark('validation-complete');
monitor.mark('proxy-start');
monitor.mark('proxy-response');
monitor.mark('response-sent');
const metrics = monitor.getMetrics();
expect(metrics).toHaveProperty('request-received');
expect(metrics).toHaveProperty('validation-complete');
expect(metrics).toHaveProperty('proxy-start');
expect(metrics).toHaveProperty('proxy-response');
expect(metrics).toHaveProperty('response-sent');
});
it('should track cache operations', () => {
monitor.mark('cache-check-start');
monitor.mark('cache-miss');
monitor.mark('upstream-request');
monitor.mark('cache-store');
const metrics = monitor.getMetrics();
expect(metrics).toHaveProperty('cache-check-start');
expect(metrics).toHaveProperty('cache-miss');
expect(metrics).toHaveProperty('upstream-request');
expect(metrics).toHaveProperty('cache-store');
});
it('should track error scenarios', () => {
monitor.mark('request-start');
monitor.mark('error-occurred');
monitor.mark('error-handled');
const metrics = monitor.getMetrics();
expect(metrics).toHaveProperty('request-start');
expect(metrics).toHaveProperty('error-occurred');
expect(metrics).toHaveProperty('error-handled');
});
});
describe('Performance Thresholds', () => {
it('should identify slow operations', () => {
monitor.mark('operation-start');
// Simulate slow operation
const slowTiming = 5000; // 5 seconds
monitor.marks.set('operation-end', slowTiming);
const metrics = monitor.getMetrics();
const operationTime = metrics['operation-end'] - (metrics['operation-start'] || 0);
// Should identify as slow (> 1 second)
expect(operationTime).toBeGreaterThan(1000);
});
it('should identify fast operations', () => {
monitor.mark('fast-operation');
const metrics = monitor.getMetrics();
const timing = metrics['fast-operation'];
// Should be fast (< 100ms for this test)
expect(timing).toBeLessThan(100);
});
});
describe('Memory and Resource Usage', () => {
it('should not leak memory with many marks', () => {
const initialSize = monitor.marks.size;
// Add many marks
for (let i = 0; i < 1000; i++) {
monitor.mark(`mark-${i}`);
}
expect(monitor.marks.size).toBe(initialSize + 1000);
// Clear marks (if such method existed)
monitor.marks.clear();
expect(monitor.marks.size).toBe(0);
});
it('should handle concurrent mark operations', () => {
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(
new Promise((/** @type {(value?: unknown) => void} */ resolve) => {
setTimeout(() => {
monitor.mark(`concurrent-${i}`);
resolve();
}, Math.random() * 10);
})
);
}
return Promise.all(promises).then(() => {
const metrics = monitor.getMetrics();
expect(Object.keys(metrics)).toHaveLength(10);
});
});
});
});