github.com/abayer/test-infra@v0.0.5/prow/plugins/trigger/ic_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 trigger 18 19 import ( 20 "testing" 21 22 "github.com/sirupsen/logrus" 23 24 "k8s.io/test-infra/prow/config" 25 "k8s.io/test-infra/prow/github" 26 "k8s.io/test-infra/prow/github/fakegithub" 27 "k8s.io/test-infra/prow/kube" 28 ) 29 30 type fkc struct { 31 started []string 32 } 33 34 func (c *fkc) CreateProwJob(pj kube.ProwJob) (kube.ProwJob, error) { 35 c.started = append(c.started, pj.Spec.Context) 36 return pj, nil 37 } 38 39 func TestHandleIssueComment(t *testing.T) { 40 var testcases = []struct { 41 name string 42 43 Author string 44 PRAuthor string 45 Body string 46 State string 47 IsPR bool 48 Branch string 49 ShouldBuild bool 50 ShouldReport bool 51 HasOkToTest bool 52 IsOkToTest bool 53 StartsExactly string 54 Presubmits map[string][]config.Presubmit 55 IssueLabels []github.Label 56 }{ 57 { 58 name: "Not a PR.", 59 60 Author: "t", 61 Body: "/ok-to-test", 62 State: "open", 63 IsPR: false, 64 ShouldBuild: false, 65 }, 66 { 67 name: "Closed PR.", 68 69 Author: "t", 70 Body: "/ok-to-test", 71 State: "closed", 72 IsPR: true, 73 ShouldBuild: false, 74 }, 75 { 76 name: "Comment by a bot.", 77 78 Author: "k8s-bot", 79 Body: "/ok-to-test", 80 State: "open", 81 IsPR: true, 82 ShouldBuild: false, 83 }, 84 { 85 name: "Non-trusted member's ok to test.", 86 87 Author: "u", 88 Body: "/ok-to-test", 89 State: "open", 90 IsPR: true, 91 ShouldBuild: false, 92 }, 93 { 94 name: "accept /test from non-trusted member if PR author is trusted", 95 Author: "u", 96 PRAuthor: "t", 97 Body: "/test all", 98 State: "open", 99 IsPR: true, 100 ShouldBuild: true, 101 }, 102 { 103 name: "reject /test from non-trusted member when PR author is untrusted", 104 Author: "u", 105 PRAuthor: "u", 106 Body: "/test all", 107 State: "open", 108 IsPR: true, 109 ShouldBuild: false, 110 }, 111 { 112 name: `Non-trusted member after "/ok-to-test".`, 113 114 Author: "u", 115 Body: "/test all", 116 State: "open", 117 IsPR: true, 118 HasOkToTest: true, 119 ShouldBuild: true, 120 }, 121 { 122 name: "Trusted member's ok to test", 123 124 Author: "t", 125 Body: "looks great, thanks!\n/ok-to-test", 126 State: "open", 127 IsPR: true, 128 ShouldBuild: true, 129 }, 130 { 131 name: "Trusted member's ok to test, trailing space.", 132 133 Author: "t", 134 Body: "looks great, thanks!\n/ok-to-test \r", 135 State: "open", 136 IsPR: true, 137 ShouldBuild: true, 138 }, 139 { 140 name: "Trusted member's not ok to test.", 141 142 Author: "t", 143 Body: "not /ok-to-test", 144 State: "open", 145 IsPR: true, 146 ShouldBuild: false, 147 }, 148 { 149 name: "Trusted member's test this.", 150 151 Author: "t", 152 Body: "/test all", 153 State: "open", 154 IsPR: true, 155 ShouldBuild: true, 156 }, 157 { 158 name: "Wrong branch.", 159 160 Author: "t", 161 Body: "/test all", 162 State: "open", 163 IsPR: true, 164 Branch: "other", 165 ShouldBuild: false, 166 ShouldReport: true, 167 }, 168 { 169 name: "Retest with one running and one failed", 170 171 Author: "t", 172 Body: "/retest", 173 State: "open", 174 IsPR: true, 175 ShouldBuild: true, 176 StartsExactly: "pull-jib", 177 }, 178 { 179 name: "Retest with one running and one failed, trailing space.", 180 181 Author: "t", 182 Body: "/retest \r", 183 State: "open", 184 IsPR: true, 185 ShouldBuild: true, 186 StartsExactly: "pull-jib", 187 }, 188 { 189 name: "needs-ok-to-test label is removed when no presubmit runs by default", 190 191 Author: "t", 192 Body: "/ok-to-test", 193 State: "open", 194 IsPR: true, 195 IsOkToTest: true, 196 ShouldBuild: false, 197 Presubmits: map[string][]config.Presubmit{ 198 "org/repo": { 199 { 200 Name: "job", 201 AlwaysRun: false, 202 Context: "pull-job", 203 Trigger: `/test all`, 204 RerunCommand: `/test all`, 205 }, 206 { 207 Name: "jib", 208 AlwaysRun: false, 209 Context: "pull-jib", 210 Trigger: `/test jib`, 211 RerunCommand: `/test jib`, 212 }, 213 }, 214 }, 215 IssueLabels: []github.Label{{Name: "needs-ok-to-test"}}, 216 }, 217 { 218 name: "Wrong branch w/ SkipReport", 219 Author: "t", 220 Body: "/test all", 221 Branch: "other", 222 State: "open", 223 IsPR: true, 224 Presubmits: map[string][]config.Presubmit{ 225 "org/repo": { 226 { 227 Name: "job", 228 AlwaysRun: true, 229 SkipReport: true, 230 Context: "pull-job", 231 Trigger: `/test all`, 232 RerunCommand: `/test all`, 233 Brancher: config.Brancher{Branches: []string{"master"}}, 234 }, 235 }, 236 }, 237 }, 238 { 239 name: "Retest of run_if_changed job that hasn't run. Changes require job", 240 Author: "t", 241 Body: "/retest", 242 State: "open", 243 IsPR: true, 244 Presubmits: map[string][]config.Presubmit{ 245 "org/repo": { 246 { 247 Name: "jab", 248 RunIfChanged: "CHANGED", 249 SkipReport: true, 250 Context: "pull-jab", 251 Trigger: `/test all`, 252 RerunCommand: `/test all`, 253 }, 254 }, 255 }, 256 ShouldBuild: true, 257 StartsExactly: "pull-jab", 258 }, 259 { 260 name: "Retest of run_if_changed job that failed. Changes require job", 261 Author: "t", 262 Body: "/retest", 263 State: "open", 264 IsPR: true, 265 Presubmits: map[string][]config.Presubmit{ 266 "org/repo": { 267 { 268 Name: "jib", 269 RunIfChanged: "CHANGED", 270 Context: "pull-jib", 271 Trigger: `/test all`, 272 RerunCommand: `/test all`, 273 }, 274 }, 275 }, 276 ShouldBuild: true, 277 StartsExactly: "pull-jib", 278 }, 279 { 280 name: "/test of run_if_changed job that has passed", 281 Author: "t", 282 Body: "/test jub", 283 State: "open", 284 IsPR: true, 285 Presubmits: map[string][]config.Presubmit{ 286 "org/repo": { 287 { 288 Name: "jub", 289 RunIfChanged: "CHANGED", 290 Context: "pull-jub", 291 Trigger: `/test jub`, 292 RerunCommand: `/test jub`, 293 }, 294 }, 295 }, 296 ShouldBuild: true, 297 StartsExactly: "pull-jub", 298 }, 299 { 300 name: "Retest of run_if_changed job that failed. Changes do not require the job", 301 Author: "t", 302 Body: "/retest", 303 State: "open", 304 IsPR: true, 305 Presubmits: map[string][]config.Presubmit{ 306 "org/repo": { 307 { 308 Name: "jib", 309 RunIfChanged: "CHANGED2", 310 Context: "pull-jib", 311 Trigger: `/test all`, 312 RerunCommand: `/test all`, 313 }, 314 }, 315 }, 316 ShouldBuild: true, 317 }, 318 { 319 name: "Run if changed job triggered by /ok-to-test", 320 Author: "t", 321 Body: "/ok-to-test", 322 State: "open", 323 IsPR: true, 324 IsOkToTest: true, 325 Presubmits: map[string][]config.Presubmit{ 326 "org/repo": { 327 { 328 Name: "jab", 329 RunIfChanged: "CHANGED", 330 Context: "pull-jab", 331 Trigger: `/test all`, 332 RerunCommand: `/test all`, 333 }, 334 }, 335 }, 336 ShouldBuild: true, 337 StartsExactly: "pull-jab", 338 IssueLabels: []github.Label{{Name: "needs-ok-to-test"}}, 339 }, 340 { 341 name: "/test of branch-sharded job", 342 Author: "t", 343 Body: "/test jab", 344 State: "open", 345 IsPR: true, 346 Presubmits: map[string][]config.Presubmit{ 347 "org/repo": { 348 { 349 Name: "jab", 350 Brancher: config.Brancher{Branches: []string{"master"}}, 351 Context: "pull-jab", 352 Trigger: `/test jab`, 353 RerunCommand: `/test jab`, 354 }, 355 { 356 Name: "jab", 357 Brancher: config.Brancher{Branches: []string{"release"}}, 358 Context: "pull-jab", 359 Trigger: `/test jab`, 360 RerunCommand: `/test jab`, 361 }, 362 }, 363 }, 364 ShouldBuild: true, 365 StartsExactly: "pull-jab", 366 }, 367 { 368 name: "branch-sharded job. no shard matches base branch", 369 Author: "t", 370 Branch: "branch", 371 Body: "/test jab", 372 State: "open", 373 IsPR: true, 374 Presubmits: map[string][]config.Presubmit{ 375 "org/repo": { 376 { 377 Name: "jab", 378 Brancher: config.Brancher{Branches: []string{"master"}}, 379 Context: "pull-jab", 380 Trigger: `/test jab`, 381 RerunCommand: `/test jab`, 382 }, 383 { 384 Name: "jab", 385 Brancher: config.Brancher{Branches: []string{"release"}}, 386 Context: "pull-jab", 387 Trigger: `/test jab`, 388 RerunCommand: `/test jab`, 389 }, 390 }, 391 }, 392 ShouldReport: true, 393 }, 394 { 395 name: "/retest of RunIfChanged job that doesn't need to run and hasn't run", 396 397 Author: "t", 398 Body: "/retest", 399 State: "open", 400 IsPR: true, 401 Presubmits: map[string][]config.Presubmit{ 402 "org/repo": { 403 { 404 Name: "jeb", 405 RunIfChanged: "CHANGED2", 406 Context: "pull-jeb", 407 Trigger: `/test all`, 408 RerunCommand: `/test all`, 409 }, 410 }, 411 }, 412 ShouldReport: true, 413 }, 414 { 415 name: "explicit /test for RunIfChanged job that doesn't need to run", 416 417 Author: "t", 418 Body: "/test pull-jeb", 419 State: "open", 420 IsPR: true, 421 Presubmits: map[string][]config.Presubmit{ 422 "org/repo": { 423 { 424 Name: "jeb", 425 RunIfChanged: "CHANGED2", 426 Context: "pull-jib", 427 Trigger: `/test (all|pull-jeb)`, 428 RerunCommand: `/test pull-jeb`, 429 }, 430 }, 431 }, 432 ShouldBuild: true, 433 }, 434 { 435 name: "/test all of run_if_changed job that has passed and needs to run", 436 Author: "t", 437 Body: "/test all", 438 State: "open", 439 IsPR: true, 440 Presubmits: map[string][]config.Presubmit{ 441 "org/repo": { 442 { 443 Name: "jub", 444 RunIfChanged: "CHANGED", 445 Context: "pull-jub", 446 Trigger: `/test jub`, 447 RerunCommand: `/test jub`, 448 }, 449 }, 450 }, 451 ShouldBuild: true, 452 StartsExactly: "pull-jub", 453 }, 454 { 455 name: "/test all of run_if_changed job that has passed and doesnt need to run", 456 Author: "t", 457 Body: "/test all", 458 State: "open", 459 IsPR: true, 460 Presubmits: map[string][]config.Presubmit{ 461 "org/repo": { 462 { 463 Name: "jub", 464 RunIfChanged: "CHANGED2", 465 Context: "pull-jub", 466 Trigger: `/test jub`, 467 RerunCommand: `/test jub`, 468 }, 469 }, 470 }, 471 ShouldReport: true, 472 }, 473 } 474 for _, tc := range testcases { 475 t.Logf("running scenario %q", tc.name) 476 if tc.Branch == "" { 477 tc.Branch = "master" 478 } 479 g := &fakegithub.FakeClient{ 480 CreatedStatuses: map[string][]github.Status{}, 481 IssueComments: map[int][]github.IssueComment{}, 482 OrgMembers: map[string][]string{"org": {"t"}}, 483 PullRequests: map[int]*github.PullRequest{ 484 0: { 485 Number: 0, 486 Head: github.PullRequestBranch{ 487 SHA: "cafe", 488 }, 489 Base: github.PullRequestBranch{ 490 Ref: tc.Branch, 491 Repo: github.Repo{ 492 Owner: github.User{Login: "org"}, 493 Name: "repo", 494 }, 495 }, 496 }, 497 }, 498 PullRequestChanges: map[int][]github.PullRequestChange{0: {{Filename: "CHANGED"}}}, 499 CombinedStatuses: map[string]*github.CombinedStatus{ 500 "cafe": { 501 Statuses: []github.Status{ 502 {State: "pending", Context: "pull-job"}, 503 {State: "failure", Context: "pull-jib"}, 504 {State: "success", Context: "pull-jub"}, 505 }, 506 }, 507 }, 508 } 509 kc := &fkc{} 510 c := client{ 511 GitHubClient: g, 512 KubeClient: kc, 513 Config: &config.Config{}, 514 Logger: logrus.WithField("plugin", pluginName), 515 } 516 presubmits := tc.Presubmits 517 if presubmits == nil { 518 presubmits = map[string][]config.Presubmit{ 519 "org/repo": { 520 { 521 Name: "job", 522 AlwaysRun: true, 523 Context: "pull-job", 524 Trigger: `/test all`, 525 RerunCommand: `/test all`, 526 Brancher: config.Brancher{Branches: []string{"master"}}, 527 }, 528 { 529 Name: "jib", 530 AlwaysRun: false, 531 Context: "pull-jib", 532 Trigger: `/test jib`, 533 RerunCommand: `/test jib`, 534 }, 535 }, 536 } 537 } 538 if err := c.Config.SetPresubmits(presubmits); err != nil { 539 t.Fatalf("failed to set presubmits: %v", err) 540 } 541 542 var pr *struct{} 543 if tc.IsPR { 544 pr = &struct{}{} 545 } 546 if tc.HasOkToTest { 547 g.IssueComments[0] = []github.IssueComment{{ 548 Body: "/ok-to-test", 549 User: github.User{Login: "t"}, 550 }} 551 } 552 event := github.IssueCommentEvent{ 553 Action: github.IssueCommentActionCreated, 554 Repo: github.Repo{ 555 Owner: github.User{Login: "org"}, 556 Name: "repo", 557 FullName: "org/repo", 558 }, 559 Comment: github.IssueComment{ 560 Body: tc.Body, 561 User: github.User{Login: tc.Author}, 562 }, 563 Issue: github.Issue{ 564 User: github.User{Login: tc.PRAuthor}, 565 PullRequest: pr, 566 State: tc.State, 567 }, 568 } 569 if len(tc.IssueLabels) > 0 { 570 event.Issue.Labels = tc.IssueLabels 571 } 572 573 if err := handleIC(c, nil, event); err != nil { 574 t.Fatalf("Didn't expect error: %s", err) 575 } 576 if len(kc.started) > 0 && !tc.ShouldBuild { 577 t.Errorf("Built but should not have: %+v", tc) 578 } else if len(kc.started) == 0 && tc.ShouldBuild { 579 t.Errorf("Not built but should have: %+v", tc) 580 } 581 if tc.StartsExactly != "" && (len(kc.started) != 1 || kc.started[0] != tc.StartsExactly) { 582 t.Errorf("Didn't build expected context %v, instead built %v", tc.StartsExactly, kc.started) 583 } 584 if tc.ShouldReport && len(g.CreatedStatuses) == 0 { 585 t.Error("Expected report to github") 586 } else if !tc.ShouldReport && len(g.CreatedStatuses) > 0 { 587 t.Errorf("Expected no reports to github, but got %d", len(g.CreatedStatuses)) 588 } 589 if tc.IsOkToTest { 590 if len(g.LabelsRemoved) != 1 { 591 t.Errorf("expected a label to be removed") 592 continue 593 } 594 expected := "org/repo#0:needs-ok-to-test" 595 if g.LabelsRemoved[0] != expected { 596 t.Errorf("expected %q to be removed, got %q", expected, g.LabelsRemoved[0]) 597 } 598 } 599 } 600 }