"""
Performance under pressure test suite.
Tests JavaScript execution performance under extreme conditions including
high CPU load, memory pressure, concurrent operations, resource exhaustion,
and stress testing scenarios that simulate production peak loads.
"""
import pytest
import asyncio
from typing import Dict, Any, List, Optional, Tuple
from unittest.mock import AsyncMock, MagicMock, patch
import time
from crawailer import get, get_many
from crawailer.browser import Browser
from crawailer.config import BrowserConfig
class TestPerformanceUnderPressure:
"""Test JavaScript execution performance under extreme conditions."""
@pytest.fixture
def base_url(self):
"""Base URL for local test server."""
return "http://localhost:8083"
@pytest.fixture
def stress_config(self):
"""Browser configuration for stress testing."""
return BrowserConfig(
headless=True,
viewport={'width': 1920, 'height': 1080},
timeout=120000, # 2 minute timeout for stress tests
user_agent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
)
# High CPU Load Scenarios
@pytest.mark.asyncio
async def test_extreme_cpu_load_scenarios(self, base_url):
"""Test JavaScript execution under extreme CPU load conditions."""
content = await get(
f"{base_url}/react/",
script="""
// Extreme CPU load testing
class CPUStressTester {
constructor() {
this.testResults = {};
this.performanceBaseline = null;
this.stressTestResults = [];
}
async establishBaseline() {
// Establish performance baseline under normal conditions
const baselineTests = {
simpleArithmetic: this.testSimpleArithmetic(1000),
arrayOperations: this.testArrayOperations(1000),
objectManipulation: this.testObjectManipulation(1000),
domOperations: this.testDOMOperations(100)
};
const baseline = {};
for (const [testName, testPromise] of Object.entries(baselineTests)) {
baseline[testName] = await testPromise;
}
this.performanceBaseline = baseline;
return baseline;
}
async testSimpleArithmetic(iterations) {
const start = performance.now();
let result = 0;
for (let i = 0; i < iterations; i++) {
result += Math.sqrt(i) * Math.sin(i) + Math.cos(i * 2);
}
const end = performance.now();
return {
duration: end - start,
iterations,
operationsPerSecond: iterations / ((end - start) / 1000),
result: result % 1000000 // Prevent overflow display issues
};
}
async testArrayOperations(size) {
const start = performance.now();
// Create large array
const array = new Array(size).fill(0).map((_, i) => ({
id: i,
value: Math.random(),
computed: Math.sqrt(i)
}));
// Perform various array operations
const filtered = array.filter(item => item.value > 0.5);
const mapped = array.map(item => ({ ...item, doubled: item.value * 2 }));
const reduced = array.reduce((sum, item) => sum + item.value, 0);
const sorted = [...array].sort((a, b) => a.value - b.value);
const end = performance.now();
return {
duration: end - start,
arraySize: size,
operationsPerformed: 4,
filteredCount: filtered.length,
reducedSum: reduced,
operationsPerSecond: (size * 4) / ((end - start) / 1000)
};
}
async testObjectManipulation(count) {
const start = performance.now();
const objects = [];
// Create objects with complex nested structures
for (let i = 0; i < count; i++) {
const obj = {
id: i,
data: {
level1: {
level2: {
level3: {
value: Math.random(),
array: new Array(10).fill(i),
timestamp: Date.now()
}
}
}
},
methods: {
calculate: function() {
return this.data.level1.level2.level3.value * 100;
},
transform: function() {
return JSON.stringify(this.data);
}
}
};
objects.push(obj);
}
// Perform object manipulations
const calculations = objects.map(obj => obj.methods.calculate());
const transformations = objects.map(obj => obj.methods.transform());
const serializations = objects.map(obj => JSON.parse(JSON.stringify(obj.data)));
const end = performance.now();
return {
duration: end - start,
objectCount: count,
operationsPerformed: 3,
avgCalculation: calculations.reduce((sum, val) => sum + val, 0) / calculations.length,
serializationSize: transformations.join('').length,
operationsPerSecond: (count * 3) / ((end - start) / 1000)
};
}
async testDOMOperations(count) {
const start = performance.now();
const container = document.createElement('div');
container.className = 'stress-test-container';
document.body.appendChild(container);
// Create complex DOM structure
for (let i = 0; i < count; i++) {
const element = document.createElement('div');
element.className = `stress-element-${i}`;
element.innerHTML = `
Element ${i}
Content for element ${i}
`;
container.appendChild(element);
}
// Perform DOM queries and manipulations
const elements = container.querySelectorAll('.stress-element-1, .stress-element-5, .stress-element-10');
elements.forEach(el => {
el.style.backgroundColor = 'lightblue';
el.style.padding = '10px';
el.style.margin = '5px';
});
// Clone and move elements
const firstElement = container.firstElementChild;
if (firstElement) {
const clone = firstElement.cloneNode(true);
container.appendChild(clone);
}
const end = performance.now();
// Cleanup
document.body.removeChild(container);
return {
duration: end - start,
elementsCreated: count,
elementsModified: elements.length,
operationsPerSecond: (count + elements.length) / ((end - start) / 1000)
};
}
async createCPUPressure(intensity = 'medium') {
// Create background CPU pressure
const pressureConfig = {
light: { workers: 1, iterations: 10000 },
medium: { workers: 2, iterations: 50000 },
heavy: { workers: 4, iterations: 100000 },
extreme: { workers: 8, iterations: 200000 }
};
const config = pressureConfig[intensity] || pressureConfig.medium;
const workers = [];
try {
for (let i = 0; i < config.workers; i++) {
const workerCode = `
let running = true;
self.onmessage = function(e) {
if (e.data === 'stop') {
running = false;
self.postMessage('stopped');
return;
}
let result = 0;
let iterations = 0;
const start = Date.now();
while (running && iterations < ${config.iterations}) {
result += Math.sqrt(iterations) * Math.sin(iterations);
iterations++;
// Yield occasionally
if (iterations % 1000 === 0) {
if (Date.now() - start > 5000) break; // Max 5 seconds
}
}
self.postMessage({ result, iterations, duration: Date.now() - start });
};
`;
const blob = new Blob([workerCode], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
const worker = new Worker(workerUrl);
workers.push({ worker, url: workerUrl });
worker.postMessage('start');
}
return workers;
} catch (error) {
// Cleanup on error
workers.forEach(({ worker, url }) => {
worker.terminate();
URL.revokeObjectURL(url);
});
throw error;
}
}
async stopCPUPressure(workers) {
const results = [];
for (const { worker, url } of workers) {
try {
const result = await new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Worker stop timeout'));
}, 2000);
worker.onmessage = (e) => {
clearTimeout(timeout);
resolve(e.data);
};
worker.postMessage('stop');
});
results.push(result);
} catch (error) {
results.push({ error: error.message });
} finally {
worker.terminate();
URL.revokeObjectURL(url);
}
}
return results;
}
async testUnderCPUPressure(intensity = 'medium') {
const workers = await this.createCPUPressure(intensity);
try {
// Wait a moment for CPU pressure to build
await new Promise(resolve => setTimeout(resolve, 1000));
// Run the same tests under pressure
const stressTests = {
simpleArithmetic: await this.testSimpleArithmetic(1000),
arrayOperations: await this.testArrayOperations(1000),
objectManipulation: await this.testObjectManipulation(1000),
domOperations: await this.testDOMOperations(100)
};
const workerResults = await this.stopCPUPressure(workers);
return {
intensity,
stressTests,
workerResults,
workersUsed: workers.length
};
} catch (error) {
await this.stopCPUPressure(workers);
throw error;
}
}
comparePerformance(baseline, stressed) {
const comparison = {};
for (const testName in baseline) {
if (stressed[testName]) {
const baseOps = baseline[testName].operationsPerSecond;
const stressOps = stressed[testName].operationsPerSecond;
comparison[testName] = {
baselineOps: baseOps,
stressedOps: stressOps,
performanceDrop: ((baseOps - stressOps) / baseOps) * 100,
slowdownFactor: baseOps / stressOps,
durationIncrease: stressed[testName].duration - baseline[testName].duration
};
}
}
return comparison;
}
async runComprehensiveStressTest() {
const results = {
startTime: Date.now(),
baseline: null,
stressTests: [],
comparisons: [],
summary: {}
};
try {
// Establish baseline
results.baseline = await this.establishBaseline();
// Test under different stress levels
const stressLevels = ['light', 'medium', 'heavy'];
for (const level of stressLevels) {
try {
const stressResult = await this.testUnderCPUPressure(level);
results.stressTests.push(stressResult);
const comparison = this.comparePerformance(results.baseline, stressResult.stressTests);
results.comparisons.push({
level,
comparison
});
} catch (error) {
results.stressTests.push({
level,
error: error.message
});
}
// Rest between stress tests
await new Promise(resolve => setTimeout(resolve, 2000));
}
// Calculate summary statistics
const avgPerformanceDrops = [];
results.comparisons.forEach(comp => {
Object.values(comp.comparison).forEach(test => {
if (typeof test.performanceDrop === 'number' && !isNaN(test.performanceDrop)) {
avgPerformanceDrops.push(test.performanceDrop);
}
});
});
results.summary = {
totalTests: results.stressTests.length,
successfulTests: results.stressTests.filter(t => !t.error).length,
averagePerformanceDrop: avgPerformanceDrops.length > 0 ?
avgPerformanceDrops.reduce((sum, drop) => sum + drop, 0) / avgPerformanceDrops.length : 0,
maxPerformanceDrop: avgPerformanceDrops.length > 0 ? Math.max(...avgPerformanceDrops) : 0,
testDuration: Date.now() - results.startTime
};
} catch (error) {
results.error = error.message;
}
return results;
}
}
const cpuTester = new CPUStressTester();
return await cpuTester.runComprehensiveStressTest();
"""
)
assert content.script_result is not None
result = content.script_result
# Verify stress test structure
assert 'baseline' in result
assert 'stressTests' in result
assert 'comparisons' in result
assert 'summary' in result
# Check baseline was established
baseline = result['baseline']
expected_baseline_tests = ['simpleArithmetic', 'arrayOperations', 'objectManipulation', 'domOperations']
for test_name in expected_baseline_tests:
assert test_name in baseline
assert baseline[test_name]['duration'] > 0
assert baseline[test_name]['operationsPerSecond'] > 0
# Verify stress tests were performed
stress_tests = result['stressTests']
assert len(stress_tests) >= 1 # At least one stress level should complete
# Check successful stress tests
successful_tests = [t for t in stress_tests if 'error' not in t]
if successful_tests:
for stress_test in successful_tests:
assert 'intensity' in stress_test
assert 'stressTests' in stress_test
assert 'workerResults' in stress_test
# Verify the same tests were run under stress
for test_name in expected_baseline_tests:
assert test_name in stress_test['stressTests']
# Check performance comparisons
comparisons = result['comparisons']
if comparisons:
for comparison in comparisons:
assert 'level' in comparison
assert 'comparison' in comparison
# Check individual test comparisons
for test_name, test_comparison in comparison['comparison'].items():
assert 'baselineOps' in test_comparison
assert 'stressedOps' in test_comparison
assert 'performanceDrop' in test_comparison
assert test_comparison['baselineOps'] > 0
assert test_comparison['stressedOps'] > 0
# Verify summary statistics
summary = result['summary']
assert summary['totalTests'] >= 0
assert summary['successfulTests'] >= 0
assert summary['testDuration'] > 0
assert summary['averagePerformanceDrop'] >= 0
@pytest.mark.asyncio
async def test_concurrent_operation_stress(self, base_url):
"""Test handling of many concurrent JavaScript operations."""
content = await get(
f"{base_url}/vue/",
script="""
// Test concurrent operation handling under stress
class ConcurrencyStressTester {
constructor() {
this.maxConcurrency = navigator.hardwareConcurrency || 4;
this.testResults = {};
}
async testPromiseConcurrency() {
const concurrencyLevels = [10, 50, 100, 500, 1000];
const results = [];
for (const level of concurrencyLevels) {
const start = performance.now();
try {
// Create many concurrent promises
const promises = [];
for (let i = 0; i < level; i++) {
promises.push(this.createAsyncOperation(i, level));
}
const promiseResults = await Promise.allSettled(promises);
const end = performance.now();
const successful = promiseResults.filter(r => r.status === 'fulfilled').length;
const failed = promiseResults.filter(r => r.status === 'rejected').length;
results.push({
concurrencyLevel: level,
duration: end - start,
successful,
failed,
successRate: (successful / level) * 100,
operationsPerSecond: level / ((end - start) / 1000)
});
} catch (error) {
const end = performance.now();
results.push({
concurrencyLevel: level,
duration: end - start,
error: error.message,
failed: true
});
}
// Brief pause between tests
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
async createAsyncOperation(id, totalOps) {
// Simulate varying async operation types
const operationType = id % 4;
switch (operationType) {
case 0:
// CPU-bound operation
return new Promise(resolve => {
setTimeout(() => {
let result = 0;
for (let i = 0; i < 1000; i++) {
result += Math.sqrt(i);
}
resolve({ id, type: 'cpu', result });
}, Math.random() * 10);
});
case 1:
// Memory allocation operation
return new Promise(resolve => {
setTimeout(() => {
const data = new Array(100).fill(Math.random());
resolve({ id, type: 'memory', size: data.length });
}, Math.random() * 20);
});
case 2:
// DOM operation
return new Promise(resolve => {
setTimeout(() => {
const element = document.createElement('div');
element.textContent = `Element ${id}`;
document.body.appendChild(element);
// Clean up immediately
document.body.removeChild(element);
resolve({ id, type: 'dom', created: true });
}, Math.random() * 5);
});
case 3:
// JSON processing operation
return new Promise(resolve => {
setTimeout(() => {
const obj = { id, data: new Array(50).fill(0).map(() => Math.random()) };
const serialized = JSON.stringify(obj);
const parsed = JSON.parse(serialized);
resolve({ id, type: 'json', size: serialized.length });
}, Math.random() * 15);
});
default:
return Promise.resolve({ id, type: 'default' });
}
}
async testSetTimeoutStress() {
const results = {
scheduled: 0,
executed: 0,
timeouts: [],
averageDelay: 0,
maxDelay: 0
};
const testCount = 1000;
const scheduledTimes = [];
// Schedule many timeouts simultaneously
for (let i = 0; i < testCount; i++) {
const scheduledTime = Date.now();
scheduledTimes.push(scheduledTime);
setTimeout(() => {
const executedTime = Date.now();
const delay = executedTime - scheduledTime;
results.executed++;
results.timeouts.push(delay);
if (delay > results.maxDelay) {
results.maxDelay = delay;
}
}, Math.random() * 100); // Random timeout between 0-100ms
results.scheduled++;
}
// Wait for all timeouts to complete
await new Promise(resolve => {
const checkCompletion = () => {
if (results.executed >= testCount * 0.95) { // Allow for 5% timeout loss
resolve();
} else if (Date.now() - scheduledTimes[0] > 5000) { // Max 5 second wait
resolve();
} else {
setTimeout(checkCompletion, 50);
}
};
checkCompletion();
});
// Calculate statistics
if (results.timeouts.length > 0) {
results.averageDelay = results.timeouts.reduce((sum, delay) => sum + delay, 0) / results.timeouts.length;
results.completionRate = (results.executed / results.scheduled) * 100;
}
return results;
}
async testRequestAnimationFrameStress() {
const results = {
requested: 0,
executed: 0,
frames: [],
averageFrameTime: 0,
droppedFrames: 0
};
const frameCount = 120; // Attempt 120 frames (2 seconds at 60fps)
let lastFrameTime = performance.now();
return new Promise(resolve => {
const frameCallback = (currentTime) => {
const frameTime = currentTime - lastFrameTime;
results.frames.push(frameTime);
results.executed++;
// Detect dropped frames (> 20ms indicates frame drop at 60fps)
if (frameTime > 20) {
results.droppedFrames++;
}
lastFrameTime = currentTime;
if (results.executed < frameCount) {
// Do some work each frame to create stress
for (let i = 0; i < 1000; i++) {
Math.sqrt(i);
}
requestAnimationFrame(frameCallback);
results.requested++;
} else {
// Calculate final statistics
if (results.frames.length > 1) {
results.averageFrameTime = results.frames.slice(1).reduce((sum, time) => sum + time, 0) / (results.frames.length - 1);
results.estimatedFPS = 1000 / results.averageFrameTime;
results.frameDropRate = (results.droppedFrames / results.executed) * 100;
}
resolve(results);
}
};
requestAnimationFrame(frameCallback);
results.requested++;
});
}
async testEventListenerStress() {
const results = {
listenersCreated: 0,
eventsDispatched: 0,
eventsReceived: 0,
averageEventTime: 0,
maxEventTime: 0
};
const eventTarget = document.createElement('div');
document.body.appendChild(eventTarget);
const eventTimes = [];
const listenerCount = 1000;
// Create many event listeners
for (let i = 0; i < listenerCount; i++) {
eventTarget.addEventListener('testEvent', (e) => {
const eventTime = performance.now() - e.detail.startTime;
eventTimes.push(eventTime);
results.eventsReceived++;
if (eventTime > results.maxEventTime) {
results.maxEventTime = eventTime;
}
});
results.listenersCreated++;
}
// Dispatch many events
const eventCount = 100;
for (let i = 0; i < eventCount; i++) {
const event = new CustomEvent('testEvent', {
detail: { startTime: performance.now(), eventId: i }
});
eventTarget.dispatchEvent(event);
results.eventsDispatched++;
// Small delay to prevent overwhelming
if (i % 10 === 0) {
await new Promise(resolve => setTimeout(resolve, 1));
}
}
// Wait for all events to be processed
await new Promise(resolve => setTimeout(resolve, 100));
// Calculate statistics
if (eventTimes.length > 0) {
results.averageEventTime = eventTimes.reduce((sum, time) => sum + time, 0) / eventTimes.length;
results.eventProcessingRate = (results.eventsReceived / results.eventsDispatched) * 100;
results.expectedEvents = results.eventsDispatched * results.listenersCreated;
results.actualEventExecutions = results.eventsReceived;
}
// Cleanup
document.body.removeChild(eventTarget);
return results;
}
async runAllConcurrencyTests() {
const allResults = {
startTime: Date.now(),
systemInfo: {
hardwareConcurrency: navigator.hardwareConcurrency,
userAgent: navigator.userAgent,
memoryInfo: performance.memory ? {
jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
totalJSHeapSize: performance.memory.totalJSHeapSize,
usedJSHeapSize: performance.memory.usedJSHeapSize
} : null
},
tests: {}
};
try {
allResults.tests.promiseConcurrency = await this.testPromiseConcurrency();
allResults.tests.setTimeoutStress = await this.testSetTimeoutStress();
allResults.tests.animationFrameStress = await this.testRequestAnimationFrameStress();
allResults.tests.eventListenerStress = await this.testEventListenerStress();
} catch (error) {
allResults.error = error.message;
}
allResults.endTime = Date.now();
allResults.totalDuration = allResults.endTime - allResults.startTime;
return allResults;
}
}
const concurrencyTester = new ConcurrencyStressTester();
return await concurrencyTester.runAllConcurrencyTests();
"""
)
assert content.script_result is not None
result = content.script_result
# Verify concurrency test structure
assert 'systemInfo' in result
assert 'tests' in result
assert 'totalDuration' in result
# Check system info
system_info = result['systemInfo']
assert 'hardwareConcurrency' in system_info
assert system_info['hardwareConcurrency'] >= 1
# Verify individual tests
tests = result['tests']
# Check promise concurrency test
if 'promiseConcurrency' in tests:
promise_test = tests['promiseConcurrency']
assert len(promise_test) > 0
for level_result in promise_test:
if 'error' not in level_result:
assert level_result['concurrencyLevel'] > 0
assert level_result['duration'] > 0
assert 'successful' in level_result
assert 'failed' in level_result
assert level_result['successRate'] >= 0
assert level_result['successRate'] <= 100
# Check setTimeout stress test
if 'setTimeoutStress' in tests:
timeout_test = tests['setTimeoutStress']
assert timeout_test['scheduled'] > 0
assert timeout_test['executed'] >= 0
assert timeout_test['averageDelay'] >= 0
# Check animation frame stress test
if 'animationFrameStress' in tests:
raf_test = tests['animationFrameStress']
assert raf_test['requested'] > 0
assert raf_test['executed'] > 0
if raf_test['frames']:
assert raf_test['averageFrameTime'] > 0
assert 'estimatedFPS' in raf_test
# Check event listener stress test
if 'eventListenerStress' in tests:
event_test = tests['eventListenerStress']
assert event_test['listenersCreated'] > 0
assert event_test['eventsDispatched'] > 0
assert event_test['eventsReceived'] >= 0
@pytest.mark.asyncio
async def test_resource_exhaustion_scenarios(self, base_url):
"""Test behavior when system resources are nearly exhausted."""
content = await get(
f"{base_url}/angular/",
script="""
// Test resource exhaustion scenarios
class ResourceExhaustionTester {
constructor() {
this.originalMemory = this.getMemorySnapshot();
this.resourceTests = {};
}
getMemorySnapshot() {
if (performance.memory) {
return {
jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
totalJSHeapSize: performance.memory.totalJSHeapSize,
usedJSHeapSize: performance.memory.usedJSHeapSize,
timestamp: Date.now()
};
}
return { timestamp: Date.now(), unavailable: true };
}
async testMemoryExhaustion() {
const memoryTest = {
phase: 'memory_exhaustion',
startMemory: this.getMemorySnapshot(),
allocations: [],
maxAllocation: 0,
allocationFailures: 0,
recoveryAttempts: 0
};
try {
// Gradually increase memory allocation until we hit limits
let allocationSize = 1024 * 1024; // Start with 1MB
let totalAllocated = 0;
while (allocationSize <= 64 * 1024 * 1024 && memoryTest.allocations.length < 100) { // Max 64MB per allocation, max 100 allocations
try {
const start = performance.now();
const allocation = new ArrayBuffer(allocationSize);
const view = new Uint8Array(allocation);
// Write to the memory to ensure it's actually allocated
for (let i = 0; i < Math.min(view.length, 1000); i += 100) {
view[i] = i % 256;
}
const end = performance.now();
memoryTest.allocations.push({
size: allocationSize,
allocTime: end - start,
memoryAfter: this.getMemorySnapshot()
});
totalAllocated += allocationSize;
if (allocationSize > memoryTest.maxAllocation) {
memoryTest.maxAllocation = allocationSize;
}
// Increase allocation size gradually
allocationSize = Math.floor(allocationSize * 1.2);
// Brief pause to allow for memory management
await new Promise(resolve => setTimeout(resolve, 10));
} catch (error) {
memoryTest.allocationFailures++;
// Try recovery
if (memoryTest.recoveryAttempts < 3) {
memoryTest.recoveryAttempts++;
// Clear some allocations
const clearedCount = Math.floor(memoryTest.allocations.length * 0.3);
memoryTest.allocations.splice(0, clearedCount);
// Try garbage collection hint
if (window.gc) {
window.gc();
}
// Reduce allocation size
allocationSize = Math.floor(allocationSize * 0.5);
await new Promise(resolve => setTimeout(resolve, 100));
} else {
break;
}
}
}
memoryTest.endMemory = this.getMemorySnapshot();
memoryTest.totalAllocated = totalAllocated;
} catch (error) {
memoryTest.error = error.message;
memoryTest.endMemory = this.getMemorySnapshot();
}
return memoryTest;
}
async testDOMNodeExhaustion() {
const domTest = {
phase: 'dom_exhaustion',
nodesCreated: 0,
maxDepth: 0,
creationFailures: 0,
performanceDegradation: []
};
const container = document.createElement('div');
container.style.display = 'none'; // Hide to prevent layout thrashing
document.body.appendChild(container);
try {
let batchSize = 1000;
let currentDepth = 0;
let parent = container;
// Create nodes in batches until we hit performance issues
while (domTest.nodesCreated < 50000 && batchSize > 10) {
const batchStart = performance.now();
let batchCreated = 0;
try {
for (let i = 0; i < batchSize; i++) {
const element = document.createElement('div');
element.className = `stress-node-${domTest.nodesCreated + i}`;
element.textContent = `Node ${domTest.nodesCreated + i}`;
// Create nested structure occasionally
if (i % 100 === 0 && currentDepth < 50) {
parent = element;
currentDepth++;
if (currentDepth > domTest.maxDepth) {
domTest.maxDepth = currentDepth;
}
}
parent.appendChild(element);
batchCreated++;
}
domTest.nodesCreated += batchCreated;
} catch (error) {
domTest.creationFailures++;
domTest.nodesCreated += batchCreated;
}
const batchEnd = performance.now();
const batchTime = batchEnd - batchStart;
domTest.performanceDegradation.push({
nodesCreated: batchCreated,
timePerNode: batchTime / batchCreated,
totalNodes: domTest.nodesCreated,
batchTime
});
// Reduce batch size if performance is degrading
if (batchTime > 1000) { // If batch takes more than 1 second
batchSize = Math.floor(batchSize * 0.8);
}
// Brief pause
await new Promise(resolve => setTimeout(resolve, 10));
}
} catch (error) {
domTest.error = error.message;
}
// Cleanup
try {
document.body.removeChild(container);
} catch (error) {
domTest.cleanupError = error.message;
}
return domTest;
}
async testFileHandleExhaustion() {
const fileTest = {
phase: 'file_handle_exhaustion',
urlsCreated: 0,
urlsRevoked: 0,
creationFailures: 0,
activeUrls: []
};
try {
// Create many blob URLs (which consume file handles)
const maxUrls = 10000;
for (let i = 0; i < maxUrls; i++) {
try {
const data = `Blob data ${i} - ${new Array(100).fill('x').join('')}`;
const blob = new Blob([data], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
fileTest.activeUrls.push(url);
fileTest.urlsCreated++;
// Occasionally revoke some URLs
if (i % 1000 === 0 && fileTest.activeUrls.length > 500) {
const urlsToRevoke = fileTest.activeUrls.splice(0, 200);
urlsToRevoke.forEach(url => {
URL.revokeObjectURL(url);
fileTest.urlsRevoked++;
});
}
} catch (error) {
fileTest.creationFailures++;
if (fileTest.creationFailures > 100) {
break; // Stop if too many failures
}
}
// Brief pause every 100 creations
if (i % 100 === 0) {
await new Promise(resolve => setTimeout(resolve, 1));
}
}
} catch (error) {
fileTest.error = error.message;
}
// Cleanup remaining URLs
try {
fileTest.activeUrls.forEach(url => {
URL.revokeObjectURL(url);
fileTest.urlsRevoked++;
});
} catch (error) {
fileTest.cleanupError = error.message;
}
return fileTest;
}
async testEventListenerExhaustion() {
const eventTest = {
phase: 'event_listener_exhaustion',
elementsCreated: 0,
listenersCreated: 0,
eventsDispatched: 0,
memorySnapshots: []
};
const elements = [];
try {
eventTest.memorySnapshots.push({
label: 'start',
memory: this.getMemorySnapshot()
});
// Create many elements with multiple event listeners
for (let i = 0; i < 5000; i++) {
const element = document.createElement('div');
element.style.display = 'none';
document.body.appendChild(element);
// Add multiple event listeners to each element
const eventTypes = ['click', 'mouseover', 'mouseout', 'focus', 'blur'];
eventTypes.forEach(eventType => {
const handler = (e) => {
// Do some work in the handler
for (let j = 0; j < 10; j++) {
Math.sqrt(j);
}
};
element.addEventListener(eventType, handler);
eventTest.listenersCreated++;
});
elements.push(element);
eventTest.elementsCreated++;
// Take memory snapshots periodically
if (i % 1000 === 0) {
eventTest.memorySnapshots.push({
label: `elements_${i}`,
memory: this.getMemorySnapshot()
});
}
// Brief pause
if (i % 100 === 0) {
await new Promise(resolve => setTimeout(resolve, 1));
}
}
// Dispatch events to test performance
const sampleElements = elements.slice(0, 100);
for (const element of sampleElements) {
const event = new Event('click');
element.dispatchEvent(event);
eventTest.eventsDispatched++;
}
eventTest.memorySnapshots.push({
label: 'after_events',
memory: this.getMemorySnapshot()
});
} catch (error) {
eventTest.error = error.message;
}
// Cleanup
try {
elements.forEach(element => {
document.body.removeChild(element);
});
} catch (error) {
eventTest.cleanupError = error.message;
}
eventTest.memorySnapshots.push({
label: 'after_cleanup',
memory: this.getMemorySnapshot()
});
return eventTest;
}
async runAllExhaustionTests() {
const results = {
startTime: Date.now(),
originalMemory: this.originalMemory,
tests: {}
};
try {
results.tests.memoryExhaustion = await this.testMemoryExhaustion();
// Brief pause between tests
await new Promise(resolve => setTimeout(resolve, 1000));
results.tests.domNodeExhaustion = await this.testDOMNodeExhaustion();
await new Promise(resolve => setTimeout(resolve, 1000));
results.tests.fileHandleExhaustion = await this.testFileHandleExhaustion();
await new Promise(resolve => setTimeout(resolve, 1000));
results.tests.eventListenerExhaustion = await this.testEventListenerExhaustion();
} catch (error) {
results.error = error.message;
}
results.endTime = Date.now();
results.totalDuration = results.endTime - results.startTime;
results.finalMemory = this.getMemorySnapshot();
return results;
}
}
const exhaustionTester = new ResourceExhaustionTester();
return await exhaustionTester.runAllExhaustionTests();
"""
)
assert content.script_result is not None
result = content.script_result
# Verify resource exhaustion test structure
assert 'originalMemory' in result
assert 'tests' in result
assert 'finalMemory' in result
assert 'totalDuration' in result
# Check individual exhaustion tests
tests = result['tests']
# Memory exhaustion test
if 'memoryExhaustion' in tests:
memory_test = tests['memoryExhaustion']
assert memory_test['phase'] == 'memory_exhaustion'
assert 'startMemory' in memory_test
assert 'allocations' in memory_test
assert memory_test['allocationFailures'] >= 0
assert memory_test['recoveryAttempts'] >= 0
# DOM node exhaustion test
if 'domNodeExhaustion' in tests:
dom_test = tests['domNodeExhaustion']
assert dom_test['phase'] == 'dom_exhaustion'
assert dom_test['nodesCreated'] > 0
assert 'performanceDegradation' in dom_test
assert len(dom_test['performanceDegradation']) > 0
# File handle exhaustion test
if 'fileHandleExhaustion' in tests:
file_test = tests['fileHandleExhaustion']
assert file_test['phase'] == 'file_handle_exhaustion'
assert file_test['urlsCreated'] > 0
assert file_test['urlsRevoked'] >= 0
assert file_test['creationFailures'] >= 0
# Event listener exhaustion test
if 'eventListenerExhaustion' in tests:
event_test = tests['eventListenerExhaustion']
assert event_test['phase'] == 'event_listener_exhaustion'
assert event_test['elementsCreated'] > 0
assert event_test['listenersCreated'] > 0
assert 'memorySnapshots' in event_test
assert len(event_test['memorySnapshots']) > 0
[{"content": "Implement Phase 2: Production Optimization", "status": "in_progress", "activeForm": "Implementing Phase 2: Production Optimization"}, {"content": "Create comprehensive network resilience test suite", "status": "completed", "activeForm": "Creating comprehensive network resilience test suite"}, {"content": "Build platform-specific edge case tests", "status": "completed", "activeForm": "Building platform-specific edge case tests"}, {"content": "Implement performance under pressure test suite", "status": "completed", "activeForm": "Implementing performance under pressure test suite"}, {"content": "Create browser engine compatibility tests", "status": "in_progress", "activeForm": "Creating browser engine compatibility tests"}, {"content": "Build memory management and leak detection tests", "status": "pending", "activeForm": "Building memory management and leak detection tests"}]