Files
boxmaker/docs/plans/M4a/files/crates/gatewayd/tests/net.rs
T
kyleandClaude Opus 5.5 0339dc13b2 Plan M4a: gatewayd in 15 tasks, with skeletons and given tests
Each task's tests were run against a reference at its end state; the end states were replayed
from master in order with the gate at each step (650 to 762 tests); each skeleton compiles
against its tests and fails them. The reference is kept off this machine. Lessons T27 (every
wait in a test has a limit) and T28 (mutate the reference before hand-over) come from this work.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:05:44 -07:00

121 lines
3.8 KiB
Rust

//! Connections, plain and TLS, against local servers with TEST-ONLY certificates (M4a spec,
//! section 5): the right CA is trusted through `ca_file`; an unknown CA and a wrong name are
//! refused, so verification is on. Do not edit.
#[path = "support/tls_server.rs"]
mod tls_server;
use std::io::{BufRead, BufReader, Write};
use std::time::Duration;
use gatewayd::config::ServerUrl;
use gatewayd::net::{Connector, NetError, Stream};
use tls_server::{echo_line, fixture, serve, server_config};
const T: Duration = Duration::from_secs(5);
fn url(tls: bool, host: &str, port: u16) -> ServerUrl {
ServerUrl {
tls,
host: host.to_string(),
port,
}
}
fn round_trip(mut stream: Stream) -> String {
stream.write_all(b"hello over the wire\n").unwrap();
stream.flush().unwrap();
let mut line = String::new();
BufReader::new(stream).read_line(&mut line).unwrap();
line
}
#[test]
fn plain_tcp() {
let addr = serve(None, echo_line);
let c = Connector::new(url(false, "127.0.0.1", addr.port()), None).unwrap();
let stream = c.connect(T).unwrap();
assert!(matches!(stream, Stream::Plain(_)));
assert_eq!(round_trip(stream), "hello over the wire\n");
}
#[test]
fn tls_to_a_server_signed_by_the_ca_file() {
let addr = serve(Some(server_config("server")), echo_line);
for host in ["localhost", "127.0.0.1"] {
let c =
Connector::new(url(true, host, addr.port()), Some(&fixture("test-ca.pem"))).unwrap();
let stream = c.connect(T).unwrap_or_else(|e| panic!("{host}: {e}"));
assert!(matches!(stream, Stream::Tls(_)));
assert_eq!(round_trip(stream), "hello over the wire\n", "{host}");
}
}
#[test]
fn an_unknown_ca_is_refused_at_connect() {
let addr = serve(Some(server_config("other-server")), echo_line);
let c = Connector::new(
url(true, "localhost", addr.port()),
Some(&fixture("test-ca.pem")),
)
.unwrap();
match c.connect(T) {
Err(NetError::Tls(why)) => assert!(why.to_lowercase().contains("certificate"), "{why}"),
Err(e) => panic!("expected a TLS error, got {e}"),
Ok(_) => panic!("a server signed by an unknown CA was accepted"),
}
}
#[test]
fn a_wrong_name_is_refused_at_connect() {
let addr = serve(Some(server_config("wrong-name")), echo_line);
let c = Connector::new(
url(true, "localhost", addr.port()),
Some(&fixture("test-ca.pem")),
)
.unwrap();
assert!(
matches!(c.connect(T), Err(NetError::Tls(_))),
"a certificate for wrong.example was accepted for localhost"
);
}
#[test]
fn tls_to_a_plain_server_fails_and_does_not_hang() {
let addr = serve(None, |_conn| std::thread::sleep(Duration::from_secs(30)));
let c = Connector::new(
url(true, "localhost", addr.port()),
Some(&fixture("test-ca.pem")),
)
.unwrap();
let started = std::time::Instant::now();
assert!(c.connect(Duration::from_millis(300)).is_err());
assert!(started.elapsed() < Duration::from_secs(3));
}
#[test]
fn a_bad_ca_file_is_an_error_before_any_connection() {
let missing = fixture("no-such.pem");
assert!(matches!(
Connector::new(url(true, "localhost", 1), Some(&missing)),
Err(NetError::Roots(_))
));
let not_pem = fixture("README.md");
assert!(matches!(
Connector::new(url(true, "localhost", 1), Some(&not_pem)),
Err(NetError::Roots(_))
));
// A plain server needs no certificates at all.
assert!(Connector::new(url(false, "localhost", 1), Some(&missing)).is_ok());
}
#[test]
fn nothing_listening_is_a_connect_error() {
let port = {
let l = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
l.local_addr().unwrap().port()
};
let c = Connector::new(url(false, "127.0.0.1", port), None).unwrap();
assert!(matches!(c.connect(T), Err(NetError::Connect(_))));
}