use super::*;
use sansio::Protocol;
use shared::error::Error;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::{Duration, Instant};
#[test]
fn test_mdns_query() {
let config = MdnsConfig::default();
let mut conn = Mdns::new(config);
let query_id = conn.query("test.local");
assert!(conn.is_query_pending(query_id));
assert_eq!(conn.pending_query_count(), 1);
let packet = conn.poll_write();
assert!(packet.is_some());
let packet = packet.unwrap();
assert_eq!(packet.transport.peer_addr, MDNS_DEST_ADDR);
}
#[test]
fn test_mdns_cancel_query() {
let config = MdnsConfig::default();
let mut conn = Mdns::new(config);
let query_id = conn.query("test.local");
assert!(conn.is_query_pending(query_id));
conn.cancel_query(query_id);
assert!(!conn.is_query_pending(query_id));
assert_eq!(conn.pending_query_count(), 0);
}
#[test]
fn test_mdns_local_names() {
let config = MdnsConfig::default()
.with_local_names(vec!["myhost.local".to_string()])
.with_local_ip(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)));
let conn = Mdns::new(config);
assert_eq!(conn.local_names, vec!["myhost.local."]);
}
#[test]
fn test_multiple_close() {
let config = MdnsConfig::default();
let mut conn = Mdns::new(config);
let result = conn.close();
assert!(result.is_ok());
let msg = TaggedBytesMut {
now: Instant::now(),
transport: TransportContext {
local_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 5353),
peer_addr: MDNS_DEST_ADDR,
transport_protocol: TransportProtocol::UDP,
ecn: None,
},
message: BytesMut::new(),
};
let result = conn.handle_read(msg);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::ErrConnectionClosed);
let result = conn.handle_timeout(Instant::now());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), Error::ErrConnectionClosed);
}
#[test]
fn test_query_timeout_behavior() {
let config = MdnsConfig::default().with_query_interval(Duration::from_millis(100));
let mut conn = Mdns::new(config);
let query_id = conn.query("invalid-host.local");
assert!(conn.is_query_pending(query_id));
let packet = conn.poll_write();
assert!(packet.is_some());
assert!(conn.poll_write().is_none());
assert!(conn.is_query_pending(query_id));
let now = Instant::now() + Duration::from_millis(150);
let result = conn.handle_timeout(now);
assert!(result.is_ok());
let packet = conn.poll_write();
assert!(packet.is_some());
assert_eq!(packet.unwrap().transport.peer_addr, MDNS_DEST_ADDR);
assert!(conn.is_query_pending(query_id));
conn.cancel_query(query_id);
assert!(!conn.is_query_pending(query_id));
}
#[test]
fn test_poll_timeout() {
let config = MdnsConfig::default().with_query_interval(Duration::from_secs(1));
let mut conn = Mdns::new(config);
assert!(conn.poll_timeout().is_none());
let _query_id = conn.query("test.local");
let timeout = conn.poll_timeout();
assert!(timeout.is_some());
}
#[test]
fn test_multiple_queries() {
let config = MdnsConfig::default();
let mut conn = Mdns::new(config);
let query1 = conn.query("host1.local");
let query2 = conn.query("host2.local");
let query3 = conn.query("host3.local");
assert_eq!(conn.pending_query_count(), 3);
assert!(conn.is_query_pending(query1));
assert!(conn.is_query_pending(query2));
assert!(conn.is_query_pending(query3));
assert!(conn.poll_write().is_some());
assert!(conn.poll_write().is_some());
assert!(conn.poll_write().is_some());
assert!(conn.poll_write().is_none());
conn.cancel_query(query2);
assert_eq!(conn.pending_query_count(), 2);
assert!(conn.is_query_pending(query1));
assert!(!conn.is_query_pending(query2));
assert!(conn.is_query_pending(query3));
}
#[test]
fn test_local_names_normalization() {
let config = MdnsConfig::default().with_local_names(vec![
"host1.local".to_string(),
"host2.local.".to_string(), ]);
let conn = Mdns::new(config);
assert_eq!(conn.local_names.len(), 2);
assert_eq!(conn.local_names[0], "host1.local.");
assert_eq!(conn.local_names[1], "host2.local.");
}
#[test]
fn test_query_interval_default() {
let config = MdnsConfig::default().with_query_interval(Duration::ZERO);
let conn = Mdns::new(config);
assert_eq!(conn.query_interval, DEFAULT_QUERY_INTERVAL);
let config = MdnsConfig::default().with_query_interval(Duration::from_millis(500));
let conn = Mdns::new(config);
assert_eq!(conn.query_interval, Duration::from_millis(500));
}
#[test]
fn test_close_clears_state() {
let config = MdnsConfig::default().with_local_names(vec!["host.local".to_string()]);
let mut conn = Mdns::new(config);
conn.query("query1.local");
conn.query("query2.local");
assert_eq!(conn.pending_query_count(), 2);
assert!(conn.poll_timeout().is_some());
conn.close().unwrap();
assert_eq!(conn.pending_query_count(), 0);
assert!(conn.poll_timeout().is_none());
assert!(conn.poll_write().is_none());
assert!(conn.poll_event().is_none());
}
#[test]
fn test_query_timeout_emits_event() {
let config = MdnsConfig::default()
.with_query_interval(Duration::from_millis(100))
.with_query_timeout(Duration::from_millis(250));
let mut conn = Mdns::new(config);
let query_id = conn.query("timeout-test.local");
assert!(conn.is_query_pending(query_id));
conn.poll_write();
let now = Instant::now();
let not_yet = now + Duration::from_millis(150);
conn.handle_timeout(not_yet).unwrap();
assert!(conn.is_query_pending(query_id));
assert!(conn.poll_event().is_none());
let past_timeout = now + Duration::from_millis(300);
conn.handle_timeout(past_timeout).unwrap();
assert!(!conn.is_query_pending(query_id));
let event = conn.poll_event();
assert!(event.is_some());
match event.unwrap() {
MdnsEvent::QueryTimeout(id) => {
assert_eq!(id, query_id);
}
_ => panic!("Expected QueryTimeout event"),
}
assert!(conn.poll_event().is_none());
}
#[test]
fn test_query_timeout_multiple_queries() {
let config = MdnsConfig::default()
.with_query_interval(Duration::from_millis(100))
.with_query_timeout(Duration::from_millis(200));
let mut conn = Mdns::new(config);
let query1 = conn.query("query1.local");
let query2 = conn.query("query2.local");
while conn.poll_write().is_some() {}
assert!(conn.is_query_pending(query1));
assert!(conn.is_query_pending(query2));
assert_eq!(conn.pending_query_count(), 2);
let start_time = conn.queries[0].start_time;
let time_150ms = start_time + Duration::from_millis(150);
conn.handle_timeout(time_150ms).unwrap();
assert!(conn.is_query_pending(query1));
assert!(conn.is_query_pending(query2));
assert_eq!(conn.pending_query_count(), 2);
assert!(conn.poll_event().is_none());
let time_250ms = start_time + Duration::from_millis(250);
conn.handle_timeout(time_250ms).unwrap();
assert!(!conn.is_query_pending(query1));
assert!(!conn.is_query_pending(query2));
assert_eq!(conn.pending_query_count(), 0);
let mut timeout_ids = Vec::new();
while let Some(event) = conn.poll_event() {
match event {
MdnsEvent::QueryTimeout(id) => timeout_ids.push(id),
_ => panic!("Expected QueryTimeout event"),
}
}
assert_eq!(timeout_ids.len(), 2);
assert!(timeout_ids.contains(&query1));
assert!(timeout_ids.contains(&query2));
}
#[test]
fn test_no_timeout_without_config() {
let config = MdnsConfig::default().with_query_interval(Duration::from_millis(100));
let mut conn = Mdns::new(config);
let query_id = conn.query("no-timeout.local");
conn.poll_write();
let now = Instant::now();
let future = now + Duration::from_secs(3600); conn.handle_timeout(future).unwrap();
assert!(conn.is_query_pending(query_id));
assert!(conn.poll_event().is_none());
}
#[test]
fn test_query_timeout_config() {
let config = MdnsConfig::default().with_query_timeout(Duration::from_secs(10));
let conn = Mdns::new(config);
assert_eq!(conn.query_timeout, Some(Duration::from_secs(10)));
let config = MdnsConfig::default();
let conn = Mdns::new(config);
assert_eq!(conn.query_timeout, None);
}