istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/gateway_test.go (about) 1 // Copyright Istio 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 package model 16 17 import ( 18 "fmt" 19 "testing" 20 21 networking "istio.io/api/networking/v1alpha3" 22 "istio.io/istio/pkg/config" 23 "istio.io/istio/pkg/util/sets" 24 ) 25 26 // nolint lll 27 func TestMergeGateways(t *testing.T) { 28 gwHTTPFoo := makeConfig("foo1", "not-default", "foo.bar.com", "name1", "http", 7, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE) 29 gwHTTPbar := makeConfig("bar1", "not-default", "bar.foo.com", "bname1", "http", 7, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE) 30 gwHTTPlocalbar := makeConfig("lcoalbar1", "not-default", "localbar.foo.com", "bname1", "http", 7, "ingressgateway", "127.0.0.1", networking.ServerTLSSettings_SIMPLE) 31 gwHTTP2Wildcard := makeConfig("foo5", "not-default", "*", "name5", "http2", 8, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE) 32 gwHTTPWildcard := makeConfig("foo3", "not-default", "*", "name3", "http", 8, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE) 33 gwTCPWildcard := makeConfig("foo4", "not-default-2", "*", "name4", "tcp", 8, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE) 34 35 gwHTTPWildcardAlternate := makeConfig("foo2", "not-default", "*", "name2", "http", 7, "ingressgateway2", "", networking.ServerTLSSettings_SIMPLE) 36 37 gwSimple := makeConfig("foo-simple", "not-default-2", "*.example.com", "https", "HTTPS", 443, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE) 38 gwPassthrough := makeConfig("foo-passthrough", "not-default-2", "foo.example.com", "tls-foo", "TLS", 443, "ingressgateway", "", networking.ServerTLSSettings_PASSTHROUGH) 39 40 // TODO(ramaraochavali): Add more test cases here. 41 tests := []struct { 42 name string 43 gwConfig []config.Config 44 mergedServersNum int 45 serverNum int 46 serversForRouteNum map[string]int 47 gatewaysNum int 48 }{ 49 { 50 "single-server-config", 51 []config.Config{gwHTTPFoo}, 52 1, 53 1, 54 map[string]int{"http.7": 1}, 55 1, 56 }, 57 { 58 "two servers on the same port", 59 []config.Config{gwHTTPFoo, gwHTTPbar}, 60 1, 61 2, 62 map[string]int{"http.7": 2}, 63 2, 64 }, 65 { 66 "two servers on the same port with different bind", 67 []config.Config{gwHTTPbar, gwHTTPlocalbar}, 68 2, 69 2, 70 map[string]int{"http.7": 1, "http.7.127.0.0.1": 1}, 71 2, 72 }, 73 { 74 "same-server-config", 75 []config.Config{gwHTTPFoo, gwHTTPWildcardAlternate}, 76 1, 77 2, 78 map[string]int{"http.7": 2}, 79 2, 80 }, 81 { 82 "multi-server-config", 83 []config.Config{gwHTTPFoo, gwHTTPWildcardAlternate, gwHTTPWildcard}, 84 2, 85 3, 86 map[string]int{"http.7": 2, "http.8": 1}, 87 3, 88 }, 89 { 90 "http-tcp-wildcard-server-config", 91 []config.Config{gwHTTPFoo, gwTCPWildcard}, 92 2, 93 2, 94 map[string]int{"http.7": 1}, 95 2, 96 }, 97 { 98 "tcp-http-server-config", 99 []config.Config{gwTCPWildcard, gwHTTPWildcard}, 100 1, 101 1, 102 map[string]int{}, 103 2, 104 }, 105 { 106 "tcp-tcp-server-config", 107 []config.Config{gwHTTPWildcard, gwTCPWildcard}, // order matters 108 1, 109 1, 110 map[string]int{"http.8": 1}, 111 2, 112 }, 113 { 114 "http-http2-server-config", 115 []config.Config{gwHTTPWildcard, gwHTTP2Wildcard}, 116 1, 117 1, 118 // http and http2 both present 119 map[string]int{"http.8": 1}, 120 2, 121 }, 122 { 123 "simple-passthrough", 124 []config.Config{gwSimple, gwPassthrough}, 125 2, 126 2, 127 map[string]int{"https.443.https.foo-simple.not-default-2": 1}, 128 2, 129 }, 130 } 131 132 for idx, tt := range tests { 133 t.Run(fmt.Sprintf("[%d] %s", idx, tt.name), func(t *testing.T) { 134 instances := []gatewayWithInstances{} 135 for _, c := range tt.gwConfig { 136 instances = append(instances, gatewayWithInstances{c, true, nil}) 137 } 138 mgw := MergeGateways(instances, &Proxy{}, nil) 139 if len(mgw.MergedServers) != tt.mergedServersNum { 140 t.Errorf("Incorrect number of merged servers. Expected: %v Got: %d", tt.mergedServersNum, len(mgw.MergedServers)) 141 } 142 if len(mgw.ServersByRouteName) != len(tt.serversForRouteNum) { 143 t.Errorf("Incorrect number of routes. Expected: %v Got: %d", len(tt.serversForRouteNum), len(mgw.ServersByRouteName)) 144 } 145 for k, v := range mgw.ServersByRouteName { 146 if tt.serversForRouteNum[k] != len(v) { 147 t.Errorf("for route %v expected %v servers got %v", k, tt.serversForRouteNum[k], len(v)) 148 } 149 } 150 ns := 0 151 for _, ms := range mgw.MergedServers { 152 ns += len(ms.Servers) 153 } 154 if ns != tt.serverNum { 155 t.Errorf("Incorrect number of total servers. Expected: %v Got: %d", tt.serverNum, ns) 156 } 157 if len(mgw.GatewayNameForServer) != tt.gatewaysNum { 158 t.Errorf("Incorrect number of gateways. Expected: %v Got: %d", tt.gatewaysNum, len(mgw.GatewayNameForServer)) 159 } 160 }) 161 } 162 } 163 164 func TestGetAutoPassthroughSNIHosts(t *testing.T) { 165 gateway := config.Config{ 166 Meta: config.Meta{ 167 Name: "gateway", 168 Namespace: "istio-system", 169 }, 170 Spec: &networking.Gateway{ 171 Selector: map[string]string{"istio": "ingressgateway"}, 172 Servers: []*networking.Server{ 173 { 174 Hosts: []string{"static.example.com"}, 175 Port: &networking.Port{Name: "http", Number: 80, Protocol: "HTTP"}, 176 }, 177 { 178 Hosts: []string{"www.example.com"}, 179 Port: &networking.Port{Name: "https", Number: 443, Protocol: "HTTPS"}, 180 Tls: &networking.ServerTLSSettings{Mode: networking.ServerTLSSettings_SIMPLE}, 181 }, 182 { 183 Hosts: []string{"a.apps.svc.cluster.local", "b.apps.svc.cluster.local"}, 184 Port: &networking.Port{Name: "tls", Number: 15443, Protocol: "TLS"}, 185 Tls: &networking.ServerTLSSettings{Mode: networking.ServerTLSSettings_AUTO_PASSTHROUGH}, 186 }, 187 }, 188 }, 189 } 190 svc := &Service{ 191 Attributes: ServiceAttributes{ 192 Labels: map[string]string{}, 193 }, 194 } 195 gatewayServiceTargets := []ServiceTarget{ 196 { 197 Service: svc, 198 Port: ServiceInstancePort{ 199 ServicePort: &Port{Port: 80}, 200 TargetPort: 80, 201 }, 202 }, 203 { 204 Service: svc, 205 Port: ServiceInstancePort{ 206 ServicePort: &Port{Port: 443}, 207 TargetPort: 443, 208 }, 209 }, 210 { 211 Service: svc, 212 Port: ServiceInstancePort{ 213 ServicePort: &Port{Port: 15443}, 214 TargetPort: 15443, 215 }, 216 }, 217 } 218 instances := []gatewayWithInstances{{gateway: gateway, instances: gatewayServiceTargets}} 219 mgw := MergeGateways(instances, &Proxy{}, nil) 220 hosts := mgw.GetAutoPassthrughGatewaySNIHosts() 221 expectedHosts := sets.Set[string]{} 222 expectedHosts.InsertAll("a.apps.svc.cluster.local", "b.apps.svc.cluster.local") 223 if !hosts.Equals(expectedHosts) { 224 t.Errorf("expected to get: [a.apps.svc.cluster.local,b.apps.svc.cluster.local], got: %s", hosts.String()) 225 } 226 } 227 228 func makeConfig(name, namespace, host, portName, portProtocol string, portNumber uint32, gw string, bind string, 229 mode networking.ServerTLSSettings_TLSmode, 230 ) config.Config { 231 c := config.Config{ 232 Meta: config.Meta{ 233 Name: name, 234 Namespace: namespace, 235 }, 236 Spec: &networking.Gateway{ 237 Selector: map[string]string{"istio": gw}, 238 Servers: []*networking.Server{ 239 { 240 Hosts: []string{host}, 241 Port: &networking.Port{Name: portName, Number: portNumber, Protocol: portProtocol}, 242 Bind: bind, 243 Tls: &networking.ServerTLSSettings{Mode: mode}, 244 }, 245 }, 246 }, 247 } 248 return c 249 } 250 251 func TestParseGatewayRDSRouteName(t *testing.T) { 252 type args struct { 253 name string 254 } 255 tests := []struct { 256 name string 257 args args 258 wantPortNumber int 259 wantPortName string 260 wantGateway string 261 }{ 262 { 263 name: "invalid rds name", 264 args: args{"https.scooby.dooby.doo"}, 265 wantPortNumber: 0, 266 wantPortName: "", 267 wantGateway: "", 268 }, 269 { 270 name: "gateway http rds name", 271 args: args{"http.80"}, 272 wantPortNumber: 80, 273 wantPortName: "", 274 wantGateway: "", 275 }, 276 { 277 name: "https rds name", 278 args: args{"https.443.app1.gw1.ns1"}, 279 wantPortNumber: 443, 280 wantPortName: "app1", 281 wantGateway: "ns1/gw1", 282 }, 283 } 284 for _, tt := range tests { 285 t.Run(tt.name, func(t *testing.T) { 286 gotPortNumber, gotPortName, gotGateway := ParseGatewayRDSRouteName(tt.args.name) 287 if gotPortNumber != tt.wantPortNumber { 288 t.Errorf("ParseGatewayRDSRouteName() gotPortNumber = %v, want %v", gotPortNumber, tt.wantPortNumber) 289 } 290 if gotPortName != tt.wantPortName { 291 t.Errorf("ParseGatewayRDSRouteName() gotPortName = %v, want %v", gotPortName, tt.wantPortName) 292 } 293 if gotGateway != tt.wantGateway { 294 t.Errorf("ParseGatewayRDSRouteName() gotGateway = %v, want %v", gotGateway, tt.wantGateway) 295 } 296 }) 297 } 298 }