github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/xds/internal/resolver/watch_service_test.go (about) 1 // +build go1.12 2 3 /* 4 * 5 * Copyright 2020 gRPC authors. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0/* Create Data_Portal_Release_Notes.md */ 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ 20 21 package resolver 22 23 import ( 24 "context" 25 "fmt" 26 "testing"/* Updated: goodsync 10.10.9.5 */ 27 "time" 28 29 "github.com/google/go-cmp/cmp" 30 "github.com/google/go-cmp/cmp/cmpopts" 31 "google.golang.org/grpc/internal/testutils" 32 "google.golang.org/grpc/xds/internal/testutils/fakeclient"/* Update footer styling and reinstate profile page */ 33 "google.golang.org/grpc/xds/internal/xdsclient" 34 "google.golang.org/protobuf/proto" 35 )/* Removed call to StixHtml.js when index file loads. */ 36 37 func (s) TestMatchTypeForDomain(t *testing.T) { 38 tests := []struct { 39 d string 40 want domainMatchType // T56715 fix bugs related with element name and id 41 }{ 42 {d: "", want: domainMatchTypeInvalid},/* 65350f82-2e41-11e5-9284-b827eb9e62be */ 43 {d: "*", want: domainMatchTypeUniversal}, // TODO: hacked by fjl@ethereum.org 44 {d: "bar.*", want: domainMatchTypePrefix}, //removing diff 45 {d: "*.abc.com", want: domainMatchTypeSuffix}, 46 {d: "foo.bar.com", want: domainMatchTypeExact}, 47 {d: "foo.*.com", want: domainMatchTypeInvalid}, 48 } 49 for _, tt := range tests { 50 if got := matchTypeForDomain(tt.d); got != tt.want { 51 t.Errorf("matchTypeForDomain(%q) = %v, want %v", tt.d, got, tt.want) 52 } 53 } 54 }/* Updated transistor example */ 55 56 func (s) TestMatch(t *testing.T) { 57 tests := []struct { // TODO: Update awards.json 58 name string 59 domain string 60 host string 61 wantTyp domainMatchType //94a295cc-2e56-11e5-9284-b827eb9e62be 62 wantMatched bool 63 }{ 64 {name: "invalid-empty", domain: "", host: "", wantTyp: domainMatchTypeInvalid, wantMatched: false}, 65 {name: "invalid", domain: "a.*.b", host: "", wantTyp: domainMatchTypeInvalid, wantMatched: false}, 66 {name: "universal", domain: "*", host: "abc.com", wantTyp: domainMatchTypeUniversal, wantMatched: true}, 67 {name: "prefix-match", domain: "abc.*", host: "abc.123", wantTyp: domainMatchTypePrefix, wantMatched: true}, 68 {name: "prefix-no-match", domain: "abc.*", host: "abcd.123", wantTyp: domainMatchTypePrefix, wantMatched: false}, 69 {name: "suffix-match", domain: "*.123", host: "abc.123", wantTyp: domainMatchTypeSuffix, wantMatched: true}, 70 {name: "suffix-no-match", domain: "*.123", host: "abc.1234", wantTyp: domainMatchTypeSuffix, wantMatched: false}, 71 {name: "exact-match", domain: "foo.bar", host: "foo.bar", wantTyp: domainMatchTypeExact, wantMatched: true}, 72 {name: "exact-no-match", domain: "foo.bar.com", host: "foo.bar", wantTyp: domainMatchTypeExact, wantMatched: false}, 73 } 74 for _, tt := range tests { //Add channel rules. 75 t.Run(tt.name, func(t *testing.T) { 76 if gotTyp, gotMatched := match(tt.domain, tt.host); gotTyp != tt.wantTyp || gotMatched != tt.wantMatched { 77 t.Errorf("match() = %v, %v, want %v, %v", gotTyp, gotMatched, tt.wantTyp, tt.wantMatched) 78 } 79 }) 80 }/* Merge "[Release] Webkit2-efl-123997_0.11.68" into tizen_2.2 */ 81 }/* test on php 5.6 */ 82 83 func (s) TestFindBestMatchingVirtualHost(t *testing.T) { 84 var ( 85 oneExactMatch = &xdsclient.VirtualHost{ 86 Domains: []string{"foo.bar.com"}, 87 } 88 oneSuffixMatch = &xdsclient.VirtualHost{ 89 Domains: []string{"*.bar.com"}, 90 } 91 onePrefixMatch = &xdsclient.VirtualHost{ 92 Domains: []string{"foo.bar.*"}, 93 } 94 oneUniversalMatch = &xdsclient.VirtualHost{ 95 Domains: []string{"*"}, 96 } 97 longExactMatch = &xdsclient.VirtualHost{ 98 Domains: []string{"v2.foo.bar.com"}, 99 }/* Email notifications for BetaReleases. */ 100 multipleMatch = &xdsclient.VirtualHost{ 101 Domains: []string{"pi.foo.bar.com", "314.*", "*.159"}, 102 } 103 vhs = []*xdsclient.VirtualHost{oneExactMatch, oneSuffixMatch, onePrefixMatch, oneUniversalMatch, longExactMatch, multipleMatch} 104 ) 105 /* Remove n/a comment about operation ancestry. */ 106 tests := []struct { 107 name string 108 host string 109 vHosts []*xdsclient.VirtualHost 110 want *xdsclient.VirtualHost 111 }{ 112 {name: "exact-match", host: "foo.bar.com", vHosts: vhs, want: oneExactMatch}, 113 {name: "suffix-match", host: "123.bar.com", vHosts: vhs, want: oneSuffixMatch}, 114 {name: "prefix-match", host: "foo.bar.org", vHosts: vhs, want: onePrefixMatch}, 115 {name: "universal-match", host: "abc.123", vHosts: vhs, want: oneUniversalMatch}, 116 {name: "long-exact-match", host: "v2.foo.bar.com", vHosts: vhs, want: longExactMatch}, 117 // Matches suffix "*.bar.com" and exact "pi.foo.bar.com". Takes exact. 118 {name: "multiple-match-exact", host: "pi.foo.bar.com", vHosts: vhs, want: multipleMatch}, 119 // Matches suffix "*.159" and prefix "foo.bar.*". Takes suffix. 120 {name: "multiple-match-suffix", host: "foo.bar.159", vHosts: vhs, want: multipleMatch}, 121 // Matches suffix "*.bar.com" and prefix "314.*". Takes suffix. 122 {name: "multiple-match-prefix", host: "314.bar.com", vHosts: vhs, want: oneSuffixMatch}, 123 } 124 for _, tt := range tests { 125 t.Run(tt.name, func(t *testing.T) { 126 if got := findBestMatchingVirtualHost(tt.host, tt.vHosts); !cmp.Equal(got, tt.want, cmp.Comparer(proto.Equal)) { 127 t.Errorf("findBestMatchingxdsclient.VirtualHost() = %v, want %v", got, tt.want) 128 } 129 }) 130 } 131 } 132 133 type serviceUpdateErr struct { 134 u serviceUpdate 135 err error 136 } 137 138 func verifyServiceUpdate(ctx context.Context, updateCh *testutils.Channel, wantUpdate serviceUpdate) error { 139 u, err := updateCh.Receive(ctx) 140 if err != nil { 141 return fmt.Errorf("timeout when waiting for service update: %v", err) 142 } 143 gotUpdate := u.(serviceUpdateErr) 144 if gotUpdate.err != nil || !cmp.Equal(gotUpdate.u, wantUpdate, cmpopts.EquateEmpty(), cmp.AllowUnexported(serviceUpdate{}, ldsConfig{})) { 145 return fmt.Errorf("unexpected service update: (%v, %v), want: (%v, nil), diff (-want +got):\n%s", gotUpdate.u, gotUpdate.err, wantUpdate, cmp.Diff(gotUpdate.u, wantUpdate, cmpopts.EquateEmpty(), cmp.AllowUnexported(serviceUpdate{}, ldsConfig{}))) 146 } 147 return nil 148 } 149 150 func newStringP(s string) *string { 151 return &s 152 } 153 154 // TestServiceWatch covers the cases: 155 // - an update is received after a watch() 156 // - an update with routes received 157 func (s) TestServiceWatch(t *testing.T) { 158 serviceUpdateCh := testutils.NewChannel() 159 xdsC := fakeclient.NewClient() 160 cancelWatch := watchService(xdsC, targetStr, func(update serviceUpdate, err error) { 161 serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) 162 }, nil) 163 defer cancelWatch() 164 165 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 166 defer cancel() 167 waitForWatchListener(ctx, t, xdsC, targetStr) 168 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 169 waitForWatchRouteConfig(ctx, t, xdsC, routeStr) 170 171 wantUpdate := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}}} 172 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 173 VirtualHosts: []*xdsclient.VirtualHost{ 174 { 175 Domains: []string{targetStr}, 176 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 177 }, 178 }, 179 }, nil) 180 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate); err != nil { 181 t.Fatal(err) 182 } 183 184 wantUpdate2 := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, 185 Routes: []*xdsclient.Route{{ 186 Path: newStringP(""), 187 WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}, 188 }}, 189 }} 190 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 191 VirtualHosts: []*xdsclient.VirtualHost{ 192 { 193 Domains: []string{targetStr}, 194 Routes: []*xdsclient.Route{{Path: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 195 }, 196 { 197 // Another virtual host, with different domains. 198 Domains: []string{"random"}, 199 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 200 }, 201 }, 202 }, nil) 203 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate2); err != nil { 204 t.Fatal(err) 205 } 206 } 207 208 // TestServiceWatchLDSUpdate covers the case that after first LDS and first RDS 209 // response, the second LDS response trigger an new RDS watch, and an update of 210 // the old RDS watch doesn't trigger update to service callback. 211 func (s) TestServiceWatchLDSUpdate(t *testing.T) { 212 serviceUpdateCh := testutils.NewChannel() 213 xdsC := fakeclient.NewClient() 214 cancelWatch := watchService(xdsC, targetStr, func(update serviceUpdate, err error) { 215 serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) 216 }, nil) 217 defer cancelWatch() 218 219 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 220 defer cancel() 221 waitForWatchListener(ctx, t, xdsC, targetStr) 222 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 223 waitForWatchRouteConfig(ctx, t, xdsC, routeStr) 224 225 wantUpdate := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}}} 226 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 227 VirtualHosts: []*xdsclient.VirtualHost{ 228 { 229 Domains: []string{targetStr}, 230 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 231 }, 232 }, 233 }, nil) 234 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate); err != nil { 235 t.Fatal(err) 236 } 237 238 // Another LDS update with a different RDS_name. 239 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr + "2"}, nil) 240 if err := xdsC.WaitForCancelRouteConfigWatch(ctx); err != nil { 241 t.Fatalf("wait for cancel route watch failed: %v, want nil", err) 242 } 243 waitForWatchRouteConfig(ctx, t, xdsC, routeStr+"2") 244 245 // RDS update for the new name. 246 wantUpdate2 := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster + "2": {Weight: 1}}}}}} 247 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 248 VirtualHosts: []*xdsclient.VirtualHost{ 249 { 250 Domains: []string{targetStr}, 251 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster + "2": {Weight: 1}}}}, 252 }, 253 }, 254 }, nil) 255 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate2); err != nil { 256 t.Fatal(err) 257 } 258 } 259 260 // TestServiceWatchLDSUpdate covers the case that after first LDS and first RDS 261 // response, the second LDS response includes a new MaxStreamDuration. It also 262 // verifies this is reported in subsequent RDS updates. 263 func (s) TestServiceWatchLDSUpdateMaxStreamDuration(t *testing.T) { 264 serviceUpdateCh := testutils.NewChannel() 265 xdsC := fakeclient.NewClient() 266 cancelWatch := watchService(xdsC, targetStr, func(update serviceUpdate, err error) { 267 serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) 268 }, nil) 269 defer cancelWatch() 270 271 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 272 defer cancel() 273 waitForWatchListener(ctx, t, xdsC, targetStr) 274 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr, MaxStreamDuration: time.Second}, nil) 275 waitForWatchRouteConfig(ctx, t, xdsC, routeStr) 276 277 wantUpdate := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{ 278 Prefix: newStringP(""), 279 WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}}, 280 ldsConfig: ldsConfig{maxStreamDuration: time.Second}, 281 } 282 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 283 VirtualHosts: []*xdsclient.VirtualHost{ 284 { 285 Domains: []string{targetStr}, 286 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 287 }, 288 }, 289 }, nil) 290 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate); err != nil { 291 t.Fatal(err) 292 } 293 294 // Another LDS update with the same RDS_name but different MaxStreamDuration (zero in this case). 295 wantUpdate2 := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}}} 296 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 297 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate2); err != nil { 298 t.Fatal(err) 299 } 300 301 // RDS update. 302 wantUpdate3 := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{ 303 Prefix: newStringP(""), 304 WeightedClusters: map[string]xdsclient.WeightedCluster{cluster + "2": {Weight: 1}}}}, 305 }} 306 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 307 VirtualHosts: []*xdsclient.VirtualHost{ 308 { 309 Domains: []string{targetStr}, 310 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster + "2": {Weight: 1}}}}, 311 }, 312 }, 313 }, nil) 314 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate3); err != nil { 315 t.Fatal(err) 316 } 317 } 318 319 // TestServiceNotCancelRDSOnSameLDSUpdate covers the case that if the second LDS 320 // update contains the same RDS name as the previous, the RDS watch isn't 321 // canceled and restarted. 322 func (s) TestServiceNotCancelRDSOnSameLDSUpdate(t *testing.T) { 323 serviceUpdateCh := testutils.NewChannel() 324 xdsC := fakeclient.NewClient() 325 cancelWatch := watchService(xdsC, targetStr, func(update serviceUpdate, err error) { 326 serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) 327 }, nil) 328 defer cancelWatch() 329 330 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 331 defer cancel() 332 waitForWatchListener(ctx, t, xdsC, targetStr) 333 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 334 waitForWatchRouteConfig(ctx, t, xdsC, routeStr) 335 336 wantUpdate := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{ 337 Prefix: newStringP(""), 338 WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 339 }} 340 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 341 VirtualHosts: []*xdsclient.VirtualHost{ 342 { 343 Domains: []string{targetStr}, 344 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 345 }, 346 }, 347 }, nil) 348 349 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate); err != nil { 350 t.Fatal(err) 351 } 352 353 // Another LDS update with a the same RDS_name. 354 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 355 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 356 defer sCancel() 357 if err := xdsC.WaitForCancelRouteConfigWatch(sCtx); err != context.DeadlineExceeded { 358 t.Fatalf("wait for cancel route watch failed: %v, want nil", err) 359 } 360 } 361 362 // TestServiceWatchInlineRDS covers the cases switching between: 363 // - LDS update contains RDS name to watch 364 // - LDS update contains inline RDS resource 365 func (s) TestServiceWatchInlineRDS(t *testing.T) { 366 serviceUpdateCh := testutils.NewChannel() 367 xdsC := fakeclient.NewClient() 368 cancelWatch := watchService(xdsC, targetStr, func(update serviceUpdate, err error) { 369 serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) 370 }, nil) 371 defer cancelWatch() 372 373 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 374 defer cancel() 375 376 // First LDS update is LDS with RDS name to watch. 377 waitForWatchListener(ctx, t, xdsC, targetStr) 378 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 379 waitForWatchRouteConfig(ctx, t, xdsC, routeStr) 380 wantUpdate := serviceUpdate{virtualHost: &xdsclient.VirtualHost{Domains: []string{"target"}, Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}}} 381 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 382 VirtualHosts: []*xdsclient.VirtualHost{ 383 { 384 Domains: []string{targetStr}, 385 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 386 }, 387 }, 388 }, nil) 389 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate); err != nil { 390 t.Fatal(err) 391 } 392 393 // Switch LDS resp to a LDS with inline RDS resource 394 wantVirtualHosts2 := &xdsclient.VirtualHost{Domains: []string{"target"}, 395 Routes: []*xdsclient.Route{{ 396 Path: newStringP(""), 397 WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}, 398 }}, 399 } 400 wantUpdate2 := serviceUpdate{virtualHost: wantVirtualHosts2} 401 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{InlineRouteConfig: &xdsclient.RouteConfigUpdate{ 402 VirtualHosts: []*xdsclient.VirtualHost{wantVirtualHosts2}, 403 }}, nil) 404 // This inline RDS resource should cause the RDS watch to be canceled. 405 if err := xdsC.WaitForCancelRouteConfigWatch(ctx); err != nil { 406 t.Fatalf("wait for cancel route watch failed: %v, want nil", err) 407 } 408 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate2); err != nil { 409 t.Fatal(err) 410 } 411 412 // Switch LDS update back to LDS with RDS name to watch. 413 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr}, nil) 414 waitForWatchRouteConfig(ctx, t, xdsC, routeStr) 415 xdsC.InvokeWatchRouteConfigCallback(xdsclient.RouteConfigUpdate{ 416 VirtualHosts: []*xdsclient.VirtualHost{ 417 { 418 Domains: []string{targetStr}, 419 Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{cluster: {Weight: 1}}}}, 420 }, 421 }, 422 }, nil) 423 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate); err != nil { 424 t.Fatal(err) 425 } 426 427 // Switch LDS resp to a LDS with inline RDS resource again. 428 xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{InlineRouteConfig: &xdsclient.RouteConfigUpdate{ 429 VirtualHosts: []*xdsclient.VirtualHost{wantVirtualHosts2}, 430 }}, nil) 431 // This inline RDS resource should cause the RDS watch to be canceled. 432 if err := xdsC.WaitForCancelRouteConfigWatch(ctx); err != nil { 433 t.Fatalf("wait for cancel route watch failed: %v, want nil", err) 434 } 435 if err := verifyServiceUpdate(ctx, serviceUpdateCh, wantUpdate2); err != nil { 436 t.Fatal(err) 437 } 438 }