|
|
|
@ -37,6 +37,7 @@ |
|
|
|
|
#include <grpc/grpc.h> |
|
|
|
|
#include <grpc/support/json.h> |
|
|
|
|
|
|
|
|
|
#include "src/core/lib/channel/metrics.h" |
|
|
|
|
#include "src/core/lib/experiments/experiments.h" |
|
|
|
|
#include "src/core/lib/gprpp/debug_location.h" |
|
|
|
|
#include "src/core/lib/gprpp/orphanable.h" |
|
|
|
@ -48,6 +49,7 @@ |
|
|
|
|
#include "src/core/load_balancing/lb_policy.h" |
|
|
|
|
#include "src/core/resolver/endpoint_addresses.h" |
|
|
|
|
#include "test/core/client_channel/lb_policy/lb_policy_test_lib.h" |
|
|
|
|
#include "test/core/util/fake_stats_plugin.h" |
|
|
|
|
#include "test/core/util/test_config.h" |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
@ -1107,6 +1109,125 @@ TEST_F(PickFirstTest, ShufflingDisabled) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_F(PickFirstTest, MetricDefinitionDisconnections) { |
|
|
|
|
const auto* descriptor = |
|
|
|
|
GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName( |
|
|
|
|
"grpc.lb.pick_first.disconnections"); |
|
|
|
|
ASSERT_NE(descriptor, nullptr); |
|
|
|
|
EXPECT_EQ(descriptor->value_type, |
|
|
|
|
GlobalInstrumentsRegistry::ValueType::kUInt64); |
|
|
|
|
EXPECT_EQ(descriptor->instrument_type, |
|
|
|
|
GlobalInstrumentsRegistry::InstrumentType::kCounter); |
|
|
|
|
EXPECT_EQ(descriptor->enable_by_default, false); |
|
|
|
|
EXPECT_EQ(descriptor->name, "grpc.lb.pick_first.disconnections"); |
|
|
|
|
EXPECT_EQ(descriptor->unit, "{disconnection}"); |
|
|
|
|
EXPECT_THAT(descriptor->label_keys, ::testing::ElementsAre("grpc.target")); |
|
|
|
|
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_F(PickFirstTest, MetricDefinitionConnectionAttemptsSucceeded) { |
|
|
|
|
const auto* descriptor = |
|
|
|
|
GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName( |
|
|
|
|
"grpc.lb.pick_first.connection_attempts_succeeded"); |
|
|
|
|
ASSERT_NE(descriptor, nullptr); |
|
|
|
|
EXPECT_EQ(descriptor->value_type, |
|
|
|
|
GlobalInstrumentsRegistry::ValueType::kUInt64); |
|
|
|
|
EXPECT_EQ(descriptor->instrument_type, |
|
|
|
|
GlobalInstrumentsRegistry::InstrumentType::kCounter); |
|
|
|
|
EXPECT_EQ(descriptor->enable_by_default, false); |
|
|
|
|
EXPECT_EQ(descriptor->name, |
|
|
|
|
"grpc.lb.pick_first.connection_attempts_succeeded"); |
|
|
|
|
EXPECT_EQ(descriptor->unit, "{attempt}"); |
|
|
|
|
EXPECT_THAT(descriptor->label_keys, ::testing::ElementsAre("grpc.target")); |
|
|
|
|
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_F(PickFirstTest, MetricDefinitionConnectionAttemptsFailed) { |
|
|
|
|
const auto* descriptor = |
|
|
|
|
GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName( |
|
|
|
|
"grpc.lb.pick_first.connection_attempts_failed"); |
|
|
|
|
ASSERT_NE(descriptor, nullptr); |
|
|
|
|
EXPECT_EQ(descriptor->value_type, |
|
|
|
|
GlobalInstrumentsRegistry::ValueType::kUInt64); |
|
|
|
|
EXPECT_EQ(descriptor->instrument_type, |
|
|
|
|
GlobalInstrumentsRegistry::InstrumentType::kCounter); |
|
|
|
|
EXPECT_EQ(descriptor->enable_by_default, false); |
|
|
|
|
EXPECT_EQ(descriptor->name, "grpc.lb.pick_first.connection_attempts_failed"); |
|
|
|
|
EXPECT_EQ(descriptor->unit, "{attempt}"); |
|
|
|
|
EXPECT_THAT(descriptor->label_keys, ::testing::ElementsAre("grpc.target")); |
|
|
|
|
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_F(PickFirstTest, MetricValues) { |
|
|
|
|
const auto kDisconnections = |
|
|
|
|
GlobalInstrumentsRegistryTestPeer::FindUInt64CounterHandleByName( |
|
|
|
|
"grpc.lb.pick_first.disconnections") |
|
|
|
|
.value(); |
|
|
|
|
const auto kConnectionAttemptsSucceeded = |
|
|
|
|
GlobalInstrumentsRegistryTestPeer::FindUInt64CounterHandleByName( |
|
|
|
|
"grpc.lb.pick_first.connection_attempts_succeeded") |
|
|
|
|
.value(); |
|
|
|
|
const auto kConnectionAttemptsFailed = |
|
|
|
|
GlobalInstrumentsRegistryTestPeer::FindUInt64CounterHandleByName( |
|
|
|
|
"grpc.lb.pick_first.connection_attempts_failed") |
|
|
|
|
.value(); |
|
|
|
|
const absl::string_view kLabelValues[] = {target_}; |
|
|
|
|
auto stats_plugin = std::make_shared<FakeStatsPlugin>( |
|
|
|
|
nullptr, /*use_disabled_by_default_metrics=*/true); |
|
|
|
|
stats_plugin_group_.push_back(stats_plugin); |
|
|
|
|
// Send an update containing two addresses.
|
|
|
|
|
constexpr std::array<absl::string_view, 2> kAddresses = { |
|
|
|
|
"ipv4:127.0.0.1:443", "ipv4:127.0.0.1:444"}; |
|
|
|
|
absl::Status status = ApplyUpdate( |
|
|
|
|
BuildUpdate(kAddresses, MakePickFirstConfig(false)), lb_policy()); |
|
|
|
|
EXPECT_TRUE(status.ok()) << status; |
|
|
|
|
// LB policy should have created a subchannel for both addresses.
|
|
|
|
|
auto* subchannel = FindSubchannel(kAddresses[0]); |
|
|
|
|
ASSERT_NE(subchannel, nullptr); |
|
|
|
|
auto* subchannel2 = FindSubchannel(kAddresses[1]); |
|
|
|
|
ASSERT_NE(subchannel2, nullptr); |
|
|
|
|
// When the LB policy receives the first subchannel's initial connectivity
|
|
|
|
|
// state notification (IDLE), it will request a connection.
|
|
|
|
|
EXPECT_TRUE(subchannel->ConnectionRequested()); |
|
|
|
|
// This causes the subchannel to start to connect, so it reports
|
|
|
|
|
// CONNECTING.
|
|
|
|
|
subchannel->SetConnectivityState(GRPC_CHANNEL_CONNECTING); |
|
|
|
|
// LB policy should have reported CONNECTING state.
|
|
|
|
|
ExpectConnectingUpdate(); |
|
|
|
|
// The second subchannel should not be connecting.
|
|
|
|
|
EXPECT_FALSE(subchannel2->ConnectionRequested()); |
|
|
|
|
// The first subchannel's connection attempt fails.
|
|
|
|
|
subchannel->SetConnectivityState(GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
|
absl::UnavailableError("failed to connect")); |
|
|
|
|
EXPECT_THAT(stats_plugin->GetCounterValue(kConnectionAttemptsFailed, |
|
|
|
|
kLabelValues, {}), |
|
|
|
|
::testing::Optional(1)); |
|
|
|
|
// The LB policy will start a connection attempt on the second subchannel.
|
|
|
|
|
EXPECT_TRUE(subchannel2->ConnectionRequested()); |
|
|
|
|
// This causes the subchannel to start to connect, so it reports
|
|
|
|
|
// CONNECTING.
|
|
|
|
|
subchannel2->SetConnectivityState(GRPC_CHANNEL_CONNECTING); |
|
|
|
|
// The connection attempt succeeds.
|
|
|
|
|
subchannel2->SetConnectivityState(GRPC_CHANNEL_READY); |
|
|
|
|
EXPECT_THAT(stats_plugin->GetCounterValue(kConnectionAttemptsSucceeded, |
|
|
|
|
kLabelValues, {}), |
|
|
|
|
::testing::Optional(1)); |
|
|
|
|
// The LB policy will report CONNECTING some number of times (doesn't
|
|
|
|
|
// matter how many) and then report READY.
|
|
|
|
|
auto picker = WaitForConnected(); |
|
|
|
|
ASSERT_NE(picker, nullptr); |
|
|
|
|
// Picker should return the same subchannel repeatedly.
|
|
|
|
|
for (size_t i = 0; i < 3; ++i) { |
|
|
|
|
EXPECT_EQ(ExpectPickComplete(picker.get()), kAddresses[1]); |
|
|
|
|
} |
|
|
|
|
// Now the subchannel becomes disconnected.
|
|
|
|
|
subchannel2->SetConnectivityState(GRPC_CHANNEL_IDLE); |
|
|
|
|
ExpectReresolutionRequest(); |
|
|
|
|
ExpectState(GRPC_CHANNEL_IDLE); |
|
|
|
|
EXPECT_THAT(stats_plugin->GetCounterValue(kDisconnections, kLabelValues, {}), |
|
|
|
|
::testing::Optional(1)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class PickFirstHealthCheckingEnabledTest : public PickFirstTest { |
|
|
|
|
protected: |
|
|
|
|
PickFirstHealthCheckingEnabledTest() |
|
|
|
|