199 lines
4.8 KiB
Rust
199 lines
4.8 KiB
Rust
mod performance;
|
|
|
|
use bottest::prelude::*;
|
|
use reqwest::Client;
|
|
use std::time::{Duration, Instant};
|
|
|
|
fn test_client() -> Client {
|
|
Client::builder()
|
|
.timeout(Duration::from_secs(30))
|
|
.build()
|
|
.expect("Failed to create HTTP client")
|
|
}
|
|
|
|
fn external_server_url() -> Option<String> {
|
|
std::env::var("BOTSERVER_URL").ok()
|
|
}
|
|
|
|
async fn get_test_server() -> Option<(Option<TestContext>, String)> {
|
|
if let Some(url) = external_server_url() {
|
|
let client = reqwest::Client::builder()
|
|
.timeout(Duration::from_secs(2))
|
|
.build()
|
|
.ok()?;
|
|
|
|
if client.get(&url).send().await.is_ok() {
|
|
return Some((None, url));
|
|
}
|
|
}
|
|
|
|
let ctx = TestHarness::quick().await.ok()?;
|
|
let server = ctx.start_botserver().await.ok()?;
|
|
|
|
if server.is_running() {
|
|
Some((Some(ctx), server.url.clone()))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
macro_rules! skip_if_no_server {
|
|
($base_url:expr) => {
|
|
if $base_url.is_none() {
|
|
eprintln!("Skipping test: no server available");
|
|
return;
|
|
}
|
|
};
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_concurrent_requests_handled() {
|
|
let server = get_test_server().await;
|
|
skip_if_no_server!(server);
|
|
|
|
let (_ctx, base_url) = server.unwrap();
|
|
let client = test_client();
|
|
|
|
let handles: Vec<_> = (0..20)
|
|
.map(|_| {
|
|
let client = client.clone();
|
|
let base_url = base_url.clone();
|
|
tokio::spawn(async move {
|
|
client
|
|
.get(format!("{}/health", base_url))
|
|
.send()
|
|
.await
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
let results = futures::future::join_all(handles).await;
|
|
|
|
let successes = results
|
|
.iter()
|
|
.filter(|r| r.as_ref().map(|resp| resp.status().is_success()).unwrap_or(false))
|
|
.count();
|
|
|
|
assert!(
|
|
successes >= 15,
|
|
"At least 75% of concurrent requests should succeed"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_response_time_acceptable() {
|
|
let server = get_test_server().await;
|
|
skip_if_no_server!(server);
|
|
|
|
let (_ctx, base_url) = server.unwrap();
|
|
let client = test_client();
|
|
|
|
let start = Instant::now();
|
|
|
|
let response = client
|
|
.get(format!("{}/health", base_url))
|
|
.send()
|
|
.await;
|
|
|
|
let elapsed = start.elapsed();
|
|
|
|
match response {
|
|
Ok(resp) => {
|
|
assert!(resp.status().is_success(), "Health should return success");
|
|
assert!(
|
|
elapsed < Duration::from_secs(5),
|
|
"Response time should be under 5s, got {:?}",
|
|
elapsed
|
|
);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("Skipping: request failed: {}", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_sustained_load() {
|
|
let server = get_test_server().await;
|
|
skip_if_no_server!(server);
|
|
|
|
let (_ctx, base_url) = server.unwrap();
|
|
let client = test_client();
|
|
|
|
let mut successes = 0;
|
|
let total_requests = 30;
|
|
|
|
for _ in 0..total_requests {
|
|
let response = client
|
|
.get(format!("{}/health", base_url))
|
|
.send()
|
|
.await;
|
|
|
|
if let Ok(resp) = response {
|
|
if resp.status().is_success() {
|
|
successes += 1;
|
|
}
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_millis(50)).await;
|
|
}
|
|
|
|
let success_rate = (successes as f64 / total_requests as f64) * 100.0;
|
|
assert!(
|
|
success_rate >= 80.0,
|
|
"Success rate should be >= 80%, got {:.1}%",
|
|
success_rate
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_improves_performance() {
|
|
let server = get_test_server().await;
|
|
skip_if_no_server!(server);
|
|
|
|
let (_ctx, base_url) = server.unwrap();
|
|
let client = test_client();
|
|
|
|
let start1 = Instant::now();
|
|
let _ = client
|
|
.get(format!("{}/version", base_url))
|
|
.send()
|
|
.await;
|
|
let first_request = start1.elapsed();
|
|
|
|
tokio::time::sleep(Duration::from_millis(50)).await;
|
|
|
|
let start2 = Instant::now();
|
|
let _ = client
|
|
.get(format!("{}/version", base_url))
|
|
.send()
|
|
.await;
|
|
let second_request = start2.elapsed();
|
|
|
|
if second_request < first_request {
|
|
assert!(
|
|
second_request < first_request * 8 / 10,
|
|
"Second request should be significantly faster due to caching"
|
|
);
|
|
} else {
|
|
eprintln!("Note: Caching may not be enabled or working");
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_memory_stability() {
|
|
let server = get_test_server().await;
|
|
skip_if_no_server!(server);
|
|
|
|
let (_ctx, base_url) = server.unwrap();
|
|
let client = test_client();
|
|
|
|
for _ in 0..20 {
|
|
let _ = client
|
|
.get(format!("{}/health", base_url))
|
|
.send()
|
|
.await;
|
|
}
|
|
|
|
eprintln!("Note: Memory profiling requires external monitoring");
|
|
}
|