github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/plugins/approve/approvers/approvers_test.go (about) 1 /* 2 Copyright 2016 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 approvers 18 19 import ( 20 "testing" 21 22 "github.com/sirupsen/logrus" 23 24 "reflect" 25 26 "k8s.io/apimachinery/pkg/util/sets" 27 ) 28 29 func TestUnapprovedFiles(t *testing.T) { 30 rootApprovers := sets.NewString("Alice", "Bob") 31 aApprovers := sets.NewString("Art", "Anne") 32 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 33 cApprovers := sets.NewString("Chris", "Carol") 34 dApprovers := sets.NewString("David", "Dan", "Debbie") 35 eApprovers := sets.NewString("Eve", "Erin") 36 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 37 FakeRepoMap := map[string]sets.String{ 38 "": rootApprovers, 39 "a": aApprovers, 40 "b": bApprovers, 41 "c": cApprovers, 42 "a/d": dApprovers, 43 "a/combo": edcApprovers, 44 } 45 tests := []struct { 46 testName string 47 filenames []string 48 currentlyApproved sets.String 49 expectedUnapproved sets.String 50 }{ 51 { 52 testName: "Empty PR", 53 filenames: []string{}, 54 currentlyApproved: sets.NewString(), 55 expectedUnapproved: sets.NewString(), 56 }, 57 { 58 testName: "Single Root File PR Approved", 59 filenames: []string{"kubernetes.go"}, 60 currentlyApproved: sets.NewString(rootApprovers.List()[0]), 61 expectedUnapproved: sets.NewString(), 62 }, 63 { 64 testName: "Single Root File PR No One Approved", 65 filenames: []string{"kubernetes.go"}, 66 currentlyApproved: sets.NewString(), 67 expectedUnapproved: sets.NewString(""), 68 }, 69 { 70 testName: "B Only UnApproved", 71 currentlyApproved: bApprovers, 72 expectedUnapproved: sets.NewString(), 73 }, 74 { 75 testName: "B Files Approved at Root", 76 filenames: []string{"b/test.go", "b/test_1.go"}, 77 currentlyApproved: rootApprovers, 78 expectedUnapproved: sets.NewString(), 79 }, 80 { 81 testName: "B Only UnApproved", 82 filenames: []string{"b/test_1.go", "b/test.go"}, 83 currentlyApproved: sets.NewString(), 84 expectedUnapproved: sets.NewString("b"), 85 }, 86 { 87 testName: "Combo and Other; Neither Approved", 88 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 89 currentlyApproved: sets.NewString(), 90 expectedUnapproved: sets.NewString("a/combo", "a/d"), 91 }, 92 { 93 testName: "Combo and Other; Combo Approved", 94 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 95 currentlyApproved: edcApprovers.Difference(dApprovers), 96 expectedUnapproved: sets.NewString("a/d"), 97 }, 98 { 99 testName: "Combo and Other; Both Approved", 100 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 101 currentlyApproved: edcApprovers.Intersection(dApprovers), 102 expectedUnapproved: sets.NewString(), 103 }, 104 } 105 106 for _, test := range tests { 107 testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TestSeed, log: logrus.WithField("plugin", "some_plugin")}) 108 testApprovers.RequireIssue = false 109 for approver := range test.currentlyApproved { 110 testApprovers.AddApprover(approver, "REFERENCE", false) 111 } 112 calculated := testApprovers.UnapprovedFiles() 113 if !test.expectedUnapproved.Equal(calculated) { 114 t.Errorf("Failed for test %v. Expected unapproved files: %v. Found %v", test.testName, test.expectedUnapproved, calculated) 115 } 116 } 117 } 118 119 func TestGetFiles(t *testing.T) { 120 rootApprovers := sets.NewString("Alice", "Bob") 121 aApprovers := sets.NewString("Art", "Anne") 122 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 123 cApprovers := sets.NewString("Chris", "Carol") 124 dApprovers := sets.NewString("David", "Dan", "Debbie") 125 eApprovers := sets.NewString("Eve", "Erin") 126 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 127 FakeRepoMap := map[string]sets.String{ 128 "": rootApprovers, 129 "a": aApprovers, 130 "b": bApprovers, 131 "c": cApprovers, 132 "a/d": dApprovers, 133 "a/combo": edcApprovers, 134 } 135 tests := []struct { 136 testName string 137 filenames []string 138 currentlyApproved sets.String 139 expectedFiles []File 140 }{ 141 { 142 testName: "Empty PR", 143 filenames: []string{}, 144 currentlyApproved: sets.NewString(), 145 expectedFiles: []File{}, 146 }, 147 { 148 testName: "Single Root File PR Approved", 149 filenames: []string{"kubernetes.go"}, 150 currentlyApproved: sets.NewString(rootApprovers.List()[0]), 151 expectedFiles: []File{ApprovedFile{"", sets.NewString(rootApprovers.List()[0]), "org", "project", "master"}}, 152 }, 153 { 154 testName: "Single File PR in B No One Approved", 155 filenames: []string{"b/test.go"}, 156 currentlyApproved: sets.NewString(), 157 expectedFiles: []File{UnapprovedFile{"b", "org", "project", "master"}}, 158 }, 159 { 160 testName: "Single File PR in B Fully Approved", 161 filenames: []string{"b/test.go"}, 162 currentlyApproved: bApprovers, 163 expectedFiles: []File{ApprovedFile{"b", bApprovers, "org", "project", "master"}}, 164 }, 165 { 166 testName: "Single Root File PR No One Approved", 167 filenames: []string{"kubernetes.go"}, 168 currentlyApproved: sets.NewString(), 169 expectedFiles: []File{UnapprovedFile{"", "org", "project", "master"}}, 170 }, 171 { 172 testName: "Combo and Other; Neither Approved", 173 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 174 currentlyApproved: sets.NewString(), 175 expectedFiles: []File{ 176 UnapprovedFile{"a/combo", "org", "project", "master"}, 177 UnapprovedFile{"a/d", "org", "project", "master"}, 178 }, 179 }, 180 { 181 testName: "Combo and Other; Combo Approved", 182 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 183 currentlyApproved: eApprovers, 184 expectedFiles: []File{ 185 ApprovedFile{"a/combo", eApprovers, "org", "project", "master"}, 186 UnapprovedFile{"a/d", "org", "project", "master"}, 187 }, 188 }, 189 { 190 testName: "Combo and Other; Both Approved", 191 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 192 currentlyApproved: edcApprovers.Intersection(dApprovers), 193 expectedFiles: []File{ 194 ApprovedFile{"a/combo", edcApprovers.Intersection(dApprovers), "org", "project", "master"}, 195 ApprovedFile{"a/d", edcApprovers.Intersection(dApprovers), "org", "project", "master"}, 196 }, 197 }, 198 { 199 testName: "Combo, C, D; Combo and C Approved", 200 filenames: []string{"a/combo/test.go", "a/d/test.go", "c/test"}, 201 currentlyApproved: cApprovers, 202 expectedFiles: []File{ 203 ApprovedFile{"a/combo", cApprovers, "org", "project", "master"}, 204 UnapprovedFile{"a/d", "org", "project", "master"}, 205 ApprovedFile{"c", cApprovers, "org", "project", "master"}, 206 }, 207 }, 208 { 209 testName: "Files Approved Multiple times", 210 filenames: []string{"a/test.go", "a/d/test.go", "b/test"}, 211 currentlyApproved: rootApprovers.Union(aApprovers).Union(bApprovers), 212 expectedFiles: []File{ 213 ApprovedFile{"a", rootApprovers.Union(aApprovers), "org", "project", "master"}, 214 ApprovedFile{"b", rootApprovers.Union(bApprovers), "org", "project", "master"}, 215 }, 216 }, 217 } 218 219 for _, test := range tests { 220 testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TestSeed, log: logrus.WithField("plugin", "some_plugin")}) 221 testApprovers.RequireIssue = false 222 for approver := range test.currentlyApproved { 223 testApprovers.AddApprover(approver, "REFERENCE", false) 224 } 225 calculated := testApprovers.GetFiles("org", "project", "master") 226 if !reflect.DeepEqual(test.expectedFiles, calculated) { 227 t.Errorf("Failed for test %v. Expected files: %v. Found %v", test.testName, test.expectedFiles, calculated) 228 } 229 } 230 } 231 232 func TestGetCCs(t *testing.T) { 233 rootApprovers := sets.NewString("Alice", "Bob") 234 aApprovers := sets.NewString("Art", "Anne") 235 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 236 cApprovers := sets.NewString("Chris", "Carol") 237 dApprovers := sets.NewString("David", "Dan", "Debbie") 238 eApprovers := sets.NewString("Eve", "Erin") 239 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 240 FakeRepoMap := map[string]sets.String{ 241 "": rootApprovers, 242 "a": aApprovers, 243 "b": bApprovers, 244 "c": cApprovers, 245 "a/d": dApprovers, 246 "a/combo": edcApprovers, 247 } 248 tests := []struct { 249 testName string 250 filenames []string 251 currentlyApproved sets.String 252 // testSeed affects who is chosen for CC 253 testSeed int64 254 assignees []string 255 // order matters for CCs 256 expectedCCs []string 257 }{ 258 { 259 testName: "Empty PR", 260 filenames: []string{}, 261 currentlyApproved: sets.NewString(), 262 testSeed: 0, 263 expectedCCs: []string{}, 264 }, 265 { 266 testName: "Single Root FFile PR Approved", 267 filenames: []string{"kubernetes.go"}, 268 currentlyApproved: sets.NewString(rootApprovers.List()[0]), 269 testSeed: 13, 270 expectedCCs: []string{}, 271 }, 272 { 273 testName: "Single Root File PR Unapproved Seed = 13", 274 filenames: []string{"kubernetes.go"}, 275 currentlyApproved: sets.NewString(), 276 testSeed: 13, 277 expectedCCs: []string{"alice"}, 278 }, 279 { 280 testName: "Single Root File PR No One Seed = 10", 281 filenames: []string{"kubernetes.go"}, 282 testSeed: 10, 283 currentlyApproved: sets.NewString(), 284 expectedCCs: []string{"bob"}, 285 }, 286 { 287 testName: "Combo and Other; Neither Approved", 288 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 289 testSeed: 0, 290 currentlyApproved: sets.NewString(), 291 expectedCCs: []string{"dan"}, 292 }, 293 { 294 testName: "Combo and Other; Combo Approved", 295 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 296 testSeed: 0, 297 currentlyApproved: eApprovers, 298 expectedCCs: []string{"dan"}, 299 }, 300 { 301 testName: "Combo and Other; Both Approved", 302 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 303 testSeed: 0, 304 currentlyApproved: dApprovers, // dApprovers can approve combo and d directory 305 expectedCCs: []string{}, 306 }, 307 { 308 testName: "Combo, C, D; None Approved", 309 filenames: []string{"a/combo/test.go", "a/d/test.go", "c/test"}, 310 testSeed: 0, 311 currentlyApproved: sets.NewString(), 312 // chris can approve c and combo, debbie can approve d 313 expectedCCs: []string{"chris", "debbie"}, 314 }, 315 { 316 testName: "A, B, C; Nothing Approved", 317 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 318 testSeed: 0, 319 currentlyApproved: sets.NewString(), 320 // Need an approver from each of the three owners files 321 expectedCCs: []string{"anne", "bill", "carol"}, 322 }, 323 { 324 testName: "A, B, C; Partially approved by non-suggested approvers", 325 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 326 testSeed: 0, 327 // Approvers are valid approvers, but not the one we would suggest 328 currentlyApproved: sets.NewString("Art", "Ben"), 329 // We don't suggest approvers for a and b, only for unapproved c. 330 expectedCCs: []string{"carol"}, 331 }, 332 { 333 testName: "A, B, C; Nothing approved, but assignees can approve", 334 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 335 testSeed: 0, 336 // Approvers are valid approvers, but not the one we would suggest 337 currentlyApproved: sets.NewString(), 338 assignees: []string{"Art", "Ben"}, 339 // We suggest assigned people rather than "suggested" people 340 // Suggested would be "Anne", "Bill", "Carol" if no one was assigned. 341 expectedCCs: []string{"art", "ben", "carol"}, 342 }, 343 { 344 testName: "A, B, C; Nothing approved, but SOME assignees can approve", 345 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 346 testSeed: 0, 347 currentlyApproved: sets.NewString(), 348 // Assignees are a mix of potential approvers and random people 349 assignees: []string{"Art", "Ben", "John", "Jack"}, 350 // We suggest assigned people rather than "suggested" people 351 expectedCCs: []string{"art", "ben", "carol"}, 352 }, 353 { 354 testName: "Assignee is top OWNER, No one has approved", 355 filenames: []string{"a/test.go"}, 356 testSeed: 0, 357 currentlyApproved: sets.NewString(), 358 // Assignee is a root approver 359 assignees: []string{"alice"}, 360 expectedCCs: []string{"alice"}, 361 }, 362 } 363 364 for _, test := range tests { 365 testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: test.testSeed, log: logrus.WithField("plugin", "some_plugin")}) 366 testApprovers.RequireIssue = false 367 for approver := range test.currentlyApproved { 368 testApprovers.AddApprover(approver, "REFERENCE", false) 369 } 370 testApprovers.AddAssignees(test.assignees...) 371 calculated := testApprovers.GetCCs() 372 if !reflect.DeepEqual(test.expectedCCs, calculated) { 373 t.Errorf("Failed for test %v. Expected CCs: %v. Found %v", test.testName, test.expectedCCs, calculated) 374 } 375 } 376 } 377 378 func TestIsApproved(t *testing.T) { 379 rootApprovers := sets.NewString("Alice", "Bob") 380 aApprovers := sets.NewString("Art", "Anne") 381 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 382 cApprovers := sets.NewString("Chris", "Carol") 383 dApprovers := sets.NewString("David", "Dan", "Debbie") 384 eApprovers := sets.NewString("Eve", "Erin") 385 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 386 FakeRepoMap := map[string]sets.String{ 387 "": rootApprovers, 388 "a": aApprovers, 389 "b": bApprovers, 390 "c": cApprovers, 391 "a/d": dApprovers, 392 "a/combo": edcApprovers, 393 } 394 tests := []struct { 395 testName string 396 filenames []string 397 currentlyApproved sets.String 398 testSeed int64 399 isApproved bool 400 }{ 401 { 402 testName: "Empty PR", 403 filenames: []string{}, 404 currentlyApproved: sets.NewString(), 405 testSeed: 0, 406 isApproved: true, 407 }, 408 { 409 testName: "Single Root File PR Approved", 410 filenames: []string{"kubernetes.go"}, 411 currentlyApproved: sets.NewString(rootApprovers.List()[0]), 412 testSeed: 3, 413 isApproved: true, 414 }, 415 { 416 testName: "Single Root File PR No One Approved", 417 filenames: []string{"kubernetes.go"}, 418 testSeed: 0, 419 currentlyApproved: sets.NewString(), 420 isApproved: false, 421 }, 422 { 423 testName: "Combo and Other; Neither Approved", 424 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 425 testSeed: 0, 426 currentlyApproved: sets.NewString(), 427 isApproved: false, 428 }, 429 { 430 testName: "Combo and Other; Both Approved", 431 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 432 testSeed: 0, 433 currentlyApproved: edcApprovers.Intersection(dApprovers), 434 isApproved: true, 435 }, 436 { 437 testName: "A, B, C; Nothing Approved", 438 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 439 testSeed: 0, 440 currentlyApproved: sets.NewString(), 441 isApproved: false, 442 }, 443 { 444 testName: "A, B, C; Partially Approved", 445 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 446 testSeed: 0, 447 currentlyApproved: aApprovers.Union(bApprovers), 448 isApproved: false, 449 }, 450 { 451 testName: "A, B, C; Approved At the Root", 452 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 453 testSeed: 0, 454 currentlyApproved: rootApprovers, 455 isApproved: true, 456 }, 457 { 458 testName: "A, B, C; Approved At the Leaves", 459 filenames: []string{"a/test.go", "b/test.go", "c/test"}, 460 testSeed: 0, 461 currentlyApproved: sets.NewString("Anne", "Ben", "Carol"), 462 isApproved: true, 463 }, 464 } 465 466 for _, test := range tests { 467 testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: test.testSeed, log: logrus.WithField("plugin", "some_plugin")}) 468 for approver := range test.currentlyApproved { 469 testApprovers.AddApprover(approver, "REFERENCE", false) 470 } 471 calculated := testApprovers.IsApproved() 472 if test.isApproved != calculated { 473 t.Errorf("Failed for test %v. Expected Approval Status: %v. Found %v", test.testName, test.isApproved, calculated) 474 } 475 } 476 } 477 478 func TestIsApprovedWithIssue(t *testing.T) { 479 aApprovers := sets.NewString("Author", "Anne", "Carl") 480 bApprovers := sets.NewString("Bill", "Carl") 481 FakeRepoMap := map[string]sets.String{"a": aApprovers, "b": bApprovers} 482 tests := []struct { 483 testName string 484 filenames []string 485 currentlyApproved map[string]bool 486 associatedIssue int 487 isApproved bool 488 }{ 489 { 490 testName: "Empty PR", 491 filenames: []string{}, 492 currentlyApproved: map[string]bool{}, 493 associatedIssue: 0, 494 isApproved: false, 495 }, 496 { 497 testName: "Single file missing issue", 498 filenames: []string{"a/file.go"}, 499 currentlyApproved: map[string]bool{"Carl": false}, 500 associatedIssue: 0, 501 isApproved: false, 502 }, 503 { 504 testName: "Single file no-issue", 505 filenames: []string{"a/file.go"}, 506 currentlyApproved: map[string]bool{"Carl": true}, 507 associatedIssue: 0, 508 isApproved: true, 509 }, 510 { 511 testName: "Single file with issue", 512 filenames: []string{"a/file.go"}, 513 currentlyApproved: map[string]bool{"Carl": false}, 514 associatedIssue: 100, 515 isApproved: true, 516 }, 517 { 518 testName: "Two files missing issue", 519 filenames: []string{"a/file.go", "b/file2.go"}, 520 currentlyApproved: map[string]bool{"Carl": false}, 521 associatedIssue: 0, 522 isApproved: false, 523 }, 524 { 525 testName: "Two files no-issue", 526 filenames: []string{"a/file.go", "b/file2.go"}, 527 currentlyApproved: map[string]bool{"Carl": true}, 528 associatedIssue: 0, 529 isApproved: true, 530 }, 531 { 532 testName: "Two files two no-issue two approvers", 533 filenames: []string{"a/file.go", "b/file2.go"}, 534 currentlyApproved: map[string]bool{"Anne": true, "Bill": true}, 535 associatedIssue: 0, 536 isApproved: true, 537 }, 538 { 539 testName: "Two files one no-issue two approvers", 540 filenames: []string{"a/file.go", "b/file2.go"}, 541 currentlyApproved: map[string]bool{"Anne": true, "Bill": false}, 542 associatedIssue: 0, 543 isApproved: true, 544 }, 545 { 546 testName: "Two files missing issue two approvers", 547 filenames: []string{"a/file.go", "b/file2.go"}, 548 currentlyApproved: map[string]bool{"Anne": false, "Bill": false}, 549 associatedIssue: 0, 550 isApproved: false, 551 }, 552 { 553 testName: "Self approval (implicit) missing issue", 554 filenames: []string{"a/file.go"}, 555 currentlyApproved: map[string]bool{}, 556 associatedIssue: 0, 557 isApproved: false, 558 }, 559 { 560 testName: "Self approval (implicit) with issue", 561 filenames: []string{"a/file.go"}, 562 currentlyApproved: map[string]bool{}, 563 associatedIssue: 10, 564 isApproved: true, 565 }, 566 { 567 testName: "Self approval (explicit) missing issue", 568 filenames: []string{"a/file.go"}, 569 currentlyApproved: map[string]bool{"Author": false}, 570 associatedIssue: 0, 571 isApproved: false, 572 }, 573 { 574 testName: "Self approval (explicit) no-issue", 575 filenames: []string{"a/file.go"}, 576 currentlyApproved: map[string]bool{"Author": true}, 577 associatedIssue: 0, 578 isApproved: true, 579 }, 580 { 581 testName: "Self approval (explicit) missing issue, two files", 582 filenames: []string{"a/file.go", "b/file2.go"}, 583 currentlyApproved: map[string]bool{"Author": false, "Bill": false}, 584 associatedIssue: 0, 585 isApproved: false, 586 }, 587 { 588 testName: "Self approval (explicit) no-issue from author, two files", 589 filenames: []string{"a/file.go", "b/file2.go"}, 590 currentlyApproved: map[string]bool{"Author": true, "Bill": false}, 591 associatedIssue: 0, 592 isApproved: true, 593 }, 594 { 595 testName: "Self approval (explicit) no-issue from friend, two files", 596 filenames: []string{"a/file.go", "b/file2.go"}, 597 currentlyApproved: map[string]bool{"Author": false, "Bill": true}, 598 associatedIssue: 0, 599 isApproved: true, 600 }, 601 } 602 603 for _, test := range tests { 604 testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: 0, log: logrus.WithField("plugin", "some_plugin")}) 605 testApprovers.RequireIssue = true 606 testApprovers.AssociatedIssue = test.associatedIssue 607 for approver, noissue := range test.currentlyApproved { 608 testApprovers.AddApprover(approver, "REFERENCE", noissue) 609 } 610 testApprovers.AddAuthorSelfApprover("Author", "REFERENCE", false) 611 calculated := testApprovers.IsApproved() 612 if test.isApproved != calculated { 613 t.Errorf("Failed for test %v. Expected Approval Status: %v. Found %v", test.testName, test.isApproved, calculated) 614 } 615 } 616 } 617 618 func TestGetFilesApprovers(t *testing.T) { 619 tests := []struct { 620 testName string 621 filenames []string 622 approvers []string 623 owners map[string]sets.String 624 expectedStatus map[string]sets.String 625 }{ 626 { 627 testName: "Empty PR", 628 filenames: []string{}, 629 approvers: []string{}, 630 owners: map[string]sets.String{}, 631 expectedStatus: map[string]sets.String{}, 632 }, 633 { 634 testName: "No approvers", 635 filenames: []string{"a/a", "c"}, 636 approvers: []string{}, 637 owners: map[string]sets.String{"": sets.NewString("RootOwner")}, 638 expectedStatus: map[string]sets.String{"": {}}, 639 }, 640 { 641 testName: "Approvers approves some", 642 filenames: []string{ 643 "a/a", 644 "c/c", 645 }, 646 approvers: []string{"CApprover"}, 647 owners: map[string]sets.String{ 648 "a": sets.NewString("AApprover"), 649 "c": sets.NewString("CApprover"), 650 }, 651 expectedStatus: map[string]sets.String{ 652 "a": {}, 653 "c": sets.NewString("CApprover"), 654 }, 655 }, 656 { 657 testName: "Multiple approvers", 658 filenames: []string{ 659 "a/a", 660 "c/c", 661 }, 662 approvers: []string{"RootApprover", "CApprover"}, 663 owners: map[string]sets.String{ 664 "": sets.NewString("RootApprover"), 665 "a": sets.NewString("AApprover"), 666 "c": sets.NewString("CApprover"), 667 }, 668 expectedStatus: map[string]sets.String{ 669 "a": sets.NewString("RootApprover"), 670 "c": sets.NewString("RootApprover", "CApprover"), 671 }, 672 }, 673 { 674 testName: "Case-insensitive approvers", 675 filenames: []string{"file"}, 676 approvers: []string{"RootApprover"}, 677 owners: map[string]sets.String{"": sets.NewString("rOOtaPProver")}, 678 expectedStatus: map[string]sets.String{"": sets.NewString("RootApprover")}, 679 }, 680 } 681 682 for _, test := range tests { 683 testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(test.owners), log: logrus.WithField("plugin", "some_plugin")}) 684 for _, approver := range test.approvers { 685 testApprovers.AddApprover(approver, "REFERENCE", false) 686 } 687 calculated := testApprovers.GetFilesApprovers() 688 if !reflect.DeepEqual(test.expectedStatus, calculated) { 689 t.Errorf("Failed for test %v. Expected approval status: %v. Found %v", test.testName, test.expectedStatus, calculated) 690 } 691 } 692 } 693 694 func TestGetMessage(t *testing.T) { 695 ap := NewApprovers( 696 Owners{ 697 filenames: []string{"a/a.go", "b/b.go"}, 698 repo: createFakeRepo(map[string]sets.String{ 699 "a": sets.NewString("Alice"), 700 "b": sets.NewString("Bill"), 701 }), 702 log: logrus.WithField("plugin", "some_plugin"), 703 }, 704 ) 705 ap.RequireIssue = true 706 ap.AddApprover("Bill", "REFERENCE", false) 707 708 want := `[APPROVALNOTIFIER] This PR is **NOT APPROVED** 709 710 This pull-request has been approved by: *<a href="REFERENCE" title="Approved">Bill</a>* 711 To fully approve this pull request, please assign additional approvers. 712 We suggest the following additional approver: **alice** 713 714 If they are not already assigned, you can assign the PR to them by writing ` + "`/assign @alice`" + ` in a comment when ready. 715 716 *No associated issue*. Update pull-request body to add a reference to an issue, or get approval with ` + "`/approve no-issue`" + ` 717 718 The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands). 719 720 The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process) 721 722 <details open> 723 Needs approval from an approver in each of these files: 724 725 - **[a/OWNERS](https://github.com/org/project/blob/dev/a/OWNERS)** 726 - ~~[b/OWNERS](https://github.com/org/project/blob/dev/b/OWNERS)~~ [Bill] 727 728 Approvers can indicate their approval by writing ` + "`/approve`" + ` in a comment 729 Approvers can cancel approval by writing ` + "`/approve cancel`" + ` in a comment 730 </details> 731 <!-- META={"approvers":["alice"]} -->` 732 if got := GetMessage(ap, "org", "project", "dev"); got == nil { 733 t.Error("GetMessage() failed") 734 } else if *got != want { 735 t.Errorf("GetMessage() = %+v, want = %+v", *got, want) 736 } 737 } 738 739 func TestGetMessageAllApproved(t *testing.T) { 740 ap := NewApprovers( 741 Owners{ 742 filenames: []string{"a/a.go", "b/b.go"}, 743 repo: createFakeRepo(map[string]sets.String{ 744 "a": sets.NewString("Alice"), 745 "b": sets.NewString("Bill"), 746 }), 747 log: logrus.WithField("plugin", "some_plugin"), 748 }, 749 ) 750 ap.RequireIssue = true 751 ap.AddApprover("Alice", "REFERENCE", false) 752 ap.AddLGTMer("Bill", "REFERENCE", false) 753 754 want := `[APPROVALNOTIFIER] This PR is **NOT APPROVED** 755 756 This pull-request has been approved by: *<a href="REFERENCE" title="Approved">Alice</a>*, *<a href="REFERENCE" title="LGTM">Bill</a>* 757 758 *No associated issue*. Update pull-request body to add a reference to an issue, or get approval with ` + "`/approve no-issue`" + ` 759 760 The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands). 761 762 The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process) 763 764 <details > 765 Needs approval from an approver in each of these files: 766 767 - ~~[a/OWNERS](https://github.com/org/project/blob/master/a/OWNERS)~~ [Alice] 768 - ~~[b/OWNERS](https://github.com/org/project/blob/master/b/OWNERS)~~ [Bill] 769 770 Approvers can indicate their approval by writing ` + "`/approve`" + ` in a comment 771 Approvers can cancel approval by writing ` + "`/approve cancel`" + ` in a comment 772 </details> 773 <!-- META={"approvers":[]} -->` 774 if got := GetMessage(ap, "org", "project", "master"); got == nil { 775 t.Error("GetMessage() failed") 776 } else if *got != want { 777 t.Errorf("GetMessage() = %+v, want = %+v", *got, want) 778 } 779 } 780 781 func TestGetMessageNoneApproved(t *testing.T) { 782 ap := NewApprovers( 783 Owners{ 784 filenames: []string{"a/a.go", "b/b.go"}, 785 repo: createFakeRepo(map[string]sets.String{ 786 "a": sets.NewString("Alice"), 787 "b": sets.NewString("Bill"), 788 }), 789 log: logrus.WithField("plugin", "some_plugin"), 790 }, 791 ) 792 ap.AddAuthorSelfApprover("John", "REFERENCE", false) 793 ap.RequireIssue = true 794 want := `[APPROVALNOTIFIER] This PR is **NOT APPROVED** 795 796 This pull-request has been approved by: *<a href="REFERENCE" title="Author self-approved">John</a>* 797 To fully approve this pull request, please assign additional approvers. 798 We suggest the following additional approvers: **alice**, **bill** 799 800 If they are not already assigned, you can assign the PR to them by writing ` + "`/assign @alice @bill`" + ` in a comment when ready. 801 802 *No associated issue*. Update pull-request body to add a reference to an issue, or get approval with ` + "`/approve no-issue`" + ` 803 804 The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands). 805 806 The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process) 807 808 <details open> 809 Needs approval from an approver in each of these files: 810 811 - **[a/OWNERS](https://github.com/org/project/blob/master/a/OWNERS)** 812 - **[b/OWNERS](https://github.com/org/project/blob/master/b/OWNERS)** 813 814 Approvers can indicate their approval by writing ` + "`/approve`" + ` in a comment 815 Approvers can cancel approval by writing ` + "`/approve cancel`" + ` in a comment 816 </details> 817 <!-- META={"approvers":["alice","bill"]} -->` 818 if got := GetMessage(ap, "org", "project", "master"); got == nil { 819 t.Error("GetMessage() failed") 820 } else if *got != want { 821 t.Errorf("GetMessage() = %+v, want = %+v", *got, want) 822 } 823 } 824 825 func TestGetMessageApprovedIssueAssociated(t *testing.T) { 826 ap := NewApprovers( 827 Owners{ 828 filenames: []string{"a/a.go", "b/b.go"}, 829 repo: createFakeRepo(map[string]sets.String{ 830 "a": sets.NewString("Alice"), 831 "b": sets.NewString("Bill"), 832 }), 833 log: logrus.WithField("plugin", "some_plugin"), 834 }, 835 ) 836 ap.RequireIssue = true 837 ap.AssociatedIssue = 12345 838 ap.AddAuthorSelfApprover("John", "REFERENCE", false) 839 ap.AddApprover("Bill", "REFERENCE", false) 840 ap.AddApprover("Alice", "REFERENCE", false) 841 842 want := `[APPROVALNOTIFIER] This PR is **APPROVED** 843 844 This pull-request has been approved by: *<a href="REFERENCE" title="Approved">Alice</a>*, *<a href="REFERENCE" title="Approved">Bill</a>*, *<a href="REFERENCE" title="Author self-approved">John</a>* 845 846 Associated issue: *#12345* 847 848 The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands). 849 850 The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process) 851 852 <details > 853 Needs approval from an approver in each of these files: 854 855 - ~~[a/OWNERS](https://github.com/org/project/blob/master/a/OWNERS)~~ [Alice] 856 - ~~[b/OWNERS](https://github.com/org/project/blob/master/b/OWNERS)~~ [Bill] 857 858 Approvers can indicate their approval by writing ` + "`/approve`" + ` in a comment 859 Approvers can cancel approval by writing ` + "`/approve cancel`" + ` in a comment 860 </details> 861 <!-- META={"approvers":[]} -->` 862 if got := GetMessage(ap, "org", "project", "master"); got == nil { 863 t.Error("GetMessage() failed") 864 } else if *got != want { 865 t.Errorf("GetMessage() = %+v, want = %+v", *got, want) 866 } 867 } 868 869 func TestGetMessageApprovedNoIssueByPassed(t *testing.T) { 870 ap := NewApprovers( 871 Owners{ 872 filenames: []string{"a/a.go", "b/b.md"}, 873 repo: createFakeRepo(map[string]sets.String{ 874 "a": sets.NewString("Alice"), 875 "b": sets.NewString("Bill"), 876 }), 877 log: logrus.WithField("plugin", "some_plugin"), 878 }, 879 ) 880 ap.RequireIssue = true 881 ap.AddAuthorSelfApprover("John", "REFERENCE", false) 882 ap.AddApprover("Bill", "REFERENCE", true) 883 ap.AddApprover("Alice", "REFERENCE", true) 884 885 want := `[APPROVALNOTIFIER] This PR is **APPROVED** 886 887 This pull-request has been approved by: *<a href="REFERENCE" title="Approved">Alice</a>*, *<a href="REFERENCE" title="Approved">Bill</a>*, *<a href="REFERENCE" title="Author self-approved">John</a>* 888 889 Associated issue requirement bypassed by: *<a href="REFERENCE" title="Approved">Alice</a>*, *<a href="REFERENCE" title="Approved">Bill</a>* 890 891 The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands). 892 893 The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process) 894 895 <details > 896 Needs approval from an approver in each of these files: 897 898 - ~~[a/OWNERS](https://github.com/org/project/blob/master/a/OWNERS)~~ [Alice] 899 - ~~[b/OWNERS](https://github.com/org/project/blob/master/b/OWNERS)~~ [Bill] 900 901 Approvers can indicate their approval by writing ` + "`/approve`" + ` in a comment 902 Approvers can cancel approval by writing ` + "`/approve cancel`" + ` in a comment 903 </details> 904 <!-- META={"approvers":[]} -->` 905 if got := GetMessage(ap, "org", "project", "master"); got == nil { 906 t.Error("GetMessage() failed") 907 } else if *got != want { 908 t.Errorf("GetMessage() = %+v, want = %+v", *got, want) 909 } 910 } 911 912 func TestGetMessageMDOwners(t *testing.T) { 913 ap := NewApprovers( 914 Owners{ 915 filenames: []string{"a/a.go", "b/README.md"}, 916 repo: createFakeRepo(map[string]sets.String{ 917 "a": sets.NewString("Alice"), 918 "b": sets.NewString("Bill"), 919 "b/README.md": sets.NewString("Doctor"), 920 }), 921 log: logrus.WithField("plugin", "some_plugin"), 922 }, 923 ) 924 ap.AddAuthorSelfApprover("John", "REFERENCE", false) 925 ap.RequireIssue = true 926 want := `[APPROVALNOTIFIER] This PR is **NOT APPROVED** 927 928 This pull-request has been approved by: *<a href="REFERENCE" title="Author self-approved">John</a>* 929 To fully approve this pull request, please assign additional approvers. 930 We suggest the following additional approvers: **alice**, **doctor** 931 932 If they are not already assigned, you can assign the PR to them by writing ` + "`/assign @alice @doctor`" + ` in a comment when ready. 933 934 *No associated issue*. Update pull-request body to add a reference to an issue, or get approval with ` + "`/approve no-issue`" + ` 935 936 The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands). 937 938 The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process) 939 940 <details open> 941 Needs approval from an approver in each of these files: 942 943 - **[a/OWNERS](https://github.com/org/project/blob/master/a/OWNERS)** 944 - **[b/README.md](https://github.com/org/project/blob/master/b/README.md)** 945 946 Approvers can indicate their approval by writing ` + "`/approve`" + ` in a comment 947 Approvers can cancel approval by writing ` + "`/approve cancel`" + ` in a comment 948 </details> 949 <!-- META={"approvers":["alice","doctor"]} -->` 950 if got := GetMessage(ap, "org", "project", "master"); got == nil { 951 t.Error("GetMessage() failed") 952 } else if *got != want { 953 t.Errorf("GetMessage() = %+v, want = %+v", *got, want) 954 } 955 }