test: add tests to sqlite_persist_catalog function
This commit is contained in:
@@ -89,29 +89,153 @@ pub fn run(path: &path::Path, catalog: &Catalog) -> result::Result<(), FailedTo>
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::{collections::HashMap, fs, path::Path};
|
||||||
|
fn setup_db(db_path: &Path) -> Connection {
|
||||||
|
let _ = fs::remove_file(db_path);
|
||||||
|
fun::sqlite_init_db::run(db_path).unwrap();
|
||||||
|
Connection::open(db_path).unwrap()
|
||||||
|
}
|
||||||
|
fn count_rows(conn: &Connection, table: &str, where_clause: &str) -> i64 {
|
||||||
|
let mut stmt = conn
|
||||||
|
.prepare(&format!(
|
||||||
|
"SELECT COUNT(*) FROM {} WHERE {}",
|
||||||
|
table, where_clause
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
stmt.query_row([], |row| row.get(0)).unwrap()
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn persist_should_insert_new_entities_and_attributes() {
|
fn persist_should_insert_new_entities_and_attributes() {
|
||||||
// Verifies that entities marked as 'New' in the catalog are inserted into the database, along with all their attributes.
|
// Verifies that entities marked as 'New' in the catalog are inserted into the database, along with all their attributes.
|
||||||
todo!();
|
let db_path = Path::new("test_insert.db");
|
||||||
|
let conn = setup_db(db_path);
|
||||||
|
let mut catalog = Catalog::new(db_path.to_str().unwrap());
|
||||||
|
let mut entity = Entity {
|
||||||
|
id: "e1".to_string(),
|
||||||
|
class: "c1".to_string(),
|
||||||
|
attributes: HashMap::new(),
|
||||||
|
state: EntityState::New,
|
||||||
|
ref_date: None,
|
||||||
|
};
|
||||||
|
entity.attributes.insert(
|
||||||
|
"a1".to_string(),
|
||||||
|
Attribute {
|
||||||
|
id: "a1".to_string(),
|
||||||
|
value: Value::Text("v1".to_string()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
catalog.items.insert("e1".to_string(), entity);
|
||||||
|
assert!(run(db_path, &catalog).is_ok());
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 1);
|
||||||
|
assert_eq!(count_rows(&conn, "attribute", "entity_id = 'e1'"), 1);
|
||||||
|
fs::remove_file(db_path).unwrap();
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn persist_should_delete_entities_marked_for_deletion() {
|
fn persist_should_delete_entities_marked_for_deletion() {
|
||||||
// Ensures that entities marked as 'ToDelete' are correctly removed from the database.
|
// Ensures that entities marked as 'ToDelete' are correctly removed from the database.
|
||||||
todo!();
|
let db_path = Path::new("test_delete.db");
|
||||||
|
let conn = setup_db(db_path);
|
||||||
|
conn.execute("INSERT INTO entity (id, class) VALUES ('e1', 'c1')", [])
|
||||||
|
.unwrap();
|
||||||
|
let mut catalog = Catalog::new(db_path.to_str().unwrap());
|
||||||
|
let entity = Entity {
|
||||||
|
id: "e1".to_string(),
|
||||||
|
class: "c1".to_string(),
|
||||||
|
attributes: HashMap::new(),
|
||||||
|
state: EntityState::ToDelete,
|
||||||
|
ref_date: None,
|
||||||
|
};
|
||||||
|
catalog.items.insert("e1".to_string(), entity);
|
||||||
|
assert!(run(db_path, &catalog).is_ok());
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 0);
|
||||||
|
fs::remove_file(db_path).unwrap();
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn persist_should_handle_a_mix_of_new_and_deleted_entities() {
|
fn persist_should_handle_a_mix_of_new_and_deleted_entities() {
|
||||||
// Tests the function's ability to handle a batch operation involving both new entities to be inserted and existing ones to be deleted.
|
// Tests the function's ability to handle a batch operation involving both new entities to be inserted and existing ones to be deleted.
|
||||||
todo!();
|
let db_path = Path::new("test_mix.db");
|
||||||
|
let conn = setup_db(db_path);
|
||||||
|
conn.execute("INSERT INTO entity (id, class) VALUES ('e1', 'c1')", [])
|
||||||
|
.unwrap();
|
||||||
|
let mut catalog = Catalog::new(db_path.to_str().unwrap());
|
||||||
|
let to_delete = Entity {
|
||||||
|
id: "e1".to_string(),
|
||||||
|
class: "c1".to_string(),
|
||||||
|
attributes: HashMap::new(),
|
||||||
|
state: EntityState::ToDelete,
|
||||||
|
ref_date: None,
|
||||||
|
};
|
||||||
|
let to_add = Entity {
|
||||||
|
id: "e2".to_string(),
|
||||||
|
class: "c2".to_string(),
|
||||||
|
attributes: HashMap::new(),
|
||||||
|
state: EntityState::New,
|
||||||
|
ref_date: None,
|
||||||
|
};
|
||||||
|
catalog.items.insert("e1".to_string(), to_delete);
|
||||||
|
catalog.items.insert("e2".to_string(), to_add);
|
||||||
|
assert!(run(db_path, &catalog).is_ok());
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 0);
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e2'"), 1);
|
||||||
|
fs::remove_file(db_path).unwrap();
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn persist_should_not_affect_unmodified_entities() {
|
fn persist_should_not_affect_unmodified_entities() {
|
||||||
// Verifies that entities in the catalog that are not marked as 'New' or 'ToDelete' remain untouched in the database.
|
// Verifies that entities in the catalog that are not marked as 'New' or 'ToDelete' remain untouched in the database.
|
||||||
todo!();
|
let db_path = Path::new("test_unmodified.db");
|
||||||
|
let conn = setup_db(db_path);
|
||||||
|
conn.execute("INSERT INTO entity (id, class) VALUES ('e1', 'c1')", [])
|
||||||
|
.unwrap();
|
||||||
|
let mut catalog = Catalog::new(db_path.to_str().unwrap());
|
||||||
|
let unmodified = Entity {
|
||||||
|
id: "e1".to_string(),
|
||||||
|
class: "c1".to_string(),
|
||||||
|
attributes: HashMap::new(),
|
||||||
|
state: EntityState::Loaded,
|
||||||
|
ref_date: None,
|
||||||
|
};
|
||||||
|
catalog.items.insert("e1".to_string(), unmodified);
|
||||||
|
assert!(run(db_path, &catalog).is_ok());
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e1'"), 1);
|
||||||
|
fs::remove_file(db_path).unwrap();
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn persist_should_rollback_transaction_on_failure() {
|
fn persist_should_rollback_transaction_on_failure() {
|
||||||
// Ensures that if any part of the persistence process fails, the entire transaction is rolled back, leaving the database state unchanged.
|
// Ensures that if any part of the persistence process fails, the entire transaction is rolled back, leaving the database state unchanged.
|
||||||
todo!();
|
let db_path = Path::new("test_rollback.db");
|
||||||
|
let conn = setup_db(db_path);
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO entity (id, class) VALUES ('e_existing', 'c1')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut catalog = Catalog::new(db_path.to_str().unwrap());
|
||||||
|
let mut new_entity = Entity {
|
||||||
|
id: "e_new".to_string(),
|
||||||
|
class: "c1".to_string(),
|
||||||
|
attributes: HashMap::new(),
|
||||||
|
state: EntityState::New,
|
||||||
|
ref_date: None,
|
||||||
|
};
|
||||||
|
new_entity.attributes.insert(
|
||||||
|
"a1".to_string(),
|
||||||
|
Attribute {
|
||||||
|
id: "a1".to_string(),
|
||||||
|
value: Value::Text("v1".to_string()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
catalog.items.insert("e_new".to_string(), new_entity);
|
||||||
|
// Corrupt the DB to cause a failure during the transaction
|
||||||
|
conn.execute("DROP TABLE attribute", []).unwrap();
|
||||||
|
drop(conn);
|
||||||
|
let result = run(db_path, &catalog);
|
||||||
|
assert!(result.is_err());
|
||||||
|
// Re-open connection to check state
|
||||||
|
let conn = Connection::open(db_path).unwrap();
|
||||||
|
// The new entity should not have been inserted due to rollback
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e_new'"), 0);
|
||||||
|
// The existing entity should still be there
|
||||||
|
assert_eq!(count_rows(&conn, "entity", "id = 'e_existing'"), 1);
|
||||||
|
fs::remove_file(db_path).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user