use beam::Node;
use beam::actor::Actor;
use beam::adapters::MemoryStorage;
use beam::types::Value;
use std::time::Duration;
#[tokio::test]
async fn e2e_put_get_roundtrip_no_sleep() {
let mut node = Node::new();
node.get("e2e_race_key")
.put("e2e_race_value".into())
.await
.expect("put should ack");
let got = node
.get("e2e_race_key")
.once(Some(Duration::from_secs(2)))
.await;
assert_eq!(
got,
Some(Value::Text("e2e_race_value".to_string())),
"race fix: get immediately after put.observe must see new value"
);
}
#[tokio::test]
async fn e2e_batch_put_map_roundtrip_no_sleep() {
let mut node = Node::new();
node.batch_put(vec![
(vec!["e2e_a".to_string()], Value::Text("1".into())),
(vec!["e2e_b".to_string()], Value::Text("2".into())),
(vec!["e2e_c".to_string()], Value::Text("3".into())),
])
.await
.expect("batch_put should ack");
let a = node.get("e2e_a").once(Some(Duration::from_secs(2))).await;
let b = node.get("e2e_b").once(Some(Duration::from_secs(2))).await;
let c = node.get("e2e_c").once(Some(Duration::from_secs(2))).await;
assert_eq!(a, Some(Value::Text("1".to_string())));
assert_eq!(b, Some(Value::Text("2".to_string())));
assert_eq!(c, Some(Value::Text("3".to_string())));
}
#[tokio::test]
async fn e2e_concurrent_puts_serialize_correctly() {
let mut node = Node::new();
for i in 0..50 {
let key = format!("conc_{}", i);
let val = format!("val_{}", i);
node.get(&key)
.put(val.clone().into())
.await
.expect("put should ack");
let got = node.get(&key).once(Some(Duration::from_secs(2))).await;
assert_eq!(
got,
Some(Value::Text(val.clone())),
"put {} → get observed {:?}, expected {:?}",
i,
got,
val
);
}
}
#[tokio::test]
async fn e2e_memory_storage_roundtrip() {
let storage = MemoryStorage::new();
let mut node = Node::new_with_config(
Default::default(),
vec![Box::new(storage) as Box<dyn Actor>],
vec![],
);
node.get("mem_key")
.put("mem_value".into())
.await
.expect("memory-storage put should ack");
let got = node.get("mem_key").once(Some(Duration::from_secs(2))).await;
assert_eq!(got, Some(Value::Text("mem_value".to_string())));
}
#[tokio::test]
async fn e2e_redb_put_await_durability() {
use beam::adapters::RedbStorage;
use std::env;
use beam::Config;
let tmp_path = env::temp_dir().join(format!(
"beam-redb-{}-{}.redb",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos()
));
let path = tmp_path.to_str().expect("temp path");
let storage = RedbStorage::new_with_config(Config::default(), path, None);
let mut node = Node::new_with_config(
Config::default(),
vec![Box::new(storage) as Box<dyn Actor>],
vec![],
);
node.get("redb_key")
.put("redb_value".into())
.await
.expect("redb put should ack after fsync");
let got = node
.get("redb_key")
.once(Some(Duration::from_secs(2)))
.await;
assert_eq!(
got,
Some(Value::Text("redb_value".to_string())),
"redb: put ack should guarantee durability"
);
node.stop();
tokio::task::yield_now().await;
let storage2 = RedbStorage::new_with_config(Config::default(), path, None);
let mut node2 = Node::new_with_config(
Config::default(),
vec![Box::new(storage2) as Box<dyn Actor>],
vec![],
);
let got2 = node2
.get("redb_key")
.once(Some(Duration::from_secs(2)))
.await;
assert_eq!(
got2,
Some(Value::Text("redb_value".to_string())),
"redb: persisted across node restart"
);
}