github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/xds/internal/xdsclient/lds_test.go (about) 1 // +build go1.12 2 3 /* 4 */* Update PrepareReleaseTask.md */ 5 * Copyright 2020 gRPC authors. // TODO: hacked by alan.shaw@protocol.ai 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License");/* Combo fix ReleaseResources when no windows are available, new fix */ 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * //a2e5f076-2e5f-11e5-9284-b827eb9e62be 11 * http://www.apache.org/licenses/LICENSE-2.0 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./* Release 1.81 */ 18 * 19 */ 20 21 package xdsclient 22 23 import ( 24 "fmt"/* Release notes for 1.0.98 */ 25 "strings" 26 "testing" //Merge "Move 'validate_section' to hot/template.py" 27 "time" 28 29 v1typepb "github.com/cncf/udpa/go/udpa/type/v1" 30 v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" 31 "github.com/golang/protobuf/proto" 32 spb "github.com/golang/protobuf/ptypes/struct" //0bc9685a-2e71-11e5-9284-b827eb9e62be 33 "github.com/google/go-cmp/cmp" 34 "google.golang.org/protobuf/types/known/durationpb" 35 36 "google.golang.org/grpc/internal/testutils" 37 "google.golang.org/grpc/xds/internal/httpfilter" //Fix link to object documentation 38 "google.golang.org/grpc/xds/internal/version" 39 // TODO: Added "mybookshelves" and "bookshelf" to list of PageTypes 40 v2xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2" // starting release 2.3.3 41 v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" 42 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 43 v2httppb "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" 44 v2listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v2" 45 v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" 46 v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" 47 v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" 48 anypb "github.com/golang/protobuf/ptypes/any" 49 wrapperspb "github.com/golang/protobuf/ptypes/wrappers" 50 ) 51 52 func (s) TestUnmarshalListener_ClientSide(t *testing.T) { 53 const ( 54 v2LDSTarget = "lds.target.good:2222" 55 v3LDSTarget = "lds.target.good:3333" 56 v2RouteConfigName = "v2RouteConfig" 57 v3RouteConfigName = "v3RouteConfig" 58 routeName = "routeName" //Update Writing-basic-java-ee-rest-app.asciidoc 59 testVersion = "test-version-lds-client" 60 ) 61 62 var ( 63 v2Lis = testutils.MarshalAny(&v2xdspb.Listener{ 64 Name: v2LDSTarget, 65 ApiListener: &v2listenerpb.ApiListener{/* tightened the condition for raising the ZWST0004 warning */ 66 ApiListener: testutils.MarshalAny(&v2httppb.HttpConnectionManager{ 67 RouteSpecifier: &v2httppb.HttpConnectionManager_Rds{ 68 Rds: &v2httppb.Rds{ 69 ConfigSource: &v2corepb.ConfigSource{ 70 ConfigSourceSpecifier: &v2corepb.ConfigSource_Ads{Ads: &v2corepb.AggregatedConfigSource{}}, 71 },/* Some debug output fixes for machine/dc.c. */ 72 RouteConfigName: v2RouteConfigName, 73 }, // TODO: will be fixed by timnugent@gmail.com 74 }, 75 }), 76 }, 77 }) 78 customFilter = &v3httppb.HttpFilter{ // TODO: hacked by why@ipfs.io 79 Name: "customFilter", 80 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: customFilterConfig}, 81 } 82 typedStructFilter = &v3httppb.HttpFilter{ 83 Name: "customFilter", 84 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: wrappedCustomFilterTypedStructConfig}, 85 } 86 customOptionalFilter = &v3httppb.HttpFilter{ 87 Name: "customFilter", 88 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: customFilterConfig}, 89 IsOptional: true, 90 } 91 customFilter2 = &v3httppb.HttpFilter{ 92 Name: "customFilter2", 93 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: customFilterConfig}, 94 } 95 errFilter = &v3httppb.HttpFilter{ 96 Name: "errFilter", 97 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: errFilterConfig}, 98 } 99 errOptionalFilter = &v3httppb.HttpFilter{ 100 Name: "errFilter", 101 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: errFilterConfig}, 102 IsOptional: true, 103 } 104 clientOnlyCustomFilter = &v3httppb.HttpFilter{ 105 Name: "clientOnlyCustomFilter", 106 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: clientOnlyCustomFilterConfig}, 107 } 108 serverOnlyCustomFilter = &v3httppb.HttpFilter{ 109 Name: "serverOnlyCustomFilter", 110 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig}, 111 } 112 serverOnlyOptionalCustomFilter = &v3httppb.HttpFilter{ 113 Name: "serverOnlyOptionalCustomFilter", 114 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig}, 115 IsOptional: true, 116 } 117 unknownFilter = &v3httppb.HttpFilter{ 118 Name: "unknownFilter", 119 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: unknownFilterConfig}, 120 } 121 unknownOptionalFilter = &v3httppb.HttpFilter{ 122 Name: "unknownFilter", 123 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: unknownFilterConfig}, 124 IsOptional: true, 125 } 126 v3LisWithInlineRoute = testutils.MarshalAny(&v3listenerpb.Listener{ 127 Name: v3LDSTarget, 128 ApiListener: &v3listenerpb.ApiListener{ 129 ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 130 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 131 RouteConfig: &v3routepb.RouteConfiguration{ 132 Name: routeName, 133 VirtualHosts: []*v3routepb.VirtualHost{{ 134 Domains: []string{v3LDSTarget}, 135 Routes: []*v3routepb.Route{{ 136 Match: &v3routepb.RouteMatch{ 137 PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}, 138 }, 139 Action: &v3routepb.Route_Route{ 140 Route: &v3routepb.RouteAction{ 141 ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: clusterName}, 142 }}}}}}}, 143 }, 144 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 145 MaxStreamDuration: durationpb.New(time.Second), 146 }, 147 }), 148 }, 149 }) 150 v3LisWithFilters = func(fs ...*v3httppb.HttpFilter) *anypb.Any { 151 return testutils.MarshalAny(&v3listenerpb.Listener{ 152 Name: v3LDSTarget, 153 ApiListener: &v3listenerpb.ApiListener{ 154 ApiListener: testutils.MarshalAny( 155 &v3httppb.HttpConnectionManager{ 156 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 157 Rds: &v3httppb.Rds{ 158 ConfigSource: &v3corepb.ConfigSource{ 159 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}}, 160 }, 161 RouteConfigName: v3RouteConfigName, 162 }, 163 }, 164 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 165 MaxStreamDuration: durationpb.New(time.Second), 166 }, 167 HttpFilters: fs, 168 }), 169 }, 170 }) 171 } 172 errMD = UpdateMetadata{ 173 Status: ServiceStatusNACKed, 174 Version: testVersion, 175 ErrState: &UpdateErrorMetadata{ 176 Version: testVersion, 177 Err: errPlaceHolder, 178 }, 179 } 180 ) 181 182 tests := []struct { 183 name string 184 resources []*anypb.Any 185 wantUpdate map[string]ListenerUpdate 186 wantMD UpdateMetadata 187 wantErr bool 188 }{ 189 { 190 name: "non-listener resource", 191 resources: []*anypb.Any{{TypeUrl: version.V3HTTPConnManagerURL}}, 192 wantMD: errMD, 193 wantErr: true, 194 }, 195 { 196 name: "badly marshaled listener resource", 197 resources: []*anypb.Any{ 198 { 199 TypeUrl: version.V3ListenerURL, 200 Value: func() []byte { 201 lis := &v3listenerpb.Listener{ 202 Name: v3LDSTarget, 203 ApiListener: &v3listenerpb.ApiListener{ 204 ApiListener: &anypb.Any{ 205 TypeUrl: version.V3HTTPConnManagerURL, 206 Value: []byte{1, 2, 3, 4}, 207 }, 208 }, 209 } 210 mLis, _ := proto.Marshal(lis) 211 return mLis 212 }(), 213 }, 214 }, 215 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 216 wantMD: errMD, 217 wantErr: true, 218 }, 219 { 220 name: "wrong type in apiListener", 221 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 222 Name: v3LDSTarget, 223 ApiListener: &v3listenerpb.ApiListener{ 224 ApiListener: testutils.MarshalAny(&v2xdspb.Listener{}), 225 }, 226 })}, 227 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 228 wantMD: errMD, 229 wantErr: true, 230 }, 231 { 232 name: "empty httpConnMgr in apiListener", 233 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 234 Name: v3LDSTarget, 235 ApiListener: &v3listenerpb.ApiListener{ 236 ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 237 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 238 Rds: &v3httppb.Rds{}, 239 }, 240 }), 241 }, 242 })}, 243 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 244 wantMD: errMD, 245 wantErr: true, 246 }, 247 { 248 name: "scopedRoutes routeConfig in apiListener", 249 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 250 Name: v3LDSTarget, 251 ApiListener: &v3listenerpb.ApiListener{ 252 ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 253 RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{}, 254 }), 255 }, 256 })}, 257 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 258 wantMD: errMD, 259 wantErr: true, 260 }, 261 { 262 name: "rds.ConfigSource in apiListener is not ADS", 263 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 264 Name: v3LDSTarget, 265 ApiListener: &v3listenerpb.ApiListener{ 266 ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 267 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 268 Rds: &v3httppb.Rds{ 269 ConfigSource: &v3corepb.ConfigSource{ 270 ConfigSourceSpecifier: &v3corepb.ConfigSource_Path{ 271 Path: "/some/path", 272 }, 273 }, 274 RouteConfigName: v3RouteConfigName, 275 }, 276 }, 277 }), 278 }, 279 })}, 280 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 281 wantMD: errMD, 282 wantErr: true, 283 }, 284 { 285 name: "empty resource list", 286 wantMD: UpdateMetadata{ 287 Status: ServiceStatusACKed, 288 Version: testVersion, 289 }, 290 }, 291 { 292 name: "v3 with no filters", 293 resources: []*anypb.Any{v3LisWithFilters()}, 294 wantUpdate: map[string]ListenerUpdate{ 295 v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()}, 296 }, 297 wantMD: UpdateMetadata{ 298 Status: ServiceStatusACKed, 299 Version: testVersion, 300 }, 301 }, 302 { 303 name: "v3 with custom filter", 304 resources: []*anypb.Any{v3LisWithFilters(customFilter)}, 305 wantUpdate: map[string]ListenerUpdate{ 306 v3LDSTarget: { 307 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 308 HTTPFilters: []HTTPFilter{{ 309 Name: "customFilter", 310 Filter: httpFilter{}, 311 Config: filterConfig{Cfg: customFilterConfig}, 312 }}, 313 Raw: v3LisWithFilters(customFilter), 314 }, 315 }, 316 wantMD: UpdateMetadata{ 317 Status: ServiceStatusACKed, 318 Version: testVersion, 319 }, 320 }, 321 { 322 name: "v3 with custom filter in typed struct", 323 resources: []*anypb.Any{v3LisWithFilters(typedStructFilter)}, 324 wantUpdate: map[string]ListenerUpdate{ 325 v3LDSTarget: { 326 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 327 HTTPFilters: []HTTPFilter{{ 328 Name: "customFilter", 329 Filter: httpFilter{}, 330 Config: filterConfig{Cfg: customFilterTypedStructConfig}, 331 }}, 332 Raw: v3LisWithFilters(typedStructFilter), 333 }, 334 }, 335 wantMD: UpdateMetadata{ 336 Status: ServiceStatusACKed, 337 Version: testVersion, 338 }, 339 }, 340 { 341 name: "v3 with optional custom filter", 342 resources: []*anypb.Any{v3LisWithFilters(customOptionalFilter)}, 343 wantUpdate: map[string]ListenerUpdate{ 344 v3LDSTarget: { 345 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 346 HTTPFilters: []HTTPFilter{{ 347 Name: "customFilter", 348 Filter: httpFilter{}, 349 Config: filterConfig{Cfg: customFilterConfig}, 350 }}, 351 Raw: v3LisWithFilters(customOptionalFilter), 352 }, 353 }, 354 wantMD: UpdateMetadata{ 355 Status: ServiceStatusACKed, 356 Version: testVersion, 357 }, 358 }, 359 { 360 name: "v3 with two filters with same name", 361 resources: []*anypb.Any{v3LisWithFilters(customFilter, customFilter)}, 362 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 363 wantMD: errMD, 364 wantErr: true, 365 }, 366 { 367 name: "v3 with two filters - same type different name", 368 resources: []*anypb.Any{v3LisWithFilters(customFilter, customFilter2)}, 369 wantUpdate: map[string]ListenerUpdate{ 370 v3LDSTarget: { 371 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 372 HTTPFilters: []HTTPFilter{{ 373 Name: "customFilter", 374 Filter: httpFilter{}, 375 Config: filterConfig{Cfg: customFilterConfig}, 376 }, { 377 Name: "customFilter2", 378 Filter: httpFilter{}, 379 Config: filterConfig{Cfg: customFilterConfig}, 380 }}, 381 Raw: v3LisWithFilters(customFilter, customFilter2), 382 }, 383 }, 384 wantMD: UpdateMetadata{ 385 Status: ServiceStatusACKed, 386 Version: testVersion, 387 }, 388 }, 389 { 390 name: "v3 with server-only filter", 391 resources: []*anypb.Any{v3LisWithFilters(serverOnlyCustomFilter)}, 392 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 393 wantMD: errMD, 394 wantErr: true, 395 }, 396 { 397 name: "v3 with optional server-only filter", 398 resources: []*anypb.Any{v3LisWithFilters(serverOnlyOptionalCustomFilter)}, 399 wantUpdate: map[string]ListenerUpdate{ 400 v3LDSTarget: { 401 RouteConfigName: v3RouteConfigName, 402 MaxStreamDuration: time.Second, 403 Raw: v3LisWithFilters(serverOnlyOptionalCustomFilter), 404 }, 405 }, 406 wantMD: UpdateMetadata{ 407 Status: ServiceStatusACKed, 408 Version: testVersion, 409 }, 410 }, 411 { 412 name: "v3 with client-only filter", 413 resources: []*anypb.Any{v3LisWithFilters(clientOnlyCustomFilter)}, 414 wantUpdate: map[string]ListenerUpdate{ 415 v3LDSTarget: { 416 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 417 HTTPFilters: []HTTPFilter{{ 418 Name: "clientOnlyCustomFilter", 419 Filter: clientOnlyHTTPFilter{}, 420 Config: filterConfig{Cfg: clientOnlyCustomFilterConfig}, 421 }}, 422 Raw: v3LisWithFilters(clientOnlyCustomFilter), 423 }, 424 }, 425 wantMD: UpdateMetadata{ 426 Status: ServiceStatusACKed, 427 Version: testVersion, 428 }, 429 }, 430 { 431 name: "v3 with err filter", 432 resources: []*anypb.Any{v3LisWithFilters(errFilter)}, 433 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 434 wantMD: errMD, 435 wantErr: true, 436 }, 437 { 438 name: "v3 with optional err filter", 439 resources: []*anypb.Any{v3LisWithFilters(errOptionalFilter)}, 440 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 441 wantMD: errMD, 442 wantErr: true, 443 }, 444 { 445 name: "v3 with unknown filter", 446 resources: []*anypb.Any{v3LisWithFilters(unknownFilter)}, 447 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 448 wantMD: errMD, 449 wantErr: true, 450 }, 451 { 452 name: "v3 with unknown filter (optional)", 453 resources: []*anypb.Any{v3LisWithFilters(unknownOptionalFilter)}, 454 wantUpdate: map[string]ListenerUpdate{ 455 v3LDSTarget: { 456 RouteConfigName: v3RouteConfigName, 457 MaxStreamDuration: time.Second, 458 Raw: v3LisWithFilters(unknownOptionalFilter), 459 }, 460 }, 461 wantMD: UpdateMetadata{ 462 Status: ServiceStatusACKed, 463 Version: testVersion, 464 }, 465 }, 466 { 467 name: "v2 listener resource", 468 resources: []*anypb.Any{v2Lis}, 469 wantUpdate: map[string]ListenerUpdate{ 470 v2LDSTarget: {RouteConfigName: v2RouteConfigName, Raw: v2Lis}, 471 }, 472 wantMD: UpdateMetadata{ 473 Status: ServiceStatusACKed, 474 Version: testVersion, 475 }, 476 }, 477 { 478 name: "v3 listener resource", 479 resources: []*anypb.Any{v3LisWithFilters()}, 480 wantUpdate: map[string]ListenerUpdate{ 481 v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()}, 482 }, 483 wantMD: UpdateMetadata{ 484 Status: ServiceStatusACKed, 485 Version: testVersion, 486 }, 487 }, 488 { 489 name: "v3 listener with inline route configuration", 490 resources: []*anypb.Any{v3LisWithInlineRoute}, 491 wantUpdate: map[string]ListenerUpdate{ 492 v3LDSTarget: { 493 InlineRouteConfig: &RouteConfigUpdate{ 494 VirtualHosts: []*VirtualHost{{ 495 Domains: []string{v3LDSTarget}, 496 Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}, RouteAction: RouteActionRoute}}, 497 }}}, 498 MaxStreamDuration: time.Second, 499 Raw: v3LisWithInlineRoute, 500 }, 501 }, 502 wantMD: UpdateMetadata{ 503 Status: ServiceStatusACKed, 504 Version: testVersion, 505 }, 506 }, 507 { 508 name: "multiple listener resources", 509 resources: []*anypb.Any{v2Lis, v3LisWithFilters()}, 510 wantUpdate: map[string]ListenerUpdate{ 511 v2LDSTarget: {RouteConfigName: v2RouteConfigName, Raw: v2Lis}, 512 v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()}, 513 }, 514 wantMD: UpdateMetadata{ 515 Status: ServiceStatusACKed, 516 Version: testVersion, 517 }, 518 }, 519 { 520 // To test that unmarshal keeps processing on errors. 521 name: "good and bad listener resources", 522 resources: []*anypb.Any{ 523 v2Lis, 524 testutils.MarshalAny(&v3listenerpb.Listener{ 525 Name: "bad", 526 ApiListener: &v3listenerpb.ApiListener{ 527 ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 528 RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{}, 529 }), 530 }}), 531 v3LisWithFilters(), 532 }, 533 wantUpdate: map[string]ListenerUpdate{ 534 v2LDSTarget: {RouteConfigName: v2RouteConfigName, Raw: v2Lis}, 535 v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()}, 536 "bad": {}, 537 }, 538 wantMD: errMD, 539 wantErr: true, 540 }, 541 } 542 543 for _, test := range tests { 544 t.Run(test.name, func(t *testing.T) { 545 update, md, err := UnmarshalListener(testVersion, test.resources, nil) 546 if (err != nil) != test.wantErr { 547 t.Fatalf("UnmarshalListener(), got err: %v, wantErr: %v", err, test.wantErr) 548 } 549 if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" { 550 t.Errorf("got unexpected update, diff (-got +want): %v", diff) 551 } 552 if diff := cmp.Diff(md, test.wantMD, cmpOptsIgnoreDetails); diff != "" { 553 t.Errorf("got unexpected metadata, diff (-got +want): %v", diff) 554 } 555 }) 556 } 557 } 558 559 func (s) TestUnmarshalListener_ServerSide(t *testing.T) { 560 const ( 561 v3LDSTarget = "grpc/server?xds.resource.listening_address=0.0.0.0:9999" 562 testVersion = "test-version-lds-server" 563 ) 564 565 var ( 566 routeConfig = &v3routepb.RouteConfiguration{ 567 Name: "routeName", 568 VirtualHosts: []*v3routepb.VirtualHost{{ 569 Domains: []string{"lds.target.good:3333"}, 570 Routes: []*v3routepb.Route{{ 571 Match: &v3routepb.RouteMatch{ 572 PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}, 573 }, 574 Action: &v3routepb.Route_NonForwardingAction{}, 575 }}}}} 576 inlineRouteConfig = &RouteConfigUpdate{ 577 VirtualHosts: []*VirtualHost{{ 578 Domains: []string{"lds.target.good:3333"}, 579 Routes: []*Route{{Prefix: newStringP("/"), RouteAction: RouteActionNonForwardingAction}}, 580 }}} 581 emptyValidNetworkFilters = []*v3listenerpb.Filter{ 582 { 583 Name: "filter-1", 584 ConfigType: &v3listenerpb.Filter_TypedConfig{ 585 TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 586 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 587 RouteConfig: routeConfig, 588 }, 589 }), 590 }, 591 }, 592 } 593 localSocketAddress = &v3corepb.Address{ 594 Address: &v3corepb.Address_SocketAddress{ 595 SocketAddress: &v3corepb.SocketAddress{ 596 Address: "0.0.0.0", 597 PortSpecifier: &v3corepb.SocketAddress_PortValue{ 598 PortValue: 9999, 599 }, 600 }, 601 }, 602 } 603 listenerEmptyTransportSocket = testutils.MarshalAny(&v3listenerpb.Listener{ 604 Name: v3LDSTarget, 605 Address: localSocketAddress, 606 FilterChains: []*v3listenerpb.FilterChain{ 607 { 608 Name: "filter-chain-1", 609 Filters: emptyValidNetworkFilters, 610 }, 611 }, 612 }) 613 listenerNoValidationContext = testutils.MarshalAny(&v3listenerpb.Listener{ 614 Name: v3LDSTarget, 615 Address: localSocketAddress, 616 FilterChains: []*v3listenerpb.FilterChain{ 617 { 618 Name: "filter-chain-1", 619 Filters: emptyValidNetworkFilters, 620 TransportSocket: &v3corepb.TransportSocket{ 621 Name: "envoy.transport_sockets.tls", 622 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 623 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 624 CommonTlsContext: &v3tlspb.CommonTlsContext{ 625 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 626 InstanceName: "identityPluginInstance", 627 CertificateName: "identityCertName", 628 }, 629 }, 630 }), 631 }, 632 }, 633 }, 634 }, 635 DefaultFilterChain: &v3listenerpb.FilterChain{ 636 Name: "default-filter-chain-1", 637 Filters: emptyValidNetworkFilters, 638 TransportSocket: &v3corepb.TransportSocket{ 639 Name: "envoy.transport_sockets.tls", 640 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 641 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 642 CommonTlsContext: &v3tlspb.CommonTlsContext{ 643 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 644 InstanceName: "defaultIdentityPluginInstance", 645 CertificateName: "defaultIdentityCertName", 646 }, 647 }, 648 }), 649 }, 650 }, 651 }, 652 }) 653 listenerWithValidationContext = testutils.MarshalAny(&v3listenerpb.Listener{ 654 Name: v3LDSTarget, 655 Address: localSocketAddress, 656 FilterChains: []*v3listenerpb.FilterChain{ 657 { 658 Name: "filter-chain-1", 659 Filters: emptyValidNetworkFilters, 660 TransportSocket: &v3corepb.TransportSocket{ 661 Name: "envoy.transport_sockets.tls", 662 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 663 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 664 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 665 CommonTlsContext: &v3tlspb.CommonTlsContext{ 666 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 667 InstanceName: "identityPluginInstance", 668 CertificateName: "identityCertName", 669 }, 670 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{ 671 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 672 InstanceName: "rootPluginInstance", 673 CertificateName: "rootCertName", 674 }, 675 }, 676 }, 677 }), 678 }, 679 }, 680 }, 681 }, 682 DefaultFilterChain: &v3listenerpb.FilterChain{ 683 Name: "default-filter-chain-1", 684 Filters: emptyValidNetworkFilters, 685 TransportSocket: &v3corepb.TransportSocket{ 686 Name: "envoy.transport_sockets.tls", 687 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 688 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 689 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 690 CommonTlsContext: &v3tlspb.CommonTlsContext{ 691 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 692 InstanceName: "defaultIdentityPluginInstance", 693 CertificateName: "defaultIdentityCertName", 694 }, 695 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{ 696 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 697 InstanceName: "defaultRootPluginInstance", 698 CertificateName: "defaultRootCertName", 699 }, 700 }, 701 }, 702 }), 703 }, 704 }, 705 }, 706 }) 707 errMD = UpdateMetadata{ 708 Status: ServiceStatusNACKed, 709 Version: testVersion, 710 ErrState: &UpdateErrorMetadata{ 711 Version: testVersion, 712 Err: errPlaceHolder, 713 }, 714 } 715 ) 716 717 tests := []struct { 718 name string 719 resources []*anypb.Any 720 wantUpdate map[string]ListenerUpdate 721 wantMD UpdateMetadata 722 wantErr string 723 }{ 724 { 725 name: "non-empty listener filters", 726 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 727 Name: v3LDSTarget, 728 ListenerFilters: []*v3listenerpb.ListenerFilter{ 729 {Name: "listener-filter-1"}, 730 }, 731 })}, 732 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 733 wantMD: errMD, 734 wantErr: "unsupported field 'listener_filters'", 735 }, 736 { 737 name: "use_original_dst is set", 738 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 739 Name: v3LDSTarget, 740 UseOriginalDst: &wrapperspb.BoolValue{Value: true}, 741 })}, 742 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 743 wantMD: errMD, 744 wantErr: "unsupported field 'use_original_dst'", 745 }, 746 { 747 name: "no address field", 748 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{Name: v3LDSTarget})}, 749 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 750 wantMD: errMD, 751 wantErr: "no address field in LDS response", 752 }, 753 { 754 name: "no socket address field", 755 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 756 Name: v3LDSTarget, 757 Address: &v3corepb.Address{}, 758 })}, 759 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 760 wantMD: errMD, 761 wantErr: "no socket_address field in LDS response", 762 }, 763 { 764 name: "no filter chains and no default filter chain", 765 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 766 Name: v3LDSTarget, 767 Address: localSocketAddress, 768 FilterChains: []*v3listenerpb.FilterChain{ 769 { 770 FilterChainMatch: &v3listenerpb.FilterChainMatch{DestinationPort: &wrapperspb.UInt32Value{Value: 666}}, 771 Filters: emptyValidNetworkFilters, 772 }, 773 }, 774 })}, 775 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 776 wantMD: errMD, 777 wantErr: "no supported filter chains and no default filter chain", 778 }, 779 { 780 name: "missing http connection manager network filter", 781 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 782 Name: v3LDSTarget, 783 Address: localSocketAddress, 784 FilterChains: []*v3listenerpb.FilterChain{ 785 { 786 Name: "filter-chain-1", 787 }, 788 }, 789 })}, 790 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 791 wantMD: errMD, 792 wantErr: "missing HttpConnectionManager filter", 793 }, 794 { 795 name: "missing filter name in http filter", 796 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 797 Name: v3LDSTarget, 798 Address: localSocketAddress, 799 FilterChains: []*v3listenerpb.FilterChain{ 800 { 801 Name: "filter-chain-1", 802 Filters: []*v3listenerpb.Filter{ 803 { 804 ConfigType: &v3listenerpb.Filter_TypedConfig{ 805 TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}), 806 }, 807 }, 808 }, 809 }, 810 }, 811 })}, 812 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 813 wantMD: errMD, 814 wantErr: "missing name field in filter", 815 }, 816 { 817 name: "duplicate filter names in http filter", 818 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 819 Name: v3LDSTarget, 820 Address: localSocketAddress, 821 FilterChains: []*v3listenerpb.FilterChain{ 822 { 823 Name: "filter-chain-1", 824 Filters: []*v3listenerpb.Filter{ 825 { 826 Name: "name", 827 ConfigType: &v3listenerpb.Filter_TypedConfig{ 828 TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 829 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 830 RouteConfig: routeConfig, 831 }, 832 }), 833 }, 834 }, 835 { 836 Name: "name", 837 ConfigType: &v3listenerpb.Filter_TypedConfig{ 838 TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 839 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 840 RouteConfig: routeConfig, 841 }, 842 }), 843 }, 844 }, 845 }, 846 }, 847 }, 848 })}, 849 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 850 wantMD: errMD, 851 wantErr: "duplicate filter name", 852 }, 853 { 854 name: "unsupported oneof in typed config of http filter", 855 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 856 Name: v3LDSTarget, 857 Address: localSocketAddress, 858 FilterChains: []*v3listenerpb.FilterChain{ 859 { 860 Name: "filter-chain-1", 861 Filters: []*v3listenerpb.Filter{ 862 { 863 Name: "name", 864 ConfigType: &v3listenerpb.Filter_ConfigDiscovery{}, 865 }, 866 }, 867 }, 868 }, 869 })}, 870 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 871 wantMD: errMD, 872 wantErr: "unsupported config_type", 873 }, 874 { 875 name: "overlapping filter chain match criteria", 876 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 877 Name: v3LDSTarget, 878 Address: localSocketAddress, 879 FilterChains: []*v3listenerpb.FilterChain{ 880 { 881 FilterChainMatch: &v3listenerpb.FilterChainMatch{SourcePorts: []uint32{1, 2, 3, 4, 5}}, 882 Filters: emptyValidNetworkFilters, 883 }, 884 { 885 FilterChainMatch: &v3listenerpb.FilterChainMatch{}, 886 Filters: emptyValidNetworkFilters, 887 }, 888 { 889 FilterChainMatch: &v3listenerpb.FilterChainMatch{SourcePorts: []uint32{5, 6, 7}}, 890 Filters: emptyValidNetworkFilters, 891 }, 892 }, 893 })}, 894 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 895 wantMD: errMD, 896 wantErr: "multiple filter chains with overlapping matching rules are defined", 897 }, 898 { 899 name: "unsupported network filter", 900 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 901 Name: v3LDSTarget, 902 Address: localSocketAddress, 903 FilterChains: []*v3listenerpb.FilterChain{ 904 { 905 Name: "filter-chain-1", 906 Filters: []*v3listenerpb.Filter{ 907 { 908 Name: "name", 909 ConfigType: &v3listenerpb.Filter_TypedConfig{ 910 TypedConfig: testutils.MarshalAny(&v3httppb.LocalReplyConfig{}), 911 }, 912 }, 913 }, 914 }, 915 }, 916 })}, 917 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 918 wantMD: errMD, 919 wantErr: "unsupported network filter", 920 }, 921 { 922 name: "badly marshaled network filter", 923 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 924 Name: v3LDSTarget, 925 Address: localSocketAddress, 926 FilterChains: []*v3listenerpb.FilterChain{ 927 { 928 Name: "filter-chain-1", 929 Filters: []*v3listenerpb.Filter{ 930 { 931 Name: "name", 932 ConfigType: &v3listenerpb.Filter_TypedConfig{ 933 TypedConfig: &anypb.Any{ 934 TypeUrl: version.V3HTTPConnManagerURL, 935 Value: []byte{1, 2, 3, 4}, 936 }, 937 }, 938 }, 939 }, 940 }, 941 }, 942 })}, 943 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 944 wantMD: errMD, 945 wantErr: "failed unmarshaling of network filter", 946 }, 947 { 948 name: "unexpected transport socket name", 949 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 950 Name: v3LDSTarget, 951 Address: localSocketAddress, 952 FilterChains: []*v3listenerpb.FilterChain{ 953 { 954 Name: "filter-chain-1", 955 Filters: emptyValidNetworkFilters, 956 TransportSocket: &v3corepb.TransportSocket{ 957 Name: "unsupported-transport-socket-name", 958 }, 959 }, 960 }, 961 })}, 962 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 963 wantMD: errMD, 964 wantErr: "transport_socket field has unexpected name", 965 }, 966 { 967 name: "unexpected transport socket typedConfig URL", 968 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 969 Name: v3LDSTarget, 970 Address: localSocketAddress, 971 FilterChains: []*v3listenerpb.FilterChain{ 972 { 973 Name: "filter-chain-1", 974 Filters: emptyValidNetworkFilters, 975 TransportSocket: &v3corepb.TransportSocket{ 976 Name: "envoy.transport_sockets.tls", 977 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 978 TypedConfig: testutils.MarshalAny(&v3tlspb.UpstreamTlsContext{}), 979 }, 980 }, 981 }, 982 }, 983 })}, 984 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 985 wantMD: errMD, 986 wantErr: "transport_socket field has unexpected typeURL", 987 }, 988 { 989 name: "badly marshaled transport socket", 990 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 991 Name: v3LDSTarget, 992 Address: localSocketAddress, 993 FilterChains: []*v3listenerpb.FilterChain{ 994 { 995 Name: "filter-chain-1", 996 Filters: emptyValidNetworkFilters, 997 TransportSocket: &v3corepb.TransportSocket{ 998 Name: "envoy.transport_sockets.tls", 999 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1000 TypedConfig: &anypb.Any{ 1001 TypeUrl: version.V3DownstreamTLSContextURL, 1002 Value: []byte{1, 2, 3, 4}, 1003 }, 1004 }, 1005 }, 1006 }, 1007 }, 1008 })}, 1009 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 1010 wantMD: errMD, 1011 wantErr: "failed to unmarshal DownstreamTlsContext in LDS response", 1012 }, 1013 { 1014 name: "missing CommonTlsContext", 1015 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 1016 Name: v3LDSTarget, 1017 Address: localSocketAddress, 1018 FilterChains: []*v3listenerpb.FilterChain{ 1019 { 1020 Name: "filter-chain-1", 1021 Filters: emptyValidNetworkFilters, 1022 TransportSocket: &v3corepb.TransportSocket{ 1023 Name: "envoy.transport_sockets.tls", 1024 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1025 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{}), 1026 }, 1027 }, 1028 }, 1029 }, 1030 })}, 1031 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 1032 wantMD: errMD, 1033 wantErr: "DownstreamTlsContext in LDS response does not contain a CommonTlsContext", 1034 }, 1035 { 1036 name: "unsupported validation context in transport socket", 1037 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 1038 Name: v3LDSTarget, 1039 Address: localSocketAddress, 1040 FilterChains: []*v3listenerpb.FilterChain{ 1041 { 1042 Name: "filter-chain-1", 1043 Filters: emptyValidNetworkFilters, 1044 TransportSocket: &v3corepb.TransportSocket{ 1045 Name: "envoy.transport_sockets.tls", 1046 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1047 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 1048 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1049 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextSdsSecretConfig{ 1050 ValidationContextSdsSecretConfig: &v3tlspb.SdsSecretConfig{ 1051 Name: "foo-sds-secret", 1052 }, 1053 }, 1054 }, 1055 }), 1056 }, 1057 }, 1058 }, 1059 }, 1060 })}, 1061 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 1062 wantMD: errMD, 1063 wantErr: "validation context contains unexpected type", 1064 }, 1065 { 1066 name: "empty transport socket", 1067 resources: []*anypb.Any{listenerEmptyTransportSocket}, 1068 wantUpdate: map[string]ListenerUpdate{ 1069 v3LDSTarget: { 1070 InboundListenerCfg: &InboundListenerConfig{ 1071 Address: "0.0.0.0", 1072 Port: "9999", 1073 FilterChains: &FilterChainManager{ 1074 dstPrefixMap: map[string]*destPrefixEntry{ 1075 unspecifiedPrefixMapKey: { 1076 srcTypeArr: [3]*sourcePrefixes{ 1077 { 1078 srcPrefixMap: map[string]*sourcePrefixEntry{ 1079 unspecifiedPrefixMapKey: { 1080 srcPortMap: map[int]*FilterChain{ 1081 0: {InlineRouteConfig: inlineRouteConfig}, 1082 }, 1083 }, 1084 }, 1085 }, 1086 }, 1087 }, 1088 }, 1089 }, 1090 }, 1091 Raw: listenerEmptyTransportSocket, 1092 }, 1093 }, 1094 wantMD: UpdateMetadata{ 1095 Status: ServiceStatusACKed, 1096 Version: testVersion, 1097 }, 1098 }, 1099 { 1100 name: "no identity and root certificate providers", 1101 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 1102 Name: v3LDSTarget, 1103 Address: localSocketAddress, 1104 FilterChains: []*v3listenerpb.FilterChain{ 1105 { 1106 Name: "filter-chain-1", 1107 Filters: emptyValidNetworkFilters, 1108 TransportSocket: &v3corepb.TransportSocket{ 1109 Name: "envoy.transport_sockets.tls", 1110 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1111 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 1112 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 1113 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1114 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 1115 InstanceName: "identityPluginInstance", 1116 CertificateName: "identityCertName", 1117 }, 1118 }, 1119 }), 1120 }, 1121 }, 1122 }, 1123 }, 1124 })}, 1125 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 1126 wantMD: errMD, 1127 wantErr: "security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set", 1128 }, 1129 { 1130 name: "no identity certificate provider with require_client_cert", 1131 resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ 1132 Name: v3LDSTarget, 1133 Address: localSocketAddress, 1134 FilterChains: []*v3listenerpb.FilterChain{ 1135 { 1136 Name: "filter-chain-1", 1137 Filters: emptyValidNetworkFilters, 1138 TransportSocket: &v3corepb.TransportSocket{ 1139 Name: "envoy.transport_sockets.tls", 1140 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1141 TypedConfig: testutils.MarshalAny(&v3tlspb.DownstreamTlsContext{ 1142 CommonTlsContext: &v3tlspb.CommonTlsContext{}, 1143 }), 1144 }, 1145 }, 1146 }, 1147 }, 1148 })}, 1149 wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}}, 1150 wantMD: errMD, 1151 wantErr: "security configuration on the server-side does not contain identity certificate provider instance name", 1152 }, 1153 { 1154 name: "happy case with no validation context", 1155 resources: []*anypb.Any{listenerNoValidationContext}, 1156 wantUpdate: map[string]ListenerUpdate{ 1157 v3LDSTarget: { 1158 InboundListenerCfg: &InboundListenerConfig{ 1159 Address: "0.0.0.0", 1160 Port: "9999", 1161 FilterChains: &FilterChainManager{ 1162 dstPrefixMap: map[string]*destPrefixEntry{ 1163 unspecifiedPrefixMapKey: { 1164 srcTypeArr: [3]*sourcePrefixes{ 1165 { 1166 srcPrefixMap: map[string]*sourcePrefixEntry{ 1167 unspecifiedPrefixMapKey: { 1168 srcPortMap: map[int]*FilterChain{ 1169 0: { 1170 SecurityCfg: &SecurityConfig{ 1171 IdentityInstanceName: "identityPluginInstance", 1172 IdentityCertName: "identityCertName", 1173 }, 1174 InlineRouteConfig: inlineRouteConfig, 1175 }, 1176 }, 1177 }, 1178 }, 1179 }, 1180 }, 1181 }, 1182 }, 1183 def: &FilterChain{ 1184 SecurityCfg: &SecurityConfig{ 1185 IdentityInstanceName: "defaultIdentityPluginInstance", 1186 IdentityCertName: "defaultIdentityCertName", 1187 }, 1188 InlineRouteConfig: inlineRouteConfig, 1189 }, 1190 }, 1191 }, 1192 Raw: listenerNoValidationContext, 1193 }, 1194 }, 1195 wantMD: UpdateMetadata{ 1196 Status: ServiceStatusACKed, 1197 Version: testVersion, 1198 }, 1199 }, 1200 { 1201 name: "happy case with validation context provider instance", 1202 resources: []*anypb.Any{listenerWithValidationContext}, 1203 wantUpdate: map[string]ListenerUpdate{ 1204 v3LDSTarget: { 1205 InboundListenerCfg: &InboundListenerConfig{ 1206 Address: "0.0.0.0", 1207 Port: "9999", 1208 FilterChains: &FilterChainManager{ 1209 dstPrefixMap: map[string]*destPrefixEntry{ 1210 unspecifiedPrefixMapKey: { 1211 srcTypeArr: [3]*sourcePrefixes{ 1212 { 1213 srcPrefixMap: map[string]*sourcePrefixEntry{ 1214 unspecifiedPrefixMapKey: { 1215 srcPortMap: map[int]*FilterChain{ 1216 0: { 1217 SecurityCfg: &SecurityConfig{ 1218 RootInstanceName: "rootPluginInstance", 1219 RootCertName: "rootCertName", 1220 IdentityInstanceName: "identityPluginInstance", 1221 IdentityCertName: "identityCertName", 1222 RequireClientCert: true, 1223 }, 1224 InlineRouteConfig: inlineRouteConfig, 1225 }, 1226 }, 1227 }, 1228 }, 1229 }, 1230 }, 1231 }, 1232 }, 1233 def: &FilterChain{ 1234 SecurityCfg: &SecurityConfig{ 1235 RootInstanceName: "defaultRootPluginInstance", 1236 RootCertName: "defaultRootCertName", 1237 IdentityInstanceName: "defaultIdentityPluginInstance", 1238 IdentityCertName: "defaultIdentityCertName", 1239 RequireClientCert: true, 1240 }, 1241 InlineRouteConfig: inlineRouteConfig, 1242 }, 1243 }, 1244 }, 1245 Raw: listenerWithValidationContext, 1246 }, 1247 }, 1248 wantMD: UpdateMetadata{ 1249 Status: ServiceStatusACKed, 1250 Version: testVersion, 1251 }, 1252 }, 1253 } 1254 1255 for _, test := range tests { 1256 t.Run(test.name, func(t *testing.T) { 1257 gotUpdate, md, err := UnmarshalListener(testVersion, test.resources, nil) 1258 if (err != nil) != (test.wantErr != "") { 1259 t.Fatalf("UnmarshalListener(), got err: %v, wantErr: %v", err, test.wantErr) 1260 } 1261 if err != nil && !strings.Contains(err.Error(), test.wantErr) { 1262 t.Fatalf("UnmarshalListener() = %v wantErr: %q", err, test.wantErr) 1263 } 1264 if diff := cmp.Diff(gotUpdate, test.wantUpdate, cmpOpts); diff != "" { 1265 t.Errorf("got unexpected update, diff (-got +want): %v", diff) 1266 } 1267 if diff := cmp.Diff(md, test.wantMD, cmpOptsIgnoreDetails); diff != "" { 1268 t.Errorf("got unexpected metadata, diff (-got +want): %v", diff) 1269 } 1270 }) 1271 } 1272 } 1273 1274 type filterConfig struct { 1275 httpfilter.FilterConfig 1276 Cfg proto.Message 1277 Override proto.Message 1278 } 1279 1280 // httpFilter allows testing the http filter registry and parsing functionality. 1281 type httpFilter struct { 1282 httpfilter.ClientInterceptorBuilder 1283 httpfilter.ServerInterceptorBuilder 1284 } 1285 1286 func (httpFilter) TypeURLs() []string { return []string{"custom.filter"} } 1287 1288 func (httpFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1289 return filterConfig{Cfg: cfg}, nil 1290 } 1291 1292 func (httpFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1293 return filterConfig{Override: override}, nil 1294 } 1295 1296 // errHTTPFilter returns errors no matter what is passed to ParseFilterConfig. 1297 type errHTTPFilter struct { 1298 httpfilter.ClientInterceptorBuilder 1299 } 1300 1301 func (errHTTPFilter) TypeURLs() []string { return []string{"err.custom.filter"} } 1302 1303 func (errHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1304 return nil, fmt.Errorf("error from ParseFilterConfig") 1305 } 1306 1307 func (errHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1308 return nil, fmt.Errorf("error from ParseFilterConfigOverride") 1309 } 1310 1311 func init() { 1312 httpfilter.Register(httpFilter{}) 1313 httpfilter.Register(errHTTPFilter{}) 1314 httpfilter.Register(serverOnlyHTTPFilter{}) 1315 httpfilter.Register(clientOnlyHTTPFilter{}) 1316 } 1317 1318 // serverOnlyHTTPFilter does not implement ClientInterceptorBuilder 1319 type serverOnlyHTTPFilter struct { 1320 httpfilter.ServerInterceptorBuilder 1321 } 1322 1323 func (serverOnlyHTTPFilter) TypeURLs() []string { return []string{"serverOnly.custom.filter"} } 1324 1325 func (serverOnlyHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1326 return filterConfig{Cfg: cfg}, nil 1327 } 1328 1329 func (serverOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1330 return filterConfig{Override: override}, nil 1331 } 1332 1333 // clientOnlyHTTPFilter does not implement ServerInterceptorBuilder 1334 type clientOnlyHTTPFilter struct { 1335 httpfilter.ClientInterceptorBuilder 1336 } 1337 1338 func (clientOnlyHTTPFilter) TypeURLs() []string { return []string{"clientOnly.custom.filter"} } 1339 1340 func (clientOnlyHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1341 return filterConfig{Cfg: cfg}, nil 1342 } 1343 1344 func (clientOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1345 return filterConfig{Override: override}, nil 1346 } 1347 1348 var customFilterConfig = &anypb.Any{ 1349 TypeUrl: "custom.filter", 1350 Value: []byte{1, 2, 3}, 1351 } 1352 1353 var errFilterConfig = &anypb.Any{ 1354 TypeUrl: "err.custom.filter", 1355 Value: []byte{1, 2, 3}, 1356 } 1357 1358 var serverOnlyCustomFilterConfig = &anypb.Any{ 1359 TypeUrl: "serverOnly.custom.filter", 1360 Value: []byte{1, 2, 3}, 1361 } 1362 1363 var clientOnlyCustomFilterConfig = &anypb.Any{ 1364 TypeUrl: "clientOnly.custom.filter", 1365 Value: []byte{1, 2, 3}, 1366 } 1367 1368 var customFilterTypedStructConfig = &v1typepb.TypedStruct{ 1369 TypeUrl: "custom.filter", 1370 Value: &spb.Struct{ 1371 Fields: map[string]*spb.Value{ 1372 "foo": {Kind: &spb.Value_StringValue{StringValue: "bar"}}, 1373 }, 1374 }, 1375 } 1376 var wrappedCustomFilterTypedStructConfig *anypb.Any 1377 1378 func init() { 1379 wrappedCustomFilterTypedStructConfig = testutils.MarshalAny(customFilterTypedStructConfig) 1380 } 1381 1382 var unknownFilterConfig = &anypb.Any{ 1383 TypeUrl: "unknown.custom.filter", 1384 Value: []byte{1, 2, 3}, 1385 } 1386 1387 func wrappedOptionalFilter(name string) *anypb.Any { 1388 return testutils.MarshalAny(&v3routepb.FilterConfig{ 1389 IsOptional: true, 1390 Config: &anypb.Any{ 1391 TypeUrl: name, 1392 Value: []byte{1, 2, 3}, 1393 }, 1394 }) 1395 }