#![cfg(not(target_arch = "wasm32"))]
use beam::adapters::{MemoryStorage, OutgoingWebsocketManager, WsServer, WsServerConfig};
use beam::{Config, Node, Value};
use std::time::Duration;
use tokio::time::sleep;
async fn start_relay(port: u16) -> Node {
let ws_config = WsServerConfig {
port,
cert_path: None,
key_path: None,
};
let node = Node::new_with_config(
Config::default(),
vec![Box::new(MemoryStorage::new())],
vec![Box::new(WsServer::new_with_config(
Config::default(),
ws_config,
))],
);
loop {
if tokio::net::TcpStream::connect(format!("127.0.0.1:{}", port))
.await
.is_ok()
{
break;
}
sleep(Duration::from_millis(50)).await;
}
sleep(Duration::from_millis(200)).await;
node
}
async fn connect_client(port: u16) -> Node {
let client = OutgoingWebsocketManager::new(
Config::default(),
vec![format!("ws://127.0.0.1:{}/ws", port)],
);
let node = Node::new_with_config(
Config::default(),
vec![Box::new(MemoryStorage::new())],
vec![Box::new(client)],
);
sleep(Duration::from_millis(300)).await;
node
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn no_echo_back_single_sender() {
let port = 9800;
let mut relay = start_relay(port).await;
let mut subscriber = connect_client(port).await;
let mut sender = connect_client(port).await;
sleep(Duration::from_millis(500)).await;
let before = relay.metrics().snapshot();
for i in 0..100 {
let _ = sender
.get(&format!("echo_test/{}", i))
.put(Value::Text(format!("val_{}", i)))
.await;
}
sleep(Duration::from_millis(500)).await;
let after = relay.metrics().snapshot();
let ws_recv = after.ws_messages_received - before.ws_messages_received;
let relayed = after.messages_relayed - before.messages_relayed;
let dropped_dup = after.messages_dropped_dup - before.messages_dropped_dup;
println!(
"ws_recv={}, relayed={}, dropped_dup={}",
ws_recv, relayed, dropped_dup
);
assert!(
ws_recv <= 250,
"relay received {} WS messages for 100 puts — echo-back detected! \
(expected ~200, got {})",
ws_recv,
ws_recv
);
assert!(
(90..=110).contains(&relayed),
"relay relayed {} messages for 100 puts — expected ~100",
relayed
);
sender.stop();
subscriber.stop();
relay.stop();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
#[ignore = "benchmark — run with --release --ignored --nocapture"]
async fn no_echo_back_10_senders() {
let port = 9802;
let mut relay = start_relay(port).await;
let mut subscriber = connect_client(port).await;
let mut senders = Vec::new();
for _ in 0..10 {
senders.push(connect_client(port).await);
}
sleep(Duration::from_millis(500)).await;
let before = relay.metrics().snapshot();
for (idx, sender) in senders.iter_mut().enumerate() {
for i in 0..50 {
let _ = sender
.get(&format!("multi/{}/{}", idx, i))
.put(Value::Text(format!("val_{}_{}", idx, i)))
.await;
}
}
sleep(Duration::from_secs(2)).await;
let after = relay.metrics().snapshot();
let ws_recv = after.ws_messages_received - before.ws_messages_received;
let relayed = after.messages_relayed - before.messages_relayed;
let total_sent = 10 * 50;
println!(
"total_sent={}, ws_recv={}, relayed={}, amplification={:.1}x",
total_sent,
ws_recv,
relayed,
ws_recv as f64 / total_sent as f64
);
let amplification = ws_recv as f64 / total_sent as f64;
assert!(
amplification < 3.0,
"message amplification is {:.1}x — echo-back still present \
(expected <3x, got {:.1}x with {} recv for {} sent)",
amplification,
amplification,
ws_recv,
total_sent
);
for mut s in senders {
s.stop();
}
subscriber.stop();
relay.stop();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn relay_forwarding_still_works() {
let port = 9804;
let mut relay = start_relay(port).await;
let mut subscriber = connect_client(port).await;
let mut sender = connect_client(port).await;
sleep(Duration::from_millis(500)).await;
let _ = subscriber.get("fwd_test").once(None).await;
sleep(Duration::from_millis(200)).await;
let before = relay.metrics().snapshot();
for i in 0..10 {
let _ = sender
.get("fwd_test")
.get(&format!("{}", i))
.put(Value::Text(format!("msg_{}", i)))
.await;
}
sleep(Duration::from_millis(500)).await;
let after = relay.metrics().snapshot();
let relayed = after.messages_relayed - before.messages_relayed;
println!("relayed={} for 10 puts", relayed);
assert!(
relayed >= 8,
"relay only relayed {} messages for 10 puts — forwarding broken!",
relayed
);
sender.stop();
subscriber.stop();
relay.stop();
}