use surrealmx::{Database, Error};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn operations_after_commit_fail() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.commit().unwrap();
assert!(matches!(tx.get("key"), Err(Error::TxClosed)));
assert!(matches!(tx.set("key2", "value2"), Err(Error::TxClosed)));
assert!(matches!(tx.put("key3", "value3"), Err(Error::TxClosed)));
assert!(matches!(tx.del("key"), Err(Error::TxClosed)));
assert!(matches!(tx.exists("key"), Err(Error::TxClosed)));
assert!(matches!(tx.commit(), Err(Error::TxClosed)));
assert!(matches!(tx.cancel(), Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn operations_after_cancel_fail() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.cancel().unwrap();
assert!(matches!(tx.get("key"), Err(Error::TxClosed)));
assert!(matches!(tx.set("key2", "value2"), Err(Error::TxClosed)));
assert!(matches!(tx.commit(), Err(Error::TxClosed)));
assert!(matches!(tx.cancel(), Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn double_commit_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
assert!(tx.commit().is_ok(), "First commit should succeed");
assert!(matches!(tx.commit(), Err(Error::TxClosed)), "Second commit should fail with TxClosed");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn double_cancel_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
assert!(tx.cancel().is_ok(), "First cancel should succeed");
assert!(matches!(tx.cancel(), Err(Error::TxClosed)), "Second cancel should fail with TxClosed");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn commit_after_cancel_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.cancel().unwrap();
assert!(matches!(tx.commit(), Err(Error::TxClosed)), "Commit after cancel should fail");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn cancel_after_commit_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.commit().unwrap();
assert!(matches!(tx.cancel(), Err(Error::TxClosed)), "Cancel after commit should fail");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn write_operations_on_read_transaction_fail() {
let db = Database::new();
{
let mut tx = db.transaction(true);
tx.set("existing_key", "value").unwrap();
tx.commit().unwrap();
}
let mut read_tx = db.transaction(false);
assert!(
matches!(read_tx.set("key", "value"), Err(Error::TxNotWritable)),
"set on read tx should fail"
);
assert!(
matches!(read_tx.put("key", "value"), Err(Error::TxNotWritable)),
"put on read tx should fail"
);
assert!(
matches!(read_tx.del("existing_key"), Err(Error::TxNotWritable)),
"del on read tx should fail"
);
assert!(
matches!(read_tx.putc("key", "value", Some("check")), Err(Error::TxNotWritable)),
"putc on read tx should fail"
);
assert!(
matches!(read_tx.delc("existing_key", Some("value")), Err(Error::TxNotWritable)),
"delc on read tx should fail"
);
assert!(read_tx.get("existing_key").is_ok());
assert!(read_tx.exists("existing_key").is_ok());
read_tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn put_existing_key_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "original").unwrap();
tx.commit().unwrap();
let mut tx = db.transaction(true);
let result = tx.put("key", "new_value");
assert!(matches!(result, Err(Error::KeyAlreadyExists)), "put existing key should fail");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn put_key_in_same_transaction_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "first").unwrap();
let result = tx.put("key", "second");
assert!(matches!(result, Err(Error::KeyAlreadyExists)), "put after set in same tx should fail");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn putc_wrong_check_value_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "actual_value").unwrap();
tx.commit().unwrap();
let mut tx = db.transaction(true);
let result = tx.putc("key", "new_value", Some("wrong_check"));
assert!(matches!(result, Err(Error::ValNotExpectedValue)), "putc with wrong check should fail");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn delc_wrong_check_value_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "actual_value").unwrap();
tx.commit().unwrap();
let mut tx = db.transaction(true);
let result = tx.delc("key", Some("wrong_check"));
assert!(matches!(result, Err(Error::ValNotExpectedValue)), "delc with wrong check should fail");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn putc_none_check_on_existing_key_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "exists").unwrap();
tx.commit().unwrap();
let mut tx = db.transaction(true);
let result = tx.putc::<_, _, &[u8]>("key", "new_value", None);
assert!(
matches!(result, Err(Error::ValNotExpectedValue)),
"putc with None check on existing key should fail"
);
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn delc_none_check_on_existing_key_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "exists").unwrap();
tx.commit().unwrap();
let mut tx = db.transaction(true);
let result = tx.delc::<_, &[u8]>("key", None);
assert!(
matches!(result, Err(Error::ValNotExpectedValue)),
"delc with None check on existing key should fail"
);
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn rollback_without_savepoint_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
let result = tx.rollback_to_savepoint();
assert!(matches!(result, Err(Error::NoSavepoint)), "rollback without savepoint should fail");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn rollback_after_all_savepoints_consumed_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set_savepoint().unwrap();
tx.set("key", "value").unwrap();
tx.rollback_to_savepoint().unwrap();
let result = tx.rollback_to_savepoint();
assert!(matches!(result, Err(Error::NoSavepoint)), "second rollback should fail");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn write_conflict_error() {
let db = Database::new();
let mut tx1 = db.transaction(true);
let mut tx2 = db.transaction(true);
tx1.set("key", "tx1").unwrap();
tx2.set("key", "tx2").unwrap();
tx1.commit().unwrap();
let result = tx2.commit();
assert!(
matches!(result, Err(Error::KeyWriteConflict)),
"concurrent write to same key should conflict"
);
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn read_conflict_error_ssi() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "initial").unwrap();
tx.commit().unwrap();
let mut tx1 = db.transaction(true).with_serializable_snapshot_isolation();
let _ = tx1.get("key").unwrap();
let mut tx2 = db.transaction(true).with_serializable_snapshot_isolation();
tx2.set("key", "modified").unwrap();
tx2.commit().unwrap();
tx1.set("other", "data").unwrap();
let result = tx1.commit();
assert!(matches!(result, Err(Error::KeyReadConflict)), "SSI should detect read conflict");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn get_at_future_version_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.commit().unwrap();
let tx = db.transaction(false);
let current_version = tx.version();
let future_version = current_version + 1_000_000_000;
let result = tx.get_at_version("key", future_version);
assert!(matches!(result, Err(Error::VersionInFuture)), "reading future version should fail");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn exists_at_future_version_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.commit().unwrap();
let tx = db.transaction(false);
let future_version = tx.version() + 1_000_000_000;
let result = tx.exists_at_version("key", future_version);
assert!(matches!(result, Err(Error::VersionInFuture)), "exists at future version should fail");
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn cursor_after_cancel_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.cancel().unwrap();
let result = tx.cursor("a".."z");
assert!(matches!(result, Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn keys_iter_after_commit_fails() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
tx.commit().unwrap();
let result = tx.keys_iter("a".."z");
assert!(matches!(result, Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn scan_iter_after_cancel_fails() {
let db = Database::new();
let mut tx = db.transaction(false);
tx.cancel().unwrap();
let result = tx.scan_iter("a".."z");
assert!(matches!(result, Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn getm_after_close_fails() {
let db = Database::new();
let mut tx = db.transaction(false);
tx.cancel().unwrap();
let result = tx.getm(vec!["key1", "key2"]);
assert!(matches!(result, Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn operations_on_dropped_transaction() {
let db = Database::new();
{
let mut tx = db.transaction(true);
tx.set("key", "value").unwrap();
}
let mut tx = db.transaction(false);
assert!(tx.get("key").unwrap().is_none(), "Dropped transaction should not commit");
tx.cancel().unwrap();
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn set_savepoint_on_closed_transaction() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.commit().unwrap();
let result = tx.set_savepoint();
assert!(matches!(result, Err(Error::TxClosed)));
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[test]
fn rollback_on_closed_transaction() {
let db = Database::new();
let mut tx = db.transaction(true);
tx.set_savepoint().unwrap();
tx.cancel().unwrap();
let result = tx.rollback_to_savepoint();
assert!(matches!(result, Err(Error::TxClosed)));
}