github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/xds/internal/xdsclient/bootstrap/bootstrap_test.go (about) 1 // +build go1.12 2 3 /* 4 * 5 * Copyright 2019 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 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 bootstrap 22 23 import ( 24 "encoding/json" 25 "errors" 26 "fmt" 27 "os" 28 "testing" 29 30 v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" 31 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 32 "github.com/golang/protobuf/proto" 33 structpb "github.com/golang/protobuf/ptypes/struct" 34 "github.com/google/go-cmp/cmp" 35 36 "google.golang.org/grpc" 37 "google.golang.org/grpc/credentials/google" 38 "google.golang.org/grpc/credentials/insecure" 39 "google.golang.org/grpc/credentials/tls/certprovider" 40 "google.golang.org/grpc/internal" 41 "google.golang.org/grpc/internal/xds/env" 42 "google.golang.org/grpc/xds/internal/version" 43 ) 44 45 var ( 46 v2BootstrapFileMap = map[string]string{ 47 "emptyNodeProto": ` 48 { 49 "xds_servers" : [{ 50 "server_uri": "trafficdirector.googleapis.com:443", 51 "channel_creds": [ 52 { "type": "insecure" } 53 ] 54 }] 55 }`, 56 "unknownTopLevelFieldInFile": ` 57 { 58 "node": { 59 "id": "ENVOY_NODE_ID", 60 "metadata": { 61 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 62 } 63 }, 64 "xds_servers" : [{ 65 "server_uri": "trafficdirector.googleapis.com:443", 66 "channel_creds": [ 67 { "type": "insecure" } 68 ] 69 }], 70 "unknownField": "foobar" 71 }`, 72 "unknownFieldInNodeProto": ` 73 { 74 "node": { 75 "id": "ENVOY_NODE_ID", 76 "unknownField": "foobar", 77 "metadata": { 78 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 79 } 80 }, 81 "xds_servers" : [{ 82 "server_uri": "trafficdirector.googleapis.com:443", 83 "channel_creds": [ 84 { "type": "insecure" } 85 ] 86 }] 87 }`, 88 "unknownFieldInXdsServer": ` 89 { 90 "node": { 91 "id": "ENVOY_NODE_ID", 92 "metadata": { 93 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 94 } 95 }, 96 "xds_servers" : [{ 97 "server_uri": "trafficdirector.googleapis.com:443", 98 "channel_creds": [ 99 { "type": "insecure" } 100 ], 101 "unknownField": "foobar" 102 }] 103 }`, 104 "multipleChannelCreds": ` 105 { 106 "node": { 107 "id": "ENVOY_NODE_ID", 108 "metadata": { 109 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 110 } 111 }, 112 "xds_servers" : [{ 113 "server_uri": "trafficdirector.googleapis.com:443", 114 "channel_creds": [ 115 { "type": "not-google-default" }, 116 { "type": "google_default" } 117 ] 118 }] 119 }`, 120 "goodBootstrap": ` 121 { 122 "node": { 123 "id": "ENVOY_NODE_ID", 124 "metadata": { 125 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 126 } 127 }, 128 "xds_servers" : [{ 129 "server_uri": "trafficdirector.googleapis.com:443", 130 "channel_creds": [ 131 { "type": "google_default" } 132 ] 133 }] 134 }`, 135 "multipleXDSServers": ` 136 { 137 "node": { 138 "id": "ENVOY_NODE_ID", 139 "metadata": { 140 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 141 } 142 }, 143 "xds_servers" : [ 144 { 145 "server_uri": "trafficdirector.googleapis.com:443", 146 "channel_creds": [{ "type": "google_default" }] 147 }, 148 { 149 "server_uri": "backup.never.use.com:1234", 150 "channel_creds": [{ "type": "not-google-default" }] 151 } 152 ] 153 }`, 154 } 155 v3BootstrapFileMap = map[string]string{ 156 "serverDoesNotSupportsV3": ` 157 { 158 "node": { 159 "id": "ENVOY_NODE_ID", 160 "metadata": { 161 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 162 } 163 }, 164 "xds_servers" : [{ 165 "server_uri": "trafficdirector.googleapis.com:443", 166 "channel_creds": [ 167 { "type": "google_default" } 168 ], 169 "server_features" : ["foo", "bar"] 170 }] 171 }`, 172 "serverSupportsV3": ` 173 { 174 "node": { 175 "id": "ENVOY_NODE_ID", 176 "metadata": { 177 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 178 } 179 }, 180 "xds_servers" : [{ 181 "server_uri": "trafficdirector.googleapis.com:443", 182 "channel_creds": [ 183 { "type": "google_default" } 184 ], 185 "server_features" : ["foo", "bar", "xds_v3"] 186 }] 187 }`, 188 } 189 metadata = &structpb.Struct{ 190 Fields: map[string]*structpb.Value{ 191 "TRAFFICDIRECTOR_GRPC_HOSTNAME": { 192 Kind: &structpb.Value_StringValue{StringValue: "trafficdirector"}, 193 }, 194 }, 195 } 196 v2NodeProto = &v2corepb.Node{ 197 Id: "ENVOY_NODE_ID", 198 Metadata: metadata, 199 BuildVersion: gRPCVersion, 200 UserAgentName: gRPCUserAgentName, 201 UserAgentVersionType: &v2corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, 202 ClientFeatures: []string{clientFeatureNoOverprovisioning}, 203 } 204 v3NodeProto = &v3corepb.Node{ 205 Id: "ENVOY_NODE_ID", 206 Metadata: metadata, 207 UserAgentName: gRPCUserAgentName, 208 UserAgentVersionType: &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, 209 ClientFeatures: []string{clientFeatureNoOverprovisioning}, 210 } 211 nilCredsConfigV2 = &Config{ 212 BalancerName: "trafficdirector.googleapis.com:443", 213 Creds: grpc.WithTransportCredentials(insecure.NewCredentials()), 214 NodeProto: v2NodeProto, 215 } 216 nonNilCredsConfigV2 = &Config{ 217 BalancerName: "trafficdirector.googleapis.com:443", 218 Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()), 219 NodeProto: v2NodeProto, 220 } 221 nonNilCredsConfigV3 = &Config{ 222 BalancerName: "trafficdirector.googleapis.com:443", 223 Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()), 224 TransportAPI: version.TransportV3, 225 NodeProto: v3NodeProto, 226 } 227 ) 228 229 func (c *Config) compare(want *Config) error { 230 if c.BalancerName != want.BalancerName { 231 return fmt.Errorf("config.BalancerName is %s, want %s", c.BalancerName, want.BalancerName) 232 } 233 // Since Creds is of type grpc.DialOption interface, where the 234 // implementation is provided by a function, it is not possible to compare. 235 if (c.Creds != nil) != (want.Creds != nil) { 236 return fmt.Errorf("config.Creds is %#v, want %#v", c.Creds, want.Creds) 237 } 238 if c.TransportAPI != want.TransportAPI { 239 return fmt.Errorf("config.TransportAPI is %v, want %v", c.TransportAPI, want.TransportAPI) 240 241 } 242 if diff := cmp.Diff(want.NodeProto, c.NodeProto, cmp.Comparer(proto.Equal)); diff != "" { 243 return fmt.Errorf("config.NodeProto diff (-want, +got):\n%s", diff) 244 } 245 if c.ServerListenerResourceNameTemplate != want.ServerListenerResourceNameTemplate { 246 return fmt.Errorf("config.ServerListenerResourceNameTemplate is %q, want %q", c.ServerListenerResourceNameTemplate, want.ServerListenerResourceNameTemplate) 247 } 248 249 // A vanilla cmp.Equal or cmp.Diff will not produce useful error message 250 // here. So, we iterate through the list of configs and compare them one at 251 // a time. 252 gotCfgs := c.CertProviderConfigs 253 wantCfgs := want.CertProviderConfigs 254 if len(gotCfgs) != len(wantCfgs) { 255 return fmt.Errorf("config.CertProviderConfigs is %d entries, want %d", len(gotCfgs), len(wantCfgs)) 256 } 257 for instance, gotCfg := range gotCfgs { 258 wantCfg, ok := wantCfgs[instance] 259 if !ok { 260 return fmt.Errorf("config.CertProviderConfigs has unexpected plugin instance %q with config %q", instance, gotCfg.String()) 261 } 262 if got, want := gotCfg.String(), wantCfg.String(); got != want { 263 return fmt.Errorf("config.CertProviderConfigs for plugin instance %q has config %q, want %q", instance, got, want) 264 } 265 } 266 return nil 267 } 268 269 func fileReadFromFileMap(bootstrapFileMap map[string]string, name string) ([]byte, error) { 270 if b, ok := bootstrapFileMap[name]; ok { 271 return []byte(b), nil 272 } 273 return nil, os.ErrNotExist 274 } 275 276 func setupBootstrapOverride(bootstrapFileMap map[string]string) func() { 277 oldFileReadFunc := bootstrapFileReadFunc 278 bootstrapFileReadFunc = func(filename string) ([]byte, error) { 279 return fileReadFromFileMap(bootstrapFileMap, filename) 280 } 281 return func() { bootstrapFileReadFunc = oldFileReadFunc } 282 } 283 284 // TODO: enable leak check for this package when 285 // https://github.com/googleapis/google-cloud-go/issues/2417 is fixed. 286 287 // This function overrides the bootstrap file NAME env variable, to test the 288 // code that reads file with the given fileName. 289 func testNewConfigWithFileNameEnv(t *testing.T, fileName string, wantError bool, wantConfig *Config) { 290 origBootstrapFileName := env.BootstrapFileName 291 env.BootstrapFileName = fileName 292 defer func() { env.BootstrapFileName = origBootstrapFileName }() 293 294 c, err := NewConfig() 295 if (err != nil) != wantError { 296 t.Fatalf("NewConfig() returned error %v, wantError: %v", err, wantError) 297 } 298 if wantError { 299 return 300 } 301 if err := c.compare(wantConfig); err != nil { 302 t.Fatal(err) 303 } 304 } 305 306 // This function overrides the bootstrap file CONTENT env variable, to test the 307 // code that uses the content from env directly. 308 func testNewConfigWithFileContentEnv(t *testing.T, fileName string, wantError bool, wantConfig *Config) { 309 b, err := bootstrapFileReadFunc(fileName) 310 if err != nil { 311 // If file reading failed, skip this test. 312 return 313 } 314 origBootstrapContent := env.BootstrapFileContent 315 env.BootstrapFileContent = string(b) 316 defer func() { env.BootstrapFileContent = origBootstrapContent }() 317 318 c, err := NewConfig() 319 if (err != nil) != wantError { 320 t.Fatalf("NewConfig() returned error %v, wantError: %v", err, wantError) 321 } 322 if wantError { 323 return 324 } 325 if err := c.compare(wantConfig); err != nil { 326 t.Fatal(err) 327 } 328 } 329 330 // TestNewConfigV2ProtoFailure exercises the functionality in NewConfig with 331 // different bootstrap file contents which are expected to fail. 332 func TestNewConfigV2ProtoFailure(t *testing.T) { 333 bootstrapFileMap := map[string]string{ 334 "empty": "", 335 "badJSON": `["test": 123]`, 336 "noBalancerName": `{"node": {"id": "ENVOY_NODE_ID"}}`, 337 "emptyXdsServer": ` 338 { 339 "node": { 340 "id": "ENVOY_NODE_ID", 341 "metadata": { 342 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 343 } 344 } 345 }`, 346 "emptyChannelCreds": ` 347 { 348 "node": { 349 "id": "ENVOY_NODE_ID", 350 "metadata": { 351 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 352 } 353 }, 354 "xds_servers" : [{ 355 "server_uri": "trafficdirector.googleapis.com:443" 356 }] 357 }`, 358 "nonGoogleDefaultCreds": ` 359 { 360 "node": { 361 "id": "ENVOY_NODE_ID", 362 "metadata": { 363 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 364 } 365 }, 366 "xds_servers" : [{ 367 "server_uri": "trafficdirector.googleapis.com:443", 368 "channel_creds": [ 369 { "type": "not-google-default" } 370 ] 371 }] 372 }`, 373 } 374 cancel := setupBootstrapOverride(bootstrapFileMap) 375 defer cancel() 376 377 tests := []struct { 378 name string 379 wantError bool 380 }{ 381 {"nonExistentBootstrapFile", true}, 382 {"empty", true}, 383 {"badJSON", true}, 384 {"noBalancerName", true}, 385 {"emptyXdsServer", true}, 386 } 387 388 for _, test := range tests { 389 t.Run(test.name, func(t *testing.T) { 390 testNewConfigWithFileNameEnv(t, test.name, true, nil) 391 testNewConfigWithFileContentEnv(t, test.name, true, nil) 392 }) 393 } 394 } 395 396 // TestNewConfigV2ProtoSuccess exercises the functionality in NewConfig with 397 // different bootstrap file contents. It overrides the fileReadFunc by returning 398 // bootstrap file contents defined in this test, instead of reading from a file. 399 func TestNewConfigV2ProtoSuccess(t *testing.T) { 400 cancel := setupBootstrapOverride(v2BootstrapFileMap) 401 defer cancel() 402 403 tests := []struct { 404 name string 405 wantConfig *Config 406 }{ 407 { 408 "emptyNodeProto", &Config{ 409 BalancerName: "trafficdirector.googleapis.com:443", 410 Creds: grpc.WithTransportCredentials(insecure.NewCredentials()), 411 NodeProto: &v2corepb.Node{ 412 BuildVersion: gRPCVersion, 413 UserAgentName: gRPCUserAgentName, 414 UserAgentVersionType: &v2corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, 415 ClientFeatures: []string{clientFeatureNoOverprovisioning}, 416 }, 417 }, 418 }, 419 {"unknownTopLevelFieldInFile", nilCredsConfigV2}, 420 {"unknownFieldInNodeProto", nilCredsConfigV2}, 421 {"unknownFieldInXdsServer", nilCredsConfigV2}, 422 {"multipleChannelCreds", nonNilCredsConfigV2}, 423 {"goodBootstrap", nonNilCredsConfigV2}, 424 {"multipleXDSServers", nonNilCredsConfigV2}, 425 } 426 427 for _, test := range tests { 428 t.Run(test.name, func(t *testing.T) { 429 testNewConfigWithFileNameEnv(t, test.name, false, test.wantConfig) 430 testNewConfigWithFileContentEnv(t, test.name, false, test.wantConfig) 431 }) 432 } 433 } 434 435 // TestNewConfigV3Support verifies bootstrap functionality involving support for 436 // the xDS v3 transport protocol. Here the client ends up using v2 or v3 based 437 // on what the server supports. 438 func TestNewConfigV3Support(t *testing.T) { 439 cancel := setupBootstrapOverride(v3BootstrapFileMap) 440 defer cancel() 441 442 tests := []struct { 443 name string 444 wantConfig *Config 445 }{ 446 {"serverDoesNotSupportsV3", nonNilCredsConfigV2}, 447 {"serverSupportsV3", nonNilCredsConfigV3}, 448 } 449 450 for _, test := range tests { 451 t.Run(test.name, func(t *testing.T) { 452 testNewConfigWithFileNameEnv(t, test.name, false, test.wantConfig) 453 testNewConfigWithFileContentEnv(t, test.name, false, test.wantConfig) 454 }) 455 } 456 } 457 458 // TestNewConfigBootstrapEnvPriority tests that the two env variables are read 459 // in correct priority. 460 // 461 // the case where the bootstrap file 462 // environment variable is not set. 463 func TestNewConfigBootstrapEnvPriority(t *testing.T) { 464 oldFileReadFunc := bootstrapFileReadFunc 465 bootstrapFileReadFunc = func(filename string) ([]byte, error) { 466 return fileReadFromFileMap(v2BootstrapFileMap, filename) 467 } 468 defer func() { bootstrapFileReadFunc = oldFileReadFunc }() 469 470 goodFileName1 := "goodBootstrap" 471 goodConfig1 := nonNilCredsConfigV2 472 473 goodFileName2 := "serverSupportsV3" 474 goodFileContent2 := v3BootstrapFileMap[goodFileName2] 475 goodConfig2 := nonNilCredsConfigV3 476 477 origBootstrapFileName := env.BootstrapFileName 478 env.BootstrapFileName = "" 479 defer func() { env.BootstrapFileName = origBootstrapFileName }() 480 481 origBootstrapContent := env.BootstrapFileContent 482 env.BootstrapFileContent = "" 483 defer func() { env.BootstrapFileContent = origBootstrapContent }() 484 485 // When both env variables are empty, NewConfig should fail. 486 if _, err := NewConfig(); err == nil { 487 t.Errorf("NewConfig() returned nil error, expected to fail") 488 } 489 490 // When one of them is set, it should be used. 491 env.BootstrapFileName = goodFileName1 492 env.BootstrapFileContent = "" 493 if c, err := NewConfig(); err != nil || c.compare(goodConfig1) != nil { 494 t.Errorf("NewConfig() = %v, %v, want: %v, %v", c, err, goodConfig1, nil) 495 } 496 497 env.BootstrapFileName = "" 498 env.BootstrapFileContent = goodFileContent2 499 if c, err := NewConfig(); err != nil || c.compare(goodConfig2) != nil { 500 t.Errorf("NewConfig() = %v, %v, want: %v, %v", c, err, goodConfig1, nil) 501 } 502 503 // Set both, file name should be read. 504 env.BootstrapFileName = goodFileName1 505 env.BootstrapFileContent = goodFileContent2 506 if c, err := NewConfig(); err != nil || c.compare(goodConfig1) != nil { 507 t.Errorf("NewConfig() = %v, %v, want: %v, %v", c, err, goodConfig1, nil) 508 } 509 } 510 511 func init() { 512 certprovider.Register(&fakeCertProviderBuilder{}) 513 } 514 515 const fakeCertProviderName = "fake-certificate-provider" 516 517 // fakeCertProviderBuilder builds new instances of fakeCertProvider and 518 // interprets the config provided to it as JSON with a single key and value. 519 type fakeCertProviderBuilder struct{} 520 521 // ParseConfig expects input in JSON format containing a map from string to 522 // string, with a single entry and mapKey being "configKey". 523 func (b *fakeCertProviderBuilder) ParseConfig(cfg interface{}) (*certprovider.BuildableConfig, error) { 524 config, ok := cfg.(json.RawMessage) 525 if !ok { 526 return nil, fmt.Errorf("fakeCertProviderBuilder received config of type %T, want []byte", config) 527 } 528 var cfgData map[string]string 529 if err := json.Unmarshal(config, &cfgData); err != nil { 530 return nil, fmt.Errorf("fakeCertProviderBuilder config parsing failed: %v", err) 531 } 532 if len(cfgData) != 1 || cfgData["configKey"] == "" { 533 return nil, errors.New("fakeCertProviderBuilder received invalid config") 534 } 535 fc := &fakeStableConfig{config: cfgData} 536 return certprovider.NewBuildableConfig(fakeCertProviderName, fc.canonical(), func(certprovider.BuildOptions) certprovider.Provider { 537 return &fakeCertProvider{} 538 }), nil 539 } 540 541 func (b *fakeCertProviderBuilder) Name() string { 542 return fakeCertProviderName 543 } 544 545 type fakeStableConfig struct { 546 config map[string]string 547 } 548 549 func (c *fakeStableConfig) canonical() []byte { 550 var cfg string 551 for k, v := range c.config { 552 cfg = fmt.Sprintf("%s:%s", k, v) 553 } 554 return []byte(cfg) 555 } 556 557 // fakeCertProvider is an empty implementation of the Provider interface. 558 type fakeCertProvider struct { 559 certprovider.Provider 560 } 561 562 func TestNewConfigWithCertificateProviders(t *testing.T) { 563 bootstrapFileMap := map[string]string{ 564 "badJSONCertProviderConfig": ` 565 { 566 "node": { 567 "id": "ENVOY_NODE_ID", 568 "metadata": { 569 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 570 } 571 }, 572 "xds_servers" : [{ 573 "server_uri": "trafficdirector.googleapis.com:443", 574 "channel_creds": [ 575 { "type": "google_default" } 576 ], 577 "server_features" : ["foo", "bar", "xds_v3"], 578 }], 579 "certificate_providers": "bad JSON" 580 }`, 581 "allUnknownCertProviders": ` 582 { 583 "node": { 584 "id": "ENVOY_NODE_ID", 585 "metadata": { 586 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 587 } 588 }, 589 "xds_servers" : [{ 590 "server_uri": "trafficdirector.googleapis.com:443", 591 "channel_creds": [ 592 { "type": "google_default" } 593 ], 594 "server_features" : ["foo", "bar", "xds_v3"] 595 }], 596 "certificate_providers": { 597 "unknownProviderInstance1": { 598 "plugin_name": "foo", 599 "config": {"foo": "bar"} 600 }, 601 "unknownProviderInstance2": { 602 "plugin_name": "bar", 603 "config": {"foo": "bar"} 604 } 605 } 606 }`, 607 "badCertProviderConfig": ` 608 { 609 "node": { 610 "id": "ENVOY_NODE_ID", 611 "metadata": { 612 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 613 } 614 }, 615 "xds_servers" : [{ 616 "server_uri": "trafficdirector.googleapis.com:443", 617 "channel_creds": [ 618 { "type": "google_default" } 619 ], 620 "server_features" : ["foo", "bar", "xds_v3"], 621 }], 622 "certificate_providers": { 623 "unknownProviderInstance": { 624 "plugin_name": "foo", 625 "config": {"foo": "bar"} 626 }, 627 "fakeProviderInstanceBad": { 628 "plugin_name": "fake-certificate-provider", 629 "config": {"configKey": 666} 630 } 631 } 632 }`, 633 "goodCertProviderConfig": ` 634 { 635 "node": { 636 "id": "ENVOY_NODE_ID", 637 "metadata": { 638 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 639 } 640 }, 641 "xds_servers" : [{ 642 "server_uri": "trafficdirector.googleapis.com:443", 643 "channel_creds": [ 644 { "type": "google_default" } 645 ], 646 "server_features" : ["foo", "bar", "xds_v3"] 647 }], 648 "certificate_providers": { 649 "unknownProviderInstance": { 650 "plugin_name": "foo", 651 "config": {"foo": "bar"} 652 }, 653 "fakeProviderInstance": { 654 "plugin_name": "fake-certificate-provider", 655 "config": {"configKey": "configValue"} 656 } 657 } 658 }`, 659 } 660 661 getBuilder := internal.GetCertificateProviderBuilder.(func(string) certprovider.Builder) 662 parser := getBuilder(fakeCertProviderName) 663 if parser == nil { 664 t.Fatalf("missing certprovider plugin %q", fakeCertProviderName) 665 } 666 wantCfg, err := parser.ParseConfig(json.RawMessage(`{"configKey": "configValue"}`)) 667 if err != nil { 668 t.Fatalf("config parsing for plugin %q failed: %v", fakeCertProviderName, err) 669 } 670 671 cancel := setupBootstrapOverride(bootstrapFileMap) 672 defer cancel() 673 674 goodConfig := &Config{ 675 BalancerName: "trafficdirector.googleapis.com:443", 676 Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()), 677 TransportAPI: version.TransportV3, 678 NodeProto: v3NodeProto, 679 CertProviderConfigs: map[string]*certprovider.BuildableConfig{ 680 "fakeProviderInstance": wantCfg, 681 }, 682 } 683 tests := []struct { 684 name string 685 wantConfig *Config 686 wantErr bool 687 }{ 688 { 689 name: "badJSONCertProviderConfig", 690 wantErr: true, 691 }, 692 { 693 694 name: "badCertProviderConfig", 695 wantErr: true, 696 }, 697 { 698 699 name: "allUnknownCertProviders", 700 wantConfig: nonNilCredsConfigV3, 701 }, 702 { 703 name: "goodCertProviderConfig", 704 wantConfig: goodConfig, 705 }, 706 } 707 708 for _, test := range tests { 709 t.Run(test.name, func(t *testing.T) { 710 testNewConfigWithFileNameEnv(t, test.name, test.wantErr, test.wantConfig) 711 testNewConfigWithFileContentEnv(t, test.name, test.wantErr, test.wantConfig) 712 }) 713 } 714 } 715 716 func TestNewConfigWithServerListenerResourceNameTemplate(t *testing.T) { 717 cancel := setupBootstrapOverride(map[string]string{ 718 "badServerListenerResourceNameTemplate:": ` 719 { 720 "node": { 721 "id": "ENVOY_NODE_ID", 722 "metadata": { 723 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 724 } 725 }, 726 "xds_servers" : [{ 727 "server_uri": "trafficdirector.googleapis.com:443", 728 "channel_creds": [ 729 { "type": "google_default" } 730 ] 731 }], 732 "server_listener_resource_name_template": 123456789 733 }`, 734 "goodServerListenerResourceNameTemplate": ` 735 { 736 "node": { 737 "id": "ENVOY_NODE_ID", 738 "metadata": { 739 "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector" 740 } 741 }, 742 "xds_servers" : [{ 743 "server_uri": "trafficdirector.googleapis.com:443", 744 "channel_creds": [ 745 { "type": "google_default" } 746 ] 747 }], 748 "server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s" 749 }`, 750 }) 751 defer cancel() 752 753 tests := []struct { 754 name string 755 wantConfig *Config 756 wantErr bool 757 }{ 758 { 759 name: "badServerListenerResourceNameTemplate", 760 wantErr: true, 761 }, 762 { 763 name: "goodServerListenerResourceNameTemplate", 764 wantConfig: &Config{ 765 BalancerName: "trafficdirector.googleapis.com:443", 766 Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()), 767 TransportAPI: version.TransportV2, 768 NodeProto: v2NodeProto, 769 ServerListenerResourceNameTemplate: "grpc/server?xds.resource.listening_address=%s", 770 }, 771 }, 772 } 773 774 for _, test := range tests { 775 t.Run(test.name, func(t *testing.T) { 776 testNewConfigWithFileNameEnv(t, test.name, test.wantErr, test.wantConfig) 777 testNewConfigWithFileContentEnv(t, test.name, test.wantErr, test.wantConfig) 778 }) 779 } 780 }