The test files had grown their own copies of the same helpers: prefix() twelve times, established() seven, an UPDATE builder six, a seventeen field PeerConfig literal in fifteen places, a timeout constant in twenty one. Each is in crates/integration-tests/src once now: peer_config() and TestServer::with_peer for a configured peer, Announcement for building UPDATEs, established(), the waits (wait_until, wait_for, wait_for_routes, wait_for_sessions), get_json, and TIMEOUT. A new field on PeerConfig is one line to add, not fifteen. TestPeer::recv has a deadline, so a test that gets nothing fails instead of hanging; is_closed, which read one byte and took a KEEPALIVE for an open connection, is closed_within and closed_unanswered. Net 788 lines fewer; every test checks what it did. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
60 lines
2.0 KiB
Rust
60 lines
2.0 KiB
Rust
//! What the server does when a part of it that it cannot do without fails.
|
|
//!
|
|
//! The local RIB's actor stops only by panicking. Before, nothing noticed:
|
|
//! sessions stayed up, nothing was announced any more, and the status page
|
|
//! showed an empty table. Now the server tells its peers it is going and
|
|
//! stops with an error, for whatever supervises it to restart it.
|
|
|
|
use std::net::Ipv4Addr;
|
|
|
|
use bgp_integration_tests::TIMEOUT;
|
|
use bgp_integration_tests::test_server::TestServer;
|
|
use bgp_packet::errors::{BgpError, CeaseSubcode};
|
|
use bgp_rib::RibStopped;
|
|
use bgp_server::error::ServerError;
|
|
use eyre::Result;
|
|
|
|
const LOCAL_ASN: u32 = 65000;
|
|
const PEER_ASN: u32 = 65001;
|
|
|
|
#[tokio::test]
|
|
async fn test_losing_the_local_rib_stops_the_server_and_tells_the_peers() -> Result<()> {
|
|
let mut server = TestServer::start(LOCAL_ASN).await?;
|
|
let (base, _http) = server.serve_http().await?;
|
|
let mut peer = server
|
|
.established(PEER_ASN, Ipv4Addr::new(10, 0, 0, 1))
|
|
.await?;
|
|
|
|
server.local_rib.stop_for_testing();
|
|
|
|
let outcome = tokio::time::timeout(TIMEOUT, server.stopped()).await?;
|
|
assert!(
|
|
matches!(outcome, Err(ServerError::RibStopped(RibStopped { rib })) if rib == "local RIB"),
|
|
"{outcome:?}"
|
|
);
|
|
assert_eq!(
|
|
peer.expect_notification().await?.error,
|
|
BgpError::Cease(CeaseSubcode::AdminShutdown)
|
|
);
|
|
|
|
// The status interface says the table cannot be read, where it used to
|
|
// show an empty one.
|
|
let client = reqwest::Client::new();
|
|
for path in ["/api/status", "/api/routes/local", "/metricz"] {
|
|
let response = client.get(format!("{base}{path}")).send().await?;
|
|
assert_eq!(response.status(), 503, "{path}");
|
|
assert_eq!(
|
|
response.text().await?,
|
|
"the local RIB has stopped",
|
|
"{path}"
|
|
);
|
|
}
|
|
// What does not need that table still answers.
|
|
let response = client
|
|
.get(format!("{base}/api/routes/received"))
|
|
.send()
|
|
.await?;
|
|
assert_eq!(response.status(), 200);
|
|
Ok(())
|
|
}
|