#![allow(unused)]
use std::{
error::Error,
sync::{Arc, LazyLock},
time::Duration,
};
use dquic::{
prelude::{
BindUri, BoundAddr, IO,
handy::{ToCertificate, ToPrivateKey},
},
qinterface::component::route::QuicRouter,
};
use h3x::{
dquic::{H3Client, H3Servers},
server::UnresolvedRequest,
};
use http::uri::Authority;
use tokio::time;
use tracing::{Instrument, level_filters::LevelFilter};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::{
Layer, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt,
};
pub const TEST_TIMEOUT: Duration = Duration::from_secs(60);
pub fn run<F: Future>(test_name: &'static str, future: F) -> F::Output {
static RT: LazyLock<tokio::runtime::Runtime> = LazyLock::new(|| {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
});
static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| {
let (non_blocking, guard) = tracing_appender::non_blocking(std::io::stdout());
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_writer(non_blocking)
.with_file(true)
.with_line_number(true)
.with_filter(LevelFilter::DEBUG),
)
.with(tracing_subscriber::filter::filter_fn(|metadata| {
!metadata.target().contains("netlink_packet_route")
}))
.init();
guard
});
RT.block_on(async move {
LazyLock::force(&TRACING);
let test = future.instrument(tracing::info_span!("test", test_name));
match time::timeout(TEST_TIMEOUT, test).await {
Ok(output) => output,
Err(_timedout) => panic!("test timed out"),
}
})
}
pub const CA_CERT: &[u8] = include_bytes!("../../tests/keychain/localhost/ca.cert");
pub const SERVER_CERT: &[u8] = include_bytes!("../../tests/keychain/localhost/server.cert");
pub const SERVER_KEY: &[u8] = include_bytes!("../../tests/keychain/localhost/server.key");
pub const TEST_DATA: &[u8] = include_bytes!("mod.rs");
pub fn test_client() -> H3Client {
let mut roots = rustls::RootCertStore::empty();
roots.add_parsable_certificates(CA_CERT.to_certificate());
H3Client::builder()
.with_root_certificates(roots)
.without_identity()
.expect("failed to initialize client tls")
.with_router(Arc::new(QuicRouter::new()))
.build()
}
pub async fn test_server<S>(router: S) -> H3Servers<S>
where
S: tower_service::Service<UnresolvedRequest, Response = ()> + Clone + Send + Sync + 'static,
S::Future: Send,
S::Error: Into<Box<dyn Error + Send + Sync>>,
{
let mut servers = H3Servers::builder()
.without_client_cert_verifier()
.expect("failed to initialize server tls")
.with_router(Arc::new(QuicRouter::new()))
.listen()
.expect("failed to listen");
servers
.add_server(
"localhost",
SERVER_CERT.to_certificate(),
SERVER_KEY.to_private_key(),
None,
[
BindUri::from("inet://127.0.0.1:0").alloc_port(),
BindUri::from("inet://[::1]:0").alloc_port(),
],
router,
)
.await
.expect("failed to add server");
servers
}
pub fn get_server_addr<S>(servers: &H3Servers<S>) -> BoundAddr {
let localhost = servers
.quic_listener()
.get_server("localhost")
.expect("server localhost must be registered");
let (_bind_uri, localhost_bind_interface) = localhost
.bind_interfaces()
.into_iter()
.next()
.expect("server localhost must have at least one bind interface");
localhost_bind_interface
.borrow()
.bound_addr()
.expect("bind interface must have local addr")
}
pub fn get_server_authority<S>(servers: &H3Servers<S>) -> Authority {
match get_server_addr(servers) {
BoundAddr::Internet(socket_addr) => {
Authority::from_maybe_shared(Vec::from(format!("localhost:{}", socket_addr.port())))
.expect("failed to parse authority")
}
_ => unimplemented!("Only Internet addresses are supported now"),
}
}