16 from typing
import Tuple
18 from absl
import flags
19 from absl.testing
import absltest
22 from framework
import xds_url_map_testcase
27 HostRule = xds_url_map_testcase.HostRule
28 PathMatcher = xds_url_map_testcase.PathMatcher
29 GcpResourceManager = xds_url_map_testcase.GcpResourceManager
30 DumpedXdsConfig = xds_url_map_testcase.DumpedXdsConfig
31 RpcTypeUnaryCall = xds_url_map_testcase.RpcTypeUnaryCall
32 RpcTypeEmptyCall = xds_url_map_testcase.RpcTypeEmptyCall
33 XdsTestClient = client_app.XdsTestClient
34 ExpectedResult = xds_url_map_testcase.ExpectedResult
37 logger = logging.getLogger(__name__)
38 flags.adopt_module_key_flags(xds_url_map_testcase)
43 _LENGTH_OF_RPC_SENDING_SEC = 16
48 _NON_RANDOM_ERROR_TOLERANCE = 0.01
53 _ERROR_TOLERANCE = 0.2
54 _DELAY_CASE_APPLICATION_TIMEOUT_SEC = 1
55 _BACKLOG_WAIT_TIME_SEC = 20
59 delay_percentage: int = 0):
63 'fullPathMatch':
'/grpc.testing.TestService/UnaryCall'
67 'faultInjectionPolicy': {
70 'percentage': abort_percentage,
76 'percentage': delay_percentage,
84 timeout: int = _BACKLOG_WAIT_TIME_SEC):
85 """ Wait until the completed RPC is close to started RPC.
87 For delay injected test cases, there might be a backlog of RPCs due to slow
88 initialization of the client. E.g., if initialization took 20s and qps is
89 25, then there will be a backlog of 500 RPCs. In normal test cases, this is
90 fine, because RPCs will fail immediately. But for delay injected test cases,
91 the RPC might linger much longer and affect the stability of test results.
93 logger.info(
'Waiting for RPC backlog to clear for %d seconds', timeout)
94 deadline = time.time() + timeout
95 while time.time() < deadline:
96 stats = test_client.get_load_balancer_accumulated_stats()
98 for rpc_type
in [RpcTypeUnaryCall, RpcTypeEmptyCall]:
99 started = stats.num_rpcs_started_by_method.get(rpc_type, 0)
100 completed = stats.num_rpcs_succeeded_by_method.get(
101 rpc_type, 0) + stats.num_rpcs_failed_by_method.get(rpc_type, 0)
104 if abs(started - completed) > xds_url_map_testcase.QPS.value * 1.1:
106 'RPC backlog exist: rpc_type=%s started=%s completed=%s',
107 rpc_type, started, completed)
108 time.sleep(_DELAY_CASE_APPLICATION_TIMEOUT_SEC)
112 'RPC backlog clear: rpc_type=%s started=%s completed=%s',
113 rpc_type, started, completed)
118 raise RuntimeError(
'failed to clear RPC backlog in %s seconds' % timeout)
122 if config.client_lang == _Lang.NODE:
123 return config.version_gte(
'v1.4.x')
136 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
137 path_matcher[
"routeRules"] = [
141 return host_rule, path_matcher
144 self.assertNumEndpoints(xds_config, 1)
145 filter_config = xds_config.rds[
'virtualHosts'][0][
'routes'][0][
146 'typedPerFilterConfig'][
'envoy.filters.http.fault']
147 self.assertEqual(
'20s', filter_config[
'delay'][
'fixedDelay'])
149 0, filter_config[
'delay'][
'percentage'].
get(
'numerator', 0))
150 self.assertEqual(
'MILLION',
151 filter_config[
'delay'][
'percentage'][
'denominator'])
152 self.assertEqual(401, filter_config[
'abort'][
'httpStatus'])
154 0, filter_config[
'abort'][
'percentage'].
get(
'numerator', 0))
155 self.assertEqual(
'MILLION',
156 filter_config[
'abort'][
'percentage'][
'denominator'])
159 self.configure_and_send(test_client,
160 rpc_types=(RpcTypeUnaryCall,),
162 self.assertRpcStatusCode(test_client,
164 rpc_type=RpcTypeUnaryCall,
165 status_code=grpc.StatusCode.OK,
167 length=_LENGTH_OF_RPC_SENDING_SEC,
168 tolerance=_NON_RANDOM_ERROR_TOLERANCE)
172 """EMPTY_CALL is not fault injected, so it should succeed."""
184 return 'EmptyCall', metadata
189 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
190 path_matcher[
"routeRules"] = [
192 delay_percentage=100)
194 return host_rule, path_matcher
197 self.assertNumEndpoints(xds_config, 1)
200 "/grpc.testing.TestService/UnaryCall",
201 xds_config.rds[
'virtualHosts'][0][
'routes'][0][
'match'][
'path'])
202 filter_config = xds_config.rds[
'virtualHosts'][0][
'routes'][0][
203 'typedPerFilterConfig'][
'envoy.filters.http.fault']
204 self.assertEqual(
'20s', filter_config[
'delay'][
'fixedDelay'])
205 self.assertEqual(1000000,
206 filter_config[
'delay'][
'percentage'][
'numerator'])
207 self.assertEqual(
'MILLION',
208 filter_config[
'delay'][
'percentage'][
'denominator'])
209 self.assertEqual(401, filter_config[
'abort'][
'httpStatus'])
210 self.assertEqual(1000000,
211 filter_config[
'abort'][
'percentage'][
'numerator'])
212 self.assertEqual(
'MILLION',
213 filter_config[
'abort'][
'percentage'][
'denominator'])
216 'envoy.filters.http.fault',
217 xds_config.rds[
'virtualHosts'][0][
'routes'][1].
get(
218 'typedPerFilterConfig', {}))
221 self.assertRpcStatusCode(test_client,
223 rpc_type=RpcTypeEmptyCall,
224 status_code=grpc.StatusCode.OK,
226 length=_LENGTH_OF_RPC_SENDING_SEC,
227 tolerance=_NON_RANDOM_ERROR_TOLERANCE)
230 @absltest.skip(
'20% RPC might pass immediately, reason unknown')
240 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
241 path_matcher[
"routeRules"] = [
243 delay_percentage=100)
245 return host_rule, path_matcher
248 self.assertNumEndpoints(xds_config, 1)
249 filter_config = xds_config.rds[
'virtualHosts'][0][
'routes'][0][
250 'typedPerFilterConfig'][
'envoy.filters.http.fault']
251 self.assertEqual(
'20s', filter_config[
'delay'][
'fixedDelay'])
252 self.assertEqual(1000000,
253 filter_config[
'delay'][
'percentage'][
'numerator'])
254 self.assertEqual(
'MILLION',
255 filter_config[
'delay'][
'percentage'][
'denominator'])
258 self.configure_and_send(test_client,
259 rpc_types=(RpcTypeUnaryCall,),
261 app_timeout=_DELAY_CASE_APPLICATION_TIMEOUT_SEC)
263 self.assertRpcStatusCode(
266 rpc_type=RpcTypeUnaryCall,
267 status_code=grpc.StatusCode.DEADLINE_EXCEEDED,
269 length=_LENGTH_OF_RPC_SENDING_SEC,
270 tolerance=_NON_RANDOM_ERROR_TOLERANCE)
282 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
283 path_matcher[
"routeRules"] = [
287 return host_rule, path_matcher
290 self.assertNumEndpoints(xds_config, 1)
291 filter_config = xds_config.rds[
'virtualHosts'][0][
'routes'][0][
292 'typedPerFilterConfig'][
'envoy.filters.http.fault']
293 self.assertEqual(401, filter_config[
'abort'][
'httpStatus'])
294 self.assertEqual(1000000,
295 filter_config[
'abort'][
'percentage'][
'numerator'])
296 self.assertEqual(
'MILLION',
297 filter_config[
'abort'][
'percentage'][
'denominator'])
300 self.configure_and_send(test_client,
301 rpc_types=(RpcTypeUnaryCall,),
303 self.assertRpcStatusCode(
306 rpc_type=RpcTypeUnaryCall,
307 status_code=grpc.StatusCode.UNAUTHENTICATED,
309 length=_LENGTH_OF_RPC_SENDING_SEC,
310 tolerance=_NON_RANDOM_ERROR_TOLERANCE)
322 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
323 path_matcher[
"routeRules"] = [
327 return host_rule, path_matcher
330 self.assertNumEndpoints(xds_config, 1)
331 filter_config = xds_config.rds[
'virtualHosts'][0][
'routes'][0][
332 'typedPerFilterConfig'][
'envoy.filters.http.fault']
333 self.assertEqual(
'20s', filter_config[
'delay'][
'fixedDelay'])
334 self.assertEqual(500000,
335 filter_config[
'delay'][
'percentage'][
'numerator'])
336 self.assertEqual(
'MILLION',
337 filter_config[
'delay'][
'percentage'][
'denominator'])
340 self.configure_and_send(test_client,
341 rpc_types=(RpcTypeUnaryCall,),
343 app_timeout=_DELAY_CASE_APPLICATION_TIMEOUT_SEC)
345 self.assertRpcStatusCode(
348 rpc_type=RpcTypeUnaryCall,
349 status_code=grpc.StatusCode.DEADLINE_EXCEEDED,
351 length=_LENGTH_OF_RPC_SENDING_SEC,
352 tolerance=_ERROR_TOLERANCE)
364 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
365 path_matcher[
"routeRules"] = [
369 return host_rule, path_matcher
372 self.assertNumEndpoints(xds_config, 1)
373 filter_config = xds_config.rds[
'virtualHosts'][0][
'routes'][0][
374 'typedPerFilterConfig'][
'envoy.filters.http.fault']
375 self.assertEqual(401, filter_config[
'abort'][
'httpStatus'])
376 self.assertEqual(500000,
377 filter_config[
'abort'][
'percentage'][
'numerator'])
378 self.assertEqual(
'MILLION',
379 filter_config[
'abort'][
'percentage'][
'denominator'])
382 self.configure_and_send(test_client,
383 rpc_types=(RpcTypeUnaryCall,),
385 self.assertRpcStatusCode(
388 rpc_type=RpcTypeUnaryCall,
389 status_code=grpc.StatusCode.UNAUTHENTICATED,
391 length=_LENGTH_OF_RPC_SENDING_SEC,
392 tolerance=_ERROR_TOLERANCE)
395 if __name__ ==
'__main__':