fix(relay): remove the bind race in the relay test fixture - #591
Conversation
|
@claude review this PR |
|
Claude finished @iamquang95's task in 7m 9s —— View job Review —
|
emlautarom1
left a comment
There was a problem hiding this comment.
As part of the refinement phase, we should try to get a proper solution in place, and retrying here seems like a hack. The original issue describes the problem as something that happens on test-code only code, in particular in CI.
Ideally, we should have something like wiremock, where we can start configure the relay server using a builder, then start it and let it live until the end of the scope (the test). The with_relay_server abstraction is introducing more complications that benefits at this point.
|
For example, tests should ideally look something like: #[tokio::test]
async fn serve_addr_enr_ext_ip() {
let relay = test_relay_server_with(|args| args.p2p.external_ip = Some("222.222.222.222".into())).await.unwrap();
let addr = relay.http_addr.unwrap();
let response = http_get(&format!("http://{addr}/enr")).await.unwrap();
let enr = Record::try_from(response.text().await.unwrap().as_str()).unwrap();
assert_eq!(enr.ip(), Some(Ipv4Addr::new(222, 222, 222, 222)));
}
#[tokio::test]
async fn run_bootnode_auto_p2p() {
let missing_key = test_relay_server_with(|args| args.relay.auto_p2p_key = false).await;
assert!(matches!(
missing_key,
Err(super::CliError::RelayP2PError(
pluto_relay_server::RelayP2PError::FailedToLoadPrivateKey(..)
))
));
let _relay = test_relay_server_with(|args| { }).await; // starts with an auto-generated key
}
#[tokio::test]
async fn taken_monitoring_port_fails_the_relay() {
let taken = net::TcpListener::bind(ANY_ADDR).await.unwrap();
let addr = taken.local_addr().unwrap().to_string();
let err = test_relay_server(|args| args.debug_monitoring.monitor_addr = Some(addr))
.await
.expect_err("relay must not start while its monitoring port is taken");
assert!(matches!(
err,
super::CliError::RelayP2PError(
pluto_relay_server::RelayP2PError::FailedToBindMonitoringListener { .. }
)
));
}The tricky part is how we can retrieve the actually bounded addresses. I think this requires some refactoring to the internals so we can split binding from serving: I explored the work a bit in |
emlautarom1
left a comment
There was a problem hiding this comment.
Test look a lot better without the retry dance. There are a few things to improve but overall LGTM, the PR solves the original problem. The PR body is stale so it should be updated with the final design.
Fix #590
Relay startup is split into bind then serve:
bind_relay()binds every listener (monitoring, ENR HTTP, libp2p) and waits for libp2p to report the addresses it bound, before anything is served.BoundRelay::serve()then runs them asselect!arms, so exiting drops the listeners.backondropped from cli dev-deps).Two follow-ons from kernel-assigned ports: external addrs are now derived from the bound addresses (
external_multiaddrs(cfg, listen_addrs)+Node::set_advertised_addrs) rather than the configured ones, which would advertise an undialable port 0; and private-address filtering moved from ingest to render time, since startup waits on every listener and a loopback-only node must still start.