use std::sync::Arc;
use std::time::Instant;
use jsdet_core::{CompiledModule, EmptyBridge, SandboxConfig};
#[test]
fn throughput_simple_scripts() {
let module = CompiledModule::new().unwrap();
let bridge = Arc::new(EmptyBridge);
let config = SandboxConfig {
timeout_ms: 100,
max_fuel: 10_000_000,
drain_timers: false,
..SandboxConfig::detonation()
};
let scripts = vec![
"var x = 1 + 2;".to_string(),
"var y = 'hello' + ' world';".to_string(),
"var z = JSON.parse('{\"a\":1}');".to_string(),
];
for _ in 0..3 {
let _ = module.execute(&scripts, bridge.clone(), &config);
}
let iterations = 100;
let start = Instant::now();
for _ in 0..iterations {
let result = module.execute(&scripts, bridge.clone(), &config).unwrap();
assert_eq!(result.scripts_executed, 3);
}
let elapsed = start.elapsed();
let per_detonation_us = elapsed.as_micros() / iterations;
let detonations_per_second = 1_000_000 / per_detonation_us.max(1);
let detonations_per_hour = detonations_per_second * 3600;
eprintln!();
eprintln!("=== Throughput: Simple Scripts ===");
eprintln!(" Iterations: {iterations}");
eprintln!(" Total: {:.1}ms", elapsed.as_millis());
eprintln!(" Per detonation: {}us", per_detonation_us);
eprintln!(
" Rate: {}/sec ({}/hour)",
detonations_per_second, detonations_per_hour
);
eprintln!();
assert!(
detonations_per_second >= 100,
"throughput too low: {detonations_per_second}/sec (need 100+)"
);
}
#[test]
fn throughput_phishing_scripts() {
let module = CompiledModule::new().unwrap();
let bridge = Arc::new(jsdet_core::EmptyBridge);
let config = SandboxConfig {
timeout_ms: 200,
max_fuel: 50_000_000,
drain_timers: false,
..SandboxConfig::detonation()
};
let script = r#"
var config = JSON.parse('{"redirect":"https://evil.com","token":"abc123"}');
var target = config.redirect;
var parts = target.split('/');
var domain = parts.length > 2 ? parts[2] : 'unknown';
var encoded = '';
for (var i = 0; i < target.length; i++) {
encoded += String.fromCharCode(target.charCodeAt(i) ^ 42);
}
for (var i = 0; i < 10; i++) {
var key = 'item_' + i;
var val = domain + '_' + i;
}
var result = { domain: domain, token: config.token, encoded: encoded };
JSON.stringify(result);
"#
.to_string();
for _ in 0..3 {
let _ = module.execute(&[script.clone()], bridge.clone(), &config);
}
let iterations = 100;
let start = Instant::now();
for _ in 0..iterations {
let result = module
.execute(&[script.clone()], bridge.clone(), &config)
.unwrap();
assert_eq!(result.scripts_executed, 1);
assert!(result.errors.is_empty());
}
let elapsed = start.elapsed();
let per_detonation_us = elapsed.as_micros() / iterations;
let detonations_per_second = 1_000_000 / per_detonation_us.max(1);
eprintln!();
eprintln!("=== Throughput: Phishing Scripts ===");
eprintln!(" Iterations: {iterations}");
eprintln!(" Total: {:.1}ms", elapsed.as_millis());
eprintln!(" Per detonation: {}us", per_detonation_us);
eprintln!(" Rate: {}/sec", detonations_per_second);
eprintln!(
" Projected 1M: {:.1} minutes",
1_000_000.0 / detonations_per_second as f64 / 60.0
);
eprintln!();
assert!(
detonations_per_second >= 50,
"throughput too low: {detonations_per_second}/sec"
);
}
#[test]
fn benchmark_module_compilation() {
let start = Instant::now();
let module = CompiledModule::new().unwrap();
let compilation_ms = start.elapsed().as_millis();
let serialized = module.serialize().unwrap();
let serialize_ms = start.elapsed().as_millis() - compilation_ms;
let deser_start = Instant::now();
let _cached = CompiledModule::load_cached(&serialized).unwrap();
let deserialize_ms = deser_start.elapsed().as_millis();
eprintln!();
eprintln!("=== Module Compilation ===");
eprintln!(" Fresh compile: {}ms", compilation_ms);
eprintln!(" Serialize: {}ms", serialize_ms);
eprintln!(" Load cached: {}ms", deserialize_ms);
eprintln!(
" Speedup: {:.0}x",
compilation_ms as f64 / deserialize_ms.max(1) as f64
);
eprintln!(" Serialized size: {} KB", serialized.len() / 1024);
eprintln!();
}
#[test]
fn benchmark_memory_per_instance() {
let module = CompiledModule::new().unwrap();
let bridge = Arc::new(EmptyBridge);
let config = SandboxConfig::detonation();
let result = module
.execute(
&[
"var x = 'a'.repeat(10000); var arr = []; for(var i=0;i<100;i++) arr.push(x+i);"
.into(),
],
bridge,
&config,
)
.unwrap();
assert!(result.errors.is_empty());
eprintln!();
eprintln!("=== Memory Per Instance ===");
eprintln!(" Execution completed in {}us", result.duration_us);
eprintln!(" Observations: {}", result.observations.len());
eprintln!();
}