8f61b10e1f963e98fa5c7172d99083eb66d957a9
[platform/upstream/grpc.git] / tools / run_tests / xds_k8s_test_driver / tests / url_map / retry_test.py
1 # Copyright 2021 The 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 import logging
15 import time
16 from typing import Tuple
17
18 from absl import flags
19 from absl.testing import absltest
20 import grpc
21
22 from framework import xds_k8s_flags
23 from framework import xds_url_map_testcase
24 from framework.test_app import client_app
25
26 # Type aliases
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 XdsTestClient = client_app.XdsTestClient
33 ExpectedResult = xds_url_map_testcase.ExpectedResult
34
35 logger = logging.getLogger(__name__)
36 flags.adopt_module_key_flags(xds_url_map_testcase)
37
38 # The first batch of RPCs don't count towards the result of test case. They are
39 # meant to prove the communication between driver and client is fine.
40 _NUM_RPCS = 10
41 _LENGTH_OF_RPC_SENDING_SEC = 16
42 # We are using sleep to synchronize test driver and the client... Even though
43 # the client is sending at QPS rate, we can't assert that exactly QPS *
44 # SLEEP_DURATION number of RPC is finished. The final completed RPC might be
45 # slightly more or less.
46 _NON_RANDOM_ERROR_TOLERANCE = 0.01
47 _RPC_BEHAVIOR_HEADER_NAME = 'rpc-behavior'
48
49
50 def _build_retry_route_rule(retryConditions, num_retries):
51     return {
52         'priority': 0,
53         'matchRules': [{
54             'fullPathMatch': '/grpc.testing.TestService/UnaryCall'
55         }],
56         'service': GcpResourceManager().default_backend_service(),
57         'routeAction': {
58             'retryPolicy': {
59                 'retryConditions': retryConditions,
60                 'numRetries': num_retries,
61             }
62         },
63     }
64
65
66 @absltest.skipUnless('cpp-client' in xds_k8s_flags.CLIENT_IMAGE.value or \
67                      'java-client' in xds_k8s_flags.CLIENT_IMAGE.value,
68                      'Xds-retry is currently only implemented in C++ and Java.')
69 class TestRetryUpTo3AttemptsAndFail(xds_url_map_testcase.XdsUrlMapTestCase):
70
71     @staticmethod
72     def url_map_change(
73             host_rule: HostRule,
74             path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
75         path_matcher["routeRules"] = [
76             _build_retry_route_rule(retryConditions=["unavailable"],
77                                     num_retries=3)
78         ]
79         return host_rule, path_matcher
80
81     def xds_config_validate(self, xds_config: DumpedXdsConfig):
82         self.assertNumEndpoints(xds_config, 1)
83         retry_config = xds_config.rds['virtualHosts'][0]['routes'][0]['route'][
84             'retryPolicy']
85         self.assertEqual(3, retry_config['numRetries'])
86         self.assertEqual('unavailable', retry_config['retryOn'])
87
88     def rpc_distribution_validate(self, test_client: XdsTestClient):
89         rpc_distribution = self.configure_and_send(
90             test_client,
91             rpc_types=[RpcTypeUnaryCall],
92             metadata=[(RpcTypeUnaryCall, _RPC_BEHAVIOR_HEADER_NAME,
93                        'error-code-14,succeed-on-retry-attempt-4')],
94             num_rpcs=_NUM_RPCS)
95         self.assertRpcStatusCode(test_client,
96                                  expected=(ExpectedResult(
97                                      rpc_type=RpcTypeUnaryCall,
98                                      status_code=grpc.StatusCode.UNAVAILABLE,
99                                      ratio=1),),
100                                  length=_LENGTH_OF_RPC_SENDING_SEC,
101                                  tolerance=_NON_RANDOM_ERROR_TOLERANCE)
102
103
104 @absltest.skipUnless('cpp-client' in xds_k8s_flags.CLIENT_IMAGE.value or \
105                      'java-client' in xds_k8s_flags.CLIENT_IMAGE.value,
106                      'Xds-retry is currently only implemented in C++ Java.')
107 class TestRetryUpTo4AttemptsAndSucceed(xds_url_map_testcase.XdsUrlMapTestCase):
108
109     @staticmethod
110     def url_map_change(
111             host_rule: HostRule,
112             path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]:
113         path_matcher["routeRules"] = [
114             _build_retry_route_rule(retryConditions=["unavailable"],
115                                     num_retries=4)
116         ]
117         return host_rule, path_matcher
118
119     def xds_config_validate(self, xds_config: DumpedXdsConfig):
120         self.assertNumEndpoints(xds_config, 1)
121         retry_config = xds_config.rds['virtualHosts'][0]['routes'][0]['route'][
122             'retryPolicy']
123         self.assertEqual(4, retry_config['numRetries'])
124         self.assertEqual('unavailable', retry_config['retryOn'])
125
126     def rpc_distribution_validate(self, test_client: XdsTestClient):
127         rpc_distribution = self.configure_and_send(
128             test_client,
129             rpc_types=[RpcTypeUnaryCall],
130             metadata=[(RpcTypeUnaryCall, _RPC_BEHAVIOR_HEADER_NAME,
131                        'error-code-14,succeed-on-retry-attempt-4')],
132             num_rpcs=_NUM_RPCS)
133         self.assertRpcStatusCode(test_client,
134                                  expected=(ExpectedResult(
135                                      rpc_type=RpcTypeUnaryCall,
136                                      status_code=grpc.StatusCode.OK,
137                                      ratio=1),),
138                                  length=_LENGTH_OF_RPC_SENDING_SEC,
139                                  tolerance=_NON_RANDOM_ERROR_TOLERANCE)
140
141
142 if __name__ == '__main__':
143     absltest.main()