xds_fault_injection_end2end_test.cc
Go to the documentation of this file.
1 // Copyright 2017 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 #include <string>
17 #include <vector>
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
23 #include "src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h"
24 #include "src/proto/grpc/testing/xds/v3/fault.grpc.pb.h"
25 #include "src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.h"
26 #include "src/proto/grpc/testing/xds/v3/router.grpc.pb.h"
29 
30 namespace grpc {
31 namespace testing {
32 namespace {
33 
34 using ::envoy::config::cluster::v3::RoutingPriority;
35 using ::envoy::extensions::filters::http::fault::v3::HTTPFault;
36 using ::envoy::extensions::filters::network::http_connection_manager::v3::
37  HttpFilter;
38 using ::envoy::type::v3::FractionalPercent;
39 
40 class FaultInjectionTest : public XdsEnd2endTest {
41  public:
42  // Builds a Listener with Fault Injection filter config. If the http_fault
43  // is nullptr, then assign an empty filter config. This filter config is
44  // required to enable the fault injection features.
45  static Listener BuildListenerWithFaultInjection(
46  const HTTPFault& http_fault = HTTPFault()) {
47  HttpConnectionManager http_connection_manager;
48  Listener listener;
49  listener.set_name(kServerName);
50  HttpFilter* fault_filter = http_connection_manager.add_http_filters();
51  fault_filter->set_name("envoy.fault");
52  fault_filter->mutable_typed_config()->PackFrom(http_fault);
53  HttpFilter* router_filter = http_connection_manager.add_http_filters();
54  router_filter->set_name("router");
55  router_filter->mutable_typed_config()->PackFrom(
56  envoy::extensions::filters::http::router::v3::Router());
57  listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
58  http_connection_manager);
59  return listener;
60  }
61 
62  RouteConfiguration BuildRouteConfigurationWithFaultInjection(
63  const HTTPFault& http_fault) {
64  // Package as Any
65  google::protobuf::Any filter_config;
66  filter_config.PackFrom(http_fault);
67  // Plug into the RouteConfiguration
68  RouteConfiguration new_route_config = default_route_config_;
69  auto* config_map = new_route_config.mutable_virtual_hosts(0)
70  ->mutable_routes(0)
71  ->mutable_typed_per_filter_config();
72  (*config_map)["envoy.fault"] = std::move(filter_config);
73  return new_route_config;
74  }
75 
76  void SetFilterConfig(HTTPFault& http_fault) {
77  switch (GetParam().filter_config_setup()) {
78  case XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute: {
79  Listener listener = BuildListenerWithFaultInjection();
80  RouteConfiguration route =
81  BuildRouteConfigurationWithFaultInjection(http_fault);
82  SetListenerAndRouteConfiguration(balancer_.get(), listener, route);
83  break;
84  }
85  case XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInListener: {
86  Listener listener = BuildListenerWithFaultInjection(http_fault);
87  SetListenerAndRouteConfiguration(balancer_.get(), listener,
88  default_route_config_);
89  }
90  };
91  }
92 };
93 
94 // Run with all combinations of RDS disabled/enabled and the HTTP filter
95 // config in the Listener vs. in the Route.
97  XdsTest, FaultInjectionTest,
99  XdsTestType(), XdsTestType().set_enable_rds_testing(),
100  XdsTestType().set_filter_config_setup(
101  XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute),
102  XdsTestType().set_enable_rds_testing().set_filter_config_setup(
103  XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute)),
105 
106 // Test to ensure the most basic fault injection config works.
107 TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysAbort) {
108  const uint32_t kAbortPercentagePerHundred = 100;
109  // Construct the fault injection filter config
110  HTTPFault http_fault;
111  auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
112  abort_percentage->set_numerator(kAbortPercentagePerHundred);
113  abort_percentage->set_denominator(FractionalPercent::HUNDRED);
114  http_fault.mutable_abort()->set_grpc_status(
115  static_cast<uint32_t>(StatusCode::ABORTED));
116  // Config fault injection via different setup
117  SetFilterConfig(http_fault);
118  // Fire several RPCs, and expect all of them to be aborted.
119  for (size_t i = 0; i < 5; ++i) {
120  CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::ABORTED, "Fault injected",
121  RpcOptions().set_wait_for_ready(true));
122  }
123 }
124 
125 // Without the listener config, the fault injection won't be enabled.
126 TEST_P(FaultInjectionTest, XdsFaultInjectionWithoutListenerFilter) {
127  CreateAndStartBackends(1);
128  const uint32_t kAbortPercentagePerHundred = 100;
129  // Create an EDS resource
130  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
131  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
132  // Construct the fault injection filter config
133  HTTPFault http_fault;
134  auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
135  abort_percentage->set_numerator(kAbortPercentagePerHundred);
136  abort_percentage->set_denominator(FractionalPercent::HUNDRED);
137  http_fault.mutable_abort()->set_grpc_status(
138  static_cast<uint32_t>(StatusCode::ABORTED));
139  // Turn on fault injection
140  RouteConfiguration route =
141  BuildRouteConfigurationWithFaultInjection(http_fault);
142  SetListenerAndRouteConfiguration(balancer_.get(), default_listener_, route);
143  // Fire several RPCs, and expect all of them to be pass.
144  CheckRpcSendOk(DEBUG_LOCATION, 5, RpcOptions().set_wait_for_ready(true));
145 }
146 
147 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbort) {
148  CreateAndStartBackends(1);
149  const uint32_t kAbortPercentagePerHundred = 50;
150  const double kAbortRate = kAbortPercentagePerHundred / 100.0;
151  const double kErrorTolerance = 0.05;
152  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
153  // Create an EDS resource
154  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
155  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
156  // Construct the fault injection filter config
157  HTTPFault http_fault;
158  auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
159  abort_percentage->set_numerator(kAbortPercentagePerHundred);
160  abort_percentage->set_denominator(FractionalPercent::HUNDRED);
161  http_fault.mutable_abort()->set_grpc_status(
162  static_cast<uint32_t>(StatusCode::ABORTED));
163  // Config fault injection via different setup
164  SetFilterConfig(http_fault);
165  // Send kNumRpcs RPCs and count the aborts.
166  size_t num_aborted = SendRpcsAndCountFailuresWithMessage(
167  DEBUG_LOCATION, kNumRpcs, StatusCode::ABORTED, "Fault injected");
168  // The abort rate should be roughly equal to the expectation.
169  const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
170  EXPECT_THAT(seen_abort_rate,
171  ::testing::DoubleNear(kAbortRate, kErrorTolerance));
172 }
173 
174 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbortViaHeaders) {
175  CreateAndStartBackends(1);
176  const uint32_t kAbortPercentageCap = 100;
177  const uint32_t kAbortPercentage = 50;
178  const double kAbortRate = kAbortPercentage / 100.0;
179  const double kErrorTolerance = 0.05;
180  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
181  // Create an EDS resource
182  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
183  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
184  // Construct the fault injection filter config
185  HTTPFault http_fault;
186  http_fault.mutable_abort()->mutable_header_abort();
187  http_fault.mutable_abort()->mutable_percentage()->set_numerator(
188  kAbortPercentageCap);
189  // Config fault injection via different setup
190  SetFilterConfig(http_fault);
191  // Send kNumRpcs RPCs and count the aborts.
192  std::vector<std::pair<std::string, std::string>> metadata = {
193  {"x-envoy-fault-abort-grpc-request", "10"},
194  {"x-envoy-fault-abort-percentage", std::to_string(kAbortPercentage)},
195  };
196  size_t num_aborted = SendRpcsAndCountFailuresWithMessage(
197  DEBUG_LOCATION, kNumRpcs, StatusCode::ABORTED, "Fault injected",
198  RpcOptions().set_metadata(metadata));
199  // The abort rate should be roughly equal to the expectation.
200  const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
201  EXPECT_THAT(seen_abort_rate,
202  ::testing::DoubleNear(kAbortRate, kErrorTolerance));
203 }
204 
205 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelay) {
206  CreateAndStartBackends(1);
207  const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 3000;
208  const uint32_t kFixedDelaySeconds = 100;
209  const uint32_t kDelayPercentagePerHundred = 50;
210  const double kDelayRate = kDelayPercentagePerHundred / 100.0;
211  const double kErrorTolerance = 0.05;
212  const size_t kNumRpcs = ComputeIdealNumRpcs(kDelayRate, kErrorTolerance);
213  const size_t kMaxConcurrentRequests = kNumRpcs;
214  // Create an EDS resource
215  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
216  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
217  // Loosen the max concurrent request limit
218  Cluster cluster = default_cluster_;
219  auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
220  threshold->set_priority(RoutingPriority::DEFAULT);
221  threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
222  balancer_->ads_service()->SetCdsResource(cluster);
223  // Construct the fault injection filter config
224  HTTPFault http_fault;
225  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
226  delay_percentage->set_numerator(kDelayPercentagePerHundred);
227  delay_percentage->set_denominator(FractionalPercent::HUNDRED);
228  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
229  fixed_delay->set_seconds(kFixedDelaySeconds);
230  // Config fault injection via different setup
231  SetFilterConfig(http_fault);
232  // Send kNumRpcs RPCs and count the delays.
233  RpcOptions rpc_options = RpcOptions()
234  .set_timeout_ms(kRpcTimeoutMilliseconds)
235  .set_skip_cancelled_check(true);
236  std::vector<ConcurrentRpc> rpcs =
237  SendConcurrentRpcs(DEBUG_LOCATION, stub_.get(), kNumRpcs, rpc_options);
238  size_t num_delayed = 0;
239  for (auto& rpc : rpcs) {
240  if (rpc.status.error_code() == StatusCode::OK) continue;
241  EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
242  ++num_delayed;
243  }
244  // The delay rate should be roughly equal to the expectation.
245  const double seen_delay_rate = static_cast<double>(num_delayed) / kNumRpcs;
246  EXPECT_THAT(seen_delay_rate,
247  ::testing::DoubleNear(kDelayRate, kErrorTolerance));
248 }
249 
250 TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelayViaHeaders) {
251  CreateAndStartBackends(1);
252  const uint32_t kFixedDelayMilliseconds = 100000;
253  const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 3000;
254  const uint32_t kDelayPercentageCap = 100;
255  const uint32_t kDelayPercentage = 50;
256  const double kDelayRate = kDelayPercentage / 100.0;
257  const double kErrorTolerance = 0.05;
258  const size_t kNumRpcs = ComputeIdealNumRpcs(kDelayRate, kErrorTolerance);
259  const size_t kMaxConcurrentRequests = kNumRpcs;
260  // Create an EDS resource
261  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
262  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
263  // Loosen the max concurrent request limit
264  Cluster cluster = default_cluster_;
265  auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
266  threshold->set_priority(RoutingPriority::DEFAULT);
267  threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
268  balancer_->ads_service()->SetCdsResource(cluster);
269  // Construct the fault injection filter config
270  HTTPFault http_fault;
271  http_fault.mutable_delay()->mutable_header_delay();
272  http_fault.mutable_delay()->mutable_percentage()->set_numerator(
273  kDelayPercentageCap);
274  // Config fault injection via different setup
275  SetFilterConfig(http_fault);
276  // Send kNumRpcs RPCs and count the delays.
277  std::vector<std::pair<std::string, std::string>> metadata = {
278  {"x-envoy-fault-delay-request", std::to_string(kFixedDelayMilliseconds)},
279  {"x-envoy-fault-delay-request-percentage",
280  std::to_string(kDelayPercentage)},
281  };
282  RpcOptions rpc_options = RpcOptions()
283  .set_metadata(metadata)
284  .set_timeout_ms(kRpcTimeoutMilliseconds)
285  .set_skip_cancelled_check(true);
286  std::vector<ConcurrentRpc> rpcs =
287  SendConcurrentRpcs(DEBUG_LOCATION, stub_.get(), kNumRpcs, rpc_options);
288  size_t num_delayed = 0;
289  for (auto& rpc : rpcs) {
290  if (rpc.status.error_code() == StatusCode::OK) continue;
291  EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
292  ++num_delayed;
293  }
294  // The delay rate should be roughly equal to the expectation.
295  const double seen_delay_rate = static_cast<double>(num_delayed) / kNumRpcs;
296  EXPECT_THAT(seen_delay_rate,
297  ::testing::DoubleNear(kDelayRate, kErrorTolerance));
298 }
299 
300 TEST_P(FaultInjectionTest, XdsFaultInjectionAbortAfterDelayForStreamCall) {
301  CreateAndStartBackends(1);
302  const uint32_t kFixedDelaySeconds = 1;
303  const uint32_t kRpcTimeoutMilliseconds = 100 * 1000; // 100s should not reach
304  // Create an EDS resource
305  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
306  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
307  // Construct the fault injection filter config
308  HTTPFault http_fault;
309  auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
310  abort_percentage->set_numerator(100); // Always inject ABORT!
311  abort_percentage->set_denominator(FractionalPercent::HUNDRED);
312  http_fault.mutable_abort()->set_grpc_status(
313  static_cast<uint32_t>(StatusCode::ABORTED));
314  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
315  delay_percentage->set_numerator(100); // Always inject DELAY!
316  delay_percentage->set_denominator(FractionalPercent::HUNDRED);
317  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
318  fixed_delay->set_seconds(kFixedDelaySeconds);
319  // Config fault injection via different setup
320  SetFilterConfig(http_fault);
321  // Send a stream RPC and check its status code
322  ClientContext context;
324  grpc_timeout_milliseconds_to_deadline(kRpcTimeoutMilliseconds));
325  auto stream = stub_->BidiStream(&context);
326  stream->WritesDone();
327  auto status = stream->Finish();
328  EXPECT_EQ(StatusCode::ABORTED, status.error_code())
329  << status.error_message() << ", " << status.error_details() << ", "
331 }
332 
333 TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysDelayPercentageAbort) {
334  CreateAndStartBackends(1);
335  const uint32_t kAbortPercentagePerHundred = 50;
336  const double kAbortRate = kAbortPercentagePerHundred / 100.0;
337  const uint32_t kFixedDelaySeconds = 1;
338  const uint32_t kRpcTimeoutMilliseconds = 100 * 1000; // 100s should not reach
339  const uint32_t kConnectionTimeoutMilliseconds =
340  10 * 1000; // 10s should not reach
341  const double kErrorTolerance = 0.05;
342  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
343  const size_t kMaxConcurrentRequests = kNumRpcs;
344  // Create an EDS resource
345  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
346  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
347  // Loosen the max concurrent request limit
348  Cluster cluster = default_cluster_;
349  auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
350  threshold->set_priority(RoutingPriority::DEFAULT);
351  threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
352  balancer_->ads_service()->SetCdsResource(cluster);
353  // Construct the fault injection filter config
354  HTTPFault http_fault;
355  auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
356  abort_percentage->set_numerator(kAbortPercentagePerHundred);
357  abort_percentage->set_denominator(FractionalPercent::HUNDRED);
358  http_fault.mutable_abort()->set_grpc_status(
359  static_cast<uint32_t>(StatusCode::ABORTED));
360  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
361  delay_percentage->set_numerator(1000000); // Always inject DELAY!
362  delay_percentage->set_denominator(FractionalPercent::MILLION);
363  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
364  fixed_delay->set_seconds(kFixedDelaySeconds);
365  // Config fault injection via different setup
366  SetFilterConfig(http_fault);
367  // Allow the channel to connect to one backends, so the herd of queued RPCs
368  // won't be executed on the same ExecCtx object and using the cached Now()
369  // value, which causes millisecond level delay error.
370  channel_->WaitForConnected(
371  grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds));
372  // Send kNumRpcs RPCs and count the aborts.
373  int num_aborted = 0;
374  RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMilliseconds);
375  std::vector<ConcurrentRpc> rpcs =
376  SendConcurrentRpcs(DEBUG_LOCATION, stub_.get(), kNumRpcs, rpc_options);
377  for (auto& rpc : rpcs) {
378  EXPECT_GE(rpc.elapsed_time,
379  grpc_core::Duration::Seconds(kFixedDelaySeconds));
380  if (rpc.status.error_code() == StatusCode::OK) continue;
381  EXPECT_EQ("Fault injected", rpc.status.error_message());
382  ++num_aborted;
383  }
384  // The abort rate should be roughly equal to the expectation.
385  const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
386  EXPECT_THAT(seen_abort_rate,
387  ::testing::DoubleNear(kAbortRate, kErrorTolerance));
388 }
389 
390 // This test and the above test apply different denominators to delay and
391 // abort. This ensures that we are using the right denominator for each
392 // injected fault in our code.
393 TEST_P(FaultInjectionTest,
394  XdsFaultInjectionAlwaysDelayPercentageAbortSwitchDenominator) {
395  CreateAndStartBackends(1);
396  const uint32_t kAbortPercentagePerMillion = 500000;
397  const double kAbortRate = kAbortPercentagePerMillion / 1000000.0;
398  const uint32_t kFixedDelaySeconds = 1; // 1s
399  const uint32_t kRpcTimeoutMilliseconds = 100 * 1000; // 100s should not reach
400  const uint32_t kConnectionTimeoutMilliseconds =
401  10 * 1000; // 10s should not reach
402  const double kErrorTolerance = 0.05;
403  const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
404  const size_t kMaxConcurrentRequests = kNumRpcs;
405  // Create an EDS resource
406  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
407  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
408  // Loosen the max concurrent request limit
409  Cluster cluster = default_cluster_;
410  auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
411  threshold->set_priority(RoutingPriority::DEFAULT);
412  threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
413  balancer_->ads_service()->SetCdsResource(cluster);
414  // Construct the fault injection filter config
415  HTTPFault http_fault;
416  auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
417  abort_percentage->set_numerator(kAbortPercentagePerMillion);
418  abort_percentage->set_denominator(FractionalPercent::MILLION);
419  http_fault.mutable_abort()->set_grpc_status(
420  static_cast<uint32_t>(StatusCode::ABORTED));
421  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
422  delay_percentage->set_numerator(100); // Always inject DELAY!
423  delay_percentage->set_denominator(FractionalPercent::HUNDRED);
424  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
425  fixed_delay->set_seconds(kFixedDelaySeconds);
426  // Config fault injection via different setup
427  SetFilterConfig(http_fault);
428  // Allow the channel to connect to one backends, so the herd of queued RPCs
429  // won't be executed on the same ExecCtx object and using the cached Now()
430  // value, which causes millisecond level delay error.
431  channel_->WaitForConnected(
432  grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds));
433  // Send kNumRpcs RPCs and count the aborts.
434  int num_aborted = 0;
435  RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMilliseconds);
436  std::vector<ConcurrentRpc> rpcs =
437  SendConcurrentRpcs(DEBUG_LOCATION, stub_.get(), kNumRpcs, rpc_options);
438  for (auto& rpc : rpcs) {
439  EXPECT_GE(rpc.elapsed_time,
440  grpc_core::Duration::Seconds(kFixedDelaySeconds));
441  if (rpc.status.error_code() == StatusCode::OK) continue;
442  EXPECT_EQ("Fault injected", rpc.status.error_message());
443  ++num_aborted;
444  }
445  // The abort rate should be roughly equal to the expectation.
446  const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
447  EXPECT_THAT(seen_abort_rate,
448  ::testing::DoubleNear(kAbortRate, kErrorTolerance));
449 }
450 
451 TEST_P(FaultInjectionTest, XdsFaultInjectionMaxFault) {
452  CreateAndStartBackends(1);
453  const uint32_t kMaxFault = 10;
454  const uint32_t kNumRpcs = 30; // kNumRpcs should be bigger than kMaxFault
455  const uint32_t kRpcTimeoutMs = 4000; // 4 seconds
456  const uint32_t kLongDelaySeconds = 100; // 100 seconds
457  const uint32_t kAlwaysDelayPercentage = 100;
458  // Create an EDS resource
459  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
460  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
461  // Construct the fault injection filter config
462  HTTPFault http_fault;
463  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
464  delay_percentage->set_numerator(
465  kAlwaysDelayPercentage); // Always inject DELAY!
466  delay_percentage->set_denominator(FractionalPercent::HUNDRED);
467  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
468  fixed_delay->set_seconds(kLongDelaySeconds);
469  http_fault.mutable_max_active_faults()->set_value(kMaxFault);
470  // Config fault injection via different setup
471  SetFilterConfig(http_fault);
472  // Sends a batch of long running RPCs with long timeout to consume all
473  // active faults quota.
474  int num_delayed = 0;
475  RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMs);
476  std::vector<ConcurrentRpc> rpcs =
477  SendConcurrentRpcs(DEBUG_LOCATION, stub_.get(), kNumRpcs, rpc_options);
478  for (auto& rpc : rpcs) {
479  if (rpc.status.error_code() == StatusCode::OK) continue;
480  EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
481  ++num_delayed;
482  }
483  // Only kMaxFault number of RPC should be fault injected.
484  EXPECT_EQ(kMaxFault, num_delayed);
485  // Conduct one more round of RPCs after previous calls are finished. The goal
486  // is to validate if the max fault counter is restored to zero.
487  num_delayed = 0;
488  rpcs = SendConcurrentRpcs(DEBUG_LOCATION, stub_.get(), kNumRpcs, rpc_options);
489  for (auto& rpc : rpcs) {
490  if (rpc.status.error_code() == StatusCode::OK) continue;
491  EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
492  ++num_delayed;
493  }
494  // Only kMaxFault number of RPC should be fault injected. If the max fault
495  // isn't restored to zero, none of the new RPCs will be fault injected.
496  EXPECT_EQ(kMaxFault, num_delayed);
497 }
498 
499 TEST_P(FaultInjectionTest, XdsFaultInjectionBidiStreamDelayOk) {
500  CreateAndStartBackends(1);
501  // kRpcTimeoutMilliseconds is 10s should never be reached.
502  const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 10000;
503  const uint32_t kFixedDelaySeconds = 1;
504  const uint32_t kDelayPercentagePerHundred = 100;
505  // Create an EDS resource
506  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
507  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
508  // Construct the fault injection filter config
509  HTTPFault http_fault;
510  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
511  delay_percentage->set_numerator(kDelayPercentagePerHundred);
512  delay_percentage->set_denominator(FractionalPercent::HUNDRED);
513  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
514  fixed_delay->set_seconds(kFixedDelaySeconds);
515  // Config fault injection via different setup
516  SetFilterConfig(http_fault);
517  ClientContext context;
519  grpc_timeout_milliseconds_to_deadline(kRpcTimeoutMilliseconds));
520  auto stream = stub_->BidiStream(&context);
521  stream->WritesDone();
522  auto status = stream->Finish();
523  EXPECT_TRUE(status.ok()) << status.error_message() << ", "
524  << status.error_details() << ", "
526 }
527 
528 // This case catches a bug in the retry code that was triggered by a bad
529 // interaction with the FI code. See https://github.com/grpc/grpc/pull/27217
530 // for description.
531 TEST_P(FaultInjectionTest, XdsFaultInjectionBidiStreamDelayError) {
532  CreateAndStartBackends(1);
533  const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 500;
534  const uint32_t kFixedDelaySeconds = 100;
535  const uint32_t kDelayPercentagePerHundred = 100;
536  // Create an EDS resource
537  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
538  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
539  // Construct the fault injection filter config
540  HTTPFault http_fault;
541  auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
542  delay_percentage->set_numerator(kDelayPercentagePerHundred);
543  delay_percentage->set_denominator(FractionalPercent::HUNDRED);
544  auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
545  fixed_delay->set_seconds(kFixedDelaySeconds);
546  // Config fault injection via different setup
547  SetFilterConfig(http_fault);
548  ClientContext context;
550  grpc_timeout_milliseconds_to_deadline(kRpcTimeoutMilliseconds));
551  auto stream = stub_->BidiStream(&context);
552  stream->WritesDone();
553  auto status = stream->Finish();
555  << status.error_message() << ", " << status.error_details() << ", "
557 }
558 
559 } // namespace
560 } // namespace testing
561 } // namespace grpc
562 
563 int main(int argc, char** argv) {
564  grpc::testing::TestEnvironment env(&argc, argv);
565  ::testing::InitGoogleTest(&argc, argv);
566  // Make the backup poller poll very frequently in order to pick up
567  // updates from all the subchannels's FDs.
568  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
569 #if TARGET_OS_IPHONE
570  // Workaround Apple CFStream bug
571  gpr_setenv("grpc_cfstream", "0");
572 #endif
573  grpc_init();
574  const auto result = RUN_ALL_TESTS();
575  grpc_shutdown();
576  return result;
577 }
grpc::EXPECT_THAT
EXPECT_THAT(status.error_message(), ::testing::HasSubstr("subject_token_type"))
Any
struct Any Any
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:633
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
testing
Definition: aws_request_signer_test.cc:25
grpc::status
auto status
Definition: cpp/client/credentials_test.cc:200
stub_
std::unique_ptr< grpc::testing::EchoTestService::Stub > stub_
Definition: client_channel_stress_test.cc:331
generate.env
env
Definition: generate.py:37
metadata
Definition: cq_verifier.cc:48
grpc
Definition: grpcpp/alarm.h:33
route
XdsRouteConfigResource::Route route
Definition: xds_resolver.cc:337
testing::DoubleNear
internal::FloatingEqMatcher< double > DoubleNear(double rhs, double max_abs_error)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8647
Listener
Definition: transport_common.h:31
grpc.StatusCode.ABORTED
tuple ABORTED
Definition: src/python/grpcio/grpc/__init__.py:274
grpc::ClientContext::set_deadline
void set_deadline(const T &deadline)
Definition: grpcpp/impl/codegen/client_context.h:274
main
int main(int argc, char **argv)
Definition: xds_fault_injection_end2end_test.cc:563
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
grpc.StatusCode.OK
tuple OK
Definition: src/python/grpcio/grpc/__init__.py:260
cluster
absl::string_view cluster
Definition: xds_resolver.cc:331
grpc_timeout_milliseconds_to_deadline
gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms)
Definition: test/core/util/test_config.cc:89
grpc_test_slowdown_factor
int64_t grpc_test_slowdown_factor()
Definition: test/core/util/test_config.cc:76
channel_
RefCountedPtr< Channel > channel_
Definition: channel_connectivity.cc:209
xds_end2end_test_lib.h
grpc::testing::INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(HistogramTestCases, HistogramTest, ::testing::Range< int >(0, GRPC_STATS_HISTOGRAM_COUNT))
backup_poller.h
kNumRpcs
const int kNumRpcs
Definition: thread_stress_test.cc:50
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
GPR_GLOBAL_CONFIG_SET
#define GPR_GLOBAL_CONFIG_SET(name, value)
Definition: global_config_generic.h:26
test_config.h
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
testing::Values
internal::ValueArray< T... > Values(T... v)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:335
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
grpc_core::Duration::Seconds
static constexpr Duration Seconds(int64_t seconds)
Definition: src/core/lib/gprpp/time.h:151
grpc::testing::EXPECT_EQ
EXPECT_EQ(options.token_exchange_service_uri, "https://foo/exchange")
Any::PackFrom
void PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message &message)
Definition: bloaty/third_party/protobuf/src/google/protobuf/any.pb.cc:88
EXPECT_GE
#define EXPECT_GE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2034
context
grpc::ClientContext context
Definition: istio_echo_server_lib.cc:61
grpc::testing::TEST_P
TEST_P(HistogramTest, IncHistogram)
Definition: stats_test.cc:87
grpc::testing::EXPECT_TRUE
EXPECT_TRUE(grpc::experimental::StsCredentialsOptionsFromJson(minimum_valid_json, &options) .ok())
grpc_init
GRPCAPI void grpc_init(void)
Definition: init.cc:146
grpc.StatusCode.DEADLINE_EXCEEDED
tuple DEADLINE_EXCEEDED
Definition: src/python/grpcio/grpc/__init__.py:264
grpc::ClientContext::debug_error_string
std::string debug_error_string() const
Definition: grpcpp/impl/codegen/client_context.h:414
to_string
static bool to_string(zval *from)
Definition: protobuf/php/ext/google/protobuf/convert.c:333
grpc_shutdown
GRPCAPI void grpc_shutdown(void)
Definition: init.cc:209
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
grpc::testing::XdsTestType::Name
static std::string Name(const ::testing::TestParamInfo< XdsTestType > &info)
Definition: xds_end2end_test_lib.h:143
gpr_setenv
void gpr_setenv(const char *name, const char *value)
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:58