#![cfg(any(feature = "tcp", feature = "uds"))]
use qmux::Version;
use web_transport_trait::Session as _;
#[cfg(feature = "tcp")]
mod tcp {
use super::*;
use qmux::Error;
use tokio::net::TcpListener;
#[tokio::test]
async fn negotiates_shared_protocol() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (sock, _) = listener.accept().await.unwrap();
qmux::tcp::Config::new(Version::QMux01)
.protocols(["moq-lite-03", "moq-lite-04"])
.accept(sock)
.await
.unwrap()
});
let client = qmux::tcp::Config::new(Version::QMux01)
.protocols(["moq-lite-04", "moq-lite-05"])
.connect(addr)
.await
.unwrap();
let server = server.await.unwrap();
assert_eq!(client.protocol(), Some("moq-lite-04"));
assert_eq!(server.protocol(), Some("moq-lite-04"));
}
#[tokio::test]
async fn no_overlap_resolves_to_none() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (sock, _) = listener.accept().await.unwrap();
qmux::tcp::Config::new(Version::QMux01)
.protocols(["moq-lite-99"])
.accept(sock)
.await
.unwrap()
});
let client = qmux::tcp::Config::new(Version::QMux01)
.protocols(["moq-lite-04"])
.connect(addr)
.await
.unwrap();
let server = server.await.unwrap();
assert_eq!(client.protocol(), None);
assert_eq!(server.protocol(), None);
}
#[tokio::test]
async fn both_without_protocols() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (sock, _) = listener.accept().await.unwrap();
qmux::tcp::Config::new(Version::QMux01)
.accept(sock)
.await
.unwrap()
});
let client = qmux::tcp::Config::new(Version::QMux01)
.connect(addr)
.await
.unwrap();
let server = server.await.unwrap();
assert_eq!(client.protocol(), None);
assert_eq!(server.protocol(), None);
}
#[tokio::test]
async fn unexpected_protocols_is_fatal() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (sock, _) = listener.accept().await.unwrap();
match qmux::tcp::Config::new(Version::QMux01).accept(sock).await {
Err(e) => e,
Ok(_) => panic!("expected establishment to fail"),
}
});
let _client = qmux::tcp::Config::new(Version::QMux01)
.protocols(["moq-lite-04"])
.connect(addr)
.await
.unwrap();
let err = server.await.unwrap();
assert!(matches!(err, Error::UnexpectedProtocols), "got {err:?}");
}
#[tokio::test]
async fn handshake_timeout_fires() {
use std::time::Duration;
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (_sock, _) = listener.accept().await.unwrap();
tokio::time::sleep(Duration::from_secs(5)).await;
});
let result = qmux::tcp::Config::new(Version::QMux01)
.handshake_timeout(Duration::from_millis(100))
.connect(addr)
.await;
match result {
Err(Error::HandshakeTimeout) => {}
Err(other) => panic!("expected HandshakeTimeout, got {other:?}"),
Ok(_) => panic!("expected HandshakeTimeout, got an established session"),
}
server.abort();
}
#[tokio::test]
async fn rejects_invalid_protocol_name() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
match qmux::tcp::Config::new(Version::QMux01)
.protocols(["bad name"])
.connect(addr)
.await
{
Err(Error::InvalidProtocol(_)) => {}
Err(other) => panic!("wrong error: {other:?}"),
Ok(_) => panic!("expected InvalidProtocol error"),
}
}
}
#[cfg(all(unix, feature = "uds"))]
mod uds {
use super::*;
use tokio::net::UnixListener;
#[tokio::test]
async fn negotiates_shared_protocol() {
let path = std::env::temp_dir().join(format!("qmux-uds-{}.sock", std::process::id()));
let _ = std::fs::remove_file(&path);
let listener = UnixListener::bind(&path).unwrap();
let server = tokio::spawn(async move {
let (sock, _) = listener.accept().await.unwrap();
qmux::uds::Config::new(Version::QMux01)
.protocols(["moq-lite-04"])
.accept(sock)
.await
.unwrap()
});
let client = qmux::uds::Config::new(Version::QMux01)
.protocols(["moq-lite-04", "moq-lite-03"])
.connect(&path)
.await
.unwrap();
let server = server.await.unwrap();
assert_eq!(client.protocol(), Some("moq-lite-04"));
assert_eq!(server.protocol(), Some("moq-lite-04"));
let _ = std::fs::remove_file(&path);
}
}