diff --git a/envoy/grpc/async_client_manager.h b/envoy/grpc/async_client_manager.h index 7cf027ee90533..629873e9f16d6 100644 --- a/envoy/grpc/async_client_manager.h +++ b/envoy/grpc/async_client_manager.h @@ -32,6 +32,32 @@ class AsyncClientFactory { using AsyncClientFactoryPtr = std::unique_ptr; +class GrpcServiceConfigWithHashKey { +public: + explicit GrpcServiceConfigWithHashKey(const envoy::config::core::v3::GrpcService& config) + : config_(config), pre_computed_hash_(Envoy::MessageUtil::hash(config)){}; + + template friend H AbslHashValue(H h, const GrpcServiceConfigWithHashKey& wrapper) { + return H::combine(std::move(h), wrapper.pre_computed_hash_); + } + + std::size_t getPreComputedHash() const { return pre_computed_hash_; } + + friend bool operator==(const GrpcServiceConfigWithHashKey& lhs, + const GrpcServiceConfigWithHashKey& rhs) { + if (lhs.pre_computed_hash_ == rhs.pre_computed_hash_) { + return Protobuf::util::MessageDifferencer::Equivalent(lhs.config_, rhs.config_); + } + return false; + } + + const envoy::config::core::v3::GrpcService& config() const { return config_; } + +private: + const envoy::config::core::v3::GrpcService config_; + const std::size_t pre_computed_hash_; +}; + // Singleton gRPC client manager. Grpc::AsyncClientManager can be used to create per-service // Grpc::AsyncClientFactory instances. All manufactured Grpc::AsyncClients must // be destroyed before the AsyncClientManager can be safely destructed. @@ -39,6 +65,7 @@ class AsyncClientManager { public: virtual ~AsyncClientManager() = default; + // TODO(diazalan) deprecate old getOrCreateRawAsyncClient once all filters have been transitioned /** * Create a Grpc::RawAsyncClient. The async client is cached thread locally and shared across * different filter instances. @@ -54,6 +81,22 @@ class AsyncClientManager { getOrCreateRawAsyncClient(const envoy::config::core::v3::GrpcService& grpc_service, Stats::Scope& scope, bool skip_cluster_check) PURE; + /** + * Create a Grpc::RawAsyncClient. The async client is cached thread locally and shared across + * different filter instances. + * @param grpc_service Envoy::Grpc::GrpcServiceConfigWithHashKey which contains config and + * hashkey. + * @param scope stats scope. + * @param skip_cluster_check if set to true skips checks for cluster presence and being statically + * configured. + * @param cache_option always use cache or use cache when runtime is enabled. + * @return RawAsyncClientPtr a grpc async client. + * @throws EnvoyException when grpc_service validation fails. + */ + virtual RawAsyncClientSharedPtr + getOrCreateRawAsyncClientWithHashKey(const GrpcServiceConfigWithHashKey& grpc_service, + Stats::Scope& scope, bool skip_cluster_check) PURE; + /** * Create a Grpc::AsyncClients factory for a service. Validation of the service is performed and * will raise an exception on failure. diff --git a/source/common/grpc/async_client_manager_impl.cc b/source/common/grpc/async_client_manager_impl.cc index 949ae4bd75391..e741ec56383dc 100644 --- a/source/common/grpc/async_client_manager_impl.cc +++ b/source/common/grpc/async_client_manager_impl.cc @@ -5,6 +5,7 @@ #include "source/common/common/base64.h" #include "source/common/grpc/async_client_impl.h" +#include "source/common/protobuf/utility.h" #include "absl/strings/match.h" @@ -136,12 +137,27 @@ AsyncClientManagerImpl::factoryForGrpcService(const envoy::config::core::v3::Grp RawAsyncClientSharedPtr AsyncClientManagerImpl::getOrCreateRawAsyncClient( const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, bool skip_cluster_check) { - RawAsyncClientSharedPtr client = raw_async_client_cache_->getCache(config); + const GrpcServiceConfigWithHashKey config_with_hash_key = GrpcServiceConfigWithHashKey(config); + RawAsyncClientSharedPtr client = raw_async_client_cache_->getCache(config_with_hash_key); if (client != nullptr) { return client; } - client = factoryForGrpcService(config, scope, skip_cluster_check)->createUncachedRawAsyncClient(); - raw_async_client_cache_->setCache(config, client); + client = factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check) + ->createUncachedRawAsyncClient(); + raw_async_client_cache_->setCache(config_with_hash_key, client); + return client; +} + +RawAsyncClientSharedPtr AsyncClientManagerImpl::getOrCreateRawAsyncClientWithHashKey( + const GrpcServiceConfigWithHashKey& config_with_hash_key, Stats::Scope& scope, + bool skip_cluster_check) { + RawAsyncClientSharedPtr client = raw_async_client_cache_->getCache(config_with_hash_key); + if (client != nullptr) { + return client; + } + client = factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check) + ->createUncachedRawAsyncClient(); + raw_async_client_cache_->setCache(config_with_hash_key, client); return client; } @@ -151,11 +167,12 @@ AsyncClientManagerImpl::RawAsyncClientCache::RawAsyncClientCache(Event::Dispatch } void AsyncClientManagerImpl::RawAsyncClientCache::setCache( - const envoy::config::core::v3::GrpcService& config, const RawAsyncClientSharedPtr& client) { - ASSERT(lru_map_.find(config) == lru_map_.end()); + const GrpcServiceConfigWithHashKey& config_with_hash_key, + const RawAsyncClientSharedPtr& client) { + ASSERT(lru_map_.find(config_with_hash_key) == lru_map_.end()); // Create a new cache entry at the beginning of the list. - lru_list_.emplace_front(config, client, dispatcher_.timeSource().monotonicTime()); - lru_map_[config] = lru_list_.begin(); + lru_list_.emplace_front(config_with_hash_key, client, dispatcher_.timeSource().monotonicTime()); + lru_map_[config_with_hash_key] = lru_list_.begin(); // If inserting to an empty cache, enable eviction timer. if (lru_list_.size() == 1) { evictEntriesAndResetEvictionTimer(); @@ -163,8 +180,8 @@ void AsyncClientManagerImpl::RawAsyncClientCache::setCache( } RawAsyncClientSharedPtr AsyncClientManagerImpl::RawAsyncClientCache::getCache( - const envoy::config::core::v3::GrpcService& config) { - auto it = lru_map_.find(config); + const GrpcServiceConfigWithHashKey& config_with_hash_key) { + auto it = lru_map_.find(config_with_hash_key); if (it == lru_map_.end()) { return nullptr; } @@ -189,7 +206,7 @@ void AsyncClientManagerImpl::RawAsyncClientCache::evictEntriesAndResetEvictionTi MonotonicTime next_expire = lru_list_.back().accessed_time_ + EntryTimeoutInterval; if (now >= next_expire) { // Erase the expired entry. - lru_map_.erase(lru_list_.back().config_); + lru_map_.erase(lru_list_.back().config_with_hash_key_); lru_list_.pop_back(); } else { cache_eviction_timer_->enableTimer( diff --git a/source/common/grpc/async_client_manager_impl.h b/source/common/grpc/async_client_manager_impl.h index eee1400ff84cd..eadf3009490cd 100644 --- a/source/common/grpc/async_client_manager_impl.h +++ b/source/common/grpc/async_client_manager_impl.h @@ -9,6 +9,7 @@ #include "envoy/upstream/cluster_manager.h" #include "source/common/grpc/stat_names.h" +#include "source/common/protobuf/utility.h" namespace Envoy { namespace Grpc { @@ -51,32 +52,35 @@ class AsyncClientManagerImpl : public AsyncClientManager { getOrCreateRawAsyncClient(const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, bool skip_cluster_check) override; + RawAsyncClientSharedPtr + getOrCreateRawAsyncClientWithHashKey(const GrpcServiceConfigWithHashKey& config_with_hash_key, + Stats::Scope& scope, bool skip_cluster_check) override; + AsyncClientFactoryPtr factoryForGrpcService(const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, bool skip_cluster_check) override; class RawAsyncClientCache : public ThreadLocal::ThreadLocalObject { public: explicit RawAsyncClientCache(Event::Dispatcher& dispatcher); - void setCache(const envoy::config::core::v3::GrpcService& config, + void setCache(const GrpcServiceConfigWithHashKey& config_with_hash_key, const RawAsyncClientSharedPtr& client); - RawAsyncClientSharedPtr getCache(const envoy::config::core::v3::GrpcService& config); + RawAsyncClientSharedPtr getCache(const GrpcServiceConfigWithHashKey& config_with_hash_key); private: void evictEntriesAndResetEvictionTimer(); struct CacheEntry { - CacheEntry(const envoy::config::core::v3::GrpcService& config, + CacheEntry(const GrpcServiceConfigWithHashKey& config_with_hash_key, RawAsyncClientSharedPtr const& client, MonotonicTime create_time) - : config_(config), client_(client), accessed_time_(create_time) {} - envoy::config::core::v3::GrpcService config_; + : config_with_hash_key_(config_with_hash_key), client_(client), + accessed_time_(create_time) {} + GrpcServiceConfigWithHashKey config_with_hash_key_; RawAsyncClientSharedPtr client_; MonotonicTime accessed_time_; }; using LruList = std::list; - absl::flat_hash_map - lru_map_; LruList lru_list_; + absl::flat_hash_map lru_map_; Event::Dispatcher& dispatcher_; Envoy::Event::TimerPtr cache_eviction_timer_; static constexpr std::chrono::seconds EntryTimeoutInterval{50}; diff --git a/source/extensions/filters/http/ext_authz/config.cc b/source/extensions/filters/http/ext_authz/config.cc index 54ca6fc5db455..1e15833e5fc14 100644 --- a/source/extensions/filters/http/ext_authz/config.cc +++ b/source/extensions/filters/http/ext_authz/config.cc @@ -6,6 +6,7 @@ #include "envoy/config/core/v3/grpc_service.pb.h" #include "envoy/extensions/filters/http/ext_authz/v3/ext_authz.pb.h" #include "envoy/extensions/filters/http/ext_authz/v3/ext_authz.pb.validate.h" +#include "envoy/grpc/async_client_manager.h" #include "envoy/registry/registry.h" #include "source/common/config/utility.h" @@ -42,34 +43,22 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( context.clusterManager(), client_config); callbacks.addStreamFilter(std::make_shared(filter_config, std::move(client))); }; - } else if (proto_config.grpc_service().has_google_grpc()) { - // Google gRPC client. + } else { + // gRPC client. const uint32_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(proto_config.grpc_service(), timeout, DefaultTimeout); Config::Utility::checkTransportVersion(proto_config); + Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key = + Envoy::Grpc::GrpcServiceConfigWithHashKey(proto_config.grpc_service()); callback = [&context, filter_config, timeout_ms, - proto_config](Http::FilterChainFactoryCallbacks& callbacks) { + config_with_hash_key](Http::FilterChainFactoryCallbacks& callbacks) { auto client = std::make_unique( - context.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( - proto_config.grpc_service(), context.scope(), true), + context.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClientWithHashKey( + config_with_hash_key, context.scope(), true), std::chrono::milliseconds(timeout_ms)); callbacks.addStreamFilter(std::make_shared(filter_config, std::move(client))); }; - } else { - // Envoy gRPC client. - const uint32_t timeout_ms = - PROTOBUF_GET_MS_OR_DEFAULT(proto_config.grpc_service(), timeout, DefaultTimeout); - Config::Utility::checkTransportVersion(proto_config); - callback = [grpc_service = proto_config.grpc_service(), &context, filter_config, - timeout_ms](Http::FilterChainFactoryCallbacks& callbacks) { - Grpc::RawAsyncClientSharedPtr raw_client = - context.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( - grpc_service, context.scope(), true); - auto client = std::make_unique( - raw_client, std::chrono::milliseconds(timeout_ms)); - callbacks.addStreamFilter(std::make_shared(filter_config, std::move(client))); - }; } return callback; diff --git a/test/common/grpc/BUILD b/test/common/grpc/BUILD index 6cf74e7f7d7e7..01458712de953 100644 --- a/test/common/grpc/BUILD +++ b/test/common/grpc/BUILD @@ -1,5 +1,7 @@ load( "//bazel:envoy_build_system.bzl", + "envoy_benchmark_test", + "envoy_cc_benchmark_binary", "envoy_cc_fuzz_test", "envoy_cc_test", "envoy_cc_test_library", @@ -213,3 +215,28 @@ envoy_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_cc_benchmark_binary( + name = "async_client_manager_benchmark", + srcs = ["async_client_manager_benchmark.cc"], + external_deps = [ + "benchmark", + ], + deps = [ + "//source/common/api:api_lib", + "//source/common/grpc:async_client_manager_lib", + "//test/mocks/stats:stats_mocks", + "//test/mocks/thread_local:thread_local_mocks", + "//test/mocks/upstream:cluster_manager_mocks", + "//test/mocks/upstream:cluster_priority_set_mocks", + "//test/test_common:test_runtime_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) + +envoy_benchmark_test( + name = "async_client_manager_benchmark_test", + timeout = "long", + benchmark_binary = "async_client_manager_benchmark", +) diff --git a/test/common/grpc/async_client_manager_benchmark.cc b/test/common/grpc/async_client_manager_benchmark.cc new file mode 100644 index 0000000000000..f23a0aba54e50 --- /dev/null +++ b/test/common/grpc/async_client_manager_benchmark.cc @@ -0,0 +1,79 @@ +#include + +#include "envoy/config/core/v3/grpc_service.pb.h" +#include "envoy/grpc/async_client.h" + +#include "source/common/api/api_impl.h" +#include "source/common/event/dispatcher_impl.h" +#include "source/common/grpc/async_client_manager_impl.h" + +#include "test/benchmark/main.h" +#include "test/mocks/stats/mocks.h" +#include "test/mocks/thread_local/mocks.h" +#include "test/mocks/upstream/cluster_manager.h" +#include "test/mocks/upstream/cluster_priority_set.h" +#include "test/test_common/test_runtime.h" +#include "test/test_common/test_time.h" +#include "test/test_common/utility.h" + +#include "benchmark/benchmark.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Grpc { +namespace { + +class AsyncClientManagerImplTest { +public: + AsyncClientManagerImplTest() + : api_(Api::createApiForTest()), stat_names_(scope_.symbolTable()), + async_client_manager_(cm_, tls_, test_time_.timeSystem(), *api_, stat_names_) {} + + Upstream::MockClusterManager cm_; + NiceMock tls_; + Stats::MockStore store_; + Stats::MockScope& scope_{store_.mockScope()}; + DangerousDeprecatedTestTime test_time_; + Api::ApiPtr api_; + StatNames stat_names_; + AsyncClientManagerImpl async_client_manager_; +}; + +void testGetOrCreateAsyncClientWithConfig(::benchmark::State& state) { + AsyncClientManagerImplTest async_client_man_test; + + envoy::config::core::v3::GrpcService grpc_service; + grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); + + for (auto _ : state) { + for (int i = 0; i < 1000; i++) { + RawAsyncClientSharedPtr foo_client0 = + async_client_man_test.async_client_manager_.getOrCreateRawAsyncClient( + grpc_service, async_client_man_test.scope_, true); + } + } +} + +void testGetOrCreateAsyncClientWithHashConfig(::benchmark::State& state) { + AsyncClientManagerImplTest async_client_man_test; + + envoy::config::core::v3::GrpcService grpc_service; + grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); + GrpcServiceConfigWithHashKey config_with_hash_key_a = GrpcServiceConfigWithHashKey(grpc_service); + + for (auto _ : state) { + for (int i = 0; i < 1000; i++) { + RawAsyncClientSharedPtr foo_client0 = + async_client_man_test.async_client_manager_.getOrCreateRawAsyncClientWithHashKey( + config_with_hash_key_a, async_client_man_test.scope_, true); + } + } +} + +BENCHMARK(testGetOrCreateAsyncClientWithConfig)->Unit(::benchmark::kMicrosecond); +BENCHMARK(testGetOrCreateAsyncClientWithHashConfig)->Unit(::benchmark::kMicrosecond); + +} // namespace +} // namespace Grpc +} // namespace Envoy diff --git a/test/common/grpc/async_client_manager_impl_test.cc b/test/common/grpc/async_client_manager_impl_test.cc index 121f8cbc533d5..36dae3f1001e9 100644 --- a/test/common/grpc/async_client_manager_impl_test.cc +++ b/test/common/grpc/async_client_manager_impl_test.cc @@ -52,16 +52,17 @@ class RawAsyncClientCacheTest : public testing::Test { TEST_F(RawAsyncClientCacheTest, CacheEviction) { envoy::config::core::v3::GrpcService foo_service; foo_service.mutable_envoy_grpc()->set_cluster_name("foo"); + GrpcServiceConfigWithHashKey config_with_hash_key(foo_service); RawAsyncClientSharedPtr foo_client = std::make_shared(); - client_cache_.setCache(foo_service, foo_client); + client_cache_.setCache(config_with_hash_key, foo_client); waitForSeconds(49); // Cache entry hasn't been evicted because it was created 49s ago. - EXPECT_EQ(client_cache_.getCache(foo_service).get(), foo_client.get()); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), foo_client.get()); waitForSeconds(49); // Cache entry hasn't been evicted because it was accessed 49s ago. - EXPECT_EQ(client_cache_.getCache(foo_service).get(), foo_client.get()); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), foo_client.get()); waitForSeconds(51); - EXPECT_EQ(client_cache_.getCache(foo_service).get(), nullptr); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), nullptr); } TEST_F(RawAsyncClientCacheTest, MultipleCacheEntriesEviction) { @@ -69,23 +70,27 @@ TEST_F(RawAsyncClientCacheTest, MultipleCacheEntriesEviction) { RawAsyncClientSharedPtr foo_client = std::make_shared(); for (int i = 1; i <= 50; i++) { grpc_service.mutable_envoy_grpc()->set_cluster_name(std::to_string(i)); - client_cache_.setCache(grpc_service, foo_client); + GrpcServiceConfigWithHashKey config_with_hash_key(grpc_service); + client_cache_.setCache(config_with_hash_key, foo_client); } waitForSeconds(20); for (int i = 51; i <= 100; i++) { grpc_service.mutable_envoy_grpc()->set_cluster_name(std::to_string(i)); - client_cache_.setCache(grpc_service, foo_client); + GrpcServiceConfigWithHashKey config_with_hash_key(grpc_service); + client_cache_.setCache(config_with_hash_key, foo_client); } waitForSeconds(30); // Cache entries created 50s before have expired. for (int i = 1; i <= 50; i++) { grpc_service.mutable_envoy_grpc()->set_cluster_name(std::to_string(i)); - EXPECT_EQ(client_cache_.getCache(grpc_service).get(), nullptr); + GrpcServiceConfigWithHashKey config_with_hash_key(grpc_service); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), nullptr); } // Cache entries 30s before haven't expired. for (int i = 51; i <= 100; i++) { grpc_service.mutable_envoy_grpc()->set_cluster_name(std::to_string(i)); - EXPECT_EQ(client_cache_.getCache(grpc_service).get(), foo_client.get()); + GrpcServiceConfigWithHashKey config_with_hash_key(grpc_service); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), foo_client.get()); } } @@ -95,14 +100,15 @@ TEST_F(RawAsyncClientCacheTest, GetExpiredButNotEvictedCacheEntry) { envoy::config::core::v3::GrpcService foo_service; foo_service.mutable_envoy_grpc()->set_cluster_name("foo"); RawAsyncClientSharedPtr foo_client = std::make_shared(); - client_cache_.setCache(foo_service, foo_client); + GrpcServiceConfigWithHashKey config_with_hash_key(foo_service); + client_cache_.setCache(config_with_hash_key, foo_client); time_system_.advanceTimeAsyncImpl(std::chrono::seconds(50)); // Cache entry hasn't been evicted because it is accessed before timer fire. - EXPECT_EQ(client_cache_.getCache(foo_service).get(), foo_client.get()); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), foo_client.get()); time_system_.advanceTimeAndRun(std::chrono::seconds(50), *dispatcher_, Event::Dispatcher::RunType::NonBlock); // Cache entry has been evicted because it is accessed after timer fire. - EXPECT_EQ(client_cache_.getCache(foo_service).get(), nullptr); + EXPECT_EQ(client_cache_.getCache(config_with_hash_key).get(), nullptr); } class AsyncClientManagerImplTest : public testing::Test { @@ -128,6 +134,25 @@ TEST_F(AsyncClientManagerImplTest, EnvoyGrpcOk) { async_client_manager_.factoryForGrpcService(grpc_service, scope_, false); } +TEST_F(AsyncClientManagerImplTest, GrpcServiceConfigWithHashKeyTest) { + envoy::config::core::v3::GrpcService grpc_service; + grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); + envoy::config::core::v3::GrpcService grpc_service_c; + grpc_service.mutable_envoy_grpc()->set_cluster_name("bar"); + + GrpcServiceConfigWithHashKey config_with_hash_key_a = GrpcServiceConfigWithHashKey(grpc_service); + GrpcServiceConfigWithHashKey config_with_hash_key_b = GrpcServiceConfigWithHashKey(grpc_service); + GrpcServiceConfigWithHashKey config_with_hash_key_c = + GrpcServiceConfigWithHashKey(grpc_service_c); + EXPECT_TRUE(config_with_hash_key_a == config_with_hash_key_b); + EXPECT_FALSE(config_with_hash_key_a == config_with_hash_key_c); + + EXPECT_EQ(config_with_hash_key_a.getPreComputedHash(), + config_with_hash_key_b.getPreComputedHash()); + EXPECT_NE(config_with_hash_key_a.getPreComputedHash(), + config_with_hash_key_c.getPreComputedHash()); +} + TEST_F(AsyncClientManagerImplTest, RawAsyncClientCache) { envoy::config::core::v3::GrpcService grpc_service; grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); diff --git a/test/extensions/filters/http/ext_authz/config_test.cc b/test/extensions/filters/http/ext_authz/config_test.cc index 6995304446fb2..2eddc7f01cec3 100644 --- a/test/extensions/filters/http/ext_authz/config_test.cc +++ b/test/extensions/filters/http/ext_authz/config_test.cc @@ -63,12 +63,14 @@ class ExtAuthzFilterTest : public Event::TestUsingSimulatedTime, const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& ext_authz_config) { // Delegate call to mock async client manager to real async client manager. ON_CALL(context_, getServerFactoryContext()).WillByDefault(testing::ReturnRef(server_context_)); - ON_CALL(context_.cluster_manager_.async_client_manager_, getOrCreateRawAsyncClient(_, _, _)) - .WillByDefault(Invoke([&](const envoy::config::core::v3::GrpcService& config, - Stats::Scope& scope, bool skip_cluster_check) { - return async_client_manager_->getOrCreateRawAsyncClient(config, scope, - skip_cluster_check); - })); + ON_CALL(context_.cluster_manager_.async_client_manager_, + getOrCreateRawAsyncClientWithHashKey(_, _, _)) + .WillByDefault( + Invoke([&](const Envoy::Grpc::GrpcServiceConfigWithHashKey& config_with_hash_key, + Stats::Scope& scope, bool skip_cluster_check) { + return async_client_manager_->getOrCreateRawAsyncClientWithHashKey( + config_with_hash_key, scope, skip_cluster_check); + })); ExtAuthzFilterConfig factory; return factory.createFilterFactoryFromProto(ext_authz_config, "stats", context_); } @@ -204,8 +206,11 @@ class ExtAuthzFilterGrpcTest : public ExtAuthzFilterTest { void expectGrpcClientSentRequest( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& ext_authz_config, int requests_sent_per_thread) { - Grpc::RawAsyncClientSharedPtr async_client = async_client_manager_->getOrCreateRawAsyncClient( - ext_authz_config.grpc_service(), context_.scope(), false); + Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key = + Envoy::Grpc::GrpcServiceConfigWithHashKey(ext_authz_config.grpc_service()); + Grpc::RawAsyncClientSharedPtr async_client = + async_client_manager_->getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, + context_.scope(), false); Grpc::MockAsyncClient* mock_async_client = dynamic_cast(async_client.get()); EXPECT_NE(mock_async_client, nullptr); diff --git a/test/mocks/grpc/mocks.h b/test/mocks/grpc/mocks.h index 3cff1d2d75aa5..620e9f6ce646a 100644 --- a/test/mocks/grpc/mocks.h +++ b/test/mocks/grpc/mocks.h @@ -116,6 +116,10 @@ class MockAsyncClientManager : public AsyncClientManager { MOCK_METHOD(RawAsyncClientSharedPtr, getOrCreateRawAsyncClient, (const envoy::config::core::v3::GrpcService& grpc_service, Stats::Scope& scope, bool skip_cluster_check)); + + MOCK_METHOD(RawAsyncClientSharedPtr, getOrCreateRawAsyncClientWithHashKey, + (const GrpcServiceConfigWithHashKey& config_with_hash_key, Stats::Scope& scope, + bool skip_cluster_check)); }; MATCHER_P(ProtoBufferEq, expected, "") {