diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc index 604004c565cdf..64b091090c36b 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc @@ -194,25 +194,28 @@ void DnsCacheImpl::startCacheLoad(const std::string& host, uint16_t default_port return; } - const auto host_attributes = Http::Utility::parseAuthority(host); + primary_host = createHost(host, default_port); + startResolve(host, *primary_host); +} +DnsCacheImpl::PrimaryHostInfo* DnsCacheImpl::createHost(const std::string& host, + uint16_t default_port) { + const auto host_attributes = Http::Utility::parseAuthority(host); // TODO(mattklein123): Right now, the same host with different ports will become two // independent primary hosts with independent DNS resolutions. I'm not sure how much this will // matter, but we could consider collapsing these down and sharing the underlying DNS resolution. { absl::WriterMutexLock writer_lock{&primary_hosts_lock_}; - primary_host = primary_hosts_ - // try_emplace() is used here for direct argument forwarding. - .try_emplace(host, std::make_unique( - *this, std::string(host_attributes.host_), - host_attributes.port_.value_or(default_port), - host_attributes.is_ip_address_, - [this, host]() { onReResolve(host); }, - [this, host]() { onResolveTimeout(host); })) - .first->second.get(); + return primary_hosts_ + // try_emplace() is used here for direct argument forwarding. + .try_emplace(host, + std::make_unique( + *this, std::string(host_attributes.host_), + host_attributes.port_.value_or(default_port), + host_attributes.is_ip_address_, [this, host]() { onReResolve(host); }, + [this, host]() { onResolveTimeout(host); })) + .first->second.get(); } - - startResolve(host, *primary_host); } DnsCacheImpl::PrimaryHostInfo& DnsCacheImpl::getPrimaryHost(const std::string& host) { @@ -288,13 +291,15 @@ void DnsCacheImpl::startResolve(const std::string& host, PrimaryHostInfo& host_i void DnsCacheImpl::finishResolve(const std::string& host, Network::DnsResolver::ResolutionStatus status, - std::list&& response, bool from_cache) { + std::list&& response, + absl::optional resolution_time) { ASSERT(main_thread_dispatcher_.isThreadSafe()); ENVOY_LOG_EVENT(debug, "dns_cache_finish_resolve", "main thread resolve complete for host '{}': {}", host, accumulateToString(response, [](const auto& dns_response) { return dns_response.address_->asString(); })); + const bool from_cache = resolution_time.has_value(); // Functions like this one that modify primary_hosts_ are only called in the main thread so we // know it is safe to use the PrimaryHostInfo pointers outside of the lock. @@ -305,9 +310,19 @@ void DnsCacheImpl::finishResolve(const std::string& host, return primary_host_it->second.get(); }(); - const bool first_resolve = !primary_host_info->host_info_->firstResolveComplete(); - primary_host_info->timeout_timer_->disableTimer(); - primary_host_info->active_query_ = nullptr; + bool first_resolve = false; + + if (!from_cache) { + first_resolve = !primary_host_info->host_info_->firstResolveComplete(); + primary_host_info->timeout_timer_->disableTimer(); + primary_host_info->active_query_ = nullptr; + + if (status == Network::DnsResolver::ResolutionStatus::Failure) { + stats_.dns_query_failure_.inc(); + } else { + stats_.dns_query_success_.inc(); + } + } // If the DNS resolver successfully resolved with an empty response list, the dns cache does not // update. This ensures that a potentially previously resolved address does not stabilize back to @@ -317,12 +332,6 @@ void DnsCacheImpl::finishResolve(const std::string& host, primary_host_info->port_) : nullptr; - if (status == Network::DnsResolver::ResolutionStatus::Failure) { - stats_.dns_query_failure_.inc(); - } else { - stats_.dns_query_success_.inc(); - } - // Only the change the address if: // 1) The new address is valid && // 2a) The host doesn't yet have an address || @@ -333,11 +342,6 @@ void DnsCacheImpl::finishResolve(const std::string& host, bool address_changed = false; auto current_address = primary_host_info->host_info_->address(); if (new_address != nullptr && (current_address == nullptr || *current_address != *new_address)) { - if (!from_cache) { - addCacheEntry(host, new_address); - } - // TODO(alyssawilk) don't immediately push cached entries to threads. - // Only serve stale entries if a configured resolve timeout has fired. ENVOY_LOG(debug, "host '{}' address has changed", host); primary_host_info->host_info_->setAddress(new_address); runAddUpdateCallbacks(host, primary_host_info->host_info_); @@ -345,14 +349,30 @@ void DnsCacheImpl::finishResolve(const std::string& host, stats_.host_address_changed_.inc(); } - if (first_resolve || address_changed) { + if (!resolution_time.has_value()) { + resolution_time = main_thread_dispatcher_.timeSource().monotonicTime(); + } + if (new_address) { + // Update the cache entry and staleness any time the ttl changes. + if (!from_cache) { + addCacheEntry(host, new_address, response.front().ttl_); + } + primary_host_info->host_info_->updateStale(resolution_time.value(), response.front().ttl_); + } + + if (first_resolve) { primary_host_info->host_info_->setFirstResolveComplete(); + } + if (first_resolve || address_changed) { + // TODO(alyssawilk) only notify threads of stale results after a resolution + // timeout. notifyThreads(host, primary_host_info->host_info_); } // Kick off the refresh timer. // TODO(mattklein123): Consider jitter here. It may not be necessary since the initial host // is populated dynamically. + // TODO(alyssawilk) also consider TTL here. if (status == Network::DnsResolver::ResolutionStatus::Success) { failure_backoff_strategy_->reset(); primary_host_info->refresh_timer_->enableTimer(refresh_interval_); @@ -429,12 +449,16 @@ DnsCacheImpl::PrimaryHostInfo::~PrimaryHostInfo() { } void DnsCacheImpl::addCacheEntry(const std::string& host, - const Network::Address::InstanceConstSharedPtr& address) { + const Network::Address::InstanceConstSharedPtr& address, + const std::chrono::seconds ttl) { if (!key_value_store_) { return; } - // TODO(alyssawilk) cache data should include TTL, or some other indicator. - const std::string value = absl::StrCat(address->asString()); + MonotonicTime now = main_thread_dispatcher_.timeSource().monotonicTime(); + uint64_t seconds_since_epoch = + std::chrono::duration_cast(now.time_since_epoch()).count(); + const std::string value = + absl::StrCat(address->asString(), "|", ttl.count(), "|", seconds_since_epoch); key_value_store_->addOrUpdate(host, value); } @@ -455,18 +479,42 @@ void DnsCacheImpl::loadCacheEntries( key_value_store_ = factory.createStore(config.key_value_config(), validation_visitor_, main_thread_dispatcher_, file_system_); KeyValueStore::ConstIterateCb load = [this](const std::string& key, const std::string& value) { - auto address = Network::Utility::parseInternetAddressAndPortNoThrow(value); - if (address == nullptr) { + Network::Address::InstanceConstSharedPtr address; + const auto parts = StringUtil::splitToken(value, "|"); + std::chrono::seconds ttl(0); + absl::optional resolution_time; + if (parts.size() == 3) { + address = Network::Utility::parseInternetAddressAndPortNoThrow(std::string(parts[0])); + if (address == nullptr) { + ENVOY_LOG(warn, "{} is not a valid address", parts[0]); + } + uint64_t ttl_int; + if (absl::SimpleAtoi(parts[1], &ttl_int) && ttl_int != 0) { + ttl = std::chrono::seconds(ttl_int); + } else { + ENVOY_LOG(warn, "{} is not a valid ttl", parts[1]); + } + uint64_t epoch_int; + if (absl::SimpleAtoi(parts[2], &epoch_int)) { + MonotonicTime now = main_thread_dispatcher_.timeSource().monotonicTime(); + const std::chrono::seconds seconds_since_epoch = + std::chrono::duration_cast(now.time_since_epoch()); + resolution_time = main_thread_dispatcher_.timeSource().monotonicTime() - + (seconds_since_epoch - std::chrono::seconds(epoch_int)); + } + } else { + ENVOY_LOG(warn, "Incorrect number of tokens in the cache line"); + } + if (address == nullptr || ttl == std::chrono::seconds(0) || !resolution_time.has_value()) { ENVOY_LOG(warn, "Unable to parse cache line '{}'", value); return KeyValueStore::Iterate::Break; } stats_.cache_load_.inc(); std::list response; - // TODO(alyssawilk) change finishResolve to actually use the TTL rather than - // putting 0 here, return the remaining TTL or indicate the result is stale. - response.emplace_back(Network::DnsResponse(address, std::chrono::seconds(0) /* ttl */)); - startCacheLoad(key, address->ip()->port()); - finishResolve(key, Network::DnsResolver::ResolutionStatus::Success, std::move(response), true); + createHost(key, address->ip()->port()); + response.emplace_back(Network::DnsResponse(address, ttl)); + finishResolve(key, Network::DnsResolver::ResolutionStatus::Success, std::move(response), + resolution_time); return KeyValueStore::Iterate::Continue; }; key_value_store_->iterate(load); diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h index 28614a0181736..4180313e09262 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h @@ -100,7 +100,8 @@ class DnsCacheImpl : public DnsCache, Logger::Loggable last_used_time_; + std::atomic stale_at_time_; bool first_resolve_complete_ ABSL_GUARDED_BY(resolve_lock_){false}; }; @@ -177,7 +182,8 @@ class DnsCacheImpl : public DnsCache, Logger::Loggable&& response, bool from_cache = false); + std::list&& response, + absl::optional resolution_time = {}); void runAddUpdateCallbacks(const std::string& host, const DnsHostInfoSharedPtr& host_info); void runRemoveCallbacks(const std::string& host); void notifyThreads(const std::string& host, const DnsHostInfoImplSharedPtr& resolved_info); @@ -186,10 +192,12 @@ class DnsCacheImpl : public DnsCache, Logger::LoggablenewStream(response_decoder_); - client_connection_.dispatcher_.time_system_.advanceTimeAsyncImpl(std::chrono::seconds(2)); + client_connection_.dispatcher_.globalTimeSystem().advanceTimeAsyncImpl(std::chrono::seconds(2)); EXPECT_CALL(*timeout_timer, enableTimer(_, _)).Times(0); EXPECT_CALL(request_decoder_, decodeHeaders_(_, true)); EXPECT_TRUE(request_encoder2->encodeHeaders(request_headers, true).ok()); 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 5b823d55118f2..022a9b5e7ec6e 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 @@ -1025,6 +1025,9 @@ TEST(UtilityTest, PrepareDnsRefreshStrategy) { } TEST_F(DnsCacheImplTest, ResolveSuccessWithCaching) { + auto* time_source = new NiceMock(); + dispatcher_.time_system_.reset(time_source); + // Configure the cache. MockKeyValueStoreFactory factory; EXPECT_CALL(factory, createEmptyConfigProto()).WillRepeatedly(Invoke([]() { @@ -1064,14 +1067,14 @@ TEST_F(DnsCacheImplTest, ResolveSuccessWithCaching) { EXPECT_CALL(*timeout_timer, disableTimer()); // Make sure the store gets the first insert. - EXPECT_CALL(*store, addOrUpdate("foo.com", "10.0.0.1:80")); EXPECT_CALL(update_callbacks_, onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); + EXPECT_CALL(*store, addOrUpdate("foo.com", "10.0.0.1:80|30|0")); EXPECT_CALL(callbacks, onLoadDnsCacheComplete(DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000), _)); resolve_cb(Network::DnsResolver::ResolutionStatus::Success, - TestUtility::makeDnsResponse({"10.0.0.1"})); + TestUtility::makeDnsResponse({"10.0.0.1"}, std::chrono::seconds(30))); checkStats(1 /* attempt */, 1 /* success */, 0 /* failure */, 1 /* address changed */, 1 /* added */, 0 /* removed */, 1 /* num hosts */); @@ -1087,9 +1090,10 @@ TEST_F(DnsCacheImplTest, ResolveSuccessWithCaching) { // Address does not change. EXPECT_CALL(*timeout_timer, disableTimer()); + EXPECT_CALL(*store, addOrUpdate("foo.com", "10.0.0.1:80|30|0")); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000), _)); resolve_cb(Network::DnsResolver::ResolutionStatus::Success, - TestUtility::makeDnsResponse({"10.0.0.1"})); + TestUtility::makeDnsResponse({"10.0.0.1"}, std::chrono::seconds(30))); checkStats(2 /* attempt */, 2 /* success */, 0 /* failure */, 1 /* address changed */, 1 /* added */, 0 /* removed */, 1 /* num hosts */); @@ -1105,15 +1109,31 @@ TEST_F(DnsCacheImplTest, ResolveSuccessWithCaching) { EXPECT_CALL(*timeout_timer, disableTimer()); // Make sure the store gets the updated address. - EXPECT_CALL(*store, addOrUpdate("foo.com", "10.0.0.2:80")); EXPECT_CALL(update_callbacks_, onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.2:80", "foo.com", false))); + EXPECT_CALL(*store, addOrUpdate("foo.com", "10.0.0.2:80|30|0")); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000), _)); resolve_cb(Network::DnsResolver::ResolutionStatus::Success, - TestUtility::makeDnsResponse({"10.0.0.2"})); + TestUtility::makeDnsResponse({"10.0.0.2"}, std::chrono::seconds(30))); checkStats(3 /* attempt */, 3 /* success */, 0 /* failure */, 2 /* address changed */, 1 /* added */, 0 /* removed */, 1 /* num hosts */); + + // Now do one more resolve, where the address does not change but the time + // does. + + // Re-resolve timer. + 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(); + + // Address does not change. + EXPECT_CALL(*timeout_timer, disableTimer()); + EXPECT_CALL(*store, addOrUpdate("foo.com", "10.0.0.2:80|40|0")); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000), _)); + resolve_cb(Network::DnsResolver::ResolutionStatus::Success, + TestUtility::makeDnsResponse({"10.0.0.2"}, std::chrono::seconds(40))); } } // namespace diff --git a/test/extensions/filters/common/local_ratelimit/local_ratelimit_test.cc b/test/extensions/filters/common/local_ratelimit/local_ratelimit_test.cc index c857bbe74a1ca..3965930cfb336 100644 --- a/test/extensions/filters/common/local_ratelimit/local_ratelimit_test.cc +++ b/test/extensions/filters/common/local_ratelimit/local_ratelimit_test.cc @@ -247,8 +247,8 @@ TEST_F(LocalRateLimiterDescriptorImplTest, CasEdgeCasesDescriptor) { synchronizer().enable(); // Start a thread and start the fill callback. This will wait pre-CAS. - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); synchronizer().waitOn("on_fill_timer_pre_cas"); std::thread t1([&] { EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); @@ -296,8 +296,8 @@ TEST_F(LocalRateLimiterDescriptorImplTest, TokenBucketDescriptor2) { EXPECT_TRUE(rate_limiter_->requestAllowed(descriptor_)); EXPECT_FALSE(rate_limiter_->requestAllowed(descriptor_)); EXPECT_FALSE(rate_limiter_->requestAllowed(descriptor_)); - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); } // Verify token bucket functionality with a single token. @@ -311,8 +311,8 @@ TEST_F(LocalRateLimiterDescriptorImplTest, TokenBucketDescriptor) { EXPECT_FALSE(rate_limiter_->requestAllowed(descriptor_)); // 0 -> 1 tokens - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); fill_timer_->invokeCallback(); @@ -321,14 +321,14 @@ TEST_F(LocalRateLimiterDescriptorImplTest, TokenBucketDescriptor) { EXPECT_FALSE(rate_limiter_->requestAllowed(descriptor_)); // 0 -> 1 tokens - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); fill_timer_->invokeCallback(); // 1 -> 1 tokens - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); fill_timer_->invokeCallback(); @@ -349,8 +349,8 @@ TEST_F(LocalRateLimiterDescriptorImplTest, TokenBucketMultipleTokensPerFillDescr EXPECT_FALSE(rate_limiter_->requestAllowed(descriptor_)); // 0 -> 2 tokens - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); fill_timer_->invokeCallback(); @@ -358,8 +358,8 @@ TEST_F(LocalRateLimiterDescriptorImplTest, TokenBucketMultipleTokensPerFillDescr EXPECT_TRUE(rate_limiter_->requestAllowed(descriptor_)); // 1 -> 2 tokens - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(100), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); fill_timer_->invokeCallback(); @@ -383,8 +383,8 @@ TEST_F(LocalRateLimiterDescriptorImplTest, TokenBucketDifferentDescriptorDiffere EXPECT_FALSE(rate_limiter_->requestAllowed(descriptor_)); // 0 -> 1 tokens for descriptor2_ - dispatcher_.time_system_.advanceTimeAndRun(std::chrono::milliseconds(50), dispatcher_, - Envoy::Event::Dispatcher::RunType::NonBlock); + dispatcher_.globalTimeSystem().advanceTimeAndRun(std::chrono::milliseconds(50), dispatcher_, + Envoy::Event::Dispatcher::RunType::NonBlock); EXPECT_CALL(*fill_timer_, enableTimer(std::chrono::milliseconds(50), nullptr)); fill_timer_->invokeCallback(); diff --git a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc index a621e3c1ad15f..4172b76b30e10 100644 --- a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc +++ b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc @@ -122,7 +122,8 @@ name: envoy.clusters.dynamic_forward_proxy if (write_cache_file_) { std::string host = fmt::format("localhost:{}", fake_upstreams_[0]->localAddress()->ip()->port()); - std::string value = fake_upstreams_[0]->localAddress()->asString(); + std::string value = + absl::StrCat(fake_upstreams_[0]->localAddress()->asString(), "|1000000|0"); TestEnvironment::writeStringToFileForTest( "dns_cache.txt", absl::StrCat(host.length(), "\n", host, value.length(), "\n", value)); } @@ -359,7 +360,6 @@ TEST_P(ProxyFilterIntegrationTest, UseCacheFile) { sendRequestAndWaitForResponse(request_headers, 1024, default_response_headers_, 1024); checkSimpleRequestSuccess(1024, 1024, response.get()); EXPECT_EQ(1, test_server_->counter("dns_cache.foo.cache_load")->value()); - EXPECT_EQ(1, test_server_->counter("dns_cache.foo.dns_query_attempt")->value()); EXPECT_EQ(1, test_server_->counter("dns_cache.foo.host_added")->value()); } #endif diff --git a/test/extensions/filters/network/thrift_proxy/router_test.cc b/test/extensions/filters/network/thrift_proxy/router_test.cc index 3bcbb4bff7d52..22bcf7ca0910e 100644 --- a/test/extensions/filters/network/thrift_proxy/router_test.cc +++ b/test/extensions/filters/network/thrift_proxy/router_test.cc @@ -1122,7 +1122,7 @@ TEST_F(ThriftRouterTest, PoolTimeoutUpstreamTimeMeasurement) { startRequest(MessageType::Call); - dispatcher_.time_system_.advanceTimeWait(std::chrono::milliseconds(500)); + dispatcher_.globalTimeSystem().advanceTimeWait(std::chrono::milliseconds(500)); EXPECT_CALL(cluster_scope, histogram("thrift.upstream_rq_time", Stats::Histogram::Unit::Milliseconds)) .Times(0); @@ -1219,7 +1219,7 @@ TEST_P(ThriftRouterFieldTypeTest, CallWithUpstreamRqTime) { sendTrivialStruct(field_type); completeRequest(); - dispatcher_.time_system_.advanceTimeWait(std::chrono::milliseconds(500)); + dispatcher_.globalTimeSystem().advanceTimeWait(std::chrono::milliseconds(500)); EXPECT_CALL(cluster_scope, histogram("thrift.upstream_rq_time", Stats::Histogram::Unit::Milliseconds)); EXPECT_CALL(cluster_scope, diff --git a/test/mocks/event/mocks.cc b/test/mocks/event/mocks.cc index f70fc602d5480..9a8f04cc23d1c 100644 --- a/test/mocks/event/mocks.cc +++ b/test/mocks/event/mocks.cc @@ -19,6 +19,7 @@ namespace Event { MockDispatcher::MockDispatcher() : MockDispatcher("test_thread") {} MockDispatcher::MockDispatcher(const std::string& name) : name_(name) { + time_system_ = std::make_unique(); ON_CALL(*this, initializeStats(_, _)).WillByDefault(Return()); ON_CALL(*this, clearDeferredDeleteList()).WillByDefault(Invoke([this]() -> void { to_delete_.clear(); diff --git a/test/mocks/event/mocks.h b/test/mocks/event/mocks.h index 26b1559e5ff95..fe7bb325436a2 100644 --- a/test/mocks/event/mocks.h +++ b/test/mocks/event/mocks.h @@ -37,7 +37,10 @@ class MockDispatcher : public Dispatcher { // Dispatcher const std::string& name() override { return name_; } - TimeSource& timeSource() override { return time_system_; } + TimeSource& timeSource() override { return *time_system_; } + GlobalTimeSystem& globalTimeSystem() { + return *(dynamic_cast(time_system_.get())); + } Network::ServerConnectionPtr createServerConnection(Network::ConnectionSocketPtr&& socket, Network::TransportSocketPtr&& transport_socket, @@ -162,7 +165,7 @@ class MockDispatcher : public Dispatcher { MOCK_METHOD(void, updateApproximateMonotonicTime, ()); MOCK_METHOD(void, shutdown, ()); - GlobalTimeSystem time_system_; + std::unique_ptr time_system_; std::list to_delete_; testing::NiceMock buffer_factory_; bool allow_null_callback_{};