From 1f2a53d34c56faf439cb8fd4bab06ed7dad0a8c1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:16:59 +0000 Subject: [PATCH 1/2] Initial plan From 8b4e696102d64b7ca7e467fe94624e9d4c82ec64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:23:29 +0000 Subject: [PATCH 2/2] dns_cache: test that zero failure backoff is floored at dns_min_refresh_rate Agent-Logs-Url: https://github.com/phlax/envoy/sessions/ba248f4d-3f4e-4efd-a832-57155165a8f1 Co-authored-by: phlax <454682+phlax@users.noreply.github.com> --- .../dns_cache_impl_test.cc | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc b/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc index 108dc38978454..54c62af5568dc 100644 --- a/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc +++ b/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc @@ -928,6 +928,65 @@ TEST_F(DnsCacheImplTest, ResolveFailureBackoffCappedByHostTtl) { 1 /* added */, 1 /* removed */, 0 /* num hosts */); } +TEST_F(DnsCacheImplTest, ResolveFailureBackoffZeroFlooredByMinRefresh) { + // Stub random() to return 0 so the jittered exponential backoff yields 0. + ON_CALL(context_.server_context_.api_.random_, random()).WillByDefault(Return(0)); + *config_.mutable_host_ttl() = Protobuf::util::TimeUtil::SecondsToDuration(60); + *config_.mutable_dns_refresh_rate() = Protobuf::util::TimeUtil::SecondsToDuration(60); + *config_.mutable_dns_min_refresh_rate() = Protobuf::util::TimeUtil::SecondsToDuration(1); + initialize(); + InSequence s; + + MockLoadDnsCacheEntryCallbacks callbacks; + Network::DnsResolver::ResolveCb resolve_cb; + Event::MockTimer* resolve_timer = new Event::MockTimer(&context_.server_context_.dispatcher_); + Event::MockTimer* timeout_timer = new Event::MockTimer(&context_.server_context_.dispatcher_); + EXPECT_CALL(*timeout_timer, enableTimer(std::chrono::milliseconds(5000), nullptr)); + EXPECT_CALL(*resolver_, resolve("foo.com", _, _)) + .WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_))); + auto result = dns_cache_->loadDnsCacheEntry("foo.com", 80, false, callbacks); + EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::Loading, result.status_); + + EXPECT_CALL(*timeout_timer, disableTimer()); + EXPECT_CALL( + update_callbacks_, + onDnsHostAddOrUpdate("foo.com:80", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); + EXPECT_CALL(callbacks, + onLoadDnsCacheComplete(DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); + EXPECT_CALL(update_callbacks_, + onDnsResolutionComplete("foo.com:80", + DnsHostInfoEquals("10.0.0.1:80", "foo.com", false), + Network::DnsResolver::ResolutionStatus::Completed)); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(dns_ttl_), _)); + resolve_cb(Network::DnsResolver::ResolutionStatus::Completed, "", + TestUtility::makeDnsResponse({"10.0.0.1"})); + + checkStats(1 /* attempt */, 1 /* success */, 0 /* failure */, 1 /* address changed */, + 1 /* added */, 0 /* removed */, 1 /* num hosts */); + + // Advance a small amount so elapsed is well below host_ttl. + simTime().advanceTimeWait(std::chrono::milliseconds(100)); + + EXPECT_CALL(*timeout_timer, enableTimer(std::chrono::milliseconds(5000), nullptr)); + EXPECT_CALL(*resolver_, resolve("foo.com", _, _)) + .WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_))); + resolve_timer->invokeCallback(); + + // DNS fails. With random()==0 the jittered backoff returns 0. The TTL cap does not kick in + // (host_ttl=60s >> elapsed=100ms). The floor at dns_min_refresh_rate (1s) lifts it to 1000ms. + EXPECT_CALL(*timeout_timer, disableTimer()); + EXPECT_CALL(update_callbacks_, onDnsHostAddOrUpdate(_, _)).Times(0); + EXPECT_CALL(callbacks, onLoadDnsCacheComplete(_)).Times(0); + EXPECT_CALL(update_callbacks_, + onDnsResolutionComplete("foo.com:80", + DnsHostInfoEquals("10.0.0.1:80", "foo.com", false), + Network::DnsResolver::ResolutionStatus::Failure)); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(1000), _)); + resolve_cb(Network::DnsResolver::ResolutionStatus::Failure, "", TestUtility::makeDnsResponse({})); + checkStats(2 /* attempt */, 1 /* success */, 1 /* failure */, 1 /* address changed */, + 1 /* added */, 0 /* removed */, 1 /* num hosts */); +} + TEST_F(DnsCacheImplTest, DisableRefreshOnFailureContainsFailedHost) { config_.set_disable_dns_refresh_on_failure(true);