#![allow(clippy::all)]
use std::path::PathBuf;
use std::process::Command;
const CLI_BINARY: &str = "cqlite";
fn run_cli_command(args: &[&str]) -> std::process::Output {
Command::new("cargo")
.args(&["run", "--quiet", "--bin", CLI_BINARY, "--"])
.args(args)
.output()
.expect("Failed to execute CLI command")
}
fn get_test_data_root() -> PathBuf {
std::env::var("CQLITE_DATASETS_ROOT")
.map(PathBuf::from)
.unwrap_or_else(|_| {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.join("test-data/datasets")
})
}
fn get_schemas_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.join("test-data/schemas")
}
#[test]
#[cfg(feature = "state_machine")]
fn test_one_shot_select_with_ingestion_basic() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found at {:?}",
data_dir
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"-e",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--format",
"json",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
eprintln!("STDERR:\n{}", String::from_utf8_lossy(&output.stderr));
assert!(
output.status.success(),
"One-shot SELECT should succeed. Exit code: {:?}",
output.status.code()
);
let _stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("error") || stderr.contains("INFO"),
"Should not contain errors in stderr"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_one_shot_select_with_invalid_schema_exit_code_3() {
let data_dir = get_test_data_root().join("sstables");
let invalid_schema = PathBuf::from("/tmp/nonexistent_schema.cql");
assert!(
data_dir.exists(),
"Test requires full SSTable dataset: test data not found at {:?}",
data_dir
);
let output = run_cli_command(&[
"--schema",
invalid_schema.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"-e",
"SELECT * FROM test_basic.simple_table LIMIT 5",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDERR:\n{}", String::from_utf8_lossy(&output.stderr));
let exit_code = output.status.code().unwrap_or(1);
assert_eq!(
exit_code, 3,
"Invalid schema should return exit code 3, got {}",
exit_code
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("schema")
|| stderr.contains("Ingestion failed")
|| stderr.contains("Path does not exist"),
"Error message should mention schema or path error"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_one_shot_select_with_invalid_data_dir_exit_code_4() {
let invalid_data_dir = PathBuf::from("/tmp/nonexistent_data_directory");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
schema_file.exists(),
"Test requires full SSTable dataset: schema not found at {:?}",
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
invalid_data_dir.to_str().unwrap(),
"-e",
"SELECT * FROM test_basic.simple_table LIMIT 5",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDERR:\n{}", String::from_utf8_lossy(&output.stderr));
let exit_code = output.status.code().unwrap_or(1);
assert_eq!(
exit_code, 4,
"Invalid data-dir should return exit code 4, got {}",
exit_code
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("data")
|| stderr.contains("directory")
|| stderr.contains("Path does not exist")
|| stderr.contains("Ingestion failed"),
"Error message should mention data directory error"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_one_shot_select_with_version_hint() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--cassandra-version",
"5.0",
"-e",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--format",
"json",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDERR:\n{}", String::from_utf8_lossy(&output.stderr));
assert!(
output.status.success(),
"One-shot SELECT with version hint should succeed"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_one_shot_select_table_format() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"-e",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--format",
"table",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
assert!(
output.status.success(),
"Table format output should succeed"
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.is_empty(), "Table format should produce output");
}
#[test]
#[cfg(feature = "state_machine")]
fn test_one_shot_select_csv_format() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"-e",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--format",
"csv",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
assert!(output.status.success(), "CSV format output should succeed");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.is_empty(), "CSV format should produce output");
}
#[test]
#[cfg(feature = "state_machine")]
fn test_query_parameter_alias_for_execute() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--query", "SELECT * FROM test_basic.simple_table LIMIT 5",
"--format",
"json",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
eprintln!("STDERR:\n{}", String::from_utf8_lossy(&output.stderr));
assert!(
output.status.success(),
"--query alias should succeed. Exit code: {:?}",
output.status.code()
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.is_empty(),
"--query should produce output identical to -e"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_out_parameter_json_format() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--query",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--out", "json",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
assert!(
output.status.success(),
"--out json should succeed. Exit code: {:?}",
output.status.code()
);
let stdout = String::from_utf8_lossy(&output.stdout);
let trimmed = stdout.trim();
assert!(
trimmed.starts_with('{') || trimmed.starts_with('['),
"--out json should produce JSON output, got: {}",
&trimmed[..trimmed.len().min(100)]
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_out_parameter_csv_format() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--query",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--out",
"csv",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
assert!(
output.status.success(),
"--out csv should succeed. Exit code: {:?}",
output.status.code()
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains(',') || stdout.lines().count() > 0,
"--out csv should produce CSV-like output"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_out_parameter_table_format() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--query",
"SELECT * FROM test_basic.simple_table LIMIT 5",
"--out",
"table",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
assert!(
output.status.success(),
"--out table should succeed. Exit code: {:?}",
output.status.code()
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.is_empty(), "--out table should produce output");
}
#[test]
#[cfg(feature = "state_machine")]
fn test_query_and_out_combined_prd_example() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--query",
"SELECT * FROM test_basic.simple_table LIMIT 3",
"--out",
"json",
]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
eprintln!("STDERR:\n{}", String::from_utf8_lossy(&output.stderr));
assert!(
output.status.success(),
"PRD example (--query + --out json) should succeed. Exit code: {:?}",
output.status.code()
);
let stdout = String::from_utf8_lossy(&output.stdout);
let trimmed = stdout.trim();
assert!(
trimmed.starts_with('{') || trimmed.starts_with('['),
"PRD example should produce JSON output"
);
}
#[test]
#[cfg(feature = "state_machine")]
fn test_out_takes_precedence_over_format() {
let data_dir = get_test_data_root().join("sstables");
let schema_file = get_schemas_dir().join("basic-types.cql");
assert!(
data_dir.exists() && schema_file.exists(),
"Test requires full SSTable dataset: test data not found. data_dir={:?}, schema_file={:?}",
data_dir,
schema_file
);
let output = run_cli_command(&[
"--schema",
schema_file.to_str().unwrap(),
"--data-dir",
data_dir.to_str().unwrap(),
"--query",
"SELECT id, name FROM test_basic.simple_table LIMIT 1",
"--format",
"table", "--out",
"json", ]);
eprintln!("Exit status: {}", output.status);
eprintln!("STDOUT:\n{}", String::from_utf8_lossy(&output.stdout));
assert!(
output.status.success(),
"--out should take precedence over --format. Exit code: {:?}",
output.status.code()
);
let stdout = String::from_utf8_lossy(&output.stdout);
let trimmed = stdout.trim();
assert!(
trimmed.starts_with('{') || trimmed.starts_with('['),
"--out json should override --format table, but got: {}",
&trimmed[..trimmed.len().min(100)]
);
}