1# Copyright 2022 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. 14import logging 15from typing import Tuple 16 17from absl import flags 18from absl.testing import absltest 19 20from framework import xds_url_map_testcase 21from framework.test_app import client_app 22 23# Type aliases 24HostRule = xds_url_map_testcase.HostRule 25PathMatcher = xds_url_map_testcase.PathMatcher 26GcpResourceManager = xds_url_map_testcase.GcpResourceManager 27DumpedXdsConfig = xds_url_map_testcase.DumpedXdsConfig 28RpcTypeUnaryCall = xds_url_map_testcase.RpcTypeUnaryCall 29RpcTypeEmptyCall = xds_url_map_testcase.RpcTypeEmptyCall 30XdsTestClient = client_app.XdsTestClient 31 32logger = logging.getLogger(__name__) 33flags.adopt_module_key_flags(xds_url_map_testcase) 34 35_NUM_RPCS = 150 36_TEST_METADATA_KEY = 'xds_md' 37_TEST_METADATA_VALUE_EMPTY = 'empty_ytpme' 38_TEST_METADATA = ((RpcTypeEmptyCall, _TEST_METADATA_KEY, 39 _TEST_METADATA_VALUE_EMPTY),) 40match_labels = [{ 41 'name': 'TRAFFICDIRECTOR_NETWORK_NAME', 42 'value': 'default-vpc' 43}] 44not_match_labels = [{'name': 'fake', 'value': 'fail'}] 45 46 47class TestMetadataFilterMatchAll(xds_url_map_testcase.XdsUrlMapTestCase): 48 """" The test url-map has two routeRules: the higher priority routes to 49 the default backends, but is supposed to be filtered out by TD because 50 of non-matching metadata filters. The lower priority routes to alternative 51 backends and metadata filter matches. Thus, it verifies that TD evaluates 52 metadata filters correctly.""" 53 54 @staticmethod 55 def url_map_change( 56 host_rule: HostRule, 57 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]: 58 path_matcher["routeRules"] = [{ 59 'priority': 0, 60 'matchRules': [{ 61 'prefixMatch': 62 '/', 63 'metadataFilters': [{ 64 'filterMatchCriteria': 'MATCH_ALL', 65 'filterLabels': not_match_labels 66 }] 67 }], 68 'service': GcpResourceManager().default_backend_service() 69 }, { 70 'priority': 1, 71 'matchRules': [{ 72 'prefixMatch': 73 '/grpc.testing.TestService/Empty', 74 'headerMatches': [{ 75 'headerName': _TEST_METADATA_KEY, 76 'exactMatch': _TEST_METADATA_VALUE_EMPTY 77 }], 78 'metadataFilters': [{ 79 'filterMatchCriteria': 'MATCH_ALL', 80 'filterLabels': match_labels 81 }] 82 }], 83 'service': GcpResourceManager().alternative_backend_service() 84 }] 85 return host_rule, path_matcher 86 87 def xds_config_validate(self, xds_config: DumpedXdsConfig): 88 self.assertNumEndpoints(xds_config, 2) 89 self.assertEqual(len(xds_config.rds['virtualHosts'][0]['routes']), 2) 90 self.assertEqual( 91 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['prefix'], 92 "/grpc.testing.TestService/Empty") 93 self.assertEqual( 94 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['headers'] 95 [0]['name'], _TEST_METADATA_KEY) 96 self.assertEqual( 97 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['headers'] 98 [0]['exactMatch'], _TEST_METADATA_VALUE_EMPTY) 99 self.assertEqual( 100 xds_config.rds['virtualHosts'][0]['routes'][1]['match']['prefix'], 101 "") 102 103 def rpc_distribution_validate(self, test_client: XdsTestClient): 104 rpc_distribution = self.configure_and_send(test_client, 105 rpc_types=[RpcTypeEmptyCall], 106 metadata=_TEST_METADATA, 107 num_rpcs=_NUM_RPCS) 108 self.assertEqual( 109 _NUM_RPCS, 110 rpc_distribution.empty_call_alternative_service_rpc_count) 111 112 113class TestMetadataFilterMatchAny(xds_url_map_testcase.XdsUrlMapTestCase): 114 115 @staticmethod 116 def url_map_change( 117 host_rule: HostRule, 118 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]: 119 path_matcher["routeRules"] = [{ 120 'priority': 0, 121 'matchRules': [{ 122 'prefixMatch': 123 '/', 124 'metadataFilters': [{ 125 'filterMatchCriteria': 'MATCH_ANY', 126 'filterLabels': not_match_labels 127 }] 128 }], 129 'service': GcpResourceManager().default_backend_service() 130 }, { 131 'priority': 1, 132 'matchRules': [{ 133 'prefixMatch': 134 '/grpc.testing.TestService/Unary', 135 'metadataFilters': [{ 136 'filterMatchCriteria': 'MATCH_ANY', 137 'filterLabels': not_match_labels + match_labels 138 }] 139 }], 140 'service': GcpResourceManager().alternative_backend_service() 141 }] 142 return host_rule, path_matcher 143 144 def xds_config_validate(self, xds_config: DumpedXdsConfig): 145 self.assertNumEndpoints(xds_config, 2) 146 self.assertEqual(len(xds_config.rds['virtualHosts'][0]['routes']), 2) 147 self.assertEqual( 148 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['prefix'], 149 "/grpc.testing.TestService/Unary") 150 self.assertEqual( 151 xds_config.rds['virtualHosts'][0]['routes'][1]['match']['prefix'], 152 "") 153 154 def rpc_distribution_validate(self, test_client: XdsTestClient): 155 rpc_distribution = self.configure_and_send( 156 test_client, rpc_types=(RpcTypeUnaryCall,), num_rpcs=_NUM_RPCS) 157 self.assertEqual( 158 _NUM_RPCS, 159 rpc_distribution.unary_call_alternative_service_rpc_count) 160 161 162class TestMetadataFilterMatchAnyAndAll(xds_url_map_testcase.XdsUrlMapTestCase): 163 164 @staticmethod 165 def url_map_change( 166 host_rule: HostRule, 167 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]: 168 path_matcher["routeRules"] = [{ 169 'priority': 0, 170 'matchRules': [{ 171 'prefixMatch': 172 '/', 173 'metadataFilters': [{ 174 'filterMatchCriteria': 'MATCH_ALL', 175 'filterLabels': not_match_labels + match_labels 176 }] 177 }], 178 'service': GcpResourceManager().default_backend_service() 179 }, { 180 'priority': 1, 181 'matchRules': [{ 182 'prefixMatch': 183 '/grpc.testing.TestService/Unary', 184 'metadataFilters': [{ 185 'filterMatchCriteria': 'MATCH_ANY', 186 'filterLabels': not_match_labels + match_labels 187 }] 188 }], 189 'service': GcpResourceManager().alternative_backend_service() 190 }] 191 return host_rule, path_matcher 192 193 def xds_config_validate(self, xds_config: DumpedXdsConfig): 194 self.assertNumEndpoints(xds_config, 2) 195 self.assertEqual(len(xds_config.rds['virtualHosts'][0]['routes']), 2) 196 self.assertEqual( 197 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['prefix'], 198 "/grpc.testing.TestService/Unary") 199 self.assertEqual( 200 xds_config.rds['virtualHosts'][0]['routes'][1]['match']['prefix'], 201 "") 202 203 def rpc_distribution_validate(self, test_client: XdsTestClient): 204 rpc_distribution = self.configure_and_send( 205 test_client, rpc_types=(RpcTypeUnaryCall,), num_rpcs=_NUM_RPCS) 206 self.assertEqual( 207 _NUM_RPCS, 208 rpc_distribution.unary_call_alternative_service_rpc_count) 209 210 211class TestMetadataFilterMatchMultipleRules( 212 xds_url_map_testcase.XdsUrlMapTestCase): 213 214 @staticmethod 215 def url_map_change( 216 host_rule: HostRule, 217 path_matcher: PathMatcher) -> Tuple[HostRule, PathMatcher]: 218 path_matcher["routeRules"] = [{ 219 'priority': 0, 220 'matchRules': [{ 221 'prefixMatch': 222 '/', 223 'headerMatches': [{ 224 'headerName': _TEST_METADATA_KEY, 225 'exactMatch': _TEST_METADATA_VALUE_EMPTY 226 }], 227 'metadataFilters': [{ 228 'filterMatchCriteria': 'MATCH_ANY', 229 'filterLabels': match_labels 230 }] 231 }], 232 'service': GcpResourceManager().alternative_backend_service() 233 }, { 234 'priority': 1, 235 'matchRules': [{ 236 'prefixMatch': 237 '/grpc.testing.TestService/Unary', 238 'metadataFilters': [{ 239 'filterMatchCriteria': 'MATCH_ALL', 240 'filterLabels': match_labels 241 }] 242 }], 243 'service': GcpResourceManager().default_backend_service() 244 }] 245 return host_rule, path_matcher 246 247 def xds_config_validate(self, xds_config: DumpedXdsConfig): 248 self.assertNumEndpoints(xds_config, 2) 249 self.assertEqual(len(xds_config.rds['virtualHosts'][0]['routes']), 3) 250 self.assertEqual( 251 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['headers'] 252 [0]['name'], _TEST_METADATA_KEY) 253 self.assertEqual( 254 xds_config.rds['virtualHosts'][0]['routes'][0]['match']['headers'] 255 [0]['exactMatch'], _TEST_METADATA_VALUE_EMPTY) 256 self.assertEqual( 257 xds_config.rds['virtualHosts'][0]['routes'][1]['match']['prefix'], 258 "/grpc.testing.TestService/Unary") 259 self.assertEqual( 260 xds_config.rds['virtualHosts'][0]['routes'][2]['match']['prefix'], 261 "") 262 263 def rpc_distribution_validate(self, test_client: XdsTestClient): 264 rpc_distribution = self.configure_and_send(test_client, 265 rpc_types=[RpcTypeEmptyCall], 266 metadata=_TEST_METADATA, 267 num_rpcs=_NUM_RPCS) 268 self.assertEqual( 269 _NUM_RPCS, 270 rpc_distribution.empty_call_alternative_service_rpc_count) 271 272 273if __name__ == '__main__': 274 absltest.main() 275