#![cfg(all(feature = "testkit", feature = "cli"))]
use meterstore::cli::{Cli, Command, Format};
fn config_file(url: &str, warehouse: &std::path::Path) -> tempfile::NamedTempFile {
use std::io::Write;
let mut file = tempfile::NamedTempFile::new().expect("temp file");
write!(
file,
r#"
[hot]
url = "{url}"
max_connections = 4
ddl_lock_timeout = "2s"
[cold]
catalog = "sql"
uri = "{url}"
warehouse = "file://{}"
namespace = "metering"
file_target_bytes = 8388608
metadata_pool_max_connections = 2
[[tables]]
name = "readings_versions"
[tables.archival]
settlement_lag = "1d"
archival_step = "1d"
"#,
warehouse.display(),
)
.expect("write");
file
}
fn cli(config: &std::path::Path, command: Command) -> Cli {
Cli {
config: config.to_path_buf(),
format: Format::Json,
log: "off".to_string(),
command,
}
}
#[tokio::test]
async fn the_commands_drive_a_real_deployment() {
let url = meterstore::testkit::postgres::fresh_database()
.await
.expect("postgres");
let warehouse = tempfile::tempdir().expect("temp warehouse");
let file = config_file(&url, warehouse.path());
let path = file.path();
cli(path, Command::Check).run().await.expect("check");
cli(path, Command::Create).run().await.expect("create");
cli(path, Command::Status)
.run()
.await
.expect("a freshly created table is healthy");
cli(
path,
Command::Archive {
table: None,
max_windows: 4,
},
)
.run()
.await
.expect("archive");
cli(path, Command::Snapshots { table: None })
.run()
.await
.expect("the archival committed a snapshot to list");
cli(
path,
Command::Query {
sql: "SELECT count(*) AS n FROM readings".to_string(),
historical: false,
operational: false,
},
)
.run()
.await
.expect("query");
cli(
path,
Command::Explain {
sql: "SELECT malo_id, SUM(value) FROM readings GROUP BY 1".to_string(),
},
)
.run()
.await
.expect("explain");
cli(
path,
Command::Completeness {
table: None,
from: None,
to: None,
month: Some("2026-06".to_string()),
sparte: "STROM".to_string(),
seen_since: Some("30d".to_string()),
malo: None,
obis: None,
gaps_only: false,
},
)
.run()
.await
.expect("completeness over a Bilanzierungsmonat");
cli(
path,
Command::Completeness {
table: Some("readings".to_string()),
from: Some("2026-06-01T00:00:00Z".to_string()),
to: Some("2026-07-01T00:00:00Z".to_string()),
month: None,
sparte: "STROM".to_string(),
seen_since: None,
malo: Some("12345678905".to_string()),
obis: Some("1-0:1.29.0".to_string()),
gaps_only: true,
},
)
.run()
.await
.expect("completeness over an explicit range");
}
#[tokio::test]
async fn a_statement_that_will_not_plan_is_not_reported_as_retryable() {
let url = meterstore::testkit::postgres::fresh_database()
.await
.expect("postgres");
let warehouse = tempfile::tempdir().expect("temp warehouse");
let file = config_file(&url, warehouse.path());
cli(file.path(), Command::Create)
.run()
.await
.expect("create");
let err = cli(
file.path(),
Command::Query {
sql: "SELECT * FROM no_such_relation".to_string(),
historical: false,
operational: false,
},
)
.run()
.await
.expect_err("there is no such relation");
assert!(!err.is_retryable(), "{err:?}");
}
#[tokio::test]
async fn a_table_flag_takes_either_of_a_tables_two_names() {
let url = meterstore::testkit::postgres::fresh_database()
.await
.expect("postgres");
let warehouse = tempfile::tempdir().expect("temp warehouse");
let file = config_file(&url, warehouse.path());
let path = file.path();
cli(path, Command::Create).run().await.expect("create");
for name in ["readings_versions", "readings"] {
cli(
path,
Command::Archive {
table: Some(name.to_string()),
max_windows: 1,
},
)
.run()
.await
.unwrap_or_else(|e| panic!("--table {name} should select the table: {e}"));
}
let err = cli(
path,
Command::Archive {
table: Some("esa_typ2".to_string()),
max_windows: 1,
},
)
.run()
.await
.expect_err("no such table");
assert!(err.to_string().contains("readings_versions"), "{err}");
}
#[tokio::test]
async fn purge_needs_the_table_named_twice() {
let url = meterstore::testkit::postgres::fresh_database()
.await
.expect("postgres");
let warehouse = tempfile::tempdir().expect("temp warehouse");
let file = config_file(&url, warehouse.path());
cli(file.path(), Command::Create)
.run()
.await
.expect("create");
let err = cli(
file.path(),
Command::Purge {
table: "readings_versions".to_string(),
confirm: "readings".to_string(),
},
)
.run()
.await
.expect_err("the confirmation does not match, and there is no recovery path");
assert!(err.to_string().contains("readings_versions"), "{err}");
cli(file.path(), Command::Status)
.run()
.await
.expect("status");
}