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>
90 lines
3.0 KiB
Rust
90 lines
3.0 KiB
Rust
//! Who may connect: only the addresses of configured peers, and each of
|
|
//! them only so many times at once.
|
|
|
|
use std::net::{Ipv4Addr, SocketAddr};
|
|
use std::time::Duration;
|
|
|
|
use bgp_integration_tests::test_peer::TestPeer;
|
|
use bgp_integration_tests::test_server::{ServerWithPeer, TestServer};
|
|
use bgp_integration_tests::{TIMEOUT, peer_config};
|
|
use bgp_server::config::PeerConfig;
|
|
use bgp_server::policy::ImportPolicy;
|
|
use eyre::Result;
|
|
|
|
const LOCAL_ASN: u32 = 65000;
|
|
const PEER_ASN: u32 = 65001;
|
|
|
|
/// A host that is not a configured peer gets nothing: no OPEN to answer,
|
|
/// no session, no routes taken from it. Any host used to be able to open a
|
|
/// session as any AS it named.
|
|
#[tokio::test]
|
|
async fn test_a_host_that_is_not_a_configured_peer_is_refused() -> Result<()> {
|
|
// The only peer configured is somewhere else (documentation space).
|
|
let server = TestServer::start_with(LOCAL_ASN, |c| {
|
|
c.accept_unconfigured_peers = false;
|
|
let elsewhere: SocketAddr = "192.0.2.9:179".parse().unwrap();
|
|
c.peers = vec![PeerConfig {
|
|
import: ImportPolicy::permissive(),
|
|
..peer_config("r1", elsewhere, PEER_ASN)
|
|
}];
|
|
})
|
|
.await?;
|
|
|
|
let mut stranger = TestPeer::connect(server.addr).await?;
|
|
assert!(stranger.closed_unanswered().await);
|
|
assert!(server.registry.list().is_empty());
|
|
Ok(())
|
|
}
|
|
|
|
/// The address of a configured peer is let in, and held to what is
|
|
/// configured for that peer.
|
|
#[tokio::test]
|
|
async fn test_a_configured_peer_is_let_in() -> Result<()> {
|
|
// The server's own dialling goes to the listener; it is never answered.
|
|
let ServerWithPeer {
|
|
server,
|
|
listener: _listener,
|
|
} = TestServer::with_peer(LOCAL_ASN, PEER_ASN, |_, peer| {
|
|
peer.import = ImportPolicy::permissive();
|
|
})
|
|
.await?;
|
|
|
|
let _peer = server
|
|
.established(PEER_ASN, Ipv4Addr::new(10, 0, 0, 2))
|
|
.await?;
|
|
assert_eq!(server.registry.list()[0].name.as_deref(), Some("r1"));
|
|
Ok(())
|
|
}
|
|
|
|
/// One address may hold only a few connections at a time, so that one host
|
|
/// cannot use up the server's sockets with connections that never get as
|
|
/// far as a session.
|
|
#[tokio::test]
|
|
async fn test_one_address_may_open_only_a_few_connections() -> Result<()> {
|
|
let server = TestServer::start(LOCAL_ASN).await?;
|
|
|
|
// Four that say nothing: each is sent the server's OPEN and waited on.
|
|
let mut held = Vec::new();
|
|
for _ in 0..4 {
|
|
let mut peer = TestPeer::connect(server.addr).await?;
|
|
peer.recv_open().await?;
|
|
held.push(peer);
|
|
}
|
|
let mut one_too_many = TestPeer::connect(server.addr).await?;
|
|
assert!(one_too_many.closed_unanswered().await);
|
|
|
|
// When one of them goes, there is room again.
|
|
held.pop();
|
|
tokio::time::timeout(TIMEOUT, async {
|
|
loop {
|
|
let mut peer = TestPeer::connect(server.addr).await?;
|
|
if peer.recv_open().await.is_ok() {
|
|
return Ok::<_, eyre::Report>(());
|
|
}
|
|
tokio::time::sleep(Duration::from_millis(20)).await;
|
|
}
|
|
})
|
|
.await??;
|
|
Ok(())
|
|
}
|