use dynoxide::Database;
use dynoxide::actions::batch_execute_statement::{
BatchExecuteStatementRequest, BatchStatementRequest,
};
use dynoxide::actions::batch_get_item::{BatchGetItemRequest, KeysAndAttributes};
use dynoxide::actions::batch_write_item::{BatchWriteItemRequest, PutRequest, WriteRequest};
use dynoxide::actions::execute_transaction::{ExecuteTransactionRequest, ParameterizedStatement};
use dynoxide::actions::transact_get_items::{
TransactGet, TransactGetItem, TransactGetItemsRequest,
};
use dynoxide::actions::transact_write_items::{
TransactPut, TransactWriteItem, TransactWriteItemsRequest,
};
use dynoxide::errors::DynoxideError;
use dynoxide::types::AttributeValue;
use std::collections::HashMap;
const BOUNDED: usize = 1_200_000;
const LIMIT: usize = 1024 * 1024;
fn assert_cut(message: &str) {
assert!(
message.len() > LIMIT,
"the echo was cut short: {} bytes",
message.len()
);
assert!(
message.len() < BOUNDED,
"the echo ran to {} bytes",
message.len()
);
assert!(
message.contains("...' at '"),
"the cut echo doesn't end with ...: {}",
&message[message.len().saturating_sub(200)..]
);
}
fn message(err: DynoxideError) -> String {
match err {
DynoxideError::ValidationException(m) => m,
other => panic!("expected a ValidationException, got {other:?}"),
}
}
#[test]
fn a_batch_write_echo_is_bounded() {
let db = Database::memory().unwrap();
let item: HashMap<String, AttributeValue> = (0..200_000)
.map(|i| (format!("a{i}"), AttributeValue::N("1".to_string())))
.collect();
let mut request_items = HashMap::new();
request_items.insert(
"a!".to_string(),
vec![WriteRequest {
put_request: Some(PutRequest { item }),
delete_request: None,
}],
);
let err = db
.batch_write_item(BatchWriteItemRequest {
request_items,
..Default::default()
})
.unwrap_err();
let message = message(err);
assert!(
message.starts_with("1 validation error detected: Value '{a!=[WriteRequest(putRequest="),
"unexpected message start: {}",
&message[..message.len().min(200)]
);
assert_cut(&message);
}
#[test]
fn a_batch_statement_echo_is_bounded() {
let db = Database::memory().unwrap();
let statements: Vec<BatchStatementRequest> = (0..26)
.map(|_| {
let mut statement = BatchStatementRequest::default();
statement.statement = "SELECT * FROM \"T\" WHERE pk = ?".to_string();
statement.parameters = Some(
(0..2_000)
.map(|_| AttributeValue::N("1".to_string()))
.collect(),
);
statement
})
.collect();
let err = db
.batch_execute_statement(BatchExecuteStatementRequest {
statements,
..Default::default()
})
.unwrap_err();
let message = message(err);
assert!(
message.starts_with("1 validation error detected: Value '[BatchStatementRequest("),
"unexpected message start: {}",
&message[..message.len().min(200)]
);
assert_cut(&message);
}
#[test]
fn a_transaction_statement_echo_is_bounded() {
let db = Database::memory().unwrap();
let statements: Vec<ParameterizedStatement> = (0..101)
.map(|_| ParameterizedStatement {
statement: "SELECT * FROM \"T\" WHERE pk = ?".to_string(),
parameters: Some(
(0..2_000)
.map(|_| AttributeValue::N("1".to_string()))
.collect(),
),
..Default::default()
})
.collect();
let err = db
.execute_transaction(ExecuteTransactionRequest {
transact_statements: statements,
..Default::default()
})
.unwrap_err();
let message = message(err);
assert!(
message.starts_with("1 validation error detected: Value '[ParameterizedStatement("),
"unexpected message start: {}",
&message[..message.len().min(200)]
);
assert_cut(&message);
}
#[test]
fn a_batch_get_echo_is_bounded() {
let db = Database::memory().unwrap();
let keys: Vec<HashMap<String, AttributeValue>> = (0..100)
.map(|i| {
HashMap::from([(
"pk".to_string(),
AttributeValue::S(format!("{i}{}", "x".repeat(20_000))),
)])
})
.collect();
let mut request_items = HashMap::new();
request_items.insert(
"a!".to_string(),
KeysAndAttributes {
keys,
..Default::default()
},
);
let err = db
.batch_get_item(BatchGetItemRequest {
request_items,
..Default::default()
})
.unwrap_err();
let message = message(err);
assert!(
message.starts_with("1 validation error detected: Value '{\"a!\":"),
"unexpected message start: {}",
&message[..message.len().min(200)]
);
assert_cut(&message);
}
fn long_key(i: usize) -> HashMap<String, AttributeValue> {
HashMap::from([(
"pk".to_string(),
AttributeValue::S(format!("{i}{}", "x".repeat(20_000))),
)])
}
#[test]
fn a_transaction_write_listing_is_bounded() {
let db = Database::memory().unwrap();
let transact_items = (0..101)
.map(|i| TransactWriteItem {
put: Some(TransactPut {
table_name: "T".to_string(),
item: long_key(i),
..Default::default()
}),
..Default::default()
})
.collect();
let err = db
.transact_write_items(TransactWriteItemsRequest {
transact_items,
..Default::default()
})
.unwrap_err();
let message = message(err);
assert!(
message.starts_with("1 validation error detected: Value '[TransactWriteItem("),
"unexpected message start: {}",
&message[..message.len().min(200)]
);
assert_cut(&message);
}
#[test]
fn a_transaction_get_listing_is_bounded() {
let db = Database::memory().unwrap();
let transact_items = (0..101)
.map(|i| TransactGetItem {
get: TransactGet {
table_name: "T".to_string(),
key: long_key(i),
..Default::default()
},
})
.collect();
let err = db
.transact_get_items(TransactGetItemsRequest {
transact_items,
..Default::default()
})
.unwrap_err();
let message = message(err);
assert!(
message.starts_with("1 validation error detected: Value '[TransactGetItem("),
"unexpected message start: {}",
&message[..message.len().min(200)]
);
assert_cut(&message);
}