1// Copyright 2018 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. 14package v2_test 15 16import ( 17 "io/ioutil" 18 "os" 19 "testing" 20 "time" 21 22 "github.com/golang/protobuf/ptypes" 23 24 "istio.io/istio/pkg/config/mesh" 25 26 v2 "istio.io/istio/pilot/pkg/proxy/envoy/v2" 27 "istio.io/istio/pilot/pkg/serviceregistry" 28 29 xdsapi "github.com/envoyproxy/go-control-plane/envoy/api/v2" 30 xdsapi_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" 31 xdsapi_http_connection_manager "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" 32 33 "istio.io/istio/pkg/config/labels" 34 "istio.io/istio/pkg/util/gogoprotomarshal" 35 36 testenv "istio.io/istio/mixer/test/client/env" 37 "istio.io/istio/pilot/pkg/bootstrap" 38 "istio.io/istio/pilot/pkg/model" 39 "istio.io/istio/pkg/adsc" 40 "istio.io/istio/pkg/test/env" 41 "istio.io/istio/tests/util" 42) 43 44// TestLDS using isolated namespaces 45func TestLDSIsolated(t *testing.T) { 46 _, tearDown := initLocalPilotTestEnv(t) 47 defer tearDown() 48 49 // Sidecar in 'none' mode 50 t.Run("sidecar_none", func(t *testing.T) { 51 // TODO: add a Service with EDS resolution in the none ns. 52 // The ServiceEntry only allows STATIC - both STATIC and EDS should generated TCP listeners on :port 53 // while DNS and NONE should generate old-style bind ports. 54 // Right now 'STATIC' and 'EDS' result in ClientSideLB in the internal object, so listener test is valid. 55 56 ldsr, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 57 Meta: model.NodeMetadata{ 58 InterceptionMode: model.InterceptionNone, 59 HTTP10: "1", 60 }.ToStruct(), 61 IP: "10.11.0.1", // matches none.yaml s1tcp.none 62 Namespace: "none", 63 }) 64 if err != nil { 65 t.Fatal(err) 66 } 67 defer ldsr.Close() 68 69 ldsr.Watch() 70 71 _, err = ldsr.Wait(5*time.Second, "lds") 72 if err != nil { 73 t.Fatal("Failed to receive LDS", err) 74 return 75 } 76 77 err = ldsr.Save(env.IstioOut + "/none") 78 if err != nil { 79 t.Fatal(err) 80 } 81 82 // 7071 (inbound), 2001 (service - also as http proxy), 18010 (fortio), 15006 (virtual inbound) 83 // We do not get mixer on 9091 because there are no services defined in istio-system namespace 84 // in the none.yaml setup 85 if len(ldsr.GetHTTPListeners()) != 4 { 86 // TODO: we are still debating if for HTTP services we have any use case to create a 127.0.0.1:port outbound 87 // for the service (the http proxy is already covering this) 88 t.Error("HTTP listeners, expecting 4 got ", len(ldsr.GetHTTPListeners()), ldsr.GetHTTPListeners()) 89 } 90 91 // s1tcp:2000 outbound, bind=true (to reach other instances of the service) 92 // s1:5005 outbound, bind=true 93 // :443 - https external, bind=false 94 // 10.11.0.1_7070, bind=true -> inbound|2000|s1 - on port 7070, fwd to 37070 95 // virtual 96 if len(ldsr.GetTCPListeners()) == 0 { 97 t.Fatal("No response") 98 } 99 100 for _, s := range []string{"lds_tcp", "lds_http", "rds", "cds", "ecds"} { 101 want, err := ioutil.ReadFile(env.IstioOut + "/none_" + s + ".json") 102 if err != nil { 103 t.Fatal(err) 104 } 105 got, err := ioutil.ReadFile("testdata/none_" + s + ".json") 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 if err = util.Compare(got, want); err != nil { 111 // Just log for now - golden changes every time there is a config generation update. 112 // It is mostly intended as a reference for what is generated - we need to add explicit checks 113 // for things we need, like the number of expected listeners. 114 // This is mainly using for debugging what changed from the snapshot in the golden files. 115 if os.Getenv("CONFIG_DIFF") == "1" { 116 t.Logf("error in golden file %s %v", s, err) 117 } 118 } 119 } 120 121 // TODO: check bind==true 122 // TODO: verify listeners for outbound are on 127.0.0.1 (not yet), port 2000, 2005, 2007 123 // TODO: verify virtual listeners for unsupported cases 124 // TODO: add and verify SNI listener on 127.0.0.1:443 125 // TODO: verify inbound service port is on 127.0.0.1, and containerPort on 0.0.0.0 126 // TODO: BUG, SE with empty endpoints is rejected - it is actually valid config (service may not have endpoints) 127 }) 128 129 // Test for the examples in the ServiceEntry doc 130 t.Run("se_example", func(t *testing.T) { 131 // TODO: add a Service with EDS resolution in the none ns. 132 // The ServiceEntry only allows STATIC - both STATIC and EDS should generated TCP listeners on :port 133 // while DNS and NONE should generate old-style bind ports. 134 // Right now 'STATIC' and 'EDS' result in ClientSideLB in the internal object, so listener test is valid. 135 136 ldsr, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 137 Meta: nil, 138 IP: "10.12.0.1", // matches none.yaml s1tcp.none 139 Namespace: "seexamples", 140 }) 141 if err != nil { 142 t.Fatal(err) 143 } 144 defer ldsr.Close() 145 146 ldsr.Watch() 147 148 if _, err := ldsr.Wait(5*time.Second, "lds"); err != nil { 149 t.Fatal("Failed to receive LDS", err) 150 return 151 } 152 153 err = ldsr.Save(env.IstioOut + "/seexample") 154 if err != nil { 155 t.Fatal(err) 156 } 157 }) 158 159 // Test for the examples in the ServiceEntry doc 160 t.Run("se_examplegw", func(t *testing.T) { 161 // TODO: add a Service with EDS resolution in the none ns. 162 // The ServiceEntry only allows STATIC - both STATIC and EDS should generated TCP listeners on :port 163 // while DNS and NONE should generate old-style bind ports. 164 // Right now 'STATIC' and 'EDS' result in ClientSideLB in the internal object, so listener test is valid. 165 166 ldsr, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 167 Meta: nil, 168 IP: "10.13.0.1", 169 Namespace: "exampleegressgw", 170 }) 171 if err != nil { 172 t.Fatal(err) 173 } 174 defer ldsr.Close() 175 176 ldsr.Watch() 177 178 if _, err = ldsr.Wait(5*time.Second, "lds"); err != nil { 179 t.Fatal("Failed to receive LDS", err) 180 return 181 } 182 183 err = ldsr.Save(env.IstioOut + "/seexample-eg") 184 if err != nil { 185 t.Fatal(err) 186 } 187 }) 188 189} 190 191// TestLDS using default sidecar in root namespace 192func TestLDSWithDefaultSidecar(t *testing.T) { 193 194 server, tearDown := util.EnsureTestServer(func(args *bootstrap.PilotArgs) { 195 args.Plugins = bootstrap.DefaultPlugins 196 args.Config.FileDir = env.IstioSrc + "/tests/testdata/networking/sidecar-ns-scope" 197 args.Mesh.MixerAddress = "" 198 args.MeshConfig = nil 199 args.Mesh.ConfigFile = env.IstioSrc + "/tests/testdata/networking/sidecar-ns-scope/mesh.yaml" 200 args.Service.Registries = []string{} 201 }) 202 testEnv = testenv.NewTestSetup(testenv.SidecarTest, t) 203 testEnv.Ports().PilotGrpcPort = uint16(util.MockPilotGrpcPort) 204 testEnv.Ports().PilotHTTPPort = uint16(util.MockPilotHTTPPort) 205 testEnv.IstioSrc = env.IstioSrc 206 testEnv.IstioOut = env.IstioOut 207 208 server.EnvoyXdsServer.ConfigUpdate(&model.PushRequest{Full: true}) 209 defer tearDown() 210 211 adsResponse, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 212 Meta: model.NodeMetadata{ 213 InstanceIPs: []string{"100.1.1.2"}, 214 ConfigNamespace: "ns1", 215 IstioVersion: "1.3.0", 216 }.ToStruct(), 217 IP: "100.1.1.2", 218 Namespace: "ns1", 219 }) 220 221 if err != nil { 222 t.Fatal(err) 223 } 224 defer adsResponse.Close() 225 226 adsResponse.Watch() 227 228 upd, err := adsResponse.Wait(10*time.Second, "lds", "rds", "cds") 229 if err != nil { 230 t.Fatal("Failed to receive XDS response", err, upd) 231 return 232 } 233 234 // Expect 6 listeners : 2 orig_dst, 4 outbound (http, tcp1, istio-policy and istio-telemetry) 235 if (len(adsResponse.GetHTTPListeners()) + len(adsResponse.GetTCPListeners())) != 6 { 236 t.Fatalf("Expected 7 listeners, got %d\n", len(adsResponse.GetHTTPListeners())+len(adsResponse.GetTCPListeners())) 237 } 238 239 // Expect 11 CDS clusters: 240 // 2 inbound(http, inbound passthroughipv4) notes: no passthroughipv6 241 // 9 outbound (2 http services, 1 tcp service, 2 istio-system services, 242 // and 2 subsets of http1, 1 blackhole, 1 passthrough) 243 if (len(adsResponse.GetClusters()) + len(adsResponse.GetEdsClusters())) != 11 { 244 t.Fatalf("Expected 12 clusters in CDS output. Got %d", len(adsResponse.GetClusters())+len(adsResponse.GetEdsClusters())) 245 } 246 247 // Expect two vhost blocks in RDS output for 8080 (one for http1, another for http2) 248 // plus one extra due to mem registry 249 if len(adsResponse.GetRoutes()["8080"].VirtualHosts) != 3 { 250 t.Fatalf("Expected 3 VirtualHosts in RDS output. Got %d", len(adsResponse.GetRoutes()["8080"].VirtualHosts)) 251 } 252} 253 254// TestLDS using gateways 255func TestLDSWithIngressGateway(t *testing.T) { 256 server, tearDown := util.EnsureTestServer(func(args *bootstrap.PilotArgs) { 257 args.Plugins = bootstrap.DefaultPlugins 258 args.Config.FileDir = env.IstioSrc + "/tests/testdata/networking/ingress-gateway" 259 args.Mesh.MixerAddress = "" 260 args.Mesh.ConfigFile = env.IstioSrc + "/tests/testdata/networking/ingress-gateway/mesh.yaml" 261 args.Service.Registries = []string{} 262 }) 263 testEnv = testenv.NewTestSetup(testenv.GatewayTest, t) 264 testEnv.Ports().PilotGrpcPort = uint16(util.MockPilotGrpcPort) 265 testEnv.Ports().PilotHTTPPort = uint16(util.MockPilotHTTPPort) 266 testEnv.IstioSrc = env.IstioSrc 267 testEnv.IstioOut = env.IstioOut 268 269 server.EnvoyXdsServer.ConfigUpdate(&model.PushRequest{Full: true}) 270 defer tearDown() 271 272 adsResponse, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 273 Meta: model.NodeMetadata{ 274 InstanceIPs: []string{"99.1.1.1"}, // as service instance of ingress gateway 275 ConfigNamespace: "istio-system", 276 IstioVersion: "1.3.0", 277 }.ToStruct(), 278 IP: "99.1.1.1", 279 Namespace: "istio-system", 280 NodeType: "router", 281 }) 282 283 if err != nil { 284 t.Fatal(err) 285 } 286 defer adsResponse.Close() 287 288 adsResponse.Watch() 289 290 _, err = adsResponse.Wait(10*time.Second, "lds") 291 if err != nil { 292 t.Fatal("Failed to receive LDS response", err) 293 return 294 } 295 296 // Expect 2 listeners : 1 for 80, 1 for 443 297 // where 443 listener has 3 filter chains 298 if (len(adsResponse.GetHTTPListeners()) + len(adsResponse.GetTCPListeners())) != 2 { 299 t.Fatalf("Expected 2 listeners, got %d\n", len(adsResponse.GetHTTPListeners())+len(adsResponse.GetTCPListeners())) 300 } 301 302 // TODO: This is flimsy. The ADSC code treats any listener with http connection manager as a HTTP listener 303 // instead of looking at it as a listener with multiple filter chains 304 l := adsResponse.GetHTTPListeners()["0.0.0.0_443"] 305 306 if l != nil { 307 if len(l.FilterChains) != 3 { 308 t.Fatalf("Expected 3 filter chains, got %d\n", len(l.FilterChains)) 309 } 310 } 311} 312 313// TestLDS is running LDSv2 tests. 314func TestLDS(t *testing.T) { 315 _, tearDown := initLocalPilotTestEnv(t) 316 defer tearDown() 317 318 t.Run("sidecar", func(t *testing.T) { 319 ldsr, cancel, err := connectADS(util.MockPilotGrpcAddr) 320 if err != nil { 321 t.Fatal(err) 322 } 323 defer cancel() 324 err = sendLDSReq(sidecarID(app3Ip, "app3"), ldsr) 325 if err != nil { 326 t.Fatal(err) 327 } 328 329 res, err := ldsr.Recv() 330 if err != nil { 331 t.Fatal("Failed to receive LDS", err) 332 return 333 } 334 335 strResponse, _ := gogoprotomarshal.ToJSONWithIndent(res, " ") 336 _ = ioutil.WriteFile(env.IstioOut+"/ldsv2_sidecar.json", []byte(strResponse), 0644) 337 338 if len(res.Resources) == 0 { 339 t.Fatal("No response") 340 } 341 }) 342 343 // 'router' or 'gateway' type of listener 344 t.Run("gateway", func(t *testing.T) { 345 ldsr, cancel, err := connectADS(util.MockPilotGrpcAddr) 346 if err != nil { 347 t.Fatal(err) 348 } 349 defer cancel() 350 err = sendLDSReqWithLabels(gatewayID(gatewayIP), ldsr, map[string]string{"version": "v2", "app": "my-gateway-controller"}) 351 if err != nil { 352 t.Fatal(err) 353 } 354 355 res, err := ldsr.Recv() 356 if err != nil { 357 t.Fatal("Failed to receive LDS", err) 358 } 359 360 strResponse, _ := gogoprotomarshal.ToJSONWithIndent(res, " ") 361 362 _ = ioutil.WriteFile(env.IstioOut+"/ldsv2_gateway.json", []byte(strResponse), 0644) 363 364 if len(res.Resources) == 0 { 365 t.Fatal("No response") 366 } 367 }) 368 369 // TODO: compare with some golden once it's stable 370 // check that each mocked service and destination rule has a corresponding resource 371 372 // TODO: dynamic checks ( see EDS ) 373} 374 375// TestLDS using sidecar scoped on workload without Service 376func TestLDSWithSidecarForWorkloadWithoutService(t *testing.T) { 377 server, tearDown := util.EnsureTestServer(func(args *bootstrap.PilotArgs) { 378 args.Plugins = bootstrap.DefaultPlugins 379 args.Config.FileDir = env.IstioSrc + "/tests/testdata/networking/sidecar-without-service" 380 args.Mesh.MixerAddress = "" 381 args.Mesh.ConfigFile = env.IstioSrc + "/tests/testdata/networking/sidecar-without-service/mesh.yaml" 382 args.Service.Registries = []string{} 383 }) 384 registry := memServiceDiscovery(server, t) 385 registry.AddWorkload("98.1.1.1", labels.Instance{"app": "consumeronly"}) // These labels must match the sidecars workload selector 386 387 testEnv = testenv.NewTestSetup(testenv.SidecarConsumerOnlyTest, t) 388 testEnv.Ports().PilotGrpcPort = uint16(util.MockPilotGrpcPort) 389 testEnv.Ports().PilotHTTPPort = uint16(util.MockPilotHTTPPort) 390 testEnv.IstioSrc = env.IstioSrc 391 testEnv.IstioOut = env.IstioOut 392 393 server.EnvoyXdsServer.ConfigUpdate(&model.PushRequest{Full: true}) 394 defer tearDown() 395 396 adsResponse, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 397 Meta: model.NodeMetadata{ 398 InstanceIPs: []string{"98.1.1.1"}, // as service instance of ingress gateway 399 ConfigNamespace: "consumerns", 400 IstioVersion: "1.3.0", 401 }.ToStruct(), 402 IP: "98.1.1.1", 403 Namespace: "consumerns", // namespace must match the namespace of the sidecar in the configs.yaml 404 NodeType: "sidecar", 405 }) 406 407 if err != nil { 408 t.Fatal(err) 409 } 410 defer adsResponse.Close() 411 412 adsResponse.Watch() 413 414 _, err = adsResponse.Wait(10*time.Second, "lds") 415 if err != nil { 416 t.Fatal("Failed to receive LDS response", err) 417 return 418 } 419 420 // Expect 2 HTTP listeners for outbound 8081 and one virtualInbound which has the same inbound 9080 421 // as a filter chain. Since the adsclient code treats any listener with a HTTP connection manager filter in ANY 422 // filter chain, as a HTTP listener, we end up getting both 9080 and virtualInbound. 423 if len(adsResponse.GetHTTPListeners()) != 2 { 424 t.Fatalf("Expected 2 http listeners, got %d", len(adsResponse.GetHTTPListeners())) 425 } 426 427 // TODO: This is flimsy. The ADSC code treats any listener with http connection manager as a HTTP listener 428 // instead of looking at it as a listener with multiple filter chains 429 if l := adsResponse.GetHTTPListeners()["0.0.0.0_8081"]; l != nil { 430 expected := 2 431 if len(l.FilterChains) != expected { 432 t.Fatalf("Expected %d filter chains, got %d", expected, len(l.FilterChains)) 433 } 434 } else { 435 t.Fatal("Expected listener for 0.0.0.0_8081") 436 } 437 438 if l := adsResponse.GetHTTPListeners()["virtualInbound"]; l == nil { 439 t.Fatal("Expected listener virtualInbound") 440 } 441 442 // Expect only one eds cluster for http1.ns1.svc.cluster.local 443 if len(adsResponse.GetEdsClusters()) != 1 { 444 t.Fatalf("Expected 1 eds cluster, got %d", len(adsResponse.GetEdsClusters())) 445 } 446 if cluster, ok := adsResponse.GetEdsClusters()["outbound|8081||http1.ns1.svc.cluster.local"]; !ok { 447 t.Fatalf("Expected eds cluster outbound|8081||http1.ns1.svc.cluster.local, got %v", cluster.Name) 448 } 449} 450 451// TestLDS using default sidecar in root namespace 452func TestLDSEnvoyFilterWithWorkloadSelector(t *testing.T) { 453 mesh.TestMode = true 454 server, tearDown := util.EnsureTestServer(func(args *bootstrap.PilotArgs) { 455 args.Plugins = bootstrap.DefaultPlugins 456 args.Config.FileDir = env.IstioSrc + "/tests/testdata/networking/envoyfilter-without-service" 457 args.Mesh.MixerAddress = "" 458 args.Mesh.ConfigFile = env.IstioSrc + "/tests/testdata/networking/envoyfilter-without-service/mesh.yaml" 459 args.Service.Registries = []string{} 460 }) 461 registry := memServiceDiscovery(server, t) 462 // The labels of 98.1.1.1 must match the envoyfilter workload selector 463 registry.AddWorkload("98.1.1.1", labels.Instance{"app": "envoyfilter-test-app", "some": "otherlabel"}) 464 registry.AddWorkload("98.1.1.2", labels.Instance{"app": "no-envoyfilter-test-app"}) 465 registry.AddWorkload("98.1.1.3", labels.Instance{}) 466 467 testEnv = testenv.NewTestSetup(testenv.SidecarConsumerOnlyTest, t) 468 testEnv.Ports().PilotGrpcPort = uint16(util.MockPilotGrpcPort) 469 testEnv.Ports().PilotHTTPPort = uint16(util.MockPilotHTTPPort) 470 testEnv.IstioSrc = env.IstioSrc 471 testEnv.IstioOut = env.IstioOut 472 473 server.EnvoyXdsServer.ConfigUpdate(&model.PushRequest{Full: true}) 474 defer tearDown() 475 476 tests := []struct { 477 name string 478 ip string 479 expectLuaFilter bool 480 }{ 481 { 482 name: "Add filter with matching labels to sidecar", 483 ip: "98.1.1.1", 484 expectLuaFilter: true, 485 }, 486 { 487 name: "Ignore filter with not matching labels to sidecar", 488 ip: "98.1.1.2", 489 expectLuaFilter: false, 490 }, 491 { 492 name: "Ignore filter with empty labels to sidecar", 493 ip: "98.1.1.3", 494 expectLuaFilter: false, 495 }, 496 } 497 498 for _, test := range tests { 499 test := test 500 t.Run(test.name, func(t *testing.T) { 501 adsResponse, err := adsc.Dial(util.MockPilotGrpcAddr, "", &adsc.Config{ 502 Meta: model.NodeMetadata{ 503 InstanceIPs: []string{test.ip}, // as service instance of ingress gateway 504 ConfigNamespace: "istio-system", 505 IstioVersion: "1.4.0", 506 }.ToStruct(), 507 IP: test.ip, 508 Namespace: "consumerns", // namespace must match the namespace of the sidecar in the configs.yaml 509 NodeType: "sidecar", 510 }) 511 if err != nil { 512 t.Fatal(err) 513 } 514 defer adsResponse.Close() 515 516 adsResponse.Watch() 517 _, err = adsResponse.Wait(10*time.Second, "lds") 518 if err != nil { 519 t.Fatal("Failed to receive LDS response", err) 520 return 521 } 522 523 // Expect 1 HTTP listeners for 8081, 1 hybrid listeners for 15006 (virtual inbound) 524 if len(adsResponse.GetHTTPListeners()) != 2 { 525 t.Fatalf("Expected 1 http listeners, got %d", len(adsResponse.GetHTTPListeners())) 526 } 527 // TODO: This is flimsy. The ADSC code treats any listener with http connection manager as a HTTP listener 528 // instead of looking at it as a listener with multiple filter chains 529 l := adsResponse.GetHTTPListeners()["0.0.0.0_8081"] 530 531 expectLuaFilter(t, l, test.expectLuaFilter) 532 }) 533 } 534} 535 536func expectLuaFilter(t *testing.T, l *xdsapi.Listener, expected bool) { 537 if l != nil { 538 var chain *xdsapi_listener.FilterChain 539 for _, fc := range l.FilterChains { 540 if len(fc.Filters) == 1 && fc.Filters[0].Name == "envoy.http_connection_manager" { 541 chain = fc 542 } 543 } 544 if chain == nil { 545 t.Fatalf("Failed to find http_connection_manager") 546 } 547 if len(chain.Filters) != 1 { 548 t.Fatalf("Expected 1 filter in first filter chain, got %d", len(l.FilterChains)) 549 } 550 filter := chain.Filters[0] 551 if filter.Name != "envoy.http_connection_manager" { 552 t.Fatalf("Expected HTTP connection, found %v", chain.Filters[0].Name) 553 } 554 httpCfg, ok := filter.ConfigType.(*xdsapi_listener.Filter_TypedConfig) 555 if !ok { 556 t.Fatalf("Expected Http Connection Manager Config Filter_TypedConfig, found %T", filter.ConfigType) 557 } 558 connectionManagerCfg := xdsapi_http_connection_manager.HttpConnectionManager{} 559 err := ptypes.UnmarshalAny(httpCfg.TypedConfig, &connectionManagerCfg) 560 if err != nil { 561 t.Fatalf("Could not deserialize http connection manager config: %v", err) 562 } 563 found := false 564 for _, filter := range connectionManagerCfg.HttpFilters { 565 if filter.Name == "envoy.lua" { 566 found = true 567 } 568 } 569 if expected != found { 570 t.Fatalf("Expected Lua filter: %v, found: %v", expected, found) 571 } 572 } 573} 574 575func memServiceDiscovery(server *bootstrap.Server, t *testing.T) *v2.MemServiceDiscovery { 576 index, found := server.ServiceController().GetRegistryIndex("v2-debug") 577 if !found { 578 t.Fatal("Could not find Mock ServiceRegistry") 579 } 580 registry, ok := server.ServiceController().GetRegistries()[index].(serviceregistry.Simple).ServiceDiscovery.(*v2.MemServiceDiscovery) 581 if !ok { 582 t.Fatal("Unexpected type of Mock ServiceRegistry") 583 } 584 return registry 585} 586 587// TODO: helper to test the http listener content 588// - file access log 589// - generate request id 590// - cors, fault, router filters 591// - tracing 592// 593