refactor: extract maybe_update_primary for testable upstream re-detection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Razvan Dimescu
2026-04-11 00:18:48 +03:00
parent c3c11c40db
commit 7d6028a0c2
2 changed files with 47 additions and 11 deletions

View File

@@ -85,6 +85,20 @@ impl UpstreamPool {
self.primary = primary;
}
/// Update the primary upstream if `new_addr` (parsed with `port`) differs
/// from the current preferred upstream. Returns `true` if the pool changed.
pub fn maybe_update_primary(&mut self, new_addr: &str, port: u16) -> bool {
let Ok(new_sock) = format!("{}:{}", new_addr, port).parse::<SocketAddr>() else {
return false;
};
let new_upstream = Upstream::Udp(new_sock);
if self.preferred() == Some(&new_upstream) {
return false;
}
self.primary = vec![new_upstream];
true
}
pub fn label(&self) -> String {
match self.preferred() {
Some(u) => {
@@ -469,4 +483,33 @@ mod tests {
assert_eq!(result.header.id, 0xABCD);
assert_eq!(result.answers.len(), 1);
}
#[test]
fn maybe_update_primary_swaps_when_different() {
let mut pool = UpstreamPool::new(
vec![Upstream::Udp("1.2.3.4:53".parse().unwrap())],
vec![Upstream::Udp("8.8.8.8:53".parse().unwrap())],
);
assert!(pool.maybe_update_primary("5.6.7.8", 53));
assert_eq!(pool.preferred().unwrap().to_string(), "5.6.7.8:53");
}
#[test]
fn maybe_update_primary_noop_when_same() {
let mut pool = UpstreamPool::new(
vec![Upstream::Udp("1.2.3.4:53".parse().unwrap())],
vec![],
);
assert!(!pool.maybe_update_primary("1.2.3.4", 53));
}
#[test]
fn maybe_update_primary_rejects_invalid_addr() {
let mut pool = UpstreamPool::new(
vec![Upstream::Udp("1.2.3.4:53".parse().unwrap())],
vec![],
);
assert!(!pool.maybe_update_primary("not-an-ip", 53));
assert_eq!(pool.preferred().unwrap().to_string(), "1.2.3.4:53");
}
}

View File

@@ -610,19 +610,12 @@ async fn network_watch_loop(ctx: Arc<numa::ctx::ServerCtx>) {
.default_upstream
.or_else(numa::system_dns::detect_dhcp_dns)
.unwrap_or_else(|| QUAD9_IP.to_string());
if let Ok(new_sock) =
format!("{}:{}", new_addr, ctx.upstream_port).parse::<SocketAddr>()
{
let new_upstream = Upstream::Udp(new_sock);
let mut pool = ctx.upstream_pool.lock().unwrap();
let current = pool.preferred().cloned();
if current.as_ref() != Some(&new_upstream) {
info!("upstream changed: {} → {}", pool.label(), new_upstream);
pool.set_primary(vec![new_upstream]);
if pool.maybe_update_primary(&new_addr, ctx.upstream_port) {
info!("upstream changed → {}", pool.label());
changed = true;
}
}
}
// Flush stale LAN peers on any network change
if changed {