github.com/jenkins-x/test-infra@v0.0.7/prow/config/config_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package config 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "reflect" 25 "testing" 26 "time" 27 28 prowjobv1 "k8s.io/test-infra/prow/apis/prowjobs/v1" 29 "k8s.io/test-infra/prow/kube" 30 31 "k8s.io/api/core/v1" 32 "k8s.io/apimachinery/pkg/util/sets" 33 //"k8s.io/apimachinery/pkg/api/equality" 34 //"k8s.io/apimachinery/pkg/util/diff" 35 buildv1alpha1 "github.com/knative/build/pkg/apis/build/v1alpha1" 36 "k8s.io/test-infra/prow/pod-utils/decorate" 37 "k8s.io/test-infra/prow/pod-utils/downwardapi" 38 ) 39 40 func TestDefaultJobBase(t *testing.T) { 41 bar := "bar" 42 filled := JobBase{ 43 Agent: "foo", 44 Namespace: &bar, 45 Cluster: "build", 46 } 47 cases := []struct { 48 name string 49 config ProwConfig 50 base func(j *JobBase) 51 expected func(j *JobBase) 52 }{ 53 { 54 name: "no changes when fields are already set", 55 }, 56 { 57 name: "empty agent results in kubernetes", 58 base: func(j *JobBase) { 59 j.Agent = "" 60 }, 61 expected: func(j *JobBase) { 62 j.Agent = string(kube.KubernetesAgent) 63 }, 64 }, 65 { 66 name: "nil namespace becomes PodNamespace", 67 config: ProwConfig{ 68 PodNamespace: "pod-namespace", 69 ProwJobNamespace: "wrong", 70 }, 71 base: func(j *JobBase) { 72 j.Namespace = nil 73 }, 74 expected: func(j *JobBase) { 75 p := "pod-namespace" 76 j.Namespace = &p 77 }, 78 }, 79 { 80 name: "empty namespace becomes PodNamespace", 81 config: ProwConfig{ 82 PodNamespace: "new-pod-namespace", 83 ProwJobNamespace: "still-wrong", 84 }, 85 base: func(j *JobBase) { 86 var empty string 87 j.Namespace = &empty 88 }, 89 expected: func(j *JobBase) { 90 p := "new-pod-namespace" 91 j.Namespace = &p 92 }, 93 }, 94 { 95 name: "empty cluster becomes DefaultClusterAlias", 96 base: func(j *JobBase) { 97 j.Cluster = "" 98 }, 99 expected: func(j *JobBase) { 100 j.Cluster = kube.DefaultClusterAlias 101 }, 102 }, 103 } 104 105 for _, tc := range cases { 106 t.Run(tc.name, func(t *testing.T) { 107 actual := filled 108 if tc.base != nil { 109 tc.base(&actual) 110 } 111 expected := actual 112 if tc.expected != nil { 113 tc.expected(&expected) 114 } 115 tc.config.defaultJobBase(&actual) 116 if !reflect.DeepEqual(actual, expected) { 117 t.Errorf("expected %#v\n!=\nactual %#v", expected, actual) 118 } 119 }) 120 } 121 } 122 123 func TestSpyglassConfig(t *testing.T) { 124 testCases := []struct { 125 name string 126 spyglassConfig string 127 expectedViewers map[string][]string 128 expectedRegexMatches map[string][]string 129 expectedSizeLimit int64 130 expectError bool 131 }{ 132 { 133 name: "Default: build log, metadata, junit", 134 spyglassConfig: ` 135 deck: 136 spyglass: 137 size_limit: 500e+6 138 viewers: 139 "started.json|finished.json": 140 - "metadata" 141 "build-log.txt": 142 - "buildlog" 143 "artifacts/junit.*\\.xml": 144 - "junit" 145 `, 146 expectedViewers: map[string][]string{ 147 "started.json|finished.json": {"metadata"}, 148 "build-log.txt": {"buildlog"}, 149 "artifacts/junit.*\\.xml": {"junit"}, 150 }, 151 expectedRegexMatches: map[string][]string{ 152 "started.json|finished.json": {"started.json", "finished.json"}, 153 "build-log.txt": {"build-log.txt"}, 154 "artifacts/junit.*\\.xml": {"artifacts/junit01.xml", "artifacts/junit_runner.xml"}, 155 }, 156 expectedSizeLimit: 500e6, 157 expectError: false, 158 }, 159 { 160 name: "Backwards compatibility", 161 spyglassConfig: ` 162 deck: 163 spyglass: 164 size_limit: 500e+6 165 viewers: 166 "started.json|finished.json": 167 - "metadata-viewer" 168 "build-log.txt": 169 - "build-log-viewer" 170 "artifacts/junit.*\\.xml": 171 - "junit-viewer" 172 `, 173 expectedViewers: map[string][]string{ 174 "started.json|finished.json": {"metadata"}, 175 "build-log.txt": {"buildlog"}, 176 "artifacts/junit.*\\.xml": {"junit"}, 177 }, 178 expectedSizeLimit: 500e6, 179 expectError: false, 180 }, 181 { 182 name: "Invalid spyglass size limit", 183 spyglassConfig: ` 184 deck: 185 spyglass: 186 size_limit: -4 187 viewers: 188 "started.json|finished.json": 189 - "metadata-viewer" 190 "build-log.txt": 191 - "build-log-viewer" 192 "artifacts/junit.*\\.xml": 193 - "junit-viewer" 194 `, 195 expectError: true, 196 }, 197 { 198 name: "Invalid Spyglass regexp", 199 spyglassConfig: ` 200 deck: 201 spyglass: 202 size_limit: 5 203 viewers: 204 "started.json\|]finished.json": 205 - "metadata-viewer" 206 `, 207 expectError: true, 208 }, 209 } 210 for _, tc := range testCases { 211 // save the config 212 spyglassConfigDir, err := ioutil.TempDir("", "spyglassConfig") 213 if err != nil { 214 t.Fatalf("fail to make tempdir: %v", err) 215 } 216 defer os.RemoveAll(spyglassConfigDir) 217 218 spyglassConfig := filepath.Join(spyglassConfigDir, "config.yaml") 219 if err := ioutil.WriteFile(spyglassConfig, []byte(tc.spyglassConfig), 0666); err != nil { 220 t.Fatalf("fail to write spyglass config: %v", err) 221 } 222 223 cfg, err := Load(spyglassConfig, "") 224 if (err != nil) != tc.expectError { 225 t.Fatalf("tc %s: expected error: %v, got: %v, error: %v", tc.name, tc.expectError, (err != nil), err) 226 } 227 228 if err != nil { 229 continue 230 } 231 got := cfg.Deck.Spyglass.Viewers 232 for re, viewNames := range got { 233 expected, ok := tc.expectedViewers[re] 234 if !ok { 235 t.Errorf("With re %s, got %s, was not found in expected.", re, viewNames) 236 continue 237 } 238 if !reflect.DeepEqual(expected, viewNames) { 239 t.Errorf("With re %s, got %s, expected view name %s", re, viewNames, expected) 240 } 241 242 } 243 for re, viewNames := range tc.expectedViewers { 244 gotNames, ok := got[re] 245 if !ok { 246 t.Errorf("With re %s, expected %s, was not found in got.", re, viewNames) 247 continue 248 } 249 if !reflect.DeepEqual(gotNames, viewNames) { 250 t.Errorf("With re %s, got %s, expected view name %s", re, gotNames, viewNames) 251 } 252 } 253 254 for expectedRegex, matches := range tc.expectedRegexMatches { 255 compiledRegex, ok := cfg.Deck.Spyglass.RegexCache[expectedRegex] 256 if !ok { 257 t.Errorf("tc %s, regex %s was not found in the spyglass regex cache", tc.name, expectedRegex) 258 continue 259 } 260 for _, match := range matches { 261 if !compiledRegex.MatchString(match) { 262 t.Errorf("tc %s expected compiled regex %s to match %s, did not match.", tc.name, expectedRegex, match) 263 } 264 } 265 266 } 267 if cfg.Deck.Spyglass.SizeLimit != tc.expectedSizeLimit { 268 t.Errorf("%s expected SizeLimit %d, got %d", tc.name, tc.expectedSizeLimit, cfg.Deck.Spyglass.SizeLimit) 269 } 270 } 271 272 } 273 274 func TestDecorationRawYaml(t *testing.T) { 275 var testCases = []struct { 276 name string 277 expectError bool 278 rawConfig string 279 expected *kube.DecorationConfig 280 }{ 281 { 282 name: "no default", 283 expectError: true, 284 rawConfig: ` 285 periodics: 286 - name: kubernetes-defaulted-decoration 287 interval: 1h 288 always_run: true 289 decorate: true 290 spec: 291 containers: 292 - image: golang:latest 293 args: 294 - "test" 295 - "./..."`, 296 }, 297 { 298 name: "with default, no explicit decorate", 299 rawConfig: ` 300 plank: 301 default_decoration_config: 302 timeout: 7200000000000 # 2h 303 grace_period: 15000000000 # 15s 304 utility_images: 305 clonerefs: "clonerefs:default" 306 initupload: "initupload:default" 307 entrypoint: "entrypoint:default" 308 sidecar: "sidecar:default" 309 gcs_configuration: 310 bucket: "default-bucket" 311 path_strategy: "legacy" 312 default_org: "kubernetes" 313 default_repo: "kubernetes" 314 gcs_credentials_secret: "default-service-account" 315 316 periodics: 317 - name: kubernetes-defaulted-decoration 318 interval: 1h 319 always_run: true 320 decorate: true 321 spec: 322 containers: 323 - image: golang:latest 324 args: 325 - "test" 326 - "./..."`, 327 expected: &kube.DecorationConfig{ 328 Timeout: 2 * time.Hour, 329 GracePeriod: 15 * time.Second, 330 UtilityImages: &kube.UtilityImages{ 331 CloneRefs: "clonerefs:default", 332 InitUpload: "initupload:default", 333 Entrypoint: "entrypoint:default", 334 Sidecar: "sidecar:default", 335 }, 336 GCSConfiguration: &kube.GCSConfiguration{ 337 Bucket: "default-bucket", 338 PathStrategy: kube.PathStrategyLegacy, 339 DefaultOrg: "kubernetes", 340 DefaultRepo: "kubernetes", 341 }, 342 GCSCredentialsSecret: "default-service-account", 343 }, 344 }, 345 { 346 name: "with default, has explicit decorate", 347 rawConfig: ` 348 plank: 349 default_decoration_config: 350 timeout: 7200000000000 # 2h 351 grace_period: 15000000000 # 15s 352 utility_images: 353 clonerefs: "clonerefs:default" 354 initupload: "initupload:default" 355 entrypoint: "entrypoint:default" 356 sidecar: "sidecar:default" 357 gcs_configuration: 358 bucket: "default-bucket" 359 path_strategy: "legacy" 360 default_org: "kubernetes" 361 default_repo: "kubernetes" 362 gcs_credentials_secret: "default-service-account" 363 364 periodics: 365 - name: kubernetes-defaulted-decoration 366 interval: 1h 367 always_run: true 368 decorate: true 369 decoration_config: 370 timeout: 1 371 grace_period: 1 372 utility_images: 373 clonerefs: "clonerefs:explicit" 374 initupload: "initupload:explicit" 375 entrypoint: "entrypoint:explicit" 376 sidecar: "sidecar:explicit" 377 gcs_configuration: 378 bucket: "explicit-bucket" 379 path_strategy: "explicit" 380 gcs_credentials_secret: "explicit-service-account" 381 spec: 382 containers: 383 - image: golang:latest 384 args: 385 - "test" 386 - "./..."`, 387 expected: &kube.DecorationConfig{ 388 Timeout: 1 * time.Nanosecond, 389 GracePeriod: 1 * time.Nanosecond, 390 UtilityImages: &kube.UtilityImages{ 391 CloneRefs: "clonerefs:explicit", 392 InitUpload: "initupload:explicit", 393 Entrypoint: "entrypoint:explicit", 394 Sidecar: "sidecar:explicit", 395 }, 396 GCSConfiguration: &kube.GCSConfiguration{ 397 Bucket: "explicit-bucket", 398 PathStrategy: kube.PathStrategyExplicit, 399 DefaultOrg: "kubernetes", 400 DefaultRepo: "kubernetes", 401 }, 402 GCSCredentialsSecret: "explicit-service-account", 403 }, 404 }, 405 } 406 407 for _, tc := range testCases { 408 // save the config 409 prowConfigDir, err := ioutil.TempDir("", "prowConfig") 410 if err != nil { 411 t.Fatalf("fail to make tempdir: %v", err) 412 } 413 defer os.RemoveAll(prowConfigDir) 414 415 prowConfig := filepath.Join(prowConfigDir, "config.yaml") 416 if err := ioutil.WriteFile(prowConfig, []byte(tc.rawConfig), 0666); err != nil { 417 t.Fatalf("fail to write prow config: %v", err) 418 } 419 420 cfg, err := Load(prowConfig, "") 421 if tc.expectError && err == nil { 422 t.Errorf("tc %s: Expect error, but got nil", tc.name) 423 } else if !tc.expectError && err != nil { 424 t.Errorf("tc %s: Expect no error, but got error %v", tc.name, err) 425 } 426 427 if tc.expected != nil { 428 if len(cfg.Periodics) != 1 { 429 t.Fatalf("tc %s: Expect to have one periodic job, got none", tc.name) 430 } 431 432 if !reflect.DeepEqual(cfg.Periodics[0].DecorationConfig, tc.expected) { 433 t.Errorf("%s: expected defaulted config:\n%#v\n but got:\n%#v\n", tc.name, tc.expected, cfg.Periodics[0].DecorationConfig) 434 } 435 } 436 } 437 438 } 439 440 func TestValidateAgent(t *testing.T) { 441 b := string(prowjobv1.KnativeBuildAgent) 442 jenk := string(prowjobv1.JenkinsAgent) 443 k := string(prowjobv1.KubernetesAgent) 444 ns := "default" 445 base := JobBase{ 446 Agent: k, 447 Namespace: &ns, 448 Spec: &v1.PodSpec{}, 449 UtilityConfig: UtilityConfig{ 450 DecorationConfig: &kube.DecorationConfig{}, 451 }, 452 } 453 454 cases := []struct { 455 name string 456 base func(j *JobBase) 457 pass bool 458 }{ 459 { 460 name: "reject unknown agent", 461 base: func(j *JobBase) { 462 j.Agent = "random-agent" 463 }, 464 }, 465 { 466 name: "spec requires kubernetes agent", 467 base: func(j *JobBase) { 468 j.Agent = b 469 }, 470 }, 471 { 472 name: "kubernetes agent requires spec", 473 base: func(j *JobBase) { 474 j.Spec = nil 475 }, 476 }, 477 { 478 name: "build_spec requires knative-build agent", 479 base: func(j *JobBase) { 480 j.DecorationConfig = nil 481 j.Spec = nil 482 483 j.BuildSpec = &buildv1alpha1.BuildSpec{} 484 }, 485 }, 486 { 487 name: "knative-build agent requires build_spec", 488 base: func(j *JobBase) { 489 j.DecorationConfig = nil 490 j.Spec = nil 491 492 j.Agent = b 493 }, 494 }, 495 { 496 name: "decoration requires kubernetes agent", 497 base: func(j *JobBase) { 498 j.Agent = b 499 j.BuildSpec = &buildv1alpha1.BuildSpec{} 500 }, 501 }, 502 { 503 name: "non-nil namespace required", 504 base: func(j *JobBase) { 505 j.Namespace = nil 506 }, 507 }, 508 { 509 name: "filled namespace required", 510 base: func(j *JobBase) { 511 var s string 512 j.Namespace = &s 513 }, 514 }, 515 { 516 name: "custom namespace requires knative-build agent", 517 base: func(j *JobBase) { 518 s := "custom-namespace" 519 j.Namespace = &s 520 }, 521 }, 522 { 523 name: "accept kubernetes agent", 524 pass: true, 525 }, 526 { 527 name: "accept kubernetes agent without decoration", 528 base: func(j *JobBase) { 529 j.DecorationConfig = nil 530 }, 531 pass: true, 532 }, 533 { 534 name: "accept knative-build agent", 535 base: func(j *JobBase) { 536 j.Agent = b 537 j.BuildSpec = &buildv1alpha1.BuildSpec{} 538 ns := "custom-namespace" 539 j.Namespace = &ns 540 j.Spec = nil 541 j.DecorationConfig = nil 542 }, 543 pass: true, 544 }, 545 { 546 name: "accept jenkins agent", 547 base: func(j *JobBase) { 548 j.Agent = jenk 549 j.Spec = nil 550 j.DecorationConfig = nil 551 }, 552 pass: true, 553 }, 554 { 555 name: "error_on_eviction requires kubernetes agent", 556 base: func(j *JobBase) { 557 j.Agent = b 558 j.ErrorOnEviction = true 559 }, 560 }, 561 { 562 name: "error_on_eviction allowed for kubernetes agent", 563 base: func(j *JobBase) { 564 j.ErrorOnEviction = true 565 }, 566 pass: true, 567 }, 568 } 569 570 for _, tc := range cases { 571 t.Run(tc.name, func(t *testing.T) { 572 jb := base 573 if tc.base != nil { 574 tc.base(&jb) 575 } 576 switch err := validateAgent(jb, ns); { 577 case err == nil && !tc.pass: 578 t.Error("validation failed to raise an error") 579 case err != nil && tc.pass: 580 t.Errorf("validation should have passed, got: %v", err) 581 } 582 }) 583 } 584 } 585 586 func TestValidatePodSpec(t *testing.T) { 587 periodEnv := sets.NewString(downwardapi.EnvForType(kube.PeriodicJob)...) 588 postEnv := sets.NewString(downwardapi.EnvForType(kube.PostsubmitJob)...) 589 preEnv := sets.NewString(downwardapi.EnvForType(kube.PresubmitJob)...) 590 cases := []struct { 591 name string 592 jobType kube.ProwJobType 593 spec func(s *v1.PodSpec) 594 noSpec bool 595 pass bool 596 }{ 597 { 598 name: "allow nil spec", 599 noSpec: true, 600 pass: true, 601 }, 602 { 603 name: "happy case", 604 pass: true, 605 }, 606 { 607 name: "reject init containers", 608 spec: func(s *v1.PodSpec) { 609 s.InitContainers = []v1.Container{ 610 {}, 611 } 612 }, 613 }, 614 { 615 name: "reject 0 containers", 616 spec: func(s *v1.PodSpec) { 617 s.Containers = nil 618 }, 619 }, 620 { 621 name: "reject 2 containers", 622 spec: func(s *v1.PodSpec) { 623 s.Containers = append(s.Containers, v1.Container{}) 624 }, 625 }, 626 { 627 name: "reject reserved presubmit env", 628 jobType: kube.PresubmitJob, 629 spec: func(s *v1.PodSpec) { 630 // find a presubmit value 631 for n := range preEnv.Difference(postEnv).Difference(periodEnv) { 632 633 s.Containers[0].Env = append(s.Containers[0].Env, v1.EnvVar{Name: n, Value: "whatever"}) 634 } 635 if len(s.Containers[0].Env) == 0 { 636 t.Fatal("empty env") 637 } 638 }, 639 }, 640 { 641 name: "reject reserved postsubmit env", 642 jobType: kube.PostsubmitJob, 643 spec: func(s *v1.PodSpec) { 644 // find a postsubmit value 645 for n := range postEnv.Difference(periodEnv) { 646 647 s.Containers[0].Env = append(s.Containers[0].Env, v1.EnvVar{Name: n, Value: "whatever"}) 648 } 649 if len(s.Containers[0].Env) == 0 { 650 t.Fatal("empty env") 651 } 652 }, 653 }, 654 { 655 name: "reject reserved periodic env", 656 jobType: kube.PeriodicJob, 657 spec: func(s *v1.PodSpec) { 658 // find a postsubmit value 659 for n := range periodEnv { 660 661 s.Containers[0].Env = append(s.Containers[0].Env, v1.EnvVar{Name: n, Value: "whatever"}) 662 } 663 if len(s.Containers[0].Env) == 0 { 664 t.Fatal("empty env") 665 } 666 }, 667 }, 668 { 669 name: "reject reserved mount name", 670 spec: func(s *v1.PodSpec) { 671 s.Containers[0].VolumeMounts = append(s.Containers[0].VolumeMounts, v1.VolumeMount{ 672 Name: decorate.VolumeMounts()[0], 673 MountPath: "/whatever", 674 }) 675 }, 676 }, 677 { 678 name: "reject reserved mount path", 679 spec: func(s *v1.PodSpec) { 680 s.Containers[0].VolumeMounts = append(s.Containers[0].VolumeMounts, v1.VolumeMount{ 681 Name: "fun", 682 MountPath: decorate.VolumeMountPaths()[0], 683 }) 684 }, 685 }, 686 { 687 name: "reject conflicting mount paths (decorate in user)", 688 spec: func(s *v1.PodSpec) { 689 s.Containers[0].VolumeMounts = append(s.Containers[0].VolumeMounts, v1.VolumeMount{ 690 Name: "foo", 691 MountPath: filepath.Dir(decorate.VolumeMountPaths()[0]), 692 }) 693 }, 694 }, 695 { 696 name: "reject conflicting mount paths (user in decorate)", 697 spec: func(s *v1.PodSpec) { 698 s.Containers[0].VolumeMounts = append(s.Containers[0].VolumeMounts, v1.VolumeMount{ 699 Name: "foo", 700 MountPath: filepath.Join(decorate.VolumeMountPaths()[0], "extra"), 701 }) 702 }, 703 }, 704 { 705 name: "reject reserved volume", 706 spec: func(s *v1.PodSpec) { 707 s.Volumes = append(s.Volumes, v1.Volume{Name: decorate.VolumeMounts()[0]}) 708 }, 709 }, 710 } 711 712 spec := v1.PodSpec{ 713 Containers: []v1.Container{ 714 {}, 715 }, 716 } 717 718 for _, tc := range cases { 719 t.Run(tc.name, func(t *testing.T) { 720 jt := kube.PresubmitJob 721 if tc.jobType != "" { 722 jt = tc.jobType 723 } 724 current := spec.DeepCopy() 725 if tc.noSpec { 726 current = nil 727 } else if tc.spec != nil { 728 tc.spec(current) 729 } 730 switch err := validatePodSpec(jt, current); { 731 case err == nil && !tc.pass: 732 t.Error("validation failed to raise an error") 733 case err != nil && tc.pass: 734 t.Errorf("validation should have passed, got: %v", err) 735 } 736 }) 737 } 738 } 739 740 func TestValidateDecoration(t *testing.T) { 741 defCfg := kube.DecorationConfig{ 742 UtilityImages: &prowjobv1.UtilityImages{ 743 CloneRefs: "clone-me", 744 InitUpload: "upload-me", 745 Entrypoint: "enter-me", 746 Sidecar: "official-drink-of-the-org", 747 }, 748 GCSCredentialsSecret: "upload-secret", 749 GCSConfiguration: &prowjobv1.GCSConfiguration{ 750 PathStrategy: prowjobv1.PathStrategyExplicit, 751 DefaultOrg: "so-org", 752 DefaultRepo: "very-repo", 753 }, 754 } 755 cases := []struct { 756 name string 757 container v1.Container 758 config *kube.DecorationConfig 759 pass bool 760 }{ 761 { 762 name: "allow no decoration", 763 pass: true, 764 }, 765 { 766 name: "happy case with cmd", 767 config: &defCfg, 768 container: v1.Container{ 769 Command: []string{"hello", "world"}, 770 }, 771 pass: true, 772 }, 773 { 774 name: "happy case with args", 775 config: &defCfg, 776 container: v1.Container{ 777 Args: []string{"hello", "world"}, 778 }, 779 pass: true, 780 }, 781 { 782 name: "reject invalid decoration config", 783 config: &kube.DecorationConfig{}, 784 container: v1.Container{ 785 Command: []string{"hello", "world"}, 786 }, 787 }, 788 { 789 name: "reject container that has no cmd, no args", 790 config: &defCfg, 791 }, 792 } 793 for _, tc := range cases { 794 t.Run(tc.name, func(t *testing.T) { 795 switch err := validateDecoration(tc.container, tc.config); { 796 case err == nil && !tc.pass: 797 t.Error("validation failed to raise an error") 798 case err != nil && tc.pass: 799 t.Errorf("validation should have passed, got: %v", err) 800 } 801 }) 802 } 803 } 804 805 func TestValidateLabels(t *testing.T) { 806 cases := []struct { 807 name string 808 labels map[string]string 809 pass bool 810 }{ 811 { 812 name: "happy case", 813 pass: true, 814 }, 815 { 816 name: "reject reserved label", 817 labels: map[string]string{ 818 decorate.Labels()[0]: "anything", 819 }, 820 }, 821 { 822 name: "reject bad label key", 823 labels: map[string]string{ 824 "_underscore-prefix": "annoying", 825 }, 826 }, 827 { 828 name: "reject bad label value", 829 labels: map[string]string{ 830 "whatever": "_private-is-rejected", 831 }, 832 }, 833 } 834 835 for _, tc := range cases { 836 t.Run(tc.name, func(t *testing.T) { 837 switch err := validateLabels(tc.labels); { 838 case err == nil && !tc.pass: 839 t.Error("validation failed to raise an error") 840 case err != nil && tc.pass: 841 t.Errorf("validation should have passed, got: %v", err) 842 } 843 }) 844 } 845 } 846 847 func TestValidateJobBase(t *testing.T) { 848 ka := string(prowjobv1.KubernetesAgent) 849 ba := string(prowjobv1.KnativeBuildAgent) 850 ja := string(prowjobv1.JenkinsAgent) 851 goodSpec := v1.PodSpec{ 852 Containers: []v1.Container{ 853 {}, 854 }, 855 } 856 ns := "target-namespace" 857 cases := []struct { 858 name string 859 base JobBase 860 pass bool 861 }{ 862 { 863 name: "valid kubernetes job", 864 base: JobBase{ 865 Name: "name", 866 Agent: ka, 867 Spec: &goodSpec, 868 Namespace: &ns, 869 }, 870 pass: true, 871 }, 872 { 873 name: "valid build job", 874 base: JobBase{ 875 Name: "name", 876 Agent: ba, 877 BuildSpec: &buildv1alpha1.BuildSpec{}, 878 Namespace: &ns, 879 }, 880 pass: true, 881 }, 882 { 883 name: "valid jenkins job", 884 base: JobBase{ 885 Name: "name", 886 Agent: ja, 887 Namespace: &ns, 888 }, 889 pass: true, 890 }, 891 { 892 name: "invalid concurrency", 893 base: JobBase{ 894 Name: "name", 895 MaxConcurrency: -1, 896 Agent: ka, 897 Spec: &goodSpec, 898 Namespace: &ns, 899 }, 900 }, 901 { 902 name: "invalid agent", 903 base: JobBase{ 904 Name: "name", 905 Agent: ba, 906 Spec: &goodSpec, // want BuildSpec 907 Namespace: &ns, 908 }, 909 }, 910 { 911 name: "invalid pod spec", 912 base: JobBase{ 913 Name: "name", 914 Agent: ka, 915 Namespace: &ns, 916 Spec: &v1.PodSpec{}, // no containers 917 }, 918 }, 919 { 920 name: "invalid decoration", 921 base: JobBase{ 922 Name: "name", 923 Agent: ka, 924 Spec: &goodSpec, 925 UtilityConfig: UtilityConfig{ 926 DecorationConfig: &prowjobv1.DecorationConfig{}, // missing many fields 927 }, 928 Namespace: &ns, 929 }, 930 }, 931 { 932 name: "invalid labels", 933 base: JobBase{ 934 Name: "name", 935 Agent: ka, 936 Spec: &goodSpec, 937 Labels: map[string]string{ 938 "_leading_underscore": "_rejected", 939 }, 940 Namespace: &ns, 941 }, 942 }, 943 { 944 name: "invalid name", 945 base: JobBase{ 946 Name: "a/b", 947 Agent: ka, 948 Spec: &goodSpec, 949 Namespace: &ns, 950 }, 951 pass: false, 952 }, 953 { 954 name: "valid complex name", 955 base: JobBase{ 956 Name: "a-b.c", 957 Agent: ka, 958 Spec: &goodSpec, 959 Namespace: &ns, 960 }, 961 pass: true, 962 }, 963 } 964 965 for _, tc := range cases { 966 t.Run(tc.name, func(t *testing.T) { 967 switch err := validateJobBase(tc.base, prowjobv1.PresubmitJob, ns); { 968 case err == nil && !tc.pass: 969 t.Error("validation failed to raise an error") 970 case err != nil && tc.pass: 971 t.Errorf("validation should have passed, got: %v", err) 972 } 973 }) 974 } 975 } 976 977 // integration test for fake config loading 978 func TestValidConfigLoading(t *testing.T) { 979 var testCases = []struct { 980 name string 981 prowConfig string 982 jobConfigs []string 983 expectError bool 984 expectPodNameSpace string 985 expectEnv map[string][]v1.EnvVar 986 }{ 987 { 988 name: "one config", 989 prowConfig: ``, 990 }, 991 { 992 name: "reject invalid kubernetes periodic", 993 prowConfig: ``, 994 jobConfigs: []string{ 995 ` 996 periodics: 997 - interval: 10m 998 agent: kubernetes 999 build_spec: 1000 name: foo`, 1001 }, 1002 expectError: true, 1003 }, 1004 { 1005 name: "reject invalid build periodic", 1006 prowConfig: ``, 1007 jobConfigs: []string{ 1008 ` 1009 periodics: 1010 - interval: 10m 1011 agent: knative-build 1012 spec: 1013 name: foo`, 1014 }, 1015 expectError: true, 1016 }, 1017 { 1018 name: "one periodic", 1019 prowConfig: ``, 1020 jobConfigs: []string{ 1021 ` 1022 periodics: 1023 - interval: 10m 1024 agent: kubernetes 1025 name: foo 1026 spec: 1027 containers: 1028 - image: alpine`, 1029 }, 1030 }, 1031 { 1032 name: "one periodic no agent, should default", 1033 prowConfig: ``, 1034 jobConfigs: []string{ 1035 ` 1036 periodics: 1037 - interval: 10m 1038 name: foo 1039 spec: 1040 containers: 1041 - image: alpine`, 1042 }, 1043 }, 1044 { 1045 name: "two periodics", 1046 prowConfig: ``, 1047 jobConfigs: []string{ 1048 ` 1049 periodics: 1050 - interval: 10m 1051 agent: kubernetes 1052 name: foo 1053 spec: 1054 containers: 1055 - image: alpine`, 1056 ` 1057 periodics: 1058 - interval: 10m 1059 agent: kubernetes 1060 name: bar 1061 spec: 1062 containers: 1063 - image: alpine`, 1064 }, 1065 }, 1066 { 1067 name: "duplicated periodics", 1068 prowConfig: ``, 1069 jobConfigs: []string{ 1070 ` 1071 periodics: 1072 - interval: 10m 1073 agent: kubernetes 1074 name: foo 1075 spec: 1076 containers: 1077 - image: alpine`, 1078 ` 1079 periodics: 1080 - interval: 10m 1081 agent: kubernetes 1082 name: foo 1083 spec: 1084 containers: 1085 - image: alpine`, 1086 }, 1087 expectError: true, 1088 }, 1089 { 1090 name: "one presubmit no context should default", 1091 prowConfig: ``, 1092 jobConfigs: []string{ 1093 ` 1094 presubmits: 1095 foo/bar: 1096 - agent: kubernetes 1097 name: presubmit-bar 1098 spec: 1099 containers: 1100 - image: alpine`, 1101 }, 1102 }, 1103 { 1104 name: "one presubmit no agent should default", 1105 prowConfig: ``, 1106 jobConfigs: []string{ 1107 ` 1108 presubmits: 1109 foo/bar: 1110 - context: bar 1111 name: presubmit-bar 1112 spec: 1113 containers: 1114 - image: alpine`, 1115 }, 1116 }, 1117 { 1118 name: "one presubmit, ok", 1119 prowConfig: ``, 1120 jobConfigs: []string{ 1121 ` 1122 presubmits: 1123 foo/bar: 1124 - agent: kubernetes 1125 name: presubmit-bar 1126 context: bar 1127 spec: 1128 containers: 1129 - image: alpine`, 1130 }, 1131 }, 1132 { 1133 name: "two presubmits", 1134 prowConfig: ``, 1135 jobConfigs: []string{ 1136 ` 1137 presubmits: 1138 foo/bar: 1139 - agent: kubernetes 1140 name: presubmit-bar 1141 context: bar 1142 spec: 1143 containers: 1144 - image: alpine`, 1145 ` 1146 presubmits: 1147 foo/baz: 1148 - agent: kubernetes 1149 name: presubmit-baz 1150 context: baz 1151 spec: 1152 containers: 1153 - image: alpine`, 1154 }, 1155 }, 1156 { 1157 name: "dup presubmits, one file", 1158 prowConfig: ``, 1159 jobConfigs: []string{ 1160 ` 1161 presubmits: 1162 foo/bar: 1163 - agent: kubernetes 1164 name: presubmit-bar 1165 context: bar 1166 spec: 1167 containers: 1168 - image: alpine 1169 - agent: kubernetes 1170 name: presubmit-bar 1171 context: bar 1172 spec: 1173 containers: 1174 - image: alpine`, 1175 }, 1176 expectError: true, 1177 }, 1178 { 1179 name: "dup presubmits, two files", 1180 prowConfig: ``, 1181 jobConfigs: []string{ 1182 ` 1183 presubmits: 1184 foo/bar: 1185 - agent: kubernetes 1186 name: presubmit-bar 1187 context: bar 1188 spec: 1189 containers: 1190 - image: alpine`, 1191 ` 1192 presubmits: 1193 foo/bar: 1194 - agent: kubernetes 1195 context: bar 1196 name: presubmit-bar 1197 spec: 1198 containers: 1199 - image: alpine`, 1200 }, 1201 expectError: true, 1202 }, 1203 { 1204 name: "dup presubmits not the same branch, two files", 1205 prowConfig: ``, 1206 jobConfigs: []string{ 1207 ` 1208 presubmits: 1209 foo/bar: 1210 - agent: kubernetes 1211 name: presubmit-bar 1212 context: bar 1213 branches: 1214 - master 1215 spec: 1216 containers: 1217 - image: alpine`, 1218 ` 1219 presubmits: 1220 foo/bar: 1221 - agent: kubernetes 1222 context: bar 1223 branches: 1224 - other 1225 name: presubmit-bar 1226 spec: 1227 containers: 1228 - image: alpine`, 1229 }, 1230 expectError: false, 1231 }, 1232 { 1233 name: "dup presubmits main file", 1234 prowConfig: ` 1235 presubmits: 1236 foo/bar: 1237 - agent: kubernetes 1238 name: presubmit-bar 1239 context: bar 1240 spec: 1241 containers: 1242 - image: alpine 1243 - agent: kubernetes 1244 context: bar 1245 name: presubmit-bar 1246 spec: 1247 containers: 1248 - image: alpine`, 1249 expectError: true, 1250 }, 1251 { 1252 name: "dup presubmits main file not on the same branch", 1253 prowConfig: ` 1254 presubmits: 1255 foo/bar: 1256 - agent: kubernetes 1257 name: presubmit-bar 1258 context: bar 1259 branches: 1260 - other 1261 spec: 1262 containers: 1263 - image: alpine 1264 - agent: kubernetes 1265 context: bar 1266 branches: 1267 - master 1268 name: presubmit-bar 1269 spec: 1270 containers: 1271 - image: alpine`, 1272 expectError: false, 1273 }, 1274 1275 { 1276 name: "one postsubmit, ok", 1277 prowConfig: ``, 1278 jobConfigs: []string{ 1279 ` 1280 postsubmits: 1281 foo/bar: 1282 - agent: kubernetes 1283 name: postsubmit-bar 1284 spec: 1285 containers: 1286 - image: alpine`, 1287 }, 1288 }, 1289 { 1290 name: "one postsubmit no agent, should default", 1291 prowConfig: ``, 1292 jobConfigs: []string{ 1293 ` 1294 postsubmits: 1295 foo/bar: 1296 - name: postsubmit-bar 1297 spec: 1298 containers: 1299 - image: alpine`, 1300 }, 1301 }, 1302 { 1303 name: "two postsubmits", 1304 prowConfig: ``, 1305 jobConfigs: []string{ 1306 ` 1307 postsubmits: 1308 foo/bar: 1309 - agent: kubernetes 1310 name: postsubmit-bar 1311 context: bar 1312 spec: 1313 containers: 1314 - image: alpine`, 1315 ` 1316 postsubmits: 1317 foo/baz: 1318 - agent: kubernetes 1319 name: postsubmit-baz 1320 context: baz 1321 spec: 1322 containers: 1323 - image: alpine`, 1324 }, 1325 }, 1326 { 1327 name: "dup postsubmits, one file", 1328 prowConfig: ``, 1329 jobConfigs: []string{ 1330 ` 1331 postsubmits: 1332 foo/bar: 1333 - agent: kubernetes 1334 name: postsubmit-bar 1335 context: bar 1336 spec: 1337 containers: 1338 - image: alpine 1339 - agent: kubernetes 1340 name: postsubmit-bar 1341 context: bar 1342 spec: 1343 containers: 1344 - image: alpine`, 1345 }, 1346 expectError: true, 1347 }, 1348 { 1349 name: "dup postsubmits, two files", 1350 prowConfig: ``, 1351 jobConfigs: []string{ 1352 ` 1353 postsubmits: 1354 foo/bar: 1355 - agent: kubernetes 1356 name: postsubmit-bar 1357 context: bar 1358 spec: 1359 containers: 1360 - image: alpine`, 1361 ` 1362 postsubmits: 1363 foo/bar: 1364 - agent: kubernetes 1365 context: bar 1366 name: postsubmit-bar 1367 spec: 1368 containers: 1369 - image: alpine`, 1370 }, 1371 expectError: true, 1372 }, 1373 { 1374 name: "overwrite PodNamespace", 1375 prowConfig: ` 1376 pod_namespace: test`, 1377 jobConfigs: []string{ 1378 ` 1379 pod_namespace: debug`, 1380 }, 1381 expectPodNameSpace: "test", 1382 }, 1383 { 1384 name: "test valid presets in main config", 1385 prowConfig: ` 1386 presets: 1387 - labels: 1388 preset-baz: "true" 1389 env: 1390 - name: baz 1391 value: fejtaverse`, 1392 jobConfigs: []string{ 1393 `periodics: 1394 - interval: 10m 1395 agent: kubernetes 1396 name: foo 1397 labels: 1398 preset-baz: "true" 1399 spec: 1400 containers: 1401 - image: alpine`, 1402 ` 1403 periodics: 1404 - interval: 10m 1405 agent: kubernetes 1406 name: bar 1407 labels: 1408 preset-baz: "true" 1409 spec: 1410 containers: 1411 - image: alpine`, 1412 }, 1413 expectEnv: map[string][]v1.EnvVar{ 1414 "foo": { 1415 { 1416 Name: "baz", 1417 Value: "fejtaverse", 1418 }, 1419 }, 1420 "bar": { 1421 { 1422 Name: "baz", 1423 Value: "fejtaverse", 1424 }, 1425 }, 1426 }, 1427 }, 1428 { 1429 name: "test valid presets in job configs", 1430 prowConfig: ``, 1431 jobConfigs: []string{ 1432 ` 1433 presets: 1434 - labels: 1435 preset-baz: "true" 1436 env: 1437 - name: baz 1438 value: fejtaverse 1439 periodics: 1440 - interval: 10m 1441 agent: kubernetes 1442 name: foo 1443 labels: 1444 preset-baz: "true" 1445 spec: 1446 containers: 1447 - image: alpine`, 1448 ` 1449 periodics: 1450 - interval: 10m 1451 agent: kubernetes 1452 name: bar 1453 labels: 1454 preset-baz: "true" 1455 spec: 1456 containers: 1457 - image: alpine`, 1458 }, 1459 expectEnv: map[string][]v1.EnvVar{ 1460 "foo": { 1461 { 1462 Name: "baz", 1463 Value: "fejtaverse", 1464 }, 1465 }, 1466 "bar": { 1467 { 1468 Name: "baz", 1469 Value: "fejtaverse", 1470 }, 1471 }, 1472 }, 1473 }, 1474 { 1475 name: "test valid presets in both main & job configs", 1476 prowConfig: ` 1477 presets: 1478 - labels: 1479 preset-baz: "true" 1480 env: 1481 - name: baz 1482 value: fejtaverse`, 1483 jobConfigs: []string{ 1484 ` 1485 presets: 1486 - labels: 1487 preset-k8s: "true" 1488 env: 1489 - name: k8s 1490 value: kubernetes 1491 periodics: 1492 - interval: 10m 1493 agent: kubernetes 1494 name: foo 1495 labels: 1496 preset-baz: "true" 1497 preset-k8s: "true" 1498 spec: 1499 containers: 1500 - image: alpine`, 1501 ` 1502 periodics: 1503 - interval: 10m 1504 agent: kubernetes 1505 name: bar 1506 labels: 1507 preset-baz: "true" 1508 spec: 1509 containers: 1510 - image: alpine`, 1511 }, 1512 expectEnv: map[string][]v1.EnvVar{ 1513 "foo": { 1514 { 1515 Name: "baz", 1516 Value: "fejtaverse", 1517 }, 1518 { 1519 Name: "k8s", 1520 Value: "kubernetes", 1521 }, 1522 }, 1523 "bar": { 1524 { 1525 Name: "baz", 1526 Value: "fejtaverse", 1527 }, 1528 }, 1529 }, 1530 }, 1531 { 1532 name: "decorated periodic missing `command`", 1533 prowConfig: ``, 1534 jobConfigs: []string{ 1535 ` 1536 periodics: 1537 - interval: 10m 1538 agent: kubernetes 1539 name: foo 1540 decorate: true 1541 spec: 1542 containers: 1543 - image: alpine`, 1544 }, 1545 expectError: true, 1546 }, 1547 } 1548 1549 for _, tc := range testCases { 1550 // save the config 1551 prowConfigDir, err := ioutil.TempDir("", "prowConfig") 1552 if err != nil { 1553 t.Fatalf("fail to make tempdir: %v", err) 1554 } 1555 defer os.RemoveAll(prowConfigDir) 1556 1557 prowConfig := filepath.Join(prowConfigDir, "config.yaml") 1558 if err := ioutil.WriteFile(prowConfig, []byte(tc.prowConfig), 0666); err != nil { 1559 t.Fatalf("fail to write prow config: %v", err) 1560 } 1561 1562 jobConfig := "" 1563 if len(tc.jobConfigs) > 0 { 1564 jobConfigDir, err := ioutil.TempDir("", "jobConfig") 1565 if err != nil { 1566 t.Fatalf("fail to make tempdir: %v", err) 1567 } 1568 defer os.RemoveAll(jobConfigDir) 1569 1570 // cover both job config as a file & a dir 1571 if len(tc.jobConfigs) == 1 { 1572 // a single file 1573 jobConfig = filepath.Join(jobConfigDir, "config.yaml") 1574 if err := ioutil.WriteFile(jobConfig, []byte(tc.jobConfigs[0]), 0666); err != nil { 1575 t.Fatalf("fail to write job config: %v", err) 1576 } 1577 } else { 1578 // a dir 1579 jobConfig = jobConfigDir 1580 for idx, config := range tc.jobConfigs { 1581 subConfig := filepath.Join(jobConfigDir, fmt.Sprintf("config_%d.yaml", idx)) 1582 if err := ioutil.WriteFile(subConfig, []byte(config), 0666); err != nil { 1583 t.Fatalf("fail to write job config: %v", err) 1584 } 1585 } 1586 } 1587 } 1588 1589 cfg, err := Load(prowConfig, jobConfig) 1590 if tc.expectError && err == nil { 1591 t.Errorf("tc %s: Expect error, but got nil", tc.name) 1592 } else if !tc.expectError && err != nil { 1593 t.Errorf("tc %s: Expect no error, but got error %v", tc.name, err) 1594 } 1595 1596 if err == nil { 1597 if tc.expectPodNameSpace == "" { 1598 tc.expectPodNameSpace = "default" 1599 } 1600 1601 if cfg.PodNamespace != tc.expectPodNameSpace { 1602 t.Errorf("tc %s: Expect PodNamespace %s, but got %v", tc.name, tc.expectPodNameSpace, cfg.PodNamespace) 1603 } 1604 1605 if len(tc.expectEnv) > 0 { 1606 for _, j := range cfg.AllPresubmits(nil) { 1607 if envs, ok := tc.expectEnv[j.Name]; ok { 1608 if !reflect.DeepEqual(envs, j.Spec.Containers[0].Env) { 1609 t.Errorf("tc %s: expect env %v for job %s, got %+v", tc.name, envs, j.Name, j.Spec.Containers[0].Env) 1610 } 1611 } 1612 } 1613 1614 for _, j := range cfg.AllPostsubmits(nil) { 1615 if envs, ok := tc.expectEnv[j.Name]; ok { 1616 if !reflect.DeepEqual(envs, j.Spec.Containers[0].Env) { 1617 t.Errorf("tc %s: expect env %v for job %s, got %+v", tc.name, envs, j.Name, j.Spec.Containers[0].Env) 1618 } 1619 } 1620 } 1621 1622 for _, j := range cfg.AllPeriodics() { 1623 if envs, ok := tc.expectEnv[j.Name]; ok { 1624 if !reflect.DeepEqual(envs, j.Spec.Containers[0].Env) { 1625 t.Errorf("tc %s: expect env %v for job %s, got %+v", tc.name, envs, j.Name, j.Spec.Containers[0].Env) 1626 } 1627 } 1628 } 1629 } 1630 } 1631 } 1632 } 1633 1634 func TestBrancher_Intersects(t *testing.T) { 1635 testCases := []struct { 1636 name string 1637 a, b Brancher 1638 result bool 1639 }{ 1640 { 1641 name: "TwodifferentBranches", 1642 a: Brancher{ 1643 Branches: []string{"a"}, 1644 }, 1645 b: Brancher{ 1646 Branches: []string{"b"}, 1647 }, 1648 }, 1649 { 1650 name: "Opposite", 1651 a: Brancher{ 1652 SkipBranches: []string{"b"}, 1653 }, 1654 b: Brancher{ 1655 Branches: []string{"b"}, 1656 }, 1657 }, 1658 { 1659 name: "BothRunOnAllBranches", 1660 a: Brancher{}, 1661 b: Brancher{}, 1662 result: true, 1663 }, 1664 { 1665 name: "RunsOnAllBranchesAndSpecified", 1666 a: Brancher{}, 1667 b: Brancher{ 1668 Branches: []string{"b"}, 1669 }, 1670 result: true, 1671 }, 1672 { 1673 name: "SkipBranchesAndSet", 1674 a: Brancher{ 1675 SkipBranches: []string{"a", "b", "c"}, 1676 }, 1677 b: Brancher{ 1678 Branches: []string{"a"}, 1679 }, 1680 }, 1681 { 1682 name: "SkipBranchesAndSet", 1683 a: Brancher{ 1684 Branches: []string{"c"}, 1685 }, 1686 b: Brancher{ 1687 Branches: []string{"a"}, 1688 }, 1689 }, 1690 { 1691 name: "BothSkipBranches", 1692 a: Brancher{ 1693 SkipBranches: []string{"a", "b", "c"}, 1694 }, 1695 b: Brancher{ 1696 SkipBranches: []string{"d", "e", "f"}, 1697 }, 1698 result: true, 1699 }, 1700 { 1701 name: "BothSkipCommonBranches", 1702 a: Brancher{ 1703 SkipBranches: []string{"a", "b", "c"}, 1704 }, 1705 b: Brancher{ 1706 SkipBranches: []string{"b", "e", "f"}, 1707 }, 1708 result: true, 1709 }, 1710 } 1711 1712 for _, tc := range testCases { 1713 t.Run(tc.name, func(st *testing.T) { 1714 r1 := tc.a.Intersects(tc.b) 1715 r2 := tc.b.Intersects(tc.a) 1716 for _, result := range []bool{r1, r2} { 1717 if result != tc.result { 1718 st.Errorf("Expected %v got %v", tc.result, result) 1719 } 1720 } 1721 }) 1722 } 1723 } 1724 1725 // Integration test for fake secrets loading in a secret agent. 1726 // Checking also if the agent changes the secret's values as expected. 1727 func TestSecretAgentLoading(t *testing.T) { 1728 tempTokenValue := "121f3cb3e7f70feeb35f9204f5a988d7292c7ba1" 1729 changedTokenValue := "121f3cb3e7f70feeb35f9204f5a988d7292c7ba0" 1730 1731 // Creating a temporary directory. 1732 secretDir, err := ioutil.TempDir("", "secretDir") 1733 if err != nil { 1734 t.Fatalf("fail to create a temporary directory: %v", err) 1735 } 1736 defer os.RemoveAll(secretDir) 1737 1738 // Create the first temporary secret. 1739 firstTempSecret := filepath.Join(secretDir, "firstTempSecret") 1740 if err := ioutil.WriteFile(firstTempSecret, []byte(tempTokenValue), 0666); err != nil { 1741 t.Fatalf("fail to write secret: %v", err) 1742 } 1743 1744 // Create the second temporary secret. 1745 secondTempSecret := filepath.Join(secretDir, "secondTempSecret") 1746 if err := ioutil.WriteFile(secondTempSecret, []byte(tempTokenValue), 0666); err != nil { 1747 t.Fatalf("fail to write secret: %v", err) 1748 } 1749 1750 tempSecrets := []string{firstTempSecret, secondTempSecret} 1751 // Starting the agent and add the two temporary secrets. 1752 secretAgent := &SecretAgent{} 1753 if err := secretAgent.Start(tempSecrets); err != nil { 1754 t.Fatalf("Error starting secrets agent. %v", err) 1755 } 1756 1757 // Check if the values are as expected. 1758 for _, tempSecret := range tempSecrets { 1759 tempSecretValue := secretAgent.GetSecret(tempSecret) 1760 if string(tempSecretValue) != tempTokenValue { 1761 t.Fatalf("In secret %s it was expected %s but found %s", 1762 tempSecret, tempTokenValue, tempSecretValue) 1763 } 1764 } 1765 1766 // Change the values of the files. 1767 if err := ioutil.WriteFile(firstTempSecret, []byte(changedTokenValue), 0666); err != nil { 1768 t.Fatalf("fail to write secret: %v", err) 1769 } 1770 if err := ioutil.WriteFile(secondTempSecret, []byte(changedTokenValue), 0666); err != nil { 1771 t.Fatalf("fail to write secret: %v", err) 1772 } 1773 1774 retries := 10 1775 var errors []string 1776 1777 // Check if the values changed as expected. 1778 for _, tempSecret := range tempSecrets { 1779 // Reset counter 1780 counter := 0 1781 for counter <= retries { 1782 tempSecretValue := secretAgent.GetSecret(tempSecret) 1783 if string(tempSecretValue) != changedTokenValue { 1784 if counter == retries { 1785 errors = append(errors, fmt.Sprintf("In secret %s it was expected %s but found %s\n", 1786 tempSecret, changedTokenValue, tempSecretValue)) 1787 } else { 1788 // Secret agent needs some time to update the values. So wait and retry. 1789 time.Sleep(400 * time.Millisecond) 1790 } 1791 } else { 1792 break 1793 } 1794 counter++ 1795 } 1796 } 1797 1798 if len(errors) > 0 { 1799 t.Fatal(errors) 1800 } 1801 1802 }