test: consolidate 25 integration crates into one it binary
Each top-level tests/*.rs was its own crate → its own binary, each statically linking the bundled engine + every dep. 26 of them, so an edit to the lib relinked all 26. Moved the 25 standalone files into tests/it/ under one tests/it/main.rs (the pattern typing_surface already uses); cargo auto-detects it as the `it` target. End state: 2 integration-test binaries instead of 26. Result: target/debug/deps 1.5 GB → 629 MB (-58%). Build time barely moved (clean 22.9s→22.4s, lib-edit relink 13.3s→12.4s) — wall-clock is dominated by compiling, not linking, so this is a disk win, not a speed win (see docs/plans/20260602-test-consolidation.md). Tests unchanged at 2151/0/1; clippy clean; no fixups needed. typing_surface_matrix stays its own already-consolidated binary. Tradeoff: the 25 files now share one crate (a compile error fails the whole `it` binary; module-scoped namespaces, no clashes) — negligible for a solo project.
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
//! Sub-phase 4d integration tests for advanced-mode SQL
|
||||
//! `DROP INDEX [IF EXISTS]` (ADR-0035 §4d).
|
||||
//!
|
||||
//! `SqlDropIndex` executes through the same `do_drop_index` machinery as
|
||||
//! the simple `drop index <name>`; the only new behaviour is `IF EXISTS`
|
||||
//! as a no-op-with-note (`DropIndexOutcome::Skipped`). These drive the
|
||||
//! worker directly; parsing (text → `Command::SqlDropIndex`) is covered
|
||||
//! by the `sql_drop_index_tests` in `src/dsl/grammar/ddl.rs`.
|
||||
|
||||
use rdbms_playground::db::{Database, DropIndexOutcome};
|
||||
use rdbms_playground::dsl::{ColumnSpec, Type};
|
||||
use rdbms_playground::persistence::Persistence;
|
||||
use rdbms_playground::project;
|
||||
|
||||
fn rt() -> tokio::runtime::Runtime {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("tokio rt")
|
||||
}
|
||||
|
||||
fn open(undo: bool) -> (project::Project, Database, tempfile::TempDir) {
|
||||
let dir = tempfile::tempdir().expect("create tempdir");
|
||||
let project =
|
||||
project::open_or_create(None, Some(dir.path())).expect("open or create project");
|
||||
let persistence = Persistence::new(project.path().to_path_buf());
|
||||
let db = Database::open_with_persistence_and_undo(project.db_path(), persistence, undo)
|
||||
.expect("open db with persistence");
|
||||
(project, db, dir)
|
||||
}
|
||||
|
||||
/// Create `T (id int primary key, email text)` and an index on `email`.
|
||||
fn make_t_with_index(db: &Database, r: &tokio::runtime::Runtime) -> String {
|
||||
r.block_on(db.sql_create_table(
|
||||
"T".to_string(),
|
||||
vec![ColumnSpec::new("id", Type::Int), ColumnSpec::new("email", Type::Text)],
|
||||
vec!["id".to_string()],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
Some("create table T (id int primary key, email text)".to_string()),
|
||||
))
|
||||
.expect("create T");
|
||||
let desc = r
|
||||
.block_on(db.add_index(
|
||||
Some("T_email_idx".to_string()),
|
||||
"T".to_string(),
|
||||
vec!["email".to_string()],
|
||||
Some("add index as T_email_idx on T (email)".to_string()),
|
||||
))
|
||||
.expect("add index");
|
||||
assert_eq!(desc.indexes.len(), 1, "index created");
|
||||
"T_email_idx".to_string()
|
||||
}
|
||||
|
||||
fn index_names(db: &Database, r: &tokio::runtime::Runtime) -> Vec<String> {
|
||||
r.block_on(db.describe_table("T".to_string(), None))
|
||||
.expect("describe")
|
||||
.indexes
|
||||
.into_iter()
|
||||
.map(|i| i.name)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_index_removes_an_existing_index_and_shows_the_table() {
|
||||
let (_p, db, _d) = open(false);
|
||||
let r = rt();
|
||||
let name = make_t_with_index(&db, &r);
|
||||
let out = r
|
||||
.block_on(db.sql_drop_index(name, false, Some("drop index T_email_idx".to_string())))
|
||||
.expect("drop index");
|
||||
// Dropped carries the de-indexed table's structure (auto-show).
|
||||
match out {
|
||||
DropIndexOutcome::Dropped(desc) => {
|
||||
assert_eq!(desc.name, "T");
|
||||
assert!(desc.indexes.is_empty(), "the index is gone from the structure");
|
||||
}
|
||||
DropIndexOutcome::Skipped => panic!("expected Dropped, got Skipped"),
|
||||
}
|
||||
assert!(index_names(&db, &r).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_exists_on_an_absent_index_is_a_noop_and_journalled() {
|
||||
let (p, db, _d) = open(false);
|
||||
let r = rt();
|
||||
let line = "drop index if exists ghost_idx";
|
||||
let out = r
|
||||
.block_on(db.sql_drop_index("ghost_idx".to_string(), true, Some(line.to_string())))
|
||||
.expect("IF EXISTS on an absent index succeeds as a no-op");
|
||||
assert!(matches!(out, DropIndexOutcome::Skipped));
|
||||
// The no-op is still journalled (ADR-0034), like the create-skip.
|
||||
let log = std::fs::read_to_string(p.path().join("history.log")).expect("read history.log");
|
||||
assert!(log.contains(line), "the skipped drop should be journalled; log:\n{log}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_drop_of_an_absent_index_errors() {
|
||||
let (_p, db, _d) = open(false);
|
||||
let r = rt();
|
||||
let res = r.block_on(db.sql_drop_index(
|
||||
"ghost_idx".to_string(),
|
||||
false,
|
||||
Some("drop index ghost_idx".to_string()),
|
||||
));
|
||||
assert!(res.is_err(), "plain DROP INDEX on an absent index errors (no IF EXISTS)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_index_is_one_undo_step_and_restores_the_index() {
|
||||
let (_p, db, _d) = open(true); // undo enabled
|
||||
let r = rt();
|
||||
let name = make_t_with_index(&db, &r);
|
||||
r.block_on(db.sql_drop_index(name.clone(), false, Some("drop index T_email_idx".to_string())))
|
||||
.expect("drop index");
|
||||
assert!(index_names(&db, &r).is_empty());
|
||||
|
||||
// One undo brings the index back.
|
||||
assert!(r.block_on(db.undo()).expect("undo").is_some(), "the drop was one undo step");
|
||||
assert_eq!(index_names(&db, &r), vec![name], "undo restored the index");
|
||||
}
|
||||
Reference in New Issue
Block a user