use std::error::Error;
use std::time::Duration;
use modelpipe::{
CloseReason, ConnectError, ConnectHandle, ConnectOptions, NetworkMetrics, PeerView, PipeStatus,
ServeError, ServeHandle, ServeOptions, Ticket, TicketParseError, TokenPolicy,
};
#[test]
fn the_public_names_resolve_at_the_crate_root() {
fn nameable<T>() {}
fn takes_any<T>(_: T) {}
nameable::<Ticket>();
nameable::<TicketParseError>();
nameable::<ServeError>();
nameable::<ServeOptions>();
nameable::<ServeHandle>();
nameable::<ConnectError>();
nameable::<ConnectOptions>();
nameable::<ConnectHandle>();
nameable::<TokenPolicy>();
nameable::<PipeStatus>();
nameable::<CloseReason>();
nameable::<PeerView>();
nameable::<NetworkMetrics>();
takes_any(modelpipe::serve);
takes_any(modelpipe::connect);
}
#[test]
fn the_options_structs_are_constructible_from_outside() {
let mut serve_opts = ServeOptions::default();
serve_opts.auth = TokenPolicy::Supplied("a-token".to_owned());
serve_opts.relay = Some("https://relay.example.com/".to_owned());
serve_opts.allow_private_backend = true;
serve_opts.port_mapping = false;
serve_opts.discovery = false;
serve_opts.relay_only = true;
let mut connect_opts = ConnectOptions::default();
connect_opts.bind = Some("127.0.0.1:8080".parse().unwrap());
connect_opts.relay = Some("https://relay.example.com/".to_owned());
connect_opts.port_mapping = false;
connect_opts.discovery = false;
connect_opts.relay_only = true;
assert!(connect_opts.bind.is_some());
assert!(serve_opts.allow_private_backend);
assert!(!connect_opts.discovery && !serve_opts.discovery);
assert!(connect_opts.relay_only && serve_opts.relay_only);
}
#[test]
fn the_default_options_keep_every_network_contact_on() {
let serve_opts = ServeOptions::default();
let connect_opts = ConnectOptions::default();
assert!(serve_opts.port_mapping && serve_opts.discovery);
assert!(connect_opts.port_mapping && connect_opts.discovery);
assert!(connect_opts.relay.is_none());
assert!(!serve_opts.relay_only && !connect_opts.relay_only);
}
#[test]
fn a_machine_failure_exposes_its_cause_and_nothing_of_the_transport() {
let e = ServeError::Bind(std::io::Error::other("no sockets left"));
let cause = e.source().expect("Bind must expose its source");
assert_eq!(cause.to_string(), "no sockets left");
assert!(
!e.to_string().contains("no sockets left"),
"the source must not be duplicated into Display: {e}"
);
let e = ServeError::BackendNotLocal {
url: "http://example.com".to_owned(),
};
assert!(e.source().is_none());
}
#[test]
fn a_dependent_can_classify_failures_without_matching_on_them() {
assert!(
!ServeError::BackendNotLocal {
url: "http://example.com".to_owned()
}
.is_retryable()
);
assert!(ConnectError::PeerUnreachable.is_retryable());
}
#[test]
fn a_status_can_be_copied_compared_and_named() {
let a = PipeStatus::Relayed;
let b = a; assert_eq!(a, b);
assert_ne!(a, PipeStatus::Direct);
assert_eq!(a.as_str(), "relayed");
}
#[test]
fn a_dependent_can_tell_a_live_pipe_from_a_close_and_a_close_from_a_failure() {
fn render(handle: &ConnectHandle) -> &'static str {
match handle.close_reason() {
None => "connecting",
Some(CloseReason::ListenerFailed) => "the local port died",
Some(_) => "disconnected",
}
}
let _ = render;
let a = CloseReason::ListenerFailed;
let b = a; assert_eq!(a, b);
assert_ne!(a, CloseReason::Shutdown);
assert_eq!(a.as_str(), "listener_failed");
}
#[test]
fn a_peer_view_is_readable_from_outside() {
fn render(handle: &ServeHandle) -> Vec<String> {
handle
.peers()
.iter()
.map(|peer: &PeerView| {
let rtt: Option<u64> = peer.rtt_ms;
let cost = rtt.map_or_else(String::new, |ms| format!(" {ms}ms"));
format!("{} {}{cost}", peer.fingerprint, peer.path.as_str())
})
.collect()
}
let _ = render;
}
#[test]
fn a_dependents_debug_output_cannot_contain_the_supplied_token() {
const SECRET: &str = "sk-zzq-external-consumer-sentinel";
#[derive(Debug)]
#[allow(dead_code)]
struct EmbedderConfig {
name: &'static str,
opts: ServeOptions,
}
let mut opts = ServeOptions::default();
opts.auth = TokenPolicy::Supplied(SECRET.to_owned());
let cfg = EmbedderConfig {
name: "daemon",
opts,
};
let rendered = format!("{cfg:?}");
assert!(
!rendered.contains(SECRET),
"the token leaked through a dependent's derived Debug: {rendered}"
);
assert!(rendered.contains("daemon"), "the rest must still render");
}
#[cfg(feature = "serde")]
#[test]
fn a_dependents_dto_serializes_a_ticket_as_its_string() {
#[derive(serde::Serialize)]
struct StatusDto {
ticket: Ticket,
path: PipeStatus,
}
let ticket: Ticket = "pipeadlvvgabqkyqvn6vjp7nhslea45a5yls6pnkmizfv4bbu2hxa5iruaaauhlp2na"
.parse()
.expect("a normative vector");
let json = serde_json::to_string(&StatusDto {
ticket: ticket.clone(),
path: PipeStatus::Direct,
})
.expect("serializes");
assert_eq!(
json,
format!(r#"{{"ticket":"{ticket}","path":"direct"}}"#),
"the ticket is its string and the status is its identifier"
);
}
#[test]
fn both_error_types_are_std_errors_and_send_sync() {
fn assert_error<T: Error + Send + Sync + 'static>() {}
assert_error::<ServeError>();
assert_error::<ConnectError>();
assert_error::<TicketParseError>();
let boxed: Box<dyn Error + Send + Sync> = Box::new(ConnectError::PeerUnreachable);
assert!(boxed.to_string().contains("could not reach"));
}
#[test]
fn a_dependent_cannot_ignore_a_grant_that_was_refused() {
fn pair(handle: &ServeHandle, code: String) -> Result<(), ServeError> {
handle.grant_once(code, std::time::Duration::from_mins(2))?;
Ok(())
}
let _ = pair;
}
#[test]
fn a_dependent_cannot_ignore_a_rotation_that_was_refused() {
fn rotate(handle: &ServeHandle, from_config: String) -> Result<(), ServeError> {
handle.set_token(from_config)?;
Ok(())
}
let _ = rotate;
let refused = ServeError::InvalidToken;
assert!(
!refused.is_retryable(),
"a blank credential does not become usable by waiting"
);
assert!(
refused.to_string().contains("empty"),
"and it says which value it means: {refused}"
);
}
#[test]
fn a_dependent_can_rotate_with_an_overlap_and_still_cannot_ignore_a_refusal() {
fn roll(handle: &ServeHandle, next: String, window: Duration) -> Result<(), ServeError> {
handle.set_token_with_grace(next, window)?;
Ok(())
}
fn cut_short(handle: &ServeHandle, current: String) -> Result<(), ServeError> {
handle.set_token(current)?;
Ok(())
}
let _ = roll;
let _ = cut_short;
let refused = ServeError::InvalidToken;
assert!(!refused.is_retryable(), "a blank credential does not ripen");
assert!(refused.to_string().contains("empty"), "{refused}");
}
#[test]
fn a_dependent_can_watch_a_status_from_its_own_snapshot_and_reach_an_end() {
async fn watch_the_old_way(handle: &ConnectHandle) -> PipeStatus {
handle.status_changed().await
}
async fn watch_connect(handle: &ConnectHandle) -> Vec<String> {
let mut held: PipeStatus = handle.status();
let mut rendered = vec![held.as_str().to_owned()];
while let Some(next) = handle.status_changed_since(held).await {
rendered.push(next.as_str().to_owned());
held = next;
}
rendered
}
async fn watch_serve(handle: &ServeHandle) -> Vec<String> {
let mut held: PipeStatus = handle.status();
let mut rendered = vec![held.as_str().to_owned()];
while let Some(next) = handle.status_changed_since(held).await {
rendered.push(next.as_str().to_owned());
held = next;
}
rendered
}
let _ = (watch_connect, watch_serve, watch_the_old_way);
}
#[test]
fn a_dependent_can_report_a_network_change_without_holding_a_transport() {
async fn on_resume(serving: &ServeHandle, connected: &ConnectHandle) {
let () = serving.notify_network_change().await;
let () = connected.notify_network_change().await;
}
let _ = on_resume;
}
#[test]
fn a_metrics_snapshot_is_a_plain_value_a_dependent_owns() {
fn read(serving: &ServeHandle, connected: &ConnectHandle) -> (NetworkMetrics, NetworkMetrics) {
(serving.network_metrics(), connected.network_metrics())
}
let _ = read;
let fresh = NetworkMetrics::default();
let ratelimited: u64 = fresh.relay_connections_ratelimited;
let connections: u64 = fresh.relay_connections;
let failed: u64 = fresh.relay_connections_failed;
assert_eq!((ratelimited, connections, failed), (0, 0, 0));
let copied = fresh; assert_eq!(copied, fresh, "two readings can be compared for sameness");
}
#[test]
fn a_dependent_can_ask_a_ticket_where_it_points() {
let ticket: Ticket = "pipeadlvvgabqkyqvn6vjp7nhslea45a5yls6pnkmizfv4bbu2hxa5iruaqaaangq5duobztulzpojswyylzfzsxqylnobwgkltdn5ws6aiaa3akqaihcfiqbrp5xr4q"
.parse()
.expect("a normative vector");
let relays: Vec<String> = ticket.relay_urls();
assert_eq!(relays, ["https://relay.example.com/"]);
let direct: Vec<std::net::SocketAddr> = ticket.direct_addrs();
assert_eq!(
direct,
["192.168.1.7:4433".parse::<std::net::SocketAddr>().unwrap()]
);
let minimal: Ticket = "pipeadlvvgabqkyqvn6vjp7nhslea45a5yls6pnkmizfv4bbu2hxa5iruaaauhlp2na"
.parse()
.expect("a normative vector");
assert!(minimal.relay_urls().is_empty());
assert!(minimal.direct_addrs().is_empty());
}
#[cfg(feature = "serde")]
#[test]
fn a_dependents_dto_serializes_the_metrics_as_plain_numbers() {
#[derive(serde::Serialize)]
struct HealthDto {
transport: NetworkMetrics,
}
let json = serde_json::to_string(&HealthDto {
transport: NetworkMetrics::default(),
})
.expect("serializes");
assert_eq!(
json,
r#"{"transport":{"relay_connections":0,"relay_connections_failed":0,"relay_connections_ratelimited":0}}"#,
"the field names are the identifiers a dashboard keys on"
);
}