diff --git a/Cargo.lock b/Cargo.lock index 778aed61..9b2595c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -989,6 +989,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fancy-regex" version = "0.13.0" @@ -1276,6 +1288,15 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "heck" version = "0.4.1" @@ -1658,6 +1679,16 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1985,6 +2016,7 @@ dependencies = [ "regex", "regex-syntax", "rlimit", + "rusqlite", "rustls", "rustls-native-certs", "rustls-pki-types", @@ -2472,6 +2504,20 @@ dependencies = [ "libc", ] +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rust_decimal" version = "1.35.0" diff --git a/Cargo.toml b/Cargo.toml index e21e8e07..850f41e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ pin-project-lite = "0.2.14" http-body-util = "0.1.2" hyper-util = { version = "0.1.6", features = ["tokio"] } tokio-vsock = { version = "0.5.0", optional = true } +rusqlite = "0.32.1" [target.'cfg(unix)'.dependencies] rlimit = "0.10.1" diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 00000000..976ccdc1 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,65 @@ +use rusqlite::Connection; + +use crate::client::{ClientError, RequestResult}; + +fn create_db(conn: &Connection) -> Result { + conn.execute( + "CREATE TABLE loadtest ( + url TEXT NOT NULL, + duration REAL, + status INTEGER, + len_bytes INTEGER + )", + (), + ) +} + +pub fn store( + db_url: &str, + req_url: String, + request_records: &[RequestResult], +) -> Result { + let conn = Connection::open(db_url)?; + _ = create_db(&conn); + + let request_url = req_url + .replace("https", "") + .replace("http", "") + .replace("://", ""); + + let affected_rows = + request_records + .into_iter() + .map(|req| { + conn.execute( + "INSERT INTO loadtest (url, duration, status, len_bytes) VALUES (?1, ?2, ?3, ?4)", + (&request_url, req.duration().as_secs_f32(), req.status.as_u16() as u32, req.len_bytes), + ).unwrap_or(0) + }) + .sum(); + + Ok(affected_rows) +} + +#[cfg(test)] +mod test_db { + use super::*; + + #[test] + fn test_store() { + let conn = Connection::open_in_memory().unwrap(); + let _ = create_db(&conn); + let test_val = RequestResult { + status: hyper::StatusCode::OK, + len_bytes: 100, + start_latency_correction: None, + start: std::time::Instant::now(), + connection_time: None, + end: std::time::Instant::now(), + }; + let test_vec = vec![test_val.clone(), test_val.clone()]; + let result = store("test.db", "test.com".to_owned(), &test_vec); + assert_eq!(result.unwrap(), 2); + std::fs::remove_file("test.db").unwrap(); + } +} diff --git a/src/main.rs b/src/main.rs index 8dd80a03..68751b4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ use url::Url; use url_generator::UrlGenerator; mod client; +mod db; mod histogram; mod monitor; mod printer; @@ -188,6 +189,8 @@ Note: If qps is specified, burst will be ignored", long = "stats-success-breakdown" )] stats_success_breakdown: bool, + #[clap(help = "sqlite datebase url E.G test.db", long = "db-url")] + db_url: Option, } /// An entry specified by `connect-to` to override DNS resolution and default @@ -654,6 +657,10 @@ async fn main() -> anyhow::Result<()> { opts.stats_success_breakdown, )?; + if let Some(db_url) = opts.db_url { + let _ = db::store(&db_url, opts.url, res.success()); + } + Ok(()) }