1# Copyright 2022 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. 14import logging 15from typing import List 16 17from absl import flags 18from absl.testing import absltest 19 20from framework import xds_k8s_flags 21from framework import xds_k8s_testcase 22from framework import xds_url_map_testcase 23from framework.helpers import skips 24 25logger = logging.getLogger(__name__) 26flags.adopt_module_key_flags(xds_k8s_testcase) 27flags.mark_flag_as_required('server_image_canonical') 28 29# Type aliases 30RpcTypeUnaryCall = xds_url_map_testcase.RpcTypeUnaryCall 31RpcTypeEmptyCall = xds_url_map_testcase.RpcTypeEmptyCall 32_XdsTestServer = xds_k8s_testcase.XdsTestServer 33_XdsTestClient = xds_k8s_testcase.XdsTestClient 34_Lang = skips.Lang 35 36# Testing consts 37_QPS = 100 38_REPLICA_COUNT = 5 39 40 41class OutlierDetectionTest(xds_k8s_testcase.RegularXdsKubernetesTestCase): 42 """ 43 Implementation of https://github.com/grpc/grpc/blob/master/doc/xds-test-descriptions.md#outlier_detection 44 45 This test verifies that the client applies the outlier detection 46 configuration and temporarily drops traffic to a server that fails 47 requests. 48 """ 49 50 @classmethod 51 def setUpClass(cls): 52 """Force the java test server for languages not yet supporting 53 the `rpc-behavior` feature. 54 55 https://github.com/grpc/grpc/blob/master/doc/xds-test-descriptions.md#server 56 """ 57 super().setUpClass() 58 if cls.lang_spec.client_lang != _Lang.JAVA: 59 # TODO(mlumish): Once rpc-behavior supported by a language, make the 60 # override version-conditional. 61 cls.server_image = xds_k8s_flags.SERVER_IMAGE_CANONICAL.value 62 63 @staticmethod 64 def is_supported(config: skips.TestConfig) -> bool: 65 if config.client_lang in _Lang.CPP | _Lang.PYTHON: 66 return config.version_gte('v1.48.x') 67 if config.client_lang == _Lang.JAVA: 68 return config.version_gte('v1.49.x') 69 if config.client_lang == _Lang.NODE: 70 return config.version_gte('v1.6.x') 71 if config.client_lang == _Lang.GO: 72 # TODO(zasweq): Update when the feature makes in a version branch. 73 return config.version_gte('master') 74 return False 75 76 def test_outlier_detection(self) -> None: 77 78 with self.subTest('00_create_health_check'): 79 self.td.create_health_check() 80 81 with self.subTest('01_create_backend_service'): 82 self.td.create_backend_service( 83 outlier_detection={ 84 'interval': { 85 'seconds': 2, 86 'nanos': 0 87 }, 88 'successRateRequestVolume': 20 89 }) 90 91 with self.subTest('02_create_url_map'): 92 self.td.create_url_map(self.server_xds_host, self.server_xds_port) 93 94 with self.subTest('03_create_target_proxy'): 95 self.td.create_target_proxy() 96 97 with self.subTest('04_create_forwarding_rule'): 98 self.td.create_forwarding_rule(self.server_xds_port) 99 100 test_servers: List[_XdsTestServer] 101 with self.subTest('05_start_test_servers'): 102 test_servers = self.startTestServers(replica_count=_REPLICA_COUNT) 103 104 with self.subTest('06_add_server_backends_to_backend_services'): 105 self.setupServerBackends() 106 107 test_client: _XdsTestClient 108 with self.subTest('07_start_test_client'): 109 test_client = self.startTestClient(test_servers[0], qps=_QPS) 110 111 with self.subTest('08_test_client_xds_config_exists'): 112 self.assertXdsConfigExists(test_client) 113 114 with self.subTest('09_test_servers_received_rpcs_from_test_client'): 115 self.assertRpcsEventuallyGoToGivenServers(test_client, test_servers) 116 117 rpc_types = (RpcTypeUnaryCall,) 118 with self.subTest('10_chosen_server_removed_by_outlier_detection'): 119 test_client.update_config.configure( 120 rpc_types=rpc_types, 121 metadata=( 122 (RpcTypeUnaryCall, 'rpc-behavior', 123 f'hostname={test_servers[0].hostname} error-code-2'),)) 124 self.assertRpcsEventuallyGoToGivenServers(test_client, 125 test_servers[1:]) 126 127 with self.subTest('11_ejected_server_returned_after_failures_stopped'): 128 test_client.update_config.configure(rpc_types=rpc_types) 129 self.assertRpcsEventuallyGoToGivenServers(test_client, test_servers) 130 131 132if __name__ == '__main__': 133 absltest.main(failfast=True) 134