From 012b35acd6e35ab624647a64c4205fbfb9df561c Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:19:26 +0200 Subject: [PATCH] arrange tests comment --- easytier/src/dns/node_mgr.rs | 60 +++++---------------- easytier/src/dns/peer_mgr.rs | 13 +---- easytier/src/dns/server.rs | 100 ++++++++++++----------------------- easytier/src/dns/tests.rs | 97 +++++++++++++++++++++++++++------ easytier/src/dns/zone.rs | 31 +++++++---- 5 files changed, 151 insertions(+), 150 deletions(-) diff --git a/easytier/src/dns/node_mgr.rs b/easytier/src/dns/node_mgr.rs index 995c3dc3..d2115079 100644 --- a/easytier/src/dns/node_mgr.rs +++ b/easytier/src/dns/node_mgr.rs @@ -161,56 +161,16 @@ impl DnsNodeMgrRpc for DnsNodeMgr { mod tests { use super::*; use crate::common::log; - use crate::dns::tests::new_request; + use crate::dns::tests::{ + dns_snapshot_with as snapshot_with, heartbeat_with_snapshot, new_request, + zone_data_a_with_forwarders as valid_zone_data, + }; use crate::dns::utils::response::ResponseHandle; - use crate::proto::common::Url; - use crate::proto::dns::ZoneData; use hickory_proto::op::{Message, ResponseCode}; use hickory_proto::rr::{rdata, RData, RecordType}; use std::net::Ipv4Addr; - use std::str::FromStr; use tokio::time::{sleep, Duration}; - fn valid_zone_data(origin: &str, record: &str, forwarders: Vec<&str>) -> ZoneData { - ZoneData { - id: Some(Uuid::new_v4().into()), - origin: origin.to_string(), - ttl: 60, - records: vec![format!("@ IN A {record}")], - forwarders: forwarders - .into_iter() - .map(|f| Url::from_str(f).expect("invalid forwarder")) - .collect(), - } - } - - fn snapshot_with( - zones: Vec, - addresses: Vec<&str>, - listeners: Vec<&str>, - ) -> DnsSnapshot { - DnsSnapshot { - zones, - addresses: addresses - .into_iter() - .map(|a| Url::from_str(a).expect("invalid address")) - .collect(), - listeners: listeners - .into_iter() - .map(|l| Url::from_str(l).expect("invalid listener")) - .collect(), - } - } - - fn heartbeat_with_snapshot(id: Uuid, snapshot: DnsSnapshot) -> HeartbeatRequest { - let mut hb = HeartbeatRequest { - id: Some(id.into()), - ..Default::default() - }; - hb.update(snapshot); - hb - } - fn heartbeat_digest_only(id: Uuid, digest: Vec) -> HeartbeatRequest { HeartbeatRequest { id: Some(id.into()), @@ -480,10 +440,12 @@ mod tests { ) .await; - let zones: Vec = mgr.collect_zones().into_iter().map(Into::into).collect(); + let zones: Vec<_> = mgr.collect_zones().into_iter().map(Into::into).collect(); let loop_zone = zones .into_iter() - .find(|z| z.origin.trim_end_matches('.') == "filter-loop.test") + .find(|z: &crate::proto::dns::ZoneData| { + z.origin.trim_end_matches('.') == "filter-loop.test" + }) .expect("test zone should exist"); let forwarders: HashSet = loop_zone @@ -528,10 +490,12 @@ mod tests { let _ = send_heartbeat(&mgr, heartbeat_with_snapshot(Uuid::new_v4(), node_a)).await; let _ = send_heartbeat(&mgr, heartbeat_with_snapshot(Uuid::new_v4(), node_b)).await; - let zones: Vec = mgr.collect_zones().into_iter().map(Into::into).collect(); + let zones: Vec<_> = mgr.collect_zones().into_iter().map(Into::into).collect(); let zone = zones .into_iter() - .find(|z| z.origin.trim_end_matches('.') == "cross-node-filter.test") + .find(|z: &crate::proto::dns::ZoneData| { + z.origin.trim_end_matches('.') == "cross-node-filter.test" + }) .expect("test zone should exist"); let forwarders: HashSet = zone diff --git a/easytier/src/dns/peer_mgr.rs b/easytier/src/dns/peer_mgr.rs index c8f81c1a..b4e74e65 100644 --- a/easytier/src/dns/peer_mgr.rs +++ b/easytier/src/dns/peer_mgr.rs @@ -198,25 +198,16 @@ mod tests { use super::*; use crate::common::global_ctx::tests::get_mock_global_ctx; use crate::dns::config::zone::ZoneConfig; + use crate::dns::tests::zone_data_a as valid_zone_data; use crate::peers::create_packet_recv_chan; use crate::peers::peer_manager::RouteAlgoType; use crate::peers::tests::{connect_peer_manager, wait_route_appear}; - use crate::proto::dns::{GetExportConfigRequest, ZoneData}; + use crate::proto::dns::GetExportConfigRequest; use std::collections::HashSet; use std::net::Ipv4Addr; use tokio::time::{sleep, Duration}; use uuid::Uuid; - fn valid_zone_data(origin: &str, record: &str) -> ZoneData { - ZoneData { - id: Some(Uuid::new_v4().into()), - origin: origin.to_string(), - ttl: 60, - records: vec![format!("@ IN A {record}")], - forwarders: vec![], - } - } - async fn create_peer_manager_with_zone( host: &str, origin: &str, diff --git a/easytier/src/dns/server.rs b/easytier/src/dns/server.rs index dd157d6d..0b10c3e9 100644 --- a/easytier/src/dns/server.rs +++ b/easytier/src/dns/server.rs @@ -478,9 +478,11 @@ impl DnsServer { #[cfg(test)] mod tests { use super::*; + use crate::dns::tests::{ + dns_snapshot_with as snapshot_with, heartbeat_with_snapshot, zone_data_a as valid_zone_data, + }; use crate::peers::tests::create_mock_peer_manager; - use crate::proto::common::Url; - use crate::proto::dns::{DnsNodeMgrRpc, DnsSnapshot, HeartbeatRequest, ZoneData}; + use crate::proto::dns::DnsNodeMgrRpc; use crate::proto::rpc_types::controller::BaseController; use hickory_client::client::{Client, ClientHandle}; use hickory_proto::op::{Message, MessageType, OpCode, Query}; @@ -618,39 +620,6 @@ mod tests { buf } - fn valid_zone_data(origin: &str, record: &str) -> ZoneData { - ZoneData { - id: Some(Uuid::new_v4().into()), - origin: origin.to_string(), - ttl: 60, - records: vec![format!("@ IN A {record}")], - forwarders: vec![], - } - } - - fn snapshot_with(zones: Vec, addresses: Vec<&str>, listeners: Vec<&str>) -> DnsSnapshot { - DnsSnapshot { - zones, - addresses: addresses - .into_iter() - .map(|a| Url::from_str(a).expect("invalid address")) - .collect(), - listeners: listeners - .into_iter() - .map(|l| Url::from_str(l).expect("invalid listener")) - .collect(), - } - } - - fn heartbeat_with_snapshot(id: Uuid, snapshot: DnsSnapshot) -> HeartbeatRequest { - let mut hb = HeartbeatRequest { - id: Some(id.into()), - ..Default::default() - }; - hb.update(snapshot); - hb - } - async fn wait_until(mut f: impl FnMut() -> bool) { for _ in 0..80 { if f() { @@ -664,19 +633,7 @@ mod tests { // ─── Tests ─────────────────────────────────────────────────────────── #[tokio::test] - async fn test_dynamic_catalog_replace() { - let catalog = DynamicCatalog::new(); - - let new_catalog = build_test_catalog(); - catalog.replace(new_catalog).await; - - // After replacement the catalog should resolve test.example.com - // This is implicitly verified by the UDP DNS test below; here we - // just make sure `replace` does not panic and completes. - } - - #[tokio::test] - async fn test_is_hijacked_ip_and_addr() { + async fn should_match_hijacked_ip_and_addr_when_address_is_registered() { let server = create_test_server().await; let addr: SocketAddr = "10.0.0.53:53".parse().unwrap(); assert!(!server.is_hijacked_ip(&addr.ip())); @@ -693,7 +650,7 @@ mod tests { } #[tokio::test] - async fn test_handle_icmp_echo_request() { + async fn should_reply_icmp_echo_and_swap_endpoints_when_packet_is_hijacked() { let server = create_test_server().await; let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); @@ -732,7 +689,7 @@ mod tests { } #[tokio::test] - async fn test_handle_icmp_non_echo_ignored() { + async fn should_ignore_icmp_when_type_is_not_echo_request() { let server = create_test_server().await; let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); @@ -759,7 +716,7 @@ mod tests { } #[tokio::test] - async fn test_non_hijacked_ip_ignored() { + async fn should_ignore_packet_when_destination_ip_is_not_hijacked() { let server = create_test_server().await; // Do NOT register any hijacked addresses. let icmp_payload = build_icmp_echo_request(); @@ -781,7 +738,7 @@ mod tests { } #[tokio::test] - async fn test_handle_udp_dns_packet() { + async fn should_rewrite_udp_dns_packet_when_query_targets_hijacked_dns_addr() { let server = create_test_server().await; let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); @@ -860,7 +817,7 @@ mod tests { /// Full end-to-end test: start a real DNS UDP listener via `ServerFuture`, /// send a query with a `hickory_client`, and verify the response. #[tokio::test] - async fn test_full_udp_dns_query() { + async fn should_resolve_record_via_real_udp_listener() { use hickory_server::ServerFuture; use tokio::net::UdpSocket; use tokio::time::timeout; @@ -916,7 +873,7 @@ mod tests { } #[tokio::test] - async fn test_try_process_packet_from_nic_and_pipeline_id() { + async fn should_process_icmp_packet_and_expose_pipeline_id() { let server = create_test_server().await; let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); @@ -927,7 +884,8 @@ mod tests { .insert(SocketAddr::new(dst_ip.into(), 53).into()); let icmp_payload = build_icmp_echo_request(); - let ip_bytes = build_ipv4_packet(src_ip, dst_ip, IpNextHeaderProtocols::Icmp, &icmp_payload); + let ip_bytes = + build_ipv4_packet(src_ip, dst_ip, IpNextHeaderProtocols::Icmp, &icmp_payload); let mut zc = ZCPacket::new_with_payload(&ip_bytes); zc.fill_peer_manager_hdr(1, 2, crate::tunnel::packet_def::PacketType::Data as u8); @@ -936,7 +894,7 @@ mod tests { } #[tokio::test] - async fn test_handle_ip_packet_non_ipv4_version_ignored() { + async fn should_ignore_packet_when_ipv4_header_has_non_ipv4_version() { let server = create_test_server().await; let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); @@ -947,7 +905,8 @@ mod tests { .insert(SocketAddr::new(dst_ip.into(), 53).into()); let icmp_payload = build_icmp_echo_request(); - let mut ip_bytes = build_ipv4_packet(src_ip, dst_ip, IpNextHeaderProtocols::Icmp, &icmp_payload); + let mut ip_bytes = + build_ipv4_packet(src_ip, dst_ip, IpNextHeaderProtocols::Icmp, &icmp_payload); ip_bytes[0] = (6 << 4) | 5; // fake IPv6 version in IPv4 header let mut zc = ZCPacket::new_with_payload(&ip_bytes); @@ -957,7 +916,7 @@ mod tests { } #[tokio::test] - async fn test_handle_ip_packet_unsupported_protocol_ignored() { + async fn should_ignore_packet_when_protocol_is_unsupported() { let server = create_test_server().await; let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); @@ -982,7 +941,7 @@ mod tests { } #[tokio::test] - async fn test_handle_udp_packet_wrong_port_ignored() { + async fn should_ignore_udp_dns_packet_when_destination_port_is_not_hijacked() { let server = create_test_server().await; let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); @@ -1004,7 +963,7 @@ mod tests { } #[tokio::test] - async fn test_handle_udp_packet_invalid_dns_payload_ignored() { + async fn should_ignore_udp_packet_when_dns_payload_is_invalid() { let server = create_test_server().await; let dst_ip: Ipv4Addr = "10.0.0.53".parse().unwrap(); let src_ip: Ipv4Addr = "10.0.0.1".parse().unwrap(); @@ -1025,7 +984,7 @@ mod tests { } #[tokio::test] - async fn test_reload_addresses_updates_public_addresses() { + async fn should_update_public_addresses_when_reload_addresses_is_called() { let server = create_test_server().await; let addrs = vec![ @@ -1045,7 +1004,7 @@ mod tests { } #[tokio::test] - async fn test_reload_listeners_partial_bind_failure_still_serves_working_listener() { + async fn should_still_serve_working_listener_when_one_bind_fails() { let server = create_test_server().await; server.catalog.replace(build_test_catalog()).await; @@ -1068,7 +1027,10 @@ mod tests { ]; let mut runtime = None; - server.reload_listeners(listeners, &mut runtime).await.unwrap(); + server + .reload_listeners(listeners, &mut runtime) + .await + .unwrap(); let conn = UdpClientStream::builder(good_addr, TokioRuntimeProvider::default()).build(); let (mut client, bg) = timeout(Duration::from_secs(2), Client::connect(conn)) @@ -1099,7 +1061,7 @@ mod tests { } #[tokio::test] - async fn test_run_applies_snapshot_updates_and_clears_on_shutdown() { + async fn should_apply_snapshot_updates_and_clear_state_on_shutdown() { let server = create_test_server().await; let token = CancellationToken::new(); let run_server = server.clone(); @@ -1152,7 +1114,13 @@ mod tests { token.cancel(); let _ = run_task.await; - assert!(server.addresses().is_empty(), "run() should clear addresses on exit"); - assert!(server.listeners.read().is_empty(), "run() should clear listeners on exit"); + assert!( + server.addresses().is_empty(), + "run() should clear addresses on exit" + ); + assert!( + server.listeners.read().is_empty(), + "run() should clear listeners on exit" + ); } } diff --git a/easytier/src/dns/tests.rs b/easytier/src/dns/tests.rs index 002da041..a3317dd4 100644 --- a/easytier/src/dns/tests.rs +++ b/easytier/src/dns/tests.rs @@ -9,15 +9,16 @@ use crate::common::config::TomlConfigLoader; use crate::common::global_ctx::tests::get_mock_global_ctx; use crate::common::global_ctx::GlobalCtx; use crate::connector::udp_hole_punch::tests::replace_stun_info_collector; +use crate::dns::config::zone::ZoneConfigInner; use crate::dns::node::DnsNode; use crate::dns::peer_mgr::DnsPeerMgr; -use crate::dns::config::zone::ZoneConfigInner; use crate::instance::instance::ArcNicCtx; use crate::instance::virtual_nic::NicCtx; use crate::peers::create_packet_recv_chan; use crate::peers::peer_manager::{PeerManager, RouteAlgoType}; use crate::peers::tests::{connect_peer_manager, wait_route_appear}; -use crate::proto::common::NatType; +use crate::proto::common::{NatType, Url}; +use crate::proto::dns::{DnsSnapshot, HeartbeatRequest, ZoneData}; use cidr::Ipv4Inet; use hickory_client::client::{Client, ClientHandle as _}; use hickory_proto::op::{Message, MessageType, OpCode, Query}; @@ -30,7 +31,9 @@ use hickory_proto::xfer::Protocol; use hickory_server::authority::MessageRequest; use hickory_server::server::Request; use tokio::sync::Notify; +use uuid::Uuid; +// TODO: move to system::tests pub async fn prepare_env(dns_name: &str, tun_ip: Ipv4Inet) -> (Arc, NicCtx) { prepare_env_with_tld_dns_zone(dns_name, tun_ip, None).await } @@ -98,6 +101,50 @@ pub async fn prepare_env_from_config_str(config_str: &str) -> Arc { peer_mgr } +pub fn zone_data_a(origin: &str, record: &str) -> ZoneData { + zone_data_a_with_forwarders(origin, record, vec![]) +} + +pub fn zone_data_a_with_forwarders(origin: &str, record: &str, forwarders: Vec<&str>) -> ZoneData { + ZoneData { + id: Some(Uuid::new_v4().into()), + origin: origin.to_string(), + ttl: 60, + records: vec![format!("@ IN A {record}")], + forwarders: forwarders + .into_iter() + .map(|f| Url::from_str(f).expect("invalid forwarder")) + .collect(), + } +} + +pub fn dns_snapshot_with( + zones: Vec, + addresses: Vec<&str>, + listeners: Vec<&str>, +) -> DnsSnapshot { + DnsSnapshot { + zones, + addresses: addresses + .into_iter() + .map(|a| Url::from_str(a).expect("invalid address")) + .collect(), + listeners: listeners + .into_iter() + .map(|l| Url::from_str(l).expect("invalid listener")) + .collect(), + } +} + +pub fn heartbeat_with_snapshot(id: Uuid, snapshot: DnsSnapshot) -> HeartbeatRequest { + let mut hb = HeartbeatRequest { + id: Some(id.into()), + ..Default::default() + }; + hb.update(snapshot); + hb +} + fn find_free_udp_port() -> u16 { std::net::UdpSocket::bind("127.0.0.1:0") .expect("failed to bind temp udp socket") @@ -539,11 +586,10 @@ records = ["api IN A 10.80.0.1"] zone.records = vec!["api IN A 10.80.0.2".to_string()]; dns.zones[zone_idx] = zone.try_into().expect("patch zone update should be valid"); peer.get_global_ctx().config.set_dns(Some(dns)); - peer.get_global_ctx().issue_event( - crate::common::global_ctx::GlobalCtxEvent::ConfigPatched( + peer.get_global_ctx() + .issue_event(crate::common::global_ctx::GlobalCtxEvent::ConfigPatched( crate::proto::api::config::InstanceConfigPatch::default(), - ), - ); + )); check_dns_record_at(server_addr, "api.patch.mesh-test.", "10.80.0.2").await; @@ -555,7 +601,12 @@ records = ["api IN A 10.80.0.1"] async fn config_patch_reloads_listener_binding() { let listener_old = find_free_udp_port(); let listener_new = find_free_udp_port(); - let config = cfg_with_listener("listener-patch", "10.144.150.11/24", "mesh-test", listener_old); + let config = cfg_with_listener( + "listener-patch", + "10.144.150.11/24", + "mesh-test", + listener_old, + ); let peer = prepare_env_from_config_str(&config).await; let dns_node = start_dns_node_without_nic(peer.clone()); @@ -570,11 +621,10 @@ async fn config_patch_reloads_listener_binding() { .expect("invalid listener")] .into(); peer.get_global_ctx().config.set_dns(Some(dns)); - peer.get_global_ctx().issue_event( - crate::common::global_ctx::GlobalCtxEvent::ConfigPatched( + peer.get_global_ctx() + .issue_event(crate::common::global_ctx::GlobalCtxEvent::ConfigPatched( crate::proto::api::config::InstanceConfigPatch::default(), - ), - ); + )); check_dns_record_at(new_addr, "listener-patch.mesh-test.", "10.144.150.11").await; check_dns_unavailable_at(old_addr, "listener-patch.mesh-test.").await; @@ -621,7 +671,13 @@ records = ["svc IN A 10.77.7.7"] let addr_a = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), listener_a); check_dns_record_at(addr_a, "node-c7.mesh7-test.", "10.144.151.13").await; check_dns_record_at(addr_a, "svc.shared-c7.mesh7-test.", "10.77.7.7").await; - wait_peer_zone_visibility(peer_a.clone(), peer_c.my_peer_id(), "node-c7.mesh7-test", true).await; + wait_peer_zone_visibility( + peer_a.clone(), + peer_c.my_peer_id(), + "node-c7.mesh7-test", + true, + ) + .await; wait_peer_zone_visibility( peer_a.clone(), peer_c.my_peer_id(), @@ -633,8 +689,13 @@ records = ["svc IN A 10.77.7.7"] disconnect_all_peer_conns(peer_b.clone(), peer_c.clone()).await; wait_route_disappear(peer_a.clone(), peer_c.my_peer_id()).await; // Validate via peer-sync snapshot to avoid process-wide DNS-server election side effects. - wait_peer_zone_visibility(peer_a.clone(), peer_c.my_peer_id(), "node-c7.mesh7-test", false) - .await; + wait_peer_zone_visibility( + peer_a.clone(), + peer_c.my_peer_id(), + "node-c7.mesh7-test", + false, + ) + .await; wait_peer_zone_visibility( peer_a.clone(), peer_c.my_peer_id(), @@ -648,7 +709,13 @@ records = ["svc IN A 10.77.7.7"] .await .expect("route a-c should recover via b"); - wait_peer_zone_visibility(peer_a.clone(), peer_c.my_peer_id(), "node-c7.mesh7-test", true).await; + wait_peer_zone_visibility( + peer_a.clone(), + peer_c.my_peer_id(), + "node-c7.mesh7-test", + true, + ) + .await; wait_peer_zone_visibility( peer_a.clone(), peer_c.my_peer_id(), diff --git a/easytier/src/dns/zone.rs b/easytier/src/dns/zone.rs index 6524afe8..1961596d 100644 --- a/easytier/src/dns/zone.rs +++ b/easytier/src/dns/zone.rs @@ -163,7 +163,7 @@ impl ZoneGroup { #[cfg(test)] mod tests { use super::*; - use crate::dns; + use crate::dns::tests::new_request; use crate::dns::utils::response::ResponseHandle; use crate::proto::common::Url; use crate::proto::dns::ZoneData; @@ -220,7 +220,7 @@ mod tests { name: &str, record_type: RecordType, ) -> anyhow::Result<(ResponseCode, Option)> { - let request = dns::tests::new_request(name, record_type)?; + let request = new_request(name, record_type)?; let response = ResponseHandle::new(1024); let info = catalog.lookup(&request, None, response.clone()).await; let message = response @@ -231,9 +231,10 @@ mod tests { } fn has_a_answer(message: &Message, expected: Ipv4Addr) -> bool { - message.answers().iter().any(|record| { - matches!(record.data(), RData::A(addr) if *addr == rdata::a::A(expected)) - }) + message + .answers() + .iter() + .any(|record| matches!(record.data(), RData::A(addr) if *addr == rdata::a::A(expected))) } async fn start_upstream_server() -> anyhow::Result<(SocketAddr, JoinHandle<()>)> { @@ -288,9 +289,7 @@ mod tests { let data = zone_data("invalid-forwarder.test", vec![], vec!["http://1.1.1.1:53"]); let err = Zone::try_from(&data).expect_err("unsupported forwarder should fail"); - assert!( - err.to_string().contains("unsupported") || err.to_string().contains("protocol") - ); + assert!(err.to_string().contains("unsupported") || err.to_string().contains("protocol")); } #[test] @@ -339,8 +338,20 @@ mod tests { let groups = zones.into_groups(); assert_eq!(groups.len(), 2); - assert_eq!(groups.get(&LowerName::from_str("same.test.")?).unwrap().len(), 2); - assert_eq!(groups.get(&LowerName::from_str("other.test.")?).unwrap().len(), 1); + assert_eq!( + groups + .get(&LowerName::from_str("same.test.")?) + .unwrap() + .len(), + 2 + ); + assert_eq!( + groups + .get(&LowerName::from_str("other.test.")?) + .unwrap() + .len(), + 1 + ); Ok(()) }