From f952033a49146d38799d792046a3dacbf4b0d028 Mon Sep 17 00:00:00 2001 From: Rama Chavali Date: Wed, 29 Aug 2018 19:01:18 +0530 Subject: [PATCH] config: fix update empty stat for eds (#4276) Fixes incorrect increment of update_empty stat for EDS when resource list contain does contain a particular cluster Risk Level: Low Testing: Automated tests Docs Changes: N/A Release Notes: N/A Fixes #4241 Signed-off-by: Rama --- source/common/config/grpc_mux_impl.cc | 9 +++- test/common/config/grpc_mux_impl_test.cc | 52 ++++++++++++++++++++++-- test/integration/ads_integration_test.cc | 2 +- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/source/common/config/grpc_mux_impl.cc b/source/common/config/grpc_mux_impl.cc index 0af5b7c50574..fa6f4fabb97b 100644 --- a/source/common/config/grpc_mux_impl.cc +++ b/source/common/config/grpc_mux_impl.cc @@ -206,6 +206,9 @@ void GrpcMuxImpl::onReceiveMessage(std::unique_ptrresources_.empty()) { watch->callbacks_.onConfigUpdate(message->resources(), message->version_info()); continue; @@ -217,7 +220,11 @@ void GrpcMuxImpl::onReceiveMessage(std::unique_ptrMergeFrom(it->second); } } - watch->callbacks_.onConfigUpdate(found_resources, message->version_info()); + // onConfigUpdate should be called only on watches(clusters/routes) that have updates in the + // message. + if (found_resources.size() > 0) { + watch->callbacks_.onConfigUpdate(found_resources, message->version_info()); + } } // TODO(mattklein123): In the future if we start tracking per-resource versions, we would do // that tracking here. diff --git a/test/common/config/grpc_mux_impl_test.cc b/test/common/config/grpc_mux_impl_test.cc index cd2293c5d0e5..0174acb538de 100644 --- a/test/common/config/grpc_mux_impl_test.cc +++ b/test/common/config/grpc_mux_impl_test.cc @@ -231,7 +231,6 @@ TEST_F(GrpcMuxImplTest, WildcardWatch) { // Validate behavior when watches specify resources (potentially overlapping). TEST_F(GrpcMuxImplTest, WatchDemux) { setup(); - InSequence s; const std::string& type_url = Config::TypeUrl::get().ClusterLoadAssignment; NiceMock foo_callbacks; @@ -251,9 +250,7 @@ TEST_F(GrpcMuxImplTest, WatchDemux) { envoy::api::v2::ClusterLoadAssignment load_assignment; load_assignment.set_cluster_name("x"); response->add_resources()->PackFrom(load_assignment); - EXPECT_CALL(bar_callbacks, onConfigUpdate(_, "1")) - .WillOnce(Invoke([](const Protobuf::RepeatedPtrField& resources, - const std::string&) { EXPECT_TRUE(resources.empty()); })); + EXPECT_CALL(bar_callbacks, onConfigUpdate(_, "1")).Times(0); EXPECT_CALL(foo_callbacks, onConfigUpdate(_, "1")) .WillOnce( Invoke([&load_assignment](const Protobuf::RepeatedPtrField& resources, @@ -311,6 +308,53 @@ TEST_F(GrpcMuxImplTest, WatchDemux) { expectSendMessage(type_url, {}, "2"); } +// Validate behavior when we have multiple watchers that send empty updates. +TEST_F(GrpcMuxImplTest, MultipleWatcherWithEmptyUpdates) { + setup(); + InSequence s; + const std::string& type_url = Config::TypeUrl::get().ClusterLoadAssignment; + NiceMock foo_callbacks; + auto foo_sub = grpc_mux_->subscribe(type_url, {"x", "y"}, foo_callbacks); + + EXPECT_CALL(*async_client_, start(_, _)).WillOnce(Return(&async_stream_)); + expectSendMessage(type_url, {"x", "y"}, ""); + grpc_mux_->start(); + + std::unique_ptr response( + new envoy::api::v2::DiscoveryResponse()); + response->set_type_url(type_url); + response->set_version_info("1"); + + EXPECT_CALL(foo_callbacks, onConfigUpdate(_, "1")).Times(0); + expectSendMessage(type_url, {"x", "y"}, "1"); + grpc_mux_->onReceiveMessage(std::move(response)); + + expectSendMessage(type_url, {}, "1"); +} + +// Validate behavior when we have Single Watcher that sends Empty updates. +TEST_F(GrpcMuxImplTest, SingleWatcherWithEmptyUpdates) { + setup(); + const std::string& type_url = Config::TypeUrl::get().Cluster; + NiceMock foo_callbacks; + auto foo_sub = grpc_mux_->subscribe(type_url, {}, foo_callbacks); + + EXPECT_CALL(*async_client_, start(_, _)).WillOnce(Return(&async_stream_)); + expectSendMessage(type_url, {}, ""); + grpc_mux_->start(); + + std::unique_ptr response( + new envoy::api::v2::DiscoveryResponse()); + response->set_type_url(type_url); + response->set_version_info("1"); + // Validate that onConfigUpdate is called with empty resources. + EXPECT_CALL(foo_callbacks, onConfigUpdate(_, "1")) + .WillOnce(Invoke([](const Protobuf::RepeatedPtrField& resources, + const std::string&) { EXPECT_TRUE(resources.empty()); })); + expectSendMessage(type_url, {}, "1"); + grpc_mux_->onReceiveMessage(std::move(response)); +} + // Verifies that warning messages get logged when Envoy detects too many requests. TEST_F(GrpcMuxImplTest, TooManyRequests) { setup(); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 37239700ede4..0847856976f7 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -758,7 +758,7 @@ TEST_P(AdsIntegrationTest, XdsBatching) { {"eds_cluster2", "eds_cluster"})); sendDiscoveryResponse( Config::TypeUrl::get().ClusterLoadAssignment, - {buildClusterLoadAssignment("eds_cluster"), buildClusterLoadAssignment("eds_cluster1")}, + {buildClusterLoadAssignment("eds_cluster"), buildClusterLoadAssignment("eds_cluster2")}, "1"); EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "",