[testing]: Add "orca_per_rpc" test case (#32524)

pull/32616/head
Eugene Ostroukhov 2 years ago committed by GitHub
parent ae55fb04ab
commit c62ecd5cb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      CMakeLists.txt
  2. 9
      build_autogenerated.yaml
  3. 13
      src/android/test/interop/app/CMakeLists.txt
  4. 8
      src/proto/grpc/testing/BUILD
  5. 5
      src/proto/grpc/testing/messages.proto
  6. 5
      src/proto/grpc/testing/xds/v3/BUILD
  7. 21
      test/cpp/interop/BUILD
  8. 12
      test/cpp/interop/README.md
  9. 247
      test/cpp/interop/backend_metrics_lb_policy.cc
  10. 54
      test/cpp/interop/backend_metrics_lb_policy.h
  11. 68
      test/cpp/interop/client.cc
  12. 37
      test/cpp/interop/client_helper.cc
  13. 4
      test/cpp/interop/client_helper.h
  14. 84
      test/cpp/interop/interop_client.cc
  15. 14
      test/cpp/interop/interop_client.h
  16. 38
      test/cpp/interop/interop_server.cc
  17. 10
      test/cpp/interop/observability_client.cc
  18. 2
      test/cpp/interop/xds_federation_client.cc
  19. 13
      test/cpp/util/create_test_channel.cc
  20. 8
      test/cpp/util/create_test_channel.h

29
CMakeLists.txt generated

@ -13604,6 +13604,10 @@ add_executable(http2_client
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/cpp/interop/http2_client.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@ -14103,7 +14107,12 @@ add_executable(interop_client
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/core/security/oauth2_utils.cc
test/cpp/interop/backend_metrics_lb_policy.cc
test/cpp/interop/client.cc
test/cpp/interop/client_helper.cc
test/cpp/interop/interop_client.cc
@ -14156,6 +14165,10 @@ add_executable(interop_server
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/cpp/interop/interop_server.cc
test/cpp/interop/interop_server_bootstrap.cc
test/cpp/interop/server_helper.cc
@ -16905,6 +16918,10 @@ add_executable(qps_json_driver
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/cpp/qps/benchmark_config.cc
test/cpp/qps/client_async.cc
test/cpp/qps/client_callback.cc
@ -16980,6 +16997,10 @@ add_executable(qps_worker
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/cpp/qps/client_async.cc
test/cpp/qps/client_callback.cc
test/cpp/qps/client_sync.cc
@ -24342,6 +24363,10 @@ add_executable(xds_interop_client
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h
@ -24417,6 +24442,10 @@ add_executable(xds_interop_server
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h

@ -8714,6 +8714,7 @@ targets:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/test.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/cpp/interop/http2_client.cc
deps:
- grpc++_test_config
@ -8960,13 +8961,16 @@ targets:
language: c++
headers:
- test/core/security/oauth2_utils.h
- test/cpp/interop/backend_metrics_lb_policy.h
- test/cpp/interop/client_helper.h
- test/cpp/interop/interop_client.h
src:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/test.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/core/security/oauth2_utils.cc
- test/cpp/interop/backend_metrics_lb_policy.cc
- test/cpp/interop/client.cc
- test/cpp/interop/client_helper.cc
- test/cpp/interop/interop_client.cc
@ -8983,6 +8987,7 @@ targets:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/test.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/cpp/interop/interop_server.cc
- test/cpp/interop/interop_server_bootstrap.cc
- test/cpp/interop/server_helper.cc
@ -10191,6 +10196,7 @@ targets:
- src/proto/grpc/testing/report_qps_scenario_service.proto
- src/proto/grpc/testing/stats.proto
- src/proto/grpc/testing/worker_service.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/cpp/qps/benchmark_config.cc
- test/cpp/qps/client_async.cc
- test/cpp/qps/client_callback.cc
@ -10228,6 +10234,7 @@ targets:
- src/proto/grpc/testing/payloads.proto
- src/proto/grpc/testing/stats.proto
- src/proto/grpc/testing/worker_service.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/cpp/qps/client_async.cc
- test/cpp/qps/client_callback.cc
- test/cpp/qps/client_sync.cc
@ -13326,6 +13333,7 @@ targets:
- src/proto/grpc/testing/xds/v3/base.proto
- src/proto/grpc/testing/xds/v3/config_dump.proto
- src/proto/grpc/testing/xds/v3/csds.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- src/proto/grpc/testing/xds/v3/percent.proto
- src/cpp/server/admin/admin_services.cc
- src/cpp/server/csds/csds.cc
@ -13351,6 +13359,7 @@ targets:
- src/proto/grpc/testing/xds/v3/base.proto
- src/proto/grpc/testing/xds/v3/config_dump.proto
- src/proto/grpc/testing/xds/v3/csds.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- src/proto/grpc/testing/xds/v3/percent.proto
- src/cpp/server/admin/admin_services.cc
- src/cpp/server/csds/csds.cc

@ -63,7 +63,9 @@ set(PROTO_BASE_DIR ${GRPC_SRC_DIR}/examples/protos)
android_protobuf_grpc_generate_cpp(
MESSAGES_PROTO_SRCS MESSAGES_PROTO_HDRS
${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/messages.proto)
${GRPC_SRC_DIR}
${GRPC_SRC_DIR}/src/proto/grpc/testing/messages.proto
${GRPC_SRC_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.proto)
add_library(messages_proto_lib
SHARED ${MESSAGES_PROTO_SRCS} ${MESSAGES_PROTO_HDRS})
@ -88,7 +90,8 @@ target_link_libraries(empty_proto_lib
log)
android_protobuf_grpc_generate_cpp(
TEST_PROTO_SRCS TEST_PROTO_HDRS ${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/test.proto)
TEST_PROTO_SRCS TEST_PROTO_HDRS
${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/test.proto)
add_library(test_proto_lib
SHARED ${TEST_PROTO_SRCS} ${TEST_PROTO_HDRS})
@ -107,10 +110,14 @@ find_library(log-lib
add_library(grpc-interop
SHARED
src/main/cpp/grpc-interop.cc
${GRPC_SRC_DIR}/test/cpp/interop/backend_metrics_lb_policy.h
${GRPC_SRC_DIR}/test/cpp/interop/backend_metrics_lb_policy.cc
${GRPC_SRC_DIR}/test/cpp/interop/interop_client.h
${GRPC_SRC_DIR}/test/cpp/interop/interop_client.cc
${GRPC_SRC_DIR}/test/core/util/histogram.h
${GRPC_SRC_DIR}/test/core/util/histogram.cc)
${GRPC_SRC_DIR}/test/core/util/histogram.cc
${GRPC_SRC_DIR}/test/core/util/test_lb_policies.h
${GRPC_SRC_DIR}/test/core/util/test_lb_policies.cc)
target_link_libraries(grpc-interop
messages_proto_lib

@ -93,11 +93,17 @@ grpc_proto_library(
name = "messages_proto",
srcs = ["messages.proto"],
has_services = False,
deps = [
"//src/proto/grpc/testing/xds/v3:orca_load_report_proto",
],
)
proto_library(
name = "messages_proto_descriptor",
srcs = ["messages.proto"],
deps = [
"//src/proto/grpc/testing/xds/v3:orca_load_report_proto_descriptor",
],
)
py_proto_library(
@ -188,7 +194,7 @@ genrule(
name = "messages_gen_proto_file",
srcs = ["messages.proto"],
outs = ["messages_gen.proto"],
cmd = "cp $< $@",
cmd = "sed '/orca_/d' $< > $@",
)
grpc_proto_library(

@ -17,6 +17,8 @@
syntax = "proto3";
import "src/proto/grpc/testing/xds/v3/orca_load_report.proto";
package grpc.testing;
// TODO(dgq): Go back to using well-known types once
@ -98,6 +100,9 @@ message SimpleRequest {
// Whether SimpleResponse should include grpclb_route_type.
bool fill_grpclb_route_type = 10;
// Orca report for this RPC
xds.data.orca.v3.OrcaLoadReport orca_per_rpc_report = 11;
}
// Unary response, as configured by the request.

@ -182,6 +182,11 @@ grpc_proto_library(
],
)
proto_library(
name = "orca_load_report_proto_descriptor",
srcs = ["orca_load_report.proto"],
)
grpc_proto_library(
name = "orca_service_proto",
srcs = [

@ -86,6 +86,7 @@ grpc_cc_library(
"//src/proto/grpc/testing:empty_proto",
"//src/proto/grpc/testing:messages_proto",
"//src/proto/grpc/testing:test_proto",
"//src/proto/grpc/testing/xds/v3:orca_load_report_proto",
"//test/cpp/util:test_config",
],
)
@ -105,6 +106,7 @@ grpc_cc_library(
],
language = "C++",
deps = [
":backend_metrics_lb_policy",
"//src/proto/grpc/testing:empty_proto",
"//src/proto/grpc/testing:messages_proto",
"//src/proto/grpc/testing:test_proto",
@ -425,3 +427,22 @@ grpc_cc_binary(
"//test/cpp/util:test_util",
],
)
grpc_cc_library(
name = "backend_metrics_lb_policy",
srcs = [
"backend_metrics_lb_policy.cc",
],
hdrs = [
"backend_metrics_lb_policy.h",
],
external_deps = [
],
language = "C++",
tags = ["nobuilder"],
deps = [
"//:grpc",
"//:grpc++",
"//src/proto/grpc/testing/xds/v3:orca_load_report_proto",
],
)

@ -0,0 +1,12 @@
# Running a test locally during development
To start a server during development:
1. Choose an available port number.
2. Start the server:
```
GRPC_VERBOSITY=DEBUG ibazel run --compilation_mode=dbg //test/cpp/interop:interop_server -- --port={port_number}
```
3. Start the client:
```
GRPC_VERBOSITY=DEBUG ibazel run --test_output=streamed //test/cpp/interop:interop_client -- --server_port={port_number} --test_case={test_case}
```

@ -0,0 +1,247 @@
//
//
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#include <grpc/support/port_platform.h>
#include "test/cpp/interop/backend_metrics_lb_policy.h"
#include "src/core/lib/iomgr/pollset_set.h"
namespace grpc {
namespace testing {
namespace {
using grpc_core::CoreConfiguration;
using grpc_core::LoadBalancingPolicy;
using grpc_core::MakeRefCounted;
using grpc_core::OrphanablePtr;
using grpc_core::RefCountedPtr;
constexpr absl::string_view kBackendMetricsLbPolicyName =
"test_backend_metrics_load_balancer";
constexpr absl::string_view kMetricsTrackerArgument = "orca_metrics_tracker";
LoadReportTracker::LoadReportEntry BackendMetricDataToOrcaLoadReport(
const grpc_core::BackendMetricData* backend_metric_data) {
if (backend_metric_data == nullptr) {
return absl::nullopt;
}
xds::data::orca::v3::OrcaLoadReport load_report;
load_report.set_cpu_utilization(backend_metric_data->cpu_utilization);
load_report.set_mem_utilization(backend_metric_data->mem_utilization);
load_report.set_rps_fractional(backend_metric_data->qps);
for (const auto& p : backend_metric_data->request_cost) {
std::string name(p.first);
(*load_report.mutable_request_cost())[name] = p.second;
}
for (const auto& p : backend_metric_data->utilization) {
std::string name(p.first);
(*load_report.mutable_utilization())[name] = p.second;
}
return load_report;
}
class BackendMetricsLbPolicy : public LoadBalancingPolicy {
public:
explicit BackendMetricsLbPolicy(Args args)
: LoadBalancingPolicy(std::move(args), /*initial_refcount=*/2) {
load_report_tracker_ =
channel_args().GetPointer<LoadReportTracker>(kMetricsTrackerArgument);
GPR_ASSERT(load_report_tracker_ != nullptr);
Args delegate_args;
delegate_args.work_serializer = work_serializer();
delegate_args.args = channel_args();
delegate_args.channel_control_helper =
std::make_unique<Helper>(RefCountedPtr<BackendMetricsLbPolicy>(this));
delegate_ =
CoreConfiguration::Get().lb_policy_registry().CreateLoadBalancingPolicy(
"pick_first", std::move(delegate_args));
grpc_pollset_set_add_pollset_set(delegate_->interested_parties(),
interested_parties());
}
~BackendMetricsLbPolicy() override = default;
absl::string_view name() const override {
return kBackendMetricsLbPolicyName;
}
absl::Status UpdateLocked(UpdateArgs args) override {
return delegate_->UpdateLocked(std::move(args));
}
void ExitIdleLocked() override { delegate_->ExitIdleLocked(); }
void ResetBackoffLocked() override { delegate_->ResetBackoffLocked(); }
private:
class Picker : public SubchannelPicker {
public:
Picker(RefCountedPtr<SubchannelPicker> delegate_picker,
LoadReportTracker* load_report_tracker)
: delegate_picker_(std::move(delegate_picker)),
load_report_tracker_(load_report_tracker) {}
PickResult Pick(PickArgs args) override {
// Do pick.
PickResult result = delegate_picker_->Pick(args);
// Intercept trailing metadata.
auto* complete_pick = absl::get_if<PickResult::Complete>(&result.result);
if (complete_pick != nullptr) {
complete_pick->subchannel_call_tracker =
std::make_unique<SubchannelCallTracker>(load_report_tracker_);
}
return result;
}
private:
RefCountedPtr<SubchannelPicker> delegate_picker_;
LoadReportTracker* load_report_tracker_;
};
class Helper : public ChannelControlHelper {
public:
explicit Helper(RefCountedPtr<BackendMetricsLbPolicy> parent)
: parent_(std::move(parent)) {}
RefCountedPtr<grpc_core::SubchannelInterface> CreateSubchannel(
grpc_core::ServerAddress address,
const grpc_core::ChannelArgs& args) override {
return parent_->channel_control_helper()->CreateSubchannel(
std::move(address), args);
}
void UpdateState(grpc_connectivity_state state, const absl::Status& status,
RefCountedPtr<SubchannelPicker> picker) override {
parent_->channel_control_helper()->UpdateState(
state, status,
MakeRefCounted<Picker>(std::move(picker),
parent_->load_report_tracker_));
}
void RequestReresolution() override {
parent_->channel_control_helper()->RequestReresolution();
}
absl::string_view GetAuthority() override {
return parent_->channel_control_helper()->GetAuthority();
}
grpc_event_engine::experimental::EventEngine* GetEventEngine() override {
return parent_->channel_control_helper()->GetEventEngine();
}
void AddTraceEvent(TraceSeverity severity,
absl::string_view message) override {
parent_->channel_control_helper()->AddTraceEvent(severity, message);
}
private:
RefCountedPtr<BackendMetricsLbPolicy> parent_;
};
class SubchannelCallTracker : public SubchannelCallTrackerInterface {
public:
explicit SubchannelCallTracker(LoadReportTracker* load_report_tracker)
: load_report_tracker_(load_report_tracker) {}
void Start() override {}
void Finish(FinishArgs args) override {
load_report_tracker_->RecordPerRpcLoadReport(
args.backend_metric_accessor->GetBackendMetricData());
}
private:
LoadReportTracker* load_report_tracker_;
};
void ShutdownLocked() override {
grpc_pollset_set_del_pollset_set(delegate_->interested_parties(),
interested_parties());
delegate_.reset();
}
OrphanablePtr<LoadBalancingPolicy> delegate_;
LoadReportTracker* load_report_tracker_;
};
class BackendMetricsLbPolicyFactory
: public grpc_core::LoadBalancingPolicyFactory {
private:
class BackendMetricsLbPolicyFactoryConfig
: public LoadBalancingPolicy::Config {
private:
absl::string_view name() const override {
return kBackendMetricsLbPolicyName;
}
};
absl::string_view name() const override {
return kBackendMetricsLbPolicyName;
}
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
LoadBalancingPolicy::Args args) const override {
return grpc_core::MakeOrphanable<BackendMetricsLbPolicy>(std::move(args));
}
absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
ParseLoadBalancingConfig(const grpc_core::Json& /*json*/) const override {
return MakeRefCounted<BackendMetricsLbPolicyFactoryConfig>();
}
};
} // namespace
void RegisterBackendMetricsLbPolicy(CoreConfiguration::Builder* builder) {
builder->lb_policy_registry()->RegisterLoadBalancingPolicyFactory(
std::make_unique<BackendMetricsLbPolicyFactory>());
}
void LoadReportTracker::RecordPerRpcLoadReport(
const grpc_core::BackendMetricData* backend_metric_data) {
absl::MutexLock lock(&per_rpc_load_reports_mu_);
per_rpc_load_reports_.emplace_back(
BackendMetricDataToOrcaLoadReport(backend_metric_data));
}
absl::optional<LoadReportTracker::LoadReportEntry>
LoadReportTracker::GetNextLoadReport() {
absl::MutexLock lock(&per_rpc_load_reports_mu_);
if (per_rpc_load_reports_.empty()) {
return absl::nullopt;
}
auto report = std::move(per_rpc_load_reports_.front());
per_rpc_load_reports_.pop_front();
return report;
}
void LoadReportTracker::ResetCollectedLoadReports() {
absl::MutexLock lock(&per_rpc_load_reports_mu_);
per_rpc_load_reports_.clear();
}
ChannelArguments LoadReportTracker::GetChannelArguments() {
ChannelArguments arguments;
arguments.SetPointer(std::string(kMetricsTrackerArgument), this);
return arguments;
}
} // namespace testing
} // namespace grpc

@ -0,0 +1,54 @@
//
//
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#ifndef GRPC_TEST_CPP_INTEROP_BACKEND_METRICS_LB_POLICY_H
#define GRPC_TEST_CPP_INTEROP_BACKEND_METRICS_LB_POLICY_H
#include <grpc/support/port_platform.h>
#include <grpcpp/support/channel_arguments.h>
#include "src/core/lib/config/core_configuration.h"
#include "src/proto/grpc/testing/xds/v3/orca_load_report.pb.h"
namespace grpc {
namespace testing {
class LoadReportTracker {
public:
// A load report, or nullopt if the call had no load report.
using LoadReportEntry = absl::optional<xds::data::orca::v3::OrcaLoadReport>;
ChannelArguments GetChannelArguments();
void ResetCollectedLoadReports();
void RecordPerRpcLoadReport(
const grpc_core::BackendMetricData* backend_metric_data);
// Returns the next load report, or nullopt if the queue is empty.
absl::optional<LoadReportEntry> GetNextLoadReport();
private:
std::deque<LoadReportEntry> per_rpc_load_reports_
ABSL_GUARDED_BY(per_rpc_load_reports_mu_);
absl::Mutex per_rpc_load_reports_mu_;
};
void RegisterBackendMetricsLbPolicy(
grpc_core::CoreConfiguration::Builder* builder);
} // namespace testing
} // namespace grpc
#endif // GRPC_TEST_CPP_INTEROP_BACKEND_METRICS_LB_POLICY_H

@ -26,6 +26,7 @@
#include <grpc/support/log.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/support/channel_arguments.h>
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/crash.h"
@ -68,6 +69,7 @@ ABSL_FLAG(
//"large_unary : single request and (large) response;\n"
//"long_lived_channel: sends large_unary rpcs over a long-lived channel;\n"
//"oauth2_auth_token: raw oauth2 access token auth;\n"
//"orca_per_rpc: custom LB policy receives per-query metric reports;\n"
//"per_rpc_creds: raw oauth2 access token on a single rpc;\n"
//"ping_pong : full-duplex streaming;\n"
//"response streaming;\n"
@ -124,6 +126,9 @@ ABSL_FLAG(
bool, log_metadata_and_status, false,
"If set to 'true', will print received initial and trailing metadata, "
"grpc-status and error message to the console, in a stable format.");
ABSL_FLAG(std::string, service_config_json, "",
"Disables service config lookups and sets the provided string as the "
"default service config");
using grpc::testing::CreateChannelForTestCase;
using grpc::testing::GetServiceAccountJsonKey;
@ -135,16 +140,18 @@ namespace {
// alphanumeric characters and dashes in keys, and any character but semicolons
// in values. Convert keys to lowercase. On failure, log an error and return
// false.
bool ParseAdditionalMetadataFlag(
const std::string& flag,
std::multimap<std::string, std::string>* additional_metadata) {
absl::StatusOr<std::multimap<std::string, std::string>>
ParseAdditionalMetadataFlag(const std::string& flag) {
std::multimap<std::string, std::string> additional_metadata;
if (flag.empty()) {
return additional_metadata;
}
size_t start_pos = 0;
while (start_pos < flag.length()) {
size_t colon_pos = flag.find(':', start_pos);
if (colon_pos == std::string::npos) {
gpr_log(GPR_ERROR,
return absl::InvalidArgumentError(
"Couldn't parse metadata flag: extra characters at end of flag");
return false;
}
size_t semicolon_pos = flag.find(';', colon_pos);
@ -157,11 +164,10 @@ bool ParseAdditionalMetadataFlag(
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (key.find_first_not_of(alphanum_and_hyphen) != std::string::npos) {
gpr_log(GPR_ERROR,
return absl::InvalidArgumentError(absl::StrCat(
"Couldn't parse metadata flag: key contains characters other "
"than alphanumeric and hyphens: %s",
key.c_str());
return false;
"than alphanumeric and hyphens: ",
key));
}
// Convert to lowercase.
@ -173,7 +179,7 @@ bool ParseAdditionalMetadataFlag(
gpr_log(GPR_INFO, "Adding additional metadata with key %s and value %s",
key.c_str(), value.c_str());
additional_metadata->insert({key, value});
additional_metadata.insert({key, value});
if (semicolon_pos == std::string::npos) {
break;
@ -182,7 +188,7 @@ bool ParseAdditionalMetadataFlag(
}
}
return true;
return additional_metadata;
}
} // namespace
@ -194,40 +200,36 @@ int main(int argc, char** argv) {
absl::GetFlag(FLAGS_test_case).c_str());
int ret = 0;
grpc::testing::ChannelCreationFunc channel_creation_func;
std::string test_case = absl::GetFlag(FLAGS_test_case);
if (absl::GetFlag(FLAGS_additional_metadata).empty()) {
channel_creation_func = [test_case]() {
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
factories;
if (absl::GetFlag(FLAGS_log_metadata_and_status)) {
factories.emplace_back(
new grpc::testing::MetadataAndStatusLoggerInterceptorFactory());
}
return CreateChannelForTestCase(test_case, std::move(factories));
};
} else {
std::multimap<std::string, std::string> additional_metadata;
if (!ParseAdditionalMetadataFlag(absl::GetFlag(FLAGS_additional_metadata),
&additional_metadata)) {
auto additional_metadata =
ParseAdditionalMetadataFlag(absl::GetFlag(FLAGS_additional_metadata));
if (!additional_metadata.ok()) {
gpr_log(GPR_ERROR, "%s",
std::string(additional_metadata.status().message()).c_str());
return 1;
}
channel_creation_func = [test_case, additional_metadata]() {
grpc::testing::ChannelCreationFunc channel_creation_func =
[test_case, &additional_metadata](grpc::ChannelArguments arguments) {
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
factories;
if (!additional_metadata->empty()) {
factories.emplace_back(
new grpc::testing::AdditionalMetadataInterceptorFactory(
additional_metadata));
*additional_metadata));
}
if (absl::GetFlag(FLAGS_log_metadata_and_status)) {
factories.emplace_back(
new grpc::testing::MetadataAndStatusLoggerInterceptorFactory());
}
return CreateChannelForTestCase(test_case, std::move(factories));
};
std::string service_config_json =
absl::GetFlag(FLAGS_service_config_json);
if (!service_config_json.empty()) {
arguments.SetServiceConfigJSON(service_config_json);
}
return CreateChannelForTestCase(test_case, std::move(factories),
arguments);
};
grpc::testing::InteropClient client(
channel_creation_func, true,
@ -267,6 +269,8 @@ int main(int argc, char** argv) {
std::bind(&grpc::testing::InteropClient::DoEmptyStream, &client);
actions["pick_first_unary"] =
std::bind(&grpc::testing::InteropClient::DoPickFirstUnary, &client);
actions["orca_per_rpc"] =
std::bind(&grpc::testing::InteropClient::DoOrcaPerRpc, &client);
if (absl::GetFlag(FLAGS_use_tls)) {
actions["compute_engine_creds"] =
std::bind(&grpc::testing::InteropClient::DoComputeEngineCreds, &client,

@ -40,17 +40,17 @@
#include "test/cpp/util/create_test_channel.h"
#include "test/cpp/util/test_credentials_provider.h"
ABSL_DECLARE_FLAG(bool, use_alts);
ABSL_DECLARE_FLAG(bool, use_tls);
ABSL_DECLARE_FLAG(std::string, custom_credentials_type);
ABSL_DECLARE_FLAG(bool, use_test_ca);
ABSL_DECLARE_FLAG(int32_t, server_port);
ABSL_DECLARE_FLAG(std::string, default_service_account);
ABSL_DECLARE_FLAG(std::string, oauth_scope);
ABSL_DECLARE_FLAG(std::string, service_account_key_file);
ABSL_DECLARE_FLAG(std::string, server_host);
ABSL_DECLARE_FLAG(std::string, server_host_override);
ABSL_DECLARE_FLAG(int32_t, server_port);
ABSL_DECLARE_FLAG(std::string, test_case);
ABSL_DECLARE_FLAG(std::string, default_service_account);
ABSL_DECLARE_FLAG(std::string, service_account_key_file);
ABSL_DECLARE_FLAG(std::string, oauth_scope);
ABSL_DECLARE_FLAG(bool, use_alts);
ABSL_DECLARE_FLAG(bool, use_test_ca);
ABSL_DECLARE_FLAG(bool, use_tls);
namespace grpc {
namespace testing {
@ -87,7 +87,8 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
const std::string& test_case,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
interceptor_creators,
ChannelArguments channel_args) {
std::string server_uri = absl::GetFlag(FLAGS_server_host);
int32_t port = absl::GetFlag(FLAGS_server_port);
if (port != 0) {
@ -113,7 +114,6 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
? nullptr
: AccessTokenCredentials(GetOauth2AccessToken());
} else if (test_case == "pick_first_unary") {
ChannelArguments channel_args;
// allow the LB policy to be configured with service config
channel_args.SetInt(GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION, 0);
return CreateTestChannel(
@ -126,18 +126,19 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
absl::GetFlag(FLAGS_use_alts)
? ALTS
: (absl::GetFlag(FLAGS_use_tls) ? TLS : INSECURE);
return CreateTestChannel(server_uri,
absl::GetFlag(FLAGS_server_host_override),
security_type, !absl::GetFlag(FLAGS_use_test_ca),
creds, std::move(interceptor_creators));
} else {
if (interceptor_creators.empty()) {
return CreateTestChannel(
server_uri, absl::GetFlag(FLAGS_custom_credentials_type), creds);
server_uri, absl::GetFlag(FLAGS_server_host_override), security_type,
!absl::GetFlag(FLAGS_use_test_ca), creds, channel_args,
std::move(interceptor_creators));
} else {
if (interceptor_creators.empty()) {
return CreateTestChannel(server_uri,
absl::GetFlag(FLAGS_custom_credentials_type),
creds, std::move(interceptor_creators));
absl::GetFlag(FLAGS_custom_credentials_type), "",
false, creds, channel_args);
} else {
return CreateTestChannel(
server_uri, absl::GetFlag(FLAGS_custom_credentials_type), creds,
std::move(interceptor_creators), channel_args);
}
}
}

@ -25,6 +25,7 @@
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/support/channel_arguments.h>
#include "src/core/lib/surface/call_test_only.h"
#include "src/core/lib/transport/transport.h"
@ -43,7 +44,8 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
const std::string& test_case,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators = {});
interceptor_creators = {},
ChannelArguments channel_args = ChannelArguments());
class InteropClientContextInspector {
public:

@ -37,11 +37,13 @@
#include <grpcpp/client_context.h>
#include <grpcpp/security/credentials.h>
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/proto/grpc/testing/empty.pb.h"
#include "src/proto/grpc/testing/messages.pb.h"
#include "src/proto/grpc/testing/test.grpc.pb.h"
#include "test/core/util/histogram.h"
#include "test/cpp/interop/backend_metrics_lb_policy.h"
#include "test/cpp/interop/client_helper.h"
namespace grpc {
@ -79,6 +81,56 @@ void UnaryCompressionChecks(const InteropClientContextInspector& inspector,
GPR_ASSERT(!(inspector.WasCompressed()));
}
}
void InitializeCustomLbPolicyIfNeeded() {
// Load balancing policy builder is global. For now, all instances of the
// LB policy will store data in the same collection. All interop_clients in
// the same process will also share the collection
// Realistically, we do not yet need synchronization as only a single test is
// running at a time.
static bool initialized = false;
if (!initialized) {
grpc_core::CoreConfiguration::RegisterBuilder(
[](grpc_core::CoreConfiguration::Builder* builder) {
RegisterBackendMetricsLbPolicy(builder);
});
initialized = true;
}
}
template <typename Map>
bool SameMaps(const std::string& path, const Map& expected, const Map& actual) {
if (expected.size() != actual.size()) {
gpr_log(GPR_ERROR, "Field %s does not match: expected %lu entries, got %lu",
path.c_str(), expected.size(), actual.size());
return false;
}
for (const auto& key_value : expected) {
auto it = actual.find(key_value.first);
if (it == actual.end()) {
gpr_log(GPR_ERROR, "In field %s, key %s was not found", path.c_str(),
key_value.first.c_str());
return false;
}
if (key_value.second != it->second) {
gpr_log(
GPR_ERROR, "In field %s, value %s mismatch: expected %f, actual: %f",
path.c_str(), key_value.first.c_str(), key_value.second, it->second);
return false;
}
}
return true;
}
void SameOrcaLoadReports(const xds::data::orca::v3::OrcaLoadReport& expected,
const xds::data::orca::v3::OrcaLoadReport& actual) {
GPR_ASSERT(expected.cpu_utilization() == actual.cpu_utilization());
GPR_ASSERT(expected.mem_utilization() == actual.mem_utilization());
GPR_ASSERT(
SameMaps("request_cost", expected.request_cost(), actual.request_cost()));
GPR_ASSERT(
SameMaps("utilization", expected.utilization(), actual.utilization()));
}
} // namespace
InteropClient::ServiceStub::ServiceStub(
@ -119,7 +171,13 @@ void InteropClient::ServiceStub::ResetChannel() {
InteropClient::InteropClient(ChannelCreationFunc channel_creation_func,
bool new_stub_every_test_case,
bool do_not_abort_on_transient_failures)
: serviceStub_(std::move(channel_creation_func), new_stub_every_test_case),
: serviceStub_(
[&]() {
InitializeCustomLbPolicyIfNeeded();
return channel_creation_func(
load_report_tracker_.GetChannelArguments());
},
new_stub_every_test_case),
do_not_abort_on_transient_failures_(do_not_abort_on_transient_failures) {}
bool InteropClient::AssertStatusOk(const Status& s,
@ -930,6 +988,30 @@ bool InteropClient::DoPickFirstUnary() {
return true;
}
bool InteropClient::DoOrcaPerRpc() {
load_report_tracker_.ResetCollectedLoadReports();
gpr_log(GPR_DEBUG, "testing orca per rpc");
SimpleRequest request;
SimpleResponse response;
ClientContext context;
auto orca_report = request.mutable_orca_per_rpc_report();
orca_report->set_cpu_utilization(0.8210);
orca_report->set_mem_utilization(0.5847);
orca_report->mutable_request_cost()->emplace("cost", 3456.32);
orca_report->mutable_utilization()->emplace("util", 0.30499);
auto status = serviceStub_.Get()->UnaryCall(&context, request, &response);
if (!AssertStatusOk(status, context.debug_error_string())) {
return false;
}
auto report = load_report_tracker_.GetNextLoadReport();
GPR_ASSERT(report.has_value());
GPR_ASSERT(report->has_value());
SameOrcaLoadReports(report->value(), *orca_report);
GPR_ASSERT(!load_report_tracker_.GetNextLoadReport().has_value());
gpr_log(GPR_DEBUG, "orca per rpc successfully finished");
return true;
}
bool InteropClient::DoCustomMetadata() {
const std::string kEchoInitialMetadataKey("x-grpc-test-echo-initial");
const std::string kInitialMetadataValue("test_initial_metadata_value");

@ -21,11 +21,14 @@
#include <memory>
#include "absl/types/optional.h"
#include <grpc/grpc.h>
#include <grpcpp/channel.h>
#include "src/proto/grpc/testing/messages.pb.h"
#include "src/proto/grpc/testing/test.grpc.pb.h"
#include "test/cpp/interop/backend_metrics_lb_policy.h"
namespace grpc {
namespace testing {
@ -35,14 +38,15 @@ typedef std::function<void(const InteropClientContextInspector&,
const SimpleRequest*, const SimpleResponse*)>
CheckerFn;
typedef std::function<std::shared_ptr<Channel>(void)> ChannelCreationFunc;
typedef std::function<std::shared_ptr<Channel>(ChannelArguments)>
ChannelCreationFunc;
class InteropClient {
public:
/// If new_stub_every_test_case is true, a new TestService::Stub object is
/// created for every test case
/// If do_not_abort_on_transient_failures is true, abort() is not called in
/// case of transient failures (like connection failures)
/// If do_not_abort_on_transient_failures is true, abort() is not called
/// in case of transient failures (like connection failures)
explicit InteropClient(ChannelCreationFunc channel_creation_func,
bool new_stub_every_test_case,
bool do_not_abort_on_transient_failures);
@ -73,6 +77,7 @@ class InteropClient {
bool DoUnimplementedService();
// all requests are sent to one server despite multiple servers are resolved
bool DoPickFirstUnary();
bool DoOrcaPerRpc();
// The following interop test are not yet part of the interop spec, and are
// not implemented cross-language. They are considered experimental for now,
@ -107,6 +112,7 @@ class InteropClient {
private:
class ServiceStub {
public:
typedef std::function<std::shared_ptr<Channel>()> ChannelCreationFunc;
// If new_stub_every_call = true, pointer to a new instance of
// TestServce::Stub is returned by Get() everytime it is called
ServiceStub(ChannelCreationFunc channel_creation_func,
@ -154,6 +160,8 @@ class InteropClient {
ServiceStub serviceStub_;
/// If true, abort() is not called for transient failures
bool do_not_abort_on_transient_failures_;
// Load Orca metrics captured by the custom LB policy.
LoadReportTracker load_report_tracker_;
};
} // namespace testing

@ -26,6 +26,8 @@
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpcpp/ext/call_metric_recorder.h>
#include <grpcpp/ext/server_metric_recorder.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
@ -36,6 +38,7 @@
#include "src/proto/grpc/testing/empty.pb.h"
#include "src/proto/grpc/testing/messages.pb.h"
#include "src/proto/grpc/testing/test.grpc.pb.h"
#include "src/proto/grpc/testing/xds/v3/orca_load_report.pb.h"
#include "test/cpp/interop/server_helper.h"
#include "test/cpp/util/test_config.h"
@ -136,6 +139,35 @@ bool CheckExpectedCompression(const ServerContext& context,
return true;
}
void RecordMetrics(ServerContext* context,
const xds::data::orca::v3::OrcaLoadReport& request_metrics) {
auto recorder = context->ExperimentalGetCallMetricRecorder();
// Do not record when zero since it indicates no test per-call report.
if (request_metrics.cpu_utilization() > 0) {
recorder->RecordCpuUtilizationMetric(request_metrics.cpu_utilization());
}
if (request_metrics.mem_utilization() > 0) {
recorder->RecordMemoryUtilizationMetric(request_metrics.mem_utilization());
}
if (request_metrics.rps_fractional() > 0) {
recorder->RecordQpsMetric(request_metrics.rps_fractional());
}
for (const auto& p : request_metrics.request_cost()) {
char* key = static_cast<char*>(
grpc_call_arena_alloc(context->c_call(), p.first.size() + 1));
strncpy(key, p.first.data(), p.first.size());
key[p.first.size()] = '\0';
recorder->RecordRequestCostMetric(key, p.second);
}
for (const auto& p : request_metrics.utilization()) {
char* key = static_cast<char*>(
grpc_call_arena_alloc(context->c_call(), p.first.size() + 1));
strncpy(key, p.first.data(), p.first.size());
key[p.first.size()] = '\0';
recorder->RecordUtilizationMetric(key, p.second);
}
}
class TestServiceImpl : public TestService::Service {
public:
Status EmptyCall(ServerContext* context,
@ -187,7 +219,9 @@ class TestServiceImpl : public TestService::Service {
static_cast<grpc::StatusCode>(request->response_status().code()),
request->response_status().message());
}
if (request->has_orca_per_rpc_report()) {
RecordMetrics(context, request->orca_per_rpc_report());
}
return Status::OK;
}
@ -360,6 +394,8 @@ void grpc::testing::interop::RunServer(
if (absl::GetFlag(FLAGS_max_send_message_size) >= 0) {
builder.SetMaxSendMessageSize(absl::GetFlag(FLAGS_max_send_message_size));
}
grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording(
nullptr);
std::unique_ptr<Server> server(builder.BuildAndStart());
gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str());

@ -209,7 +209,7 @@ int main(int argc, char** argv) {
grpc::testing::ChannelCreationFunc channel_creation_func;
std::string test_case = absl::GetFlag(FLAGS_test_case);
if (absl::GetFlag(FLAGS_additional_metadata).empty()) {
channel_creation_func = [test_case]() {
channel_creation_func = [test_case](auto arguments) {
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
factories;
@ -217,7 +217,8 @@ int main(int argc, char** argv) {
factories.emplace_back(
new grpc::testing::MetadataAndStatusLoggerInterceptorFactory());
}
return CreateChannelForTestCase(test_case, std::move(factories));
return CreateChannelForTestCase(test_case, std::move(factories),
arguments);
};
} else {
std::multimap<std::string, std::string> additional_metadata;
@ -226,7 +227,7 @@ int main(int argc, char** argv) {
return 1;
}
channel_creation_func = [test_case, additional_metadata]() {
channel_creation_func = [test_case, additional_metadata](auto arguments) {
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
factories;
@ -237,7 +238,8 @@ int main(int argc, char** argv) {
factories.emplace_back(
new grpc::testing::MetadataAndStatusLoggerInterceptorFactory());
}
return CreateChannelForTestCase(test_case, std::move(factories));
return CreateChannelForTestCase(test_case, std::move(factories),
arguments);
};
}

@ -88,7 +88,7 @@ int main(int argc, char** argv) {
std::vector<std::thread> threads;
for (size_t i = 0; i < uris.size(); i++) {
threads.push_back(std::thread([uris, creds, i, test_case]() {
auto channel_creation_func = [uris, creds, i]() {
auto channel_creation_func = [uris, creds, i](grpc::ChannelArguments) {
return grpc::CreateTestChannel(uris[i], creds[i],
nullptr /* call creds */);
};

@ -236,7 +236,18 @@ std::shared_ptr<Channel> CreateTestChannel(
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
ChannelArguments channel_args;
return CreateTestChannel(server, credential_type, creds,
std::move(interceptor_creators),
{} /* channel_args */);
}
std::shared_ptr<Channel> CreateTestChannel(
const std::string& server, const std::string& credential_type,
const std::shared_ptr<CallCredentials>& creds,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators,
ChannelArguments channel_args) {
MaybeSetCustomChannelArgs(&channel_args);
std::shared_ptr<ChannelCredentials> channel_creds =
testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,

@ -94,6 +94,14 @@ std::shared_ptr<Channel> CreateTestChannel(
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
std::shared_ptr<Channel> CreateTestChannel(
const std::string& server, const std::string& credential_type,
const std::shared_ptr<CallCredentials>& creds,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators,
ChannelArguments channel_args);
} // namespace grpc
#endif // GRPC_TEST_CPP_UTIL_CREATE_TEST_CHANNEL_H

Loading…
Cancel
Save