Update test framework: fix run_tests.py to support all test files, add auto-import-check for test files

This commit is contained in:
qiaoxinjiu
2026-05-09 15:11:30 +08:00
parent eb053a347f
commit eaba8328da
21739 changed files with 2236758 additions and 719 deletions

View File

@@ -0,0 +1,2 @@
export * from './types.js';
export * from './limiter.js';

View File

@@ -0,0 +1,3 @@
// Rate limiting module exports
export * from './types.js';
export * from './limiter.js';

View File

@@ -0,0 +1,107 @@
import { RateLimitConfig, RateLimitResult, RateLimitStats, ResourceLimitConfig } from './types';
/**
* Rate Limiter Class
* Implements request throttling and resource protection
*/
export declare class RateLimiter {
private config;
private store;
private categoryConfigs;
private stats;
private cleanupInterval?;
constructor(config: RateLimitConfig);
/**
* Set rate limit configuration for a specific category
* @param category Rate limit category
* @param config Category-specific configuration
*/
setCategoryConfig(category: string, config: RateLimitConfig): void;
/**
* Check if request is within rate limits
* @param key Rate limit key (usually IP or user ID)
* @param category Request category
* @returns Rate limit check result
*/
checkLimit(key: string, category?: string): RateLimitResult;
/**
* Reset rate limits for a specific key
* @param key Rate limit key to reset
*/
resetLimits(key: string): void;
/**
* Reset all rate limits
*/
resetAllLimits(): void;
/**
* Get rate limiter statistics
* @returns Current statistics
*/
getStats(): RateLimitStats;
/**
* Get current entries count
* @returns Number of active rate limit entries
*/
getActiveEntries(): number;
/**
* Check if a key is currently rate limited
* @param key Rate limit key
* @param category Request category
* @returns Whether the key is rate limited
*/
isRateLimited(key: string, category?: string): boolean;
/**
* Get remaining requests for a key
* @param key Rate limit key
* @param category Request category
* @returns Number of remaining requests
*/
getRemainingRequests(key: string, category?: string): number;
/**
* Start cleanup interval to remove expired entries
*/
private startCleanup;
/**
* Stop cleanup interval
*/
stopCleanup(): void;
/**
* Remove expired rate limit entries
*/
private cleanup;
}
/**
* Resource Limiter Class
* Manages system resource limits
*/
export declare class ResourceLimiter {
private config;
private activeBrowsers;
constructor(config: ResourceLimitConfig);
/**
* Check if browser instance can be created
* @returns Whether browser creation is allowed
*/
canCreateBrowser(): boolean;
/**
* Register a new browser instance
*/
registerBrowser(): void;
/**
* Unregister a browser instance
*/
unregisterBrowser(): void;
/**
* Get current browser count
*/
getActiveBrowserCount(): number;
/**
* Check current memory usage
* @returns Whether memory usage is within limits
*/
checkMemoryUsage(): boolean;
/**
* Get current memory usage percentage
* @returns Memory usage as percentage of limit
*/
getMemoryUsagePercent(): number;
}

View File

@@ -0,0 +1,208 @@
import { RateLimitCategory } from './types';
/**
* Rate Limiter Class
* Implements request throttling and resource protection
*/
export class RateLimiter {
constructor(config) {
this.store = new Map();
this.categoryConfigs = new Map();
this.config = config;
this.stats = {
totalRequests: 0,
blockedRequests: 0,
activeEntries: 0,
byCategory: {},
timestamp: Date.now()
};
// Start cleanup interval to remove expired entries
this.startCleanup();
}
/**
* Set rate limit configuration for a specific category
* @param category Rate limit category
* @param config Category-specific configuration
*/
setCategoryConfig(category, config) {
this.categoryConfigs.set(category, config);
}
/**
* Check if request is within rate limits
* @param key Rate limit key (usually IP or user ID)
* @param category Request category
* @returns Rate limit check result
*/
checkLimit(key, category = RateLimitCategory.GENERAL) {
const config = this.categoryConfigs.get(category) || this.config;
const now = Date.now();
const windowStart = now - config.windowMs;
// Get or create entry for this key
let entry = this.store.get(key);
if (!entry || entry.windowStart < windowStart) {
// Create new window
entry = {
count: 0,
windowStart: now,
firstRequest: now
};
this.store.set(key, entry);
}
// Update statistics
this.stats.totalRequests++;
if (!this.stats.byCategory[category]) {
this.stats.byCategory[category] = { requests: 0, blocked: 0 };
}
this.stats.byCategory[category].requests++;
// Check if limit exceeded
const allowed = entry.count < config.maxRequests;
if (allowed) {
entry.count++;
}
else {
this.stats.blockedRequests++;
this.stats.byCategory[category].blocked++;
}
const resetTime = entry.windowStart + config.windowMs;
const retryAfter = allowed ? undefined : Math.ceil((resetTime - now) / 1000);
return {
allowed,
remaining: Math.max(0, config.maxRequests - entry.count),
resetTime,
retryAfter,
limit: config.maxRequests,
current: entry.count
};
}
/**
* Reset rate limits for a specific key
* @param key Rate limit key to reset
*/
resetLimits(key) {
this.store.delete(key);
}
/**
* Reset all rate limits
*/
resetAllLimits() {
this.store.clear();
}
/**
* Get rate limiter statistics
* @returns Current statistics
*/
getStats() {
this.stats.activeEntries = this.store.size;
this.stats.timestamp = Date.now();
return { ...this.stats };
}
/**
* Get current entries count
* @returns Number of active rate limit entries
*/
getActiveEntries() {
return this.store.size;
}
/**
* Check if a key is currently rate limited
* @param key Rate limit key
* @param category Request category
* @returns Whether the key is rate limited
*/
isRateLimited(key, category = RateLimitCategory.GENERAL) {
const result = this.checkLimit(key, category);
return !result.allowed;
}
/**
* Get remaining requests for a key
* @param key Rate limit key
* @param category Request category
* @returns Number of remaining requests
*/
getRemainingRequests(key, category = RateLimitCategory.GENERAL) {
const result = this.checkLimit(key, category);
return result.remaining;
}
/**
* Start cleanup interval to remove expired entries
*/
startCleanup() {
this.cleanupInterval = setInterval(() => {
this.cleanup();
}, 60000); // Cleanup every minute
}
/**
* Stop cleanup interval
*/
stopCleanup() {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
this.cleanupInterval = undefined;
}
}
/**
* Remove expired rate limit entries
*/
cleanup() {
const now = Date.now();
const expiredKeys = [];
for (const [key, entry] of this.store.entries()) {
// Remove entries older than the longest window
const maxWindow = Math.max(this.config.windowMs, ...Array.from(this.categoryConfigs.values()).map(c => c.windowMs));
if (entry.windowStart < now - maxWindow) {
expiredKeys.push(key);
}
}
expiredKeys.forEach(key => this.store.delete(key));
}
}
/**
* Resource Limiter Class
* Manages system resource limits
*/
export class ResourceLimiter {
constructor(config) {
this.activeBrowsers = 0;
this.config = config;
}
/**
* Check if browser instance can be created
* @returns Whether browser creation is allowed
*/
canCreateBrowser() {
return this.activeBrowsers < this.config.maxBrowsers;
}
/**
* Register a new browser instance
*/
registerBrowser() {
this.activeBrowsers++;
}
/**
* Unregister a browser instance
*/
unregisterBrowser() {
this.activeBrowsers = Math.max(0, this.activeBrowsers - 1);
}
/**
* Get current browser count
*/
getActiveBrowserCount() {
return this.activeBrowsers;
}
/**
* Check current memory usage
* @returns Whether memory usage is within limits
*/
checkMemoryUsage() {
const memoryUsage = process.memoryUsage();
return memoryUsage.heapUsed < this.config.maxMemoryUsage;
}
/**
* Get current memory usage percentage
* @returns Memory usage as percentage of limit
*/
getMemoryUsagePercent() {
const memoryUsage = process.memoryUsage();
return (memoryUsage.heapUsed / this.config.maxMemoryUsage) * 100;
}
}

View File

@@ -0,0 +1,89 @@
/**
* Rate Limit Configuration
*/
export interface RateLimitConfig {
/** Time window in milliseconds */
windowMs: number;
/** Maximum requests allowed in the window */
maxRequests: number;
/** Maximum concurrent browser instances */
maxBrowsers: number;
/** Skip counting successful requests */
skipSuccessfulRequests: boolean;
/** Function to generate rate limit key from request */
keyGenerator: (req: any) => string;
/** Custom message for rate limit exceeded */
message?: string;
/** Headers to include in rate limit response */
standardHeaders?: boolean;
}
/**
* Rate Limit Check Result
*/
export interface RateLimitResult {
/** Whether the request is allowed */
allowed: boolean;
/** Number of requests remaining in current window */
remaining: number;
/** Timestamp when the rate limit resets */
resetTime: number;
/** Seconds to wait before retrying (if not allowed) */
retryAfter?: number;
/** Total requests allowed in window */
limit: number;
/** Current request count in window */
current: number;
}
/**
* Rate Limit Store Entry
*/
export interface RateLimitEntry {
/** Request count in current window */
count: number;
/** Window start timestamp */
windowStart: number;
/** First request timestamp in window */
firstRequest: number;
}
/**
* Rate Limit Categories
*/
export declare enum RateLimitCategory {
BROWSER = "browser",
API = "api",
SCREENSHOT = "screenshot",
NAVIGATION = "navigation",
INTERACTION = "interaction",
GENERAL = "general"
}
/**
* Rate Limit Statistics
*/
export interface RateLimitStats {
/** Total requests processed */
totalRequests: number;
/** Total requests blocked */
blockedRequests: number;
/** Active rate limit entries */
activeEntries: number;
/** Statistics by category */
byCategory: Record<string, {
requests: number;
blocked: number;
}>;
/** Current timestamp */
timestamp: number;
}
/**
* Resource Limit Configuration
*/
export interface ResourceLimitConfig {
/** Maximum concurrent browser instances */
maxBrowsers: number;
/** Maximum memory usage in bytes */
maxMemoryUsage: number;
/** Maximum CPU usage percentage */
maxCpuUsage: number;
/** Enable resource monitoring */
enableMonitoring: boolean;
}

View File

@@ -0,0 +1,12 @@
/**
* Rate Limit Categories
*/
export var RateLimitCategory;
(function (RateLimitCategory) {
RateLimitCategory["BROWSER"] = "browser";
RateLimitCategory["API"] = "api";
RateLimitCategory["SCREENSHOT"] = "screenshot";
RateLimitCategory["NAVIGATION"] = "navigation";
RateLimitCategory["INTERACTION"] = "interaction";
RateLimitCategory["GENERAL"] = "general";
})(RateLimitCategory || (RateLimitCategory = {}));