mod utils;
use eyre::Result;
use ion_binary_rs::IonValue;
use qldb::QldbClient;
use qldb::QldbError::SendCommandError;
use rusoto_core::RusotoError::Service;
use rusoto_qldb_session::SendCommandError::OccConflict;
use std::collections::HashMap;
use utils::ensure_test_table;
#[async_std::test]
async fn qldb_transaction() -> Result<()> {
let client = QldbClient::default("rust-crate-test", 200).await?;
let test_table = ensure_test_table(&client).await;
client
.transaction_within(|client| async move {
let result = client
.query(&format!(r#"SELECT COUNT(*) FROM {};"#, test_table))
.execute()
.await;
println!("{:?}", result);
let count = result?;
let first_count = match &count[0].get("_1") {
Some(IonValue::Integer(count)) => count,
_ => panic!("First count returned a non integer"),
};
let result = client
.query(&format!("INSERT INTO {} VALUE ?", test_table))
.param(get_value_to_insert())
.execute()
.await;
println!("{:?}", result);
let count = client
.query(&format!("SELECT COUNT(*) FROM {}", test_table))
.count()
.await?;
assert_eq!(count, first_count + 1);
Ok(())
})
.await?;
Ok(())
}
#[async_std::test]
async fn qldb_transaction_rollback() -> Result<()> {
let client = QldbClient::default("rust-crate-test", 200).await?;
let test_table = ensure_test_table(&client).await;
let first_count = client
.transaction_within(|client| {
let test_table = test_table.clone();
async move {
let result = client
.query(&format!(r#"SELECT COUNT(*) FROM {};"#, test_table))
.execute()
.await;
let count = result?;
let count = match &count[0].get("_1") {
Some(IonValue::Integer(count)) => count,
_ => panic!("First count returned a non integer"),
};
Ok(*count)
}
})
.await?;
client
.transaction_within(|client| {
let test_table = test_table.clone();
async move {
let _ = client
.query(&format!("INSERT INTO {} VALUE ?", test_table))
.param(get_value_to_insert())
.execute()
.await;
client.rollback().await
}
})
.await?;
let second_count = client
.transaction_within(|client| {
let test_table = test_table.clone();
async move {
let count = client
.query(&format!("SELECT COUNT(*) FROM {}", test_table))
.count()
.await?;
Ok(count)
}
})
.await?;
assert_eq!(second_count, first_count);
Ok(())
}
#[async_std::test]
async fn qldb_transaction_occ_conflict() -> Result<()> {
let client = QldbClient::default("rust-crate-test", 200).await?;
let test_table = ensure_test_table(&client).await;
let future_a = client.transaction_within(|client| {
let test_table = test_table.clone();
async move {
client
.query(&format!(r#"SELECT COUNT(*) FROM {};"#, test_table))
.execute()
.await?;
async_std::task::sleep(std::time::Duration::from_millis(500)).await;
Ok(())
}
});
let future_b = client.transaction_within(|client| {
let test_table = test_table.clone();
async move {
async_std::task::sleep(std::time::Duration::from_millis(100)).await;
client
.query(&format!("INSERT INTO {} VALUE ?", test_table))
.param(get_value_to_insert())
.execute()
.await?;
Ok(())
}
});
let result = futures::join!(future_a, future_b);
if result.1.is_err() {
panic!("OCC test failed in the wrong transaction.")
}
match result.0 {
Err(SendCommandError(Service(OccConflict(_)))) => {}
_ => panic!("Non OCC error on the OCC test!"),
}
Ok(())
}
#[async_std::test]
async fn qldb_transaction_simple_select() -> Result<()> {
let client = QldbClient::default("rust-crate-test", 200).await?;
let test_table = ensure_test_table(&client).await;
client
.read_query(&format!(r#"SELECT COUNT(*) FROM {};"#, test_table))
.await?
.execute()
.await
.unwrap();
Ok(())
}
fn get_value_to_insert() -> IonValue {
let mut map = HashMap::new();
map.insert("test_column".to_string(), IonValue::String("test_value".to_string()));
IonValue::Struct(map)
}