#![allow(clippy::unwrap_used, clippy::expect_used)]
use std::sync::Arc;
use std::time::Duration;
use chronix::Chronix;
use chronix::prelude::*;
fn expired_db(points: i64) -> (Arc<Chronix>, tempfile::TempDir, i64) {
let tmp = tempfile::tempdir().expect("tempdir");
let config = ChronixConfig::builder()
.data_dir(tmp.path().to_path_buf())
.query_timeout(Duration::from_nanos(1))
.build()
.expect("config");
let db = Arc::new(Chronix::open(config).expect("open"));
let base = 1_700_000_000_000_000_000i64;
let batch: Vec<Point> = (0..points)
.map(|i| {
Point::new(
SeriesKey::new("cpu", chronix::tags! { "host" => "a" }).expect("key"),
chronix::fields! { "value" => i as f64 },
base + i * 1_000_000_000,
)
.expect("point")
})
.collect();
db.insert_batch(&batch)
.expect("insert")
.into_complete()
.expect("all accepted");
db.flush().expect("flush");
(db, tmp, base)
}
#[test]
fn a_spent_budget_stops_the_streaming_read() {
let (db, _tmp, base) = expired_db(500);
let plan = db
.query()
.measurement("cpu")
.range(base, base + 500_000_000_000)
.build()
.expect("plan");
let err = db
.execute_iter(&plan)
.expect("the stream is built")
.collect::<Result<Vec<_>, _>>()
.expect_err("a spent budget must refuse the scan");
assert!(
matches!(err, chronix::DbError::QueryTimeout(_)),
"expected a query timeout, got {err}"
);
}
#[test]
fn a_spent_budget_stops_the_collecting_read() {
let (db, _tmp, base) = expired_db(500);
let plan = db
.query()
.measurement("cpu")
.range(base, base + 500_000_000_000)
.build()
.expect("plan");
let err = db.execute(&plan).expect_err("a spent budget refuses");
assert!(
matches!(err, chronix::DbError::QueryTimeout(_)),
"expected a query timeout, got {err}"
);
}
#[test]
fn maintenance_work_is_not_bounded_by_a_query_deadline() {
let (db, _tmp, base) = expired_db(500);
let plan = db
.query()
.measurement("cpu")
.range(base, base + 500_000_000_000)
.build()
.expect("plan");
let rows: usize = db
.execute_iter(&plan)
.expect("stream")
.without_deadline()
.map(|b| {
b.expect("a scan with no deadline cannot time out")
.num_rows()
})
.sum();
assert_eq!(rows, 500, "every row is still read");
}
#[test]
fn export_and_rollups_run_under_an_expired_deadline() {
let (db, tmp, base) = expired_db(500);
let plan = db
.query()
.measurement("cpu")
.range(base, base + 500_000_000_000)
.build()
.expect("plan");
let out = tmp.path().join("export.parquet");
db.export_parquet(&plan, &out, &chronix::ParquetExportConfig::default())
.expect("an export is not bounded by query_timeout");
assert!(out.exists(), "the export wrote its file");
db.create_rollup(
RollupBuilder::new()
.name("cpu_1m")
.source("cpu")
.target("cpu_1m")
.every("1m")
.aggregation(RollupAggFn::Avg)
.build()
.expect("rollup config"),
)
.expect("create rollup");
db.materialise_rollups()
.expect("materialisation is not bounded by query_timeout");
}