lightweight-browser-load-tester
Version:
A lightweight load testing tool using real browsers for streaming applications with DRM support
867 lines (686 loc) • 23.4 kB
Markdown
# API Documentation
This document provides detailed information about all public interfaces and classes in the Lightweight Browser Load Tester.
## Table of Contents
- [Core Classes](#core-classes)
- [Configuration Interfaces](#configuration-interfaces)
- [Result Interfaces](#result-interfaces)
- [Utility Classes](#utility-classes)
- [Error Handling](#error-handling)
- [Events](#events)
## Core Classes
### LoadTesterApp
Main application class that coordinates all components.
```typescript
class LoadTesterApp {
constructor(config: TestConfiguration)
// Start the load test application
async start(): Promise<TestResults>
// Stop the application gracefully
async stop(): Promise<TestResults | null>
// Get current test status
getStatus(): {
status: 'not_started' | 'running' | 'completed';
testId?: string;
monitoring?: any;
}
}
```
**Usage Example:**
```typescript
import { LoadTesterApp, TestConfiguration } from 'lightweight-browser-load-tester';
const config: TestConfiguration = {
concurrentUsers: 10,
testDuration: 300,
rampUpTime: 30,
streamingUrl: 'https://example.com/stream',
requestParameters: [],
resourceLimits: {
maxMemoryPerInstance: 512,
maxCpuPercentage: 80,
maxConcurrentInstances: 20
}
};
const app = new LoadTesterApp(config);
const results = await app.start();
```
### TestRunner
Orchestrates browser instances and executes load tests.
```typescript
class TestRunner extends EventEmitter {
constructor(config: TestConfiguration)
// Start the load test
async startTest(): Promise<void>
// Stop the load test
async stopTest(): Promise<TestResults>
// Check if test is currently running
isTestRunning(): boolean
// Get unique test identifier
getTestId(): string
// Get real-time monitoring data
getMonitoringData(): MonitoringData
}
```
**Events:**
- `test-started`: Emitted when test begins
- `test-completed`: Emitted when test finishes successfully
- `test-failed`: Emitted when test fails
- `ramp-up-completed`: Emitted when all users are active
- `monitoring-update`: Emitted with real-time metrics
- `session-failed`: Emitted when a browser session fails
### BrowserPool
Manages browser instance lifecycle and resource optimization.
```typescript
class BrowserPool {
constructor(config: BrowserPoolConfig)
// Get an available browser instance
async acquireInstance(): Promise<ManagedBrowserInstance>
// Return a browser instance to the pool
async releaseInstance(instance: ManagedBrowserInstance): Promise<void>
// Get current pool statistics
getPoolStats(): {
total: number;
active: number;
idle: number;
memoryUsage: number;
}
// Cleanup all browser instances
async cleanup(): Promise<void>
}
```
### RequestInterceptor
Intercepts and modifies network requests during page interactions.
```typescript
class RequestInterceptor {
constructor(parameterTemplates: ParameterTemplate[])
// Set up request interception for a page
async setupInterception(page: Page): Promise<void>
// Process and modify a request
async processRequest(request: Request): Promise<void>
// Get collected network metrics
getNetworkMetrics(): NetworkMetrics[]
// Get DRM-specific metrics
getDRMMetrics(): DRMMetrics[]
}
```
### ResultsAggregator
Collects and processes test results from all browser instances.
```typescript
class ResultsAggregator {
// Add metrics from a browser instance
addBrowserMetrics(metrics: BrowserMetrics): void
// Add network request metrics
addNetworkMetrics(metrics: NetworkMetrics[]): void
// Add DRM-specific metrics
addDRMMetrics(metrics: DRMMetrics): void
// Add error log entry
addError(error: ErrorLog): void
// Generate final test results
generateResults(): TestResults
// Reset all collected data
reset(): void
}
```
### ConfigurationManager
Handles configuration parsing and validation.
```typescript
class ConfigurationManager {
// Parse configuration from file and CLI arguments
static async parseConfiguration(options: {
configFile?: string;
cliArgs?: string[];
validateOnly?: boolean;
}): Promise<{ config: TestConfiguration }>
// Generate example configuration
static generateExampleConfig(format: 'json' | 'yaml'): string
// Validate configuration object
static validateConfiguration(config: any): TestConfiguration
}
```
## Configuration Interfaces
### TestConfiguration
Main configuration interface for the load tester.
```typescript
interface TestConfiguration {
concurrentUsers: number; // Number of concurrent browser instances
testDuration: number; // Test duration in seconds (0 = infinite)
rampUpTime: number; // Time to gradually start all users
streamingUrl: string; // Target streaming URL
drmConfig?: DRMConfiguration; // Optional DRM configuration
requestParameters: ParameterTemplate[]; // Request parameter injection
localStorage?: LocalStorageEntry[]; // Pre-populate localStorage for authenticated sessions
resourceLimits: ResourceLimits; // Resource usage limits
prometheus?: PrometheusConfiguration; // Prometheus metrics export
opentelemetry?: OpenTelemetryConfiguration; // OpenTelemetry export
}
```
### DRMConfiguration
Configuration for DRM systems.
```typescript
interface DRMConfiguration {
type: 'widevine' | 'playready' | 'fairplay'; // DRM system type
licenseUrl: string; // License server URL
certificateUrl?: string; // Certificate URL (optional)
customHeaders?: Record<string, string>; // Custom headers for requests
}
```
### ParameterTemplate
Template for selective request parameterization. **Always use URL patterns for precise targeting**.
```typescript
interface ParameterTemplate {
target: 'header' | 'query' | 'body'; // Where to inject the parameter
name: string; // Parameter name
valueTemplate: string; // Template with variable substitution
scope: 'global' | 'per-session'; // Parameter scope
urlPattern?: string; // URL pattern to match (RECOMMENDED)
method?: string; // HTTP method to match (optional)
}
```
**Selective Request Targeting (Primary Feature):**
- `urlPattern`: URL pattern to match (wildcards, regex) - **Use this for precision**
- `method`: HTTP method to match (GET, POST, PUT, DELETE, etc.)
**Target Types:**
- `header`: Inject into HTTP headers for specific URL patterns
- `query`: Inject into URL query parameters for targeted requests
- `body`: Inject into request body (JSON and form data) for specific endpoints
**URL Pattern Examples:**
- `"*/api/*"` - All API endpoints
- `"*.m3u8"` - HLS manifest files
- `"*/auth/*"` - Authentication endpoints
- `"/^https:\\/\\/cdn[0-9]+\\.example\\.com/"` - CDN servers (regex)
**Variable Substitution:**
- `{{sessionId}}`: Unique session identifier
- `{{timestamp}}`: Current timestamp
- `{{random}}`: Random number
- `{{token}}`: Authentication token
- `{{requestCount}}`: Current request count
- `{{random:uuid}}`: Generate UUID
- `{{random:1-100}}`: Random number in range
- `{{randomFrom:arrayName}}`: Random selection from array
- `{{randomFromFile:path}}`: Random selection from file
**Request Body Support:**
- **JSON bodies**: Automatically parsed and modified
- **Form data**: URL-encoded form data support
- **Error handling**: Graceful fallback for unsupported formats
### LocalStorageEntry
Configuration for pre-populating browser localStorage to simulate authenticated sessions.
```typescript
interface LocalStorageEntry {
domain: string; // Domain for localStorage data
data: Record<string, string>; // Key-value pairs to store
}
```
**Domain Configuration:**
- Can be a simple domain: `"example.com"`
- Can include subdomain: `"app.example.com"`
- Can include protocol: `"https://secure.example.com"`
- Each domain is visited separately to set localStorage
**Data Requirements:**
- All keys and values must be strings (localStorage limitation)
- Complex objects should be JSON-stringified
- Empty data objects are allowed
- Values support randomization functions for unique data per browser instance
**Randomization Support:**
localStorage values support the same randomization functions as request parameters:
- `{{random:uuid}}` - Generate UUID
- `{{random:number}}` - Random number 0-999999
- `{{random:timestamp}}` - Current timestamp
- `{{random:alphanumeric}}` - 8-character alphanumeric string
- `{{random:1-100}}` - Random number in range
- `{{randomFrom:arrayName}}` - Random selection from predefined array
- `{{randomFromFile:./path/to/file.txt}}` - Random line from file
**Common Use Cases:**
```typescript
// Static authentication tokens
{
domain: "app.example.com",
data: {
"auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def50200a1b2c3d4e5f6...",
"user_id": "user_12345"
}
}
// Randomized authentication for unique users
{
domain: "app.example.com",
data: {
"auth_token": "Bearer {{random:uuid}}",
"refresh_token": "refresh_{{random:alphanumeric}}",
"user_id": "{{randomFrom:userIds}}",
"session_expires": "{{random:timestamp}}"
}
}
// User preferences with randomization
{
domain: "streaming.example.com",
data: {
"user_preferences": '{"quality":"{{randomFrom:videoQualities}}","autoplay":{{randomFrom:booleans}}}',
"volume_level": "{{random:1-100}}",
"theme": "{{randomFrom:themes}}",
"device_id": "device_{{random:1-9999}}"
}
}
// Complex application state with randomization
{
domain: "ecommerce.example.com",
data: {
"cart_items": '[{"id":"{{random:uuid}}","quantity":{{random:1-5}}}]',
"recently_viewed": '["prod_{{random:1-1000}}","prod_{{random:1-1000}}"]',
"user_location": '{"country":"US","currency":"{{randomFrom:currencies}}"}'
}
}
```
**Predefined Arrays:**
The system provides built-in arrays for common randomization needs:
- `userIds` - ['user_001', 'user_002', 'user_003', 'user_004', 'user_005']
- `deviceTypes` - ['desktop', 'mobile', 'tablet']
- `themes` - ['light', 'dark', 'auto']
- `languages` - ['en', 'es', 'fr', 'de', 'ja']
- `currencies` - ['USD', 'EUR', 'GBP', 'JPY', 'CAD']
- `videoQualities` - ['480p', '720p', '1080p', '4K']
- `subscriptionTiers` - ['free', 'basic', 'premium', 'enterprise']
- `booleans` - ['true', 'false']
- `playbackSpeeds` - ['0.5', '0.75', '1.0', '1.25', '1.5', '2.0']
**Multi-Domain Support:**
```typescript
localStorage: [
{
domain: "main-app.com",
data: {
"session_token": "main_token_123",
"user_id": "user_456"
}
},
{
domain: "api.main-app.com",
data: {
"api_version": "v3",
"rate_limit": "1000"
}
},
{
domain: "cdn.main-app.com",
data: {
"cache_version": "v2.1.0",
"preferences": '{"webp_support":true}'
}
}
]
```
**Performance Considerations:**
- localStorage initialization adds startup time to browser instances
- Each domain requires a separate page navigation
- Keep data payloads reasonable in size
- Consider if all localStorage data is necessary for your test
### ResourceLimits
Resource limits for browser instances.
```typescript
interface ResourceLimits {
maxMemoryPerInstance: number; // Maximum memory per instance (MB)
maxCpuPercentage: number; // Maximum CPU usage percentage
maxConcurrentInstances: number; // Maximum concurrent browser instances
}
```
### PrometheusConfiguration
Configuration for Prometheus metrics export.
```typescript
interface PrometheusConfiguration {
enabled: boolean; // Enable Prometheus export
remoteWriteUrl: string; // Prometheus RemoteWrite endpoint
username?: string; // Authentication username
password?: string; // Authentication password
headers?: Record<string, string>; // Custom headers
batchSize?: number; // Metrics batch size (default: 100)
flushInterval?: number; // Flush interval in seconds (default: 30)
timeout?: number; // Request timeout in ms (default: 10000)
retryAttempts?: number; // Retry attempts (default: 3)
retryDelay?: number; // Retry delay in ms (default: 1000)
}
```
### OpenTelemetryConfiguration
Configuration for OpenTelemetry metrics export.
```typescript
interface OpenTelemetryConfiguration {
enabled: boolean; // Enable OpenTelemetry export
endpoint: string; // OTLP endpoint URL
protocol: 'http/protobuf' | 'http/json' | 'grpc'; // Protocol type
headers?: Record<string, string>; // Custom headers
serviceName?: string; // Service name (default: 'load-tester')
serviceVersion?: string; // Service version
timeout?: number; // Request timeout in ms
compression?: 'gzip' | 'none'; // Compression type
batchTimeout?: number; // Batch timeout in ms
maxExportBatchSize?: number; // Maximum batch size
maxQueueSize?: number; // Maximum queue size
exportTimeout?: number; // Export timeout in ms
}
```
## Result Interfaces
### TestResults
Complete test results structure.
```typescript
interface TestResults {
summary: TestSummary; // Test execution summary
browserMetrics: BrowserMetrics[]; // Browser instance metrics
drmMetrics: DRMMetrics[]; // DRM-specific metrics
networkMetrics: NetworkMetrics[]; // Network request metrics
errors: ErrorLog[]; // Error log entries
}
```
### TestSummary
Summary of test execution results.
```typescript
interface TestSummary {
totalRequests: number; // Total number of requests made
successfulRequests: number; // Number of successful requests
failedRequests: number; // Number of failed requests
averageResponseTime: number; // Average response time in ms
peakConcurrentUsers: number; // Peak number of concurrent users
testDuration: number; // Actual test duration in seconds
}
```
### BrowserMetrics
Metrics for individual browser instances.
```typescript
interface BrowserMetrics {
instanceId: string; // Unique instance identifier
memoryUsage: number; // Memory usage in MB
cpuUsage: number; // CPU usage percentage
requestCount: number; // Number of requests made
errorCount: number; // Number of errors encountered
uptime: number; // Instance uptime in seconds
}
```
### DRMMetrics
DRM performance metrics.
```typescript
interface DRMMetrics {
licenseRequestCount: number; // Number of license requests
averageLicenseTime: number; // Average license acquisition time (ms)
licenseSuccessRate: number; // License success rate (0-1)
drmType: string; // DRM system type
errors: DRMError[]; // DRM-specific errors
}
```
### NetworkMetrics
Network request performance metrics.
```typescript
interface NetworkMetrics {
url: string; // Request URL
method: string; // HTTP method
responseTime: number; // Response time in ms
statusCode: number; // HTTP status code
timestamp: Date; // Request timestamp
requestSize: number; // Request size in bytes
responseSize: number; // Response size in bytes
isStreamingRelated?: boolean; // Whether request is streaming-related
streamingType?: 'manifest' | 'segment' | 'license' | 'api' | 'other';
}
```
### ErrorLog
Error log entry.
```typescript
interface ErrorLog {
timestamp: Date; // Error timestamp
level: 'error' | 'warning' | 'info'; // Error severity level
message: string; // Error message
stack?: string; // Stack trace (if available)
context?: Record<string, any>; // Additional context information
}
```
## Utility Classes
### ErrorRecoveryManager
Handles error recovery and browser restart logic.
```typescript
class ErrorRecoveryManager {
constructor(config: ResourceLimits)
// Handle browser instance failure
async handleBrowserFailure(instanceId: string, error: Error): Promise<boolean>
// Check if instance should be restarted
shouldRestartInstance(instanceId: string): boolean
// Get failure statistics
getFailureStats(): {
totalFailures: number;
restartAttempts: number;
circuitBreakerActive: boolean;
}
}
```
### PrometheusExporter
Exports metrics to Prometheus RemoteWrite endpoint.
```typescript
class PrometheusExporter {
constructor(config: PrometheusConfiguration)
// Export test summary metrics
async exportTestSummary(summary: TestSummary): Promise<void>
// Export browser metrics
async exportBrowserMetrics(metrics: BrowserMetrics[]): Promise<void>
// Export DRM metrics
async exportDRMMetrics(metrics: DRMMetrics[]): Promise<void>
// Shutdown and flush remaining metrics
async shutdown(): Promise<void>
}
```
### OpenTelemetryExporter
Exports metrics to OpenTelemetry OTLP endpoint.
```typescript
class OpenTelemetryExporter {
constructor(config: OpenTelemetryConfiguration)
// Initialize the exporter
async initialize(): Promise<void>
// Export test summary metrics
async exportTestSummary(summary: TestSummary): Promise<void>
// Export browser metrics
async exportBrowserMetrics(metrics: BrowserMetrics[]): Promise<void>
// Export DRM metrics
async exportDRMMetrics(metrics: DRMMetrics[]): Promise<void>
// Shutdown the exporter
async shutdown(): Promise<void>
}
```
## Error Handling
### ConfigurationError
Thrown when configuration is invalid.
```typescript
class ConfigurationError extends Error {
constructor(message: string, source?: string)
source?: string; // Source of the configuration error
}
```
### BrowserError
Thrown when browser operations fail.
```typescript
class BrowserError extends Error {
constructor(message: string, instanceId?: string, cause?: Error)
instanceId?: string; // Browser instance ID
cause?: Error; // Original error cause
}
```
### NetworkError
Thrown when network operations fail.
```typescript
class NetworkError extends Error {
constructor(message: string, url?: string, statusCode?: number)
url?: string; // Request URL
statusCode?: number; // HTTP status code
}
```
## Events
### TestRunner Events
The TestRunner class extends EventEmitter and emits the following events:
#### test-started
Emitted when a test begins execution.
```typescript
testRunner.on('test-started', ({ testId }: { testId: string }) => {
console.log(`Test started with ID: ${testId}`);
});
```
#### test-completed
Emitted when a test completes successfully.
```typescript
testRunner.on('test-completed', ({ results }: { results: TestResults }) => {
console.log('Test completed:', results.summary);
});
```
#### test-failed
Emitted when a test fails.
```typescript
testRunner.on('test-failed', ({ error }: { error: Error }) => {
console.error('Test failed:', error.message);
});
```
#### ramp-up-completed
Emitted when the ramp-up phase is completed and all users are active.
```typescript
testRunner.on('ramp-up-completed', () => {
console.log('All users are now active');
});
```
#### monitoring-update
Emitted periodically with real-time monitoring data.
```typescript
interface MonitoringData {
elapsedTime: number;
remainingTime: number;
activeSessions: number;
totalRequests: number;
successfulRequests: number;
failedRequests: number;
currentRps: number;
averageResponseTime: number;
memoryUsage: number;
}
testRunner.on('monitoring-update', ({ data }: { data: MonitoringData }) => {
console.log(`Active sessions: ${data.activeSessions}, RPS: ${data.currentRps}`);
});
```
#### session-failed
Emitted when an individual browser session fails.
```typescript
testRunner.on('session-failed', ({ sessionId, error }: {
sessionId: string;
error: Error;
}) => {
console.warn(`Session ${sessionId} failed: ${error.message}`);
});
```
## Usage Examples
### Basic Load Test
```typescript
import { LoadTesterApp, TestConfiguration } from 'lightweight-browser-load-tester';
const config: TestConfiguration = {
concurrentUsers: 5,
testDuration: 300,
rampUpTime: 30,
streamingUrl: 'https://example.com/stream',
requestParameters: [],
resourceLimits: {
maxMemoryPerInstance: 512,
maxCpuPercentage: 80,
maxConcurrentInstances: 10
}
};
const app = new LoadTesterApp(config);
try {
const results = await app.start();
console.log('Test Results:', results.summary);
} catch (error) {
console.error('Test failed:', error);
}
```
### DRM Testing
```typescript
const drmConfig: TestConfiguration = {
concurrentUsers: 10,
testDuration: 600,
rampUpTime: 60,
streamingUrl: 'https://example.com/drm-stream',
drmConfig: {
type: 'widevine',
licenseUrl: 'https://example.com/license',
customHeaders: {
'Authorization': 'Bearer token123'
}
},
requestParameters: [
{
target: 'header',
name: 'Authorization',
valueTemplate: 'Bearer {{token}}',
scope: 'per-session'
}
],
resourceLimits: {
maxMemoryPerInstance: 1024,
maxCpuPercentage: 90,
maxConcurrentInstances: 20
}
};
const app = new LoadTesterApp(drmConfig);
const results = await app.start();
// Access DRM-specific metrics
results.drmMetrics.forEach(drm => {
console.log(`${drm.drmType}: ${drm.licenseSuccessRate * 100}% success rate`);
});
```
### Event Monitoring
```typescript
import { TestRunner } from 'lightweight-browser-load-tester';
const testRunner = new TestRunner(config);
testRunner.on('monitoring-update', ({ data }) => {
const progress = (data.elapsedTime / config.testDuration) * 100;
console.log(`Progress: ${progress.toFixed(1)}%`);
console.log(`Active Sessions: ${data.activeSessions}`);
console.log(`Current RPS: ${data.currentRps.toFixed(1)}`);
});
testRunner.on('session-failed', ({ sessionId, error }) => {
console.warn(`Session ${sessionId} failed: ${error.message}`);
});
await testRunner.startTest();
```
### Metrics Export
```typescript
const configWithMetrics: TestConfiguration = {
// ... basic config
prometheus: {
enabled: true,
remoteWriteUrl: 'https://prometheus.example.com/api/v1/write',
username: 'user',
password: 'pass',
batchSize: 100,
flushInterval: 30
},
opentelemetry: {
enabled: true,
endpoint: 'https://otel.example.com/v1/metrics',
protocol: 'http/protobuf',
serviceName: 'load-tester',
serviceVersion: '1.0.0'
}
};
const app = new LoadTesterApp(configWithMetrics);
await app.start(); // Metrics will be exported automatically
```
## Type Definitions
All TypeScript type definitions are available in the main package export:
```typescript
import {
// Core types
TestConfiguration,
TestResults,
TestSummary,
// Configuration types
DRMConfiguration,
ParameterTemplate,
ResourceLimits,
PrometheusConfiguration,
OpenTelemetryConfiguration,
// Metrics types
BrowserMetrics,
DRMMetrics,
NetworkMetrics,
ErrorLog,
// Utility types
ManagedBrowserInstance,
BrowserPoolConfig
} from 'lightweight-browser-load-tester';
```