github.com/jenkins-x/test-infra@v0.0.7/prow/config/tide_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 "reflect" 21 "strings" 22 "testing" 23 24 "k8s.io/apimachinery/pkg/util/sets" 25 "k8s.io/test-infra/prow/github" 26 "k8s.io/test-infra/prow/labels" 27 ) 28 29 var testQuery = TideQuery{ 30 Orgs: []string{"org"}, 31 Repos: []string{"k/k", "k/t-i"}, 32 Labels: []string{labels.LGTM, labels.Approved}, 33 MissingLabels: []string{"foo"}, 34 Milestone: "milestone", 35 ReviewApprovedRequired: true, 36 } 37 38 func TestTideQuery(t *testing.T) { 39 q := " " + testQuery.Query() + " " 40 checkTok := func(tok string) { 41 if !strings.Contains(q, " "+tok+" ") { 42 t.Errorf("Expected query to contain \"%s\", got \"%s\"", tok, q) 43 } 44 } 45 46 checkTok("is:pr") 47 checkTok("state:open") 48 checkTok("org:\"org\"") 49 checkTok("repo:\"k/k\"") 50 checkTok("repo:\"k/t-i\"") 51 checkTok("label:\"lgtm\"") 52 checkTok("label:\"approved\"") 53 checkTok("-label:\"foo\"") 54 checkTok("milestone:\"milestone\"") 55 checkTok("review:approved") 56 } 57 58 func TestOrgExceptionsAndRepos(t *testing.T) { 59 queries := TideQueries{ 60 { 61 Orgs: []string{"k8s"}, 62 ExcludedRepos: []string{"k8s/k8s"}, 63 }, 64 { 65 Orgs: []string{"kuber"}, 66 Repos: []string{"foo/bar", "baz/bar"}, 67 ExcludedRepos: []string{"kuber/netes"}, 68 }, 69 { 70 Orgs: []string{"k8s"}, 71 ExcludedRepos: []string{"k8s/k8s", "k8s/t-i"}, 72 }, 73 { 74 Orgs: []string{"org", "org2"}, 75 ExcludedRepos: []string{"org2/repo", "org2/repo2", "org2/repo3"}, 76 }, 77 { 78 Orgs: []string{"foo"}, 79 Repos: []string{"org2/repo3"}, 80 }, 81 } 82 83 expectedOrgs := map[string]sets.String{ 84 "foo": sets.NewString(), 85 "k8s": sets.NewString("k8s/k8s"), 86 "kuber": sets.NewString("kuber/netes"), 87 "org": sets.NewString(), 88 "org2": sets.NewString("org2/repo", "org2/repo2"), 89 } 90 expectedRepos := sets.NewString("foo/bar", "baz/bar", "org2/repo3") 91 92 orgs, repos := queries.OrgExceptionsAndRepos() 93 if !reflect.DeepEqual(orgs, expectedOrgs) { 94 t.Errorf("Expected org map %v, but got %v.", expectedOrgs, orgs) 95 } 96 if !repos.Equal(expectedRepos) { 97 t.Errorf("Expected repo set %v, but got %v.", expectedRepos, repos) 98 } 99 } 100 101 func TestMergeMethod(t *testing.T) { 102 ti := &Tide{ 103 MergeType: map[string]github.PullRequestMergeType{ 104 "kubernetes/kops": github.MergeRebase, 105 "kubernetes/charts": github.MergeSquash, 106 "helm/charts": github.MergeSquash, 107 "kubernetes-helm": github.MergeSquash, 108 "kubernetes-helm/chartmuseum": github.MergeMerge, 109 }, 110 } 111 112 var testcases = []struct { 113 org string 114 repo string 115 expected github.PullRequestMergeType 116 }{ 117 { 118 "kubernetes", 119 "kubernetes", 120 github.MergeMerge, 121 }, 122 { 123 "kubernetes", 124 "kops", 125 github.MergeRebase, 126 }, 127 { 128 "kubernetes", 129 "charts", 130 github.MergeSquash, 131 }, 132 { 133 "kubernetes-helm", 134 "monocular", 135 github.MergeSquash, 136 }, 137 { 138 "kubernetes-helm", 139 "chartmuseum", 140 github.MergeMerge, 141 }, 142 } 143 144 for _, test := range testcases { 145 if ti.MergeMethod(test.org, test.repo) != test.expected { 146 t.Errorf("Expected merge method %q but got %q for %s/%s", test.expected, ti.MergeMethod(test.org, test.repo), test.org, test.repo) 147 } 148 } 149 } 150 151 func TestParseTideContextPolicyOptions(t *testing.T) { 152 yes := true 153 no := false 154 org, repo, branch := "org", "repo", "branch" 155 testCases := []struct { 156 name string 157 config TideContextPolicyOptions 158 expected TideContextPolicy 159 }{ 160 { 161 name: "empty", 162 }, 163 { 164 name: "global config", 165 config: TideContextPolicyOptions{ 166 TideContextPolicy: TideContextPolicy{ 167 FromBranchProtection: &yes, 168 SkipUnknownContexts: &yes, 169 RequiredContexts: []string{"r1"}, 170 OptionalContexts: []string{"o1"}, 171 }, 172 }, 173 expected: TideContextPolicy{ 174 SkipUnknownContexts: &yes, 175 RequiredContexts: []string{"r1"}, 176 OptionalContexts: []string{"o1"}, 177 FromBranchProtection: &yes, 178 }, 179 }, 180 { 181 name: "org config", 182 config: TideContextPolicyOptions{ 183 TideContextPolicy: TideContextPolicy{ 184 RequiredContexts: []string{"r1"}, 185 OptionalContexts: []string{"o1"}, 186 FromBranchProtection: &no, 187 }, 188 Orgs: map[string]TideOrgContextPolicy{ 189 "org": { 190 TideContextPolicy: TideContextPolicy{ 191 SkipUnknownContexts: &yes, 192 RequiredContexts: []string{"r2"}, 193 OptionalContexts: []string{"o2"}, 194 FromBranchProtection: &yes, 195 }, 196 }, 197 }, 198 }, 199 expected: TideContextPolicy{ 200 SkipUnknownContexts: &yes, 201 RequiredContexts: []string{"r1", "r2"}, 202 OptionalContexts: []string{"o1", "o2"}, 203 FromBranchProtection: &yes, 204 }, 205 }, 206 { 207 name: "repo config", 208 config: TideContextPolicyOptions{ 209 TideContextPolicy: TideContextPolicy{ 210 RequiredContexts: []string{"r1"}, 211 OptionalContexts: []string{"o1"}, 212 FromBranchProtection: &no, 213 }, 214 Orgs: map[string]TideOrgContextPolicy{ 215 "org": { 216 TideContextPolicy: TideContextPolicy{ 217 SkipUnknownContexts: &no, 218 RequiredContexts: []string{"r2"}, 219 OptionalContexts: []string{"o2"}, 220 FromBranchProtection: &no, 221 }, 222 Repos: map[string]TideRepoContextPolicy{ 223 "repo": { 224 TideContextPolicy: TideContextPolicy{ 225 SkipUnknownContexts: &yes, 226 RequiredContexts: []string{"r3"}, 227 OptionalContexts: []string{"o3"}, 228 FromBranchProtection: &yes, 229 }, 230 }, 231 }, 232 }, 233 }, 234 }, 235 expected: TideContextPolicy{ 236 SkipUnknownContexts: &yes, 237 RequiredContexts: []string{"r1", "r2", "r3"}, 238 OptionalContexts: []string{"o1", "o2", "o3"}, 239 FromBranchProtection: &yes, 240 }, 241 }, 242 { 243 name: "branch config", 244 config: TideContextPolicyOptions{ 245 TideContextPolicy: TideContextPolicy{ 246 RequiredContexts: []string{"r1"}, 247 OptionalContexts: []string{"o1"}, 248 }, 249 Orgs: map[string]TideOrgContextPolicy{ 250 "org": { 251 TideContextPolicy: TideContextPolicy{ 252 RequiredContexts: []string{"r2"}, 253 OptionalContexts: []string{"o2"}, 254 }, 255 Repos: map[string]TideRepoContextPolicy{ 256 "repo": { 257 TideContextPolicy: TideContextPolicy{ 258 RequiredContexts: []string{"r3"}, 259 OptionalContexts: []string{"o3"}, 260 }, 261 Branches: map[string]TideContextPolicy{ 262 "branch": { 263 RequiredContexts: []string{"r4"}, 264 OptionalContexts: []string{"o4"}, 265 }, 266 }, 267 }, 268 }, 269 }, 270 }, 271 }, 272 expected: TideContextPolicy{ 273 RequiredContexts: []string{"r1", "r2", "r3", "r4"}, 274 OptionalContexts: []string{"o1", "o2", "o3", "o4"}, 275 }, 276 }, 277 } 278 for _, tc := range testCases { 279 policy := parseTideContextPolicyOptions(org, repo, branch, tc.config) 280 if !reflect.DeepEqual(policy, tc.expected) { 281 t.Errorf("%s - expected %v got %v", tc.name, tc.expected, policy) 282 } 283 } 284 } 285 286 func TestConfigGetTideContextPolicy(t *testing.T) { 287 yes := true 288 no := false 289 org, repo, branch := "org", "repo", "branch" 290 testCases := []struct { 291 name string 292 config Config 293 expected TideContextPolicy 294 error string 295 }{ 296 { 297 name: "no policy - use prow jobs", 298 config: Config{ 299 ProwConfig: ProwConfig{ 300 BranchProtection: BranchProtection{ 301 Policy: Policy{ 302 Protect: &yes, 303 RequiredStatusChecks: &ContextPolicy{ 304 Contexts: []string{"r1", "r2"}, 305 }, 306 }, 307 }, 308 }, 309 JobConfig: JobConfig{ 310 Presubmits: map[string][]Presubmit{ 311 "org/repo": { 312 Presubmit{ 313 Context: "pr1", 314 AlwaysRun: true, 315 }, 316 Presubmit{ 317 Context: "po1", 318 AlwaysRun: true, 319 Optional: true, 320 }, 321 }, 322 }, 323 }, 324 }, 325 expected: TideContextPolicy{ 326 RequiredContexts: []string{"pr1"}, 327 OptionalContexts: []string{"po1"}, 328 }, 329 }, 330 { 331 name: "no policy no prow jobs defined - empty", 332 config: Config{ 333 ProwConfig: ProwConfig{ 334 BranchProtection: BranchProtection{ 335 Policy: Policy{ 336 Protect: &yes, 337 RequiredStatusChecks: &ContextPolicy{ 338 Contexts: []string{"r1", "r2"}, 339 }, 340 }, 341 }, 342 }, 343 }, 344 expected: TideContextPolicy{ 345 RequiredContexts: []string{}, 346 OptionalContexts: []string{}, 347 }, 348 }, 349 { 350 name: "no branch protection", 351 config: Config{ 352 ProwConfig: ProwConfig{ 353 Tide: Tide{ 354 ContextOptions: TideContextPolicyOptions{ 355 TideContextPolicy: TideContextPolicy{ 356 FromBranchProtection: &yes, 357 }, 358 }, 359 }, 360 }, 361 }, 362 expected: TideContextPolicy{ 363 RequiredContexts: []string{}, 364 OptionalContexts: []string{}, 365 }, 366 }, 367 { 368 name: "invalid branch protection", 369 config: Config{ 370 ProwConfig: ProwConfig{ 371 BranchProtection: BranchProtection{ 372 Orgs: map[string]Org{ 373 "org": { 374 Policy: Policy{ 375 Protect: &no, 376 }, 377 }, 378 }, 379 }, 380 Tide: Tide{ 381 ContextOptions: TideContextPolicyOptions{ 382 TideContextPolicy: TideContextPolicy{ 383 FromBranchProtection: &yes, 384 }, 385 }, 386 }, 387 }, 388 }, 389 expected: TideContextPolicy{ 390 RequiredContexts: []string{}, 391 OptionalContexts: []string{}, 392 }, 393 }, 394 { 395 name: "manually defined policy", 396 config: Config{ 397 ProwConfig: ProwConfig{ 398 Tide: Tide{ 399 ContextOptions: TideContextPolicyOptions{ 400 TideContextPolicy: TideContextPolicy{ 401 RequiredContexts: []string{"r1"}, 402 OptionalContexts: []string{"o1"}, 403 SkipUnknownContexts: &yes, 404 }, 405 }, 406 }, 407 }, 408 }, 409 expected: TideContextPolicy{ 410 RequiredContexts: []string{"r1"}, 411 OptionalContexts: []string{"o1"}, 412 SkipUnknownContexts: &yes, 413 }, 414 }, 415 } 416 417 for _, tc := range testCases { 418 p, err := tc.config.GetTideContextPolicy(org, repo, branch) 419 if !reflect.DeepEqual(p, &tc.expected) { 420 t.Errorf("%s - expected contexts %v got %v", tc.name, &tc.expected, p) 421 } 422 if err != nil { 423 if err.Error() != tc.error { 424 t.Errorf("%s - expected error %v got %v", tc.name, tc.error, err.Error()) 425 } 426 } else if tc.error != "" { 427 t.Errorf("%s - expected error %v got nil", tc.name, tc.error) 428 } 429 } 430 } 431 432 func TestMergeTideContextPolicyConfig(t *testing.T) { 433 yes := true 434 no := false 435 testCases := []struct { 436 name string 437 a, b, c TideContextPolicy 438 }{ 439 { 440 name: "all empty", 441 }, 442 { 443 name: "empty a", 444 b: TideContextPolicy{ 445 SkipUnknownContexts: &yes, 446 FromBranchProtection: &no, 447 RequiredContexts: []string{"r1"}, 448 OptionalContexts: []string{"o1"}, 449 }, 450 c: TideContextPolicy{ 451 SkipUnknownContexts: &yes, 452 FromBranchProtection: &no, 453 RequiredContexts: []string{"r1"}, 454 OptionalContexts: []string{"o1"}, 455 }, 456 }, 457 { 458 name: "empty b", 459 a: TideContextPolicy{ 460 SkipUnknownContexts: &yes, 461 FromBranchProtection: &no, 462 RequiredContexts: []string{"r1"}, 463 OptionalContexts: []string{"o1"}, 464 }, 465 c: TideContextPolicy{ 466 SkipUnknownContexts: &yes, 467 FromBranchProtection: &no, 468 RequiredContexts: []string{"r1"}, 469 OptionalContexts: []string{"o1"}, 470 }, 471 }, 472 { 473 name: "merging unset boolean", 474 a: TideContextPolicy{ 475 FromBranchProtection: &no, 476 RequiredContexts: []string{"r1"}, 477 OptionalContexts: []string{"o1"}, 478 }, 479 b: TideContextPolicy{ 480 SkipUnknownContexts: &yes, 481 RequiredContexts: []string{"r2"}, 482 OptionalContexts: []string{"o2"}, 483 }, 484 c: TideContextPolicy{ 485 SkipUnknownContexts: &yes, 486 FromBranchProtection: &no, 487 RequiredContexts: []string{"r1", "r2"}, 488 OptionalContexts: []string{"o1", "o2"}, 489 }, 490 }, 491 { 492 name: "merging unset contexts in a", 493 a: TideContextPolicy{ 494 FromBranchProtection: &no, 495 SkipUnknownContexts: &yes, 496 }, 497 b: TideContextPolicy{ 498 FromBranchProtection: &yes, 499 SkipUnknownContexts: &no, 500 RequiredContexts: []string{"r1"}, 501 OptionalContexts: []string{"o1"}, 502 }, 503 c: TideContextPolicy{ 504 FromBranchProtection: &yes, 505 SkipUnknownContexts: &no, 506 RequiredContexts: []string{"r1"}, 507 OptionalContexts: []string{"o1"}, 508 }, 509 }, 510 { 511 name: "merging unset contexts in b", 512 a: TideContextPolicy{ 513 FromBranchProtection: &yes, 514 SkipUnknownContexts: &no, 515 RequiredContexts: []string{"r1"}, 516 OptionalContexts: []string{"o1"}, 517 }, 518 b: TideContextPolicy{ 519 FromBranchProtection: &no, 520 SkipUnknownContexts: &yes, 521 }, 522 c: TideContextPolicy{ 523 FromBranchProtection: &no, 524 SkipUnknownContexts: &yes, 525 RequiredContexts: []string{"r1"}, 526 OptionalContexts: []string{"o1"}, 527 }, 528 }, 529 } 530 531 for _, tc := range testCases { 532 c := mergeTideContextPolicy(tc.a, tc.b) 533 if !reflect.DeepEqual(c, tc.c) { 534 t.Errorf("%s - expected %v got %v", tc.name, tc.c, c) 535 } 536 } 537 } 538 539 func TestTideQuery_Validate(t *testing.T) { 540 testCases := []struct { 541 name string 542 query TideQuery 543 expectError bool 544 }{ 545 { 546 name: "good query", 547 query: TideQuery{ 548 Orgs: []string{"kuber"}, 549 Repos: []string{"foo/bar", "baz/bar"}, 550 ExcludedRepos: []string{"kuber/netes"}, 551 IncludedBranches: []string{"master"}, 552 Milestone: "backlog-forever", 553 Labels: []string{labels.LGTM, labels.Approved}, 554 MissingLabels: []string{"do-not-merge/evil-code"}, 555 ReviewApprovedRequired: true, 556 }, 557 expectError: false, 558 }, 559 { 560 name: "simple org query is valid", 561 query: TideQuery{ 562 Orgs: []string{"kuber"}, 563 }, 564 expectError: false, 565 }, 566 { 567 name: "org with slash is invalid", 568 query: TideQuery{ 569 Orgs: []string{"kube/r"}, 570 }, 571 expectError: true, 572 }, 573 { 574 name: "empty org is invalid", 575 query: TideQuery{ 576 Orgs: []string{""}, 577 }, 578 expectError: true, 579 }, 580 { 581 name: "duplicate org is invalid", 582 query: TideQuery{ 583 Orgs: []string{"kuber", "kuber"}, 584 }, 585 expectError: true, 586 }, 587 { 588 name: "simple repo query is valid", 589 query: TideQuery{ 590 Repos: []string{"kuber/netes"}, 591 }, 592 expectError: false, 593 }, 594 { 595 name: "repo without slash is invalid", 596 query: TideQuery{ 597 Repos: []string{"foobar", "baz/bar"}, 598 }, 599 expectError: true, 600 }, 601 { 602 name: "repo included with parent org is invalid", 603 query: TideQuery{ 604 Orgs: []string{"kuber"}, 605 Repos: []string{"foo/bar", "kuber/netes"}, 606 }, 607 expectError: true, 608 }, 609 { 610 name: "duplicate repo is invalid", 611 query: TideQuery{ 612 Repos: []string{"baz/bar", "foo/bar", "baz/bar"}, 613 }, 614 expectError: true, 615 }, 616 { 617 name: "empty orgs and repos is invalid", 618 query: TideQuery{ 619 IncludedBranches: []string{"master"}, 620 Milestone: "backlog-forever", 621 Labels: []string{labels.LGTM, labels.Approved}, 622 MissingLabels: []string{"do-not-merge/evil-code"}, 623 ReviewApprovedRequired: true, 624 }, 625 expectError: true, 626 }, 627 { 628 name: "simple excluded repo query is valid", 629 query: TideQuery{ 630 Orgs: []string{"kuber"}, 631 ExcludedRepos: []string{"kuber/netes"}, 632 }, 633 expectError: false, 634 }, 635 { 636 name: "excluded repo without slash is invalid", 637 query: TideQuery{ 638 Orgs: []string{"kuber"}, 639 ExcludedRepos: []string{"kubernetes"}, 640 }, 641 expectError: true, 642 }, 643 { 644 name: "excluded repo included without parent org is invalid", 645 query: TideQuery{ 646 Repos: []string{"foo/bar", "baz/bar"}, 647 ExcludedRepos: []string{"kuber/netes"}, 648 }, 649 expectError: true, 650 }, 651 { 652 name: "duplicate excluded repo is invalid", 653 query: TideQuery{ 654 Orgs: []string{"kuber"}, 655 ExcludedRepos: []string{"kuber/netes", "kuber/netes"}, 656 ReviewApprovedRequired: true, 657 }, 658 expectError: true, 659 }, 660 { 661 name: "label cannot be required and forbidden", 662 query: TideQuery{ 663 Orgs: []string{"kuber"}, 664 Labels: []string{labels.LGTM, labels.Approved}, 665 MissingLabels: []string{"do-not-merge/evil-code", labels.LGTM}, 666 }, 667 expectError: true, 668 }, 669 { 670 name: "simple excluded branches query is valid", 671 query: TideQuery{ 672 Orgs: []string{"kuber"}, 673 ExcludedBranches: []string{"dev"}, 674 }, 675 expectError: false, 676 }, 677 { 678 name: "specifying both included and excluded branches is invalid", 679 query: TideQuery{ 680 Orgs: []string{"kuber"}, 681 IncludedBranches: []string{"master"}, 682 ExcludedBranches: []string{"dev"}, 683 }, 684 expectError: true, 685 }, 686 } 687 for _, tc := range testCases { 688 t.Run(tc.name, func(t *testing.T) { 689 err := tc.query.Validate() 690 if err != nil && !tc.expectError { 691 t.Errorf("Unexpected error: %v.", err) 692 } else if err == nil && tc.expectError { 693 t.Error("Expected a validation error, but didn't get one.") 694 } 695 }) 696 697 } 698 } 699 700 func TestTideContextPolicy_Validate(t *testing.T) { 701 testCases := []struct { 702 name string 703 t TideContextPolicy 704 failed bool 705 }{ 706 { 707 name: "good policy", 708 t: TideContextPolicy{ 709 OptionalContexts: []string{"o1"}, 710 RequiredContexts: []string{"r1"}, 711 }, 712 }, 713 { 714 name: "optional contexts must differ from required contexts", 715 t: TideContextPolicy{ 716 OptionalContexts: []string{"c1"}, 717 RequiredContexts: []string{"c1"}, 718 }, 719 failed: true, 720 }, 721 { 722 name: "individual contexts cannot be both optional and required", 723 t: TideContextPolicy{ 724 OptionalContexts: []string{"c1", "c2", "c3", "c4"}, 725 RequiredContexts: []string{"c1", "c4"}, 726 }, 727 failed: true, 728 }, 729 } 730 for _, tc := range testCases { 731 err := tc.t.Validate() 732 failed := err != nil 733 if failed != tc.failed { 734 t.Errorf("%s - expected %v got %v", tc.name, tc.failed, err) 735 } 736 } 737 } 738 739 func TestTideContextPolicy_IsOptional(t *testing.T) { 740 testCases := []struct { 741 name string 742 skipUnknownContexts bool 743 required, optional []string 744 contexts []string 745 results []bool 746 }{ 747 { 748 name: "only optional contexts registered - skipUnknownContexts false", 749 contexts: []string{"c1", "o1", "o2"}, 750 optional: []string{"o1", "o2"}, 751 results: []bool{false, true, true}, 752 }, 753 { 754 name: "no contexts registered - skipUnknownContexts false", 755 contexts: []string{"t2"}, 756 results: []bool{false}, 757 }, 758 { 759 name: "only required contexts registered - skipUnknownContexts false", 760 required: []string{"c1", "c2", "c3"}, 761 contexts: []string{"c1", "c2", "c3", "t1"}, 762 results: []bool{false, false, false, false}, 763 }, 764 { 765 name: "optional and required contexts registered - skipUnknownContexts false", 766 optional: []string{"o1", "o2"}, 767 required: []string{"c1", "c2", "c3"}, 768 contexts: []string{"o1", "o2", "c1", "c2", "c3", "t1"}, 769 results: []bool{true, true, false, false, false, false}, 770 }, 771 { 772 name: "only optional contexts registered - skipUnknownContexts true", 773 contexts: []string{"c1", "o1", "o2"}, 774 optional: []string{"o1", "o2"}, 775 skipUnknownContexts: true, 776 results: []bool{true, true, true}, 777 }, 778 { 779 name: "no contexts registered - skipUnknownContexts true", 780 contexts: []string{"t2"}, 781 skipUnknownContexts: true, 782 results: []bool{true}, 783 }, 784 { 785 name: "only required contexts registered - skipUnknownContexts true", 786 required: []string{"c1", "c2", "c3"}, 787 contexts: []string{"c1", "c2", "c3", "t1"}, 788 skipUnknownContexts: true, 789 results: []bool{false, false, false, true}, 790 }, 791 { 792 name: "optional and required contexts registered - skipUnknownContexts true", 793 optional: []string{"o1", "o2"}, 794 required: []string{"c1", "c2", "c3"}, 795 contexts: []string{"o1", "o2", "c1", "c2", "c3", "t1"}, 796 skipUnknownContexts: true, 797 results: []bool{true, true, false, false, false, true}, 798 }, 799 } 800 801 for _, tc := range testCases { 802 cp := TideContextPolicy{ 803 SkipUnknownContexts: &tc.skipUnknownContexts, 804 RequiredContexts: tc.required, 805 OptionalContexts: tc.optional, 806 } 807 for i, c := range tc.contexts { 808 if cp.IsOptional(c) != tc.results[i] { 809 t.Errorf("%s - IsOptional for %s should return %t", tc.name, c, tc.results[i]) 810 } 811 } 812 } 813 } 814 815 func TestTideContextPolicy_MissingRequiredContexts(t *testing.T) { 816 testCases := []struct { 817 name string 818 skipUnknownContexts bool 819 required, optional []string 820 existingContexts, expectedContexts []string 821 }{ 822 { 823 name: "no contexts registered", 824 existingContexts: []string{"c1", "c2"}, 825 }, 826 { 827 name: "optional contexts registered / no missing contexts", 828 optional: []string{"o1", "o2", "o3"}, 829 existingContexts: []string{"c1", "c2"}, 830 }, 831 { 832 name: "required contexts registered / missing contexts", 833 required: []string{"c1", "c2", "c3"}, 834 existingContexts: []string{"c1", "c2"}, 835 expectedContexts: []string{"c3"}, 836 }, 837 { 838 name: "required contexts registered / no missing contexts", 839 required: []string{"c1", "c2", "c3"}, 840 existingContexts: []string{"c1", "c2", "c3"}, 841 }, 842 { 843 name: "optional and required contexts registered / missing contexts", 844 optional: []string{"o1", "o2", "o3"}, 845 required: []string{"c1", "c2", "c3"}, 846 existingContexts: []string{"c1", "c2"}, 847 expectedContexts: []string{"c3"}, 848 }, 849 { 850 name: "optional and required contexts registered / no missing contexts", 851 optional: []string{"o1", "o2", "o3"}, 852 required: []string{"c1", "c2"}, 853 existingContexts: []string{"c1", "c2", "c4"}, 854 }, 855 } 856 857 for _, tc := range testCases { 858 cp := TideContextPolicy{ 859 SkipUnknownContexts: &tc.skipUnknownContexts, 860 RequiredContexts: tc.required, 861 OptionalContexts: tc.optional, 862 } 863 missingContexts := cp.MissingRequiredContexts(tc.existingContexts) 864 if !sets.NewString(missingContexts...).Equal(sets.NewString(tc.expectedContexts...)) { 865 t.Errorf("%s - expected %v got %v", tc.name, tc.expectedContexts, missingContexts) 866 } 867 } 868 }