github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/dashboard/app/jobs_test.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package main 5 6 import ( 7 "bytes" 8 "fmt" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/google/syzkaller/dashboard/dashapi" 14 "github.com/google/syzkaller/pkg/email" 15 "github.com/stretchr/testify/assert" 16 db "google.golang.org/appengine/v2/datastore" 17 ) 18 19 const sampleGitPatch = `--- a/mm/kasan/kasan.c 20 +++ b/mm/kasan/kasan.c 21 - current->kasan_depth++; 22 + current->kasan_depth--; 23 ` 24 25 const syzTestGitBranchSamplePatch = "#syz test: git://git.git/git.git kernel-branch\n" + sampleGitPatch 26 27 // nolint: funlen 28 func TestJob(t *testing.T) { 29 c := NewCtx(t) 30 defer c.Close() 31 32 client := c.publicClient 33 build := testBuild(1) 34 client.UploadBuild(build) 35 36 // Report crash without repro, check that test requests are not accepted. 37 crash := testCrash(build, 1) 38 crash.Maintainers = []string{"maintainer@kernel.org"} 39 client.ReportCrash(crash) 40 41 sender := c.pollEmailBug().Sender 42 c.incomingEmail(sender, "#syz upstream\n") 43 sender = c.pollEmailBug().Sender 44 _, extBugID, err := email.RemoveAddrContext(sender) 45 c.expectOK(err) 46 mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email 47 c.incomingEmail(sender, "bla-bla-bla", EmailOptFrom("maintainer@kernel.org"), 48 EmailOptCC([]string{mailingList, "kernel@mailing.list"})) 49 50 c.incomingEmail(sender, syzTestGitBranchSamplePatch, 51 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 52 body := c.pollEmailBug().Body 53 t.Logf("body: %s", body) 54 c.expectEQ(strings.Contains(body, "This crash does not have a reproducer"), true) 55 56 // Report crash with repro. 57 crash.ReproOpts = []byte("repro opts") 58 crash.ReproSyz = []byte("repro syz") 59 crash.ReproC = []byte("repro C") 60 client.ReportCrash(crash) 61 client.pollAndFailBisectJob(build.Manager) 62 63 body = c.pollEmailBug().Body 64 c.expectEQ(strings.Contains(body, "syzbot has found a reproducer"), true) 65 66 c.incomingEmail(sender, "#syz test: repo", 67 EmailOptFrom("test@requester.com"), EmailOptSubject("my-subject"), EmailOptCC([]string{mailingList})) 68 msg := c.pollEmailBug() 69 c.expectEQ(strings.Contains(msg.Body, "want either no args or 2 args"), true) 70 c.expectEQ(msg.Subject, "Re: my-subject") 71 72 c.incomingEmail(sender, "#syz test: repo branch commit", 73 EmailOptFrom("test@requester.com"), EmailOptSubject("Re: my-subject"), EmailOptCC([]string{mailingList})) 74 msg = c.pollEmailBug() 75 c.expectEQ(strings.Contains(msg.Body, "want either no args or 2 args"), true) 76 c.expectEQ(msg.Subject, "Re: my-subject") 77 78 c.incomingEmail(sender, "#syz test: repo branch", 79 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 80 body = c.pollEmailBug().Body 81 c.expectEQ(strings.Contains(body, "does not look like a valid git repo"), true) 82 83 c.incomingEmail(sender, syzTestGitBranchSamplePatch, 84 EmailOptFrom("\"foo\" <blOcKed@dOmain.COM>")) 85 c.expectNoEmail() 86 pollResp := client.pollJobs(build.Manager) 87 c.expectEQ(pollResp.ID, "") 88 89 // This submits actual test request. 90 c.incomingEmail(sender, syzTestGitBranchSamplePatch, 91 EmailOptMessageID(1), EmailOptFrom("test@requester.com"), 92 EmailOptCC([]string{"somebody@else.com", "test@syzkaller.com"})) 93 c.expectNoEmail() 94 95 // A dup of the same request with the same Message-ID. 96 c.incomingEmail(sender, syzTestGitBranchSamplePatch, 97 EmailOptMessageID(1), EmailOptFrom("test@requester.com"), 98 EmailOptCC([]string{"somebody@else.com", "test@syzkaller.com"})) 99 c.expectNoEmail() 100 101 pollResp = client.pollJobs("foobar") 102 c.expectEQ(pollResp.ID, "") 103 pollResp = client.pollJobs(build.Manager) 104 c.expectNE(pollResp.ID, "") 105 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 106 c.expectEQ(pollResp.Manager, build.Manager) 107 c.expectEQ(pollResp.KernelRepo, "git://git.git/git.git") 108 c.expectEQ(pollResp.KernelBranch, "kernel-branch") 109 c.expectEQ(pollResp.KernelConfig, build.KernelConfig) 110 c.expectEQ(pollResp.SyzkallerCommit, build.SyzkallerCommit) 111 c.expectEQ(pollResp.Patch, []byte(sampleGitPatch)) 112 c.expectEQ(pollResp.ReproOpts, []byte("repro opts")) 113 c.expectEQ(pollResp.ReproSyz, []byte( 114 "# See https://goo.gl/kgGztJ for information about syzkaller reproducers.\n"+ 115 "#repro opts\n"+ 116 "repro syz")) 117 c.expectEQ(pollResp.ReproC, []byte("repro C")) 118 119 jobDoneReq := &dashapi.JobDoneReq{ 120 ID: pollResp.ID, 121 Build: *build, 122 CrashTitle: "test crash title", 123 CrashLog: []byte("test crash log"), 124 CrashReport: []byte("test crash report"), 125 } 126 client.JobDone(jobDoneReq) 127 128 { 129 dbJob, dbBuild, _ := c.loadJob(pollResp.ID) 130 patchLink := externalLink(c.ctx, textPatch, dbJob.Patch) 131 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 132 logLink := externalLink(c.ctx, textCrashLog, dbJob.CrashLog) 133 msg := c.pollEmailBug() 134 to := email.MergeEmailLists([]string{"test@requester.com", "somebody@else.com", mailingList}) 135 c.expectEQ(msg.To, to) 136 c.expectEQ(msg.Subject, "Re: [syzbot] "+crash.Title) 137 c.expectEQ(len(msg.Attachments), 0) 138 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 139 140 syzbot has tested the proposed patch but the reproducer is still triggering an issue: 141 test crash title 142 143 test crash report 144 145 Tested on: 146 147 commit: 11111111 kernel_commit_title1 148 git tree: repo1 branch1 149 console output: %[3]v 150 kernel config: %[2]v 151 dashboard link: https://testapp.appspot.com/bug?extid=%[4]v 152 compiler: compiler1 153 patch: %[1]v 154 155 `, patchLink, kernelConfigLink, logLink, extBugID)) 156 c.checkURLContents(patchLink, []byte(sampleGitPatch)) 157 c.checkURLContents(kernelConfigLink, build.KernelConfig) 158 c.checkURLContents(logLink, jobDoneReq.CrashLog) 159 } 160 161 // Testing fails with an error. 162 c.incomingEmail(sender, syzTestGitBranchSamplePatch, EmailOptMessageID(2)) 163 pollResp = client.pollJobs(build.Manager) 164 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 165 jobDoneReq = &dashapi.JobDoneReq{ 166 ID: pollResp.ID, 167 Build: *build, 168 Error: []byte("failed to apply patch"), 169 } 170 client.JobDone(jobDoneReq) 171 { 172 dbJob, dbBuild, _ := c.loadJob(pollResp.ID) 173 patchLink := externalLink(c.ctx, textPatch, dbJob.Patch) 174 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 175 msg := c.pollEmailBug() 176 c.expectEQ(len(msg.Attachments), 0) 177 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 178 179 syzbot tried to test the proposed patch but the build/boot failed: 180 181 failed to apply patch 182 183 184 Tested on: 185 186 commit: 11111111 kernel_commit_title1 187 git tree: repo1 branch1 188 kernel config: %[2]v 189 dashboard link: https://testapp.appspot.com/bug?extid=%[3]v 190 compiler: compiler1 191 patch: %[1]v 192 193 `, patchLink, kernelConfigLink, extBugID)) 194 c.checkURLContents(patchLink, []byte(sampleGitPatch)) 195 c.checkURLContents(kernelConfigLink, build.KernelConfig) 196 } 197 198 // Testing fails with a huge error that can't be inlined in email. 199 c.incomingEmail(sender, syzTestGitBranchSamplePatch, EmailOptMessageID(3)) 200 pollResp = client.pollJobs(build.Manager) 201 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 202 jobDoneReq = &dashapi.JobDoneReq{ 203 ID: pollResp.ID, 204 Build: *build, 205 Error: bytes.Repeat([]byte{'a', 'b', 'c'}, (maxInlineError+100)/3), 206 } 207 client.JobDone(jobDoneReq) 208 { 209 dbJob, dbBuild, _ := c.loadJob(pollResp.ID) 210 patchLink := externalLink(c.ctx, textPatch, dbJob.Patch) 211 errorLink := externalLink(c.ctx, textError, dbJob.Error) 212 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 213 msg := c.pollEmailBug() 214 c.expectEQ(len(msg.Attachments), 0) 215 truncatedError := string(jobDoneReq.Error[len(jobDoneReq.Error)-maxInlineError:]) 216 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 217 218 syzbot tried to test the proposed patch but the build/boot failed: 219 220 %[1]v 221 222 Error text is too large and was truncated, full error text is at: 223 %[2]v 224 225 226 Tested on: 227 228 commit: 11111111 kernel_commit_title1 229 git tree: repo1 branch1 230 kernel config: %[4]v 231 dashboard link: https://testapp.appspot.com/bug?extid=%[5]v 232 compiler: compiler1 233 patch: %[3]v 234 235 `, truncatedError, errorLink, patchLink, kernelConfigLink, extBugID)) 236 c.checkURLContents(patchLink, []byte(sampleGitPatch)) 237 c.checkURLContents(errorLink, jobDoneReq.Error) 238 c.checkURLContents(kernelConfigLink, build.KernelConfig) 239 } 240 241 c.incomingEmail(sender, syzTestGitBranchSamplePatch, EmailOptMessageID(4)) 242 pollResp = client.pollJobs(build.Manager) 243 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 244 jobDoneReq = &dashapi.JobDoneReq{ 245 ID: pollResp.ID, 246 Build: *build, 247 CrashLog: []byte("console output"), 248 } 249 client.JobDone(jobDoneReq) 250 { 251 dbJob, dbBuild, _ := c.loadJob(pollResp.ID) 252 patchLink := externalLink(c.ctx, textPatch, dbJob.Patch) 253 logLink := externalLink(c.ctx, textCrashLog, dbJob.CrashLog) 254 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 255 msg := c.pollEmailBug() 256 c.expectEQ(len(msg.Attachments), 0) 257 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 258 259 syzbot has tested the proposed patch and the reproducer did not trigger any issue: 260 261 Reported-and-tested-by: syzbot+%v@testapp.appspotmail.com 262 263 Tested on: 264 265 commit: 11111111 kernel_commit_title1 266 git tree: repo1 branch1 267 console output: %[4]v 268 kernel config: %[3]v 269 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 270 compiler: compiler1 271 patch: %[2]v 272 273 Note: testing is done by a robot and is best-effort only. 274 `, extBugID, patchLink, kernelConfigLink, logLink)) 275 c.checkURLContents(patchLink, []byte(sampleGitPatch)) 276 c.checkURLContents(kernelConfigLink, build.KernelConfig) 277 } 278 279 pollResp = client.pollJobs(build.Manager) 280 c.expectEQ(pollResp.ID, "") 281 } 282 283 // Test whether we can test boot time crashes. 284 func TestBootErrorPatch(t *testing.T) { 285 c := NewCtx(t) 286 defer c.Close() 287 288 build := testBuild(1) 289 c.client2.UploadBuild(build) 290 291 crash := testCrash(build, 2) 292 crash.Title = "riscv/fixes boot error: can't ssh into the instance" 293 c.client2.ReportCrash(crash) 294 295 report := c.pollEmailBug() 296 c.incomingEmail(report.Sender, "#syz upstream\n", EmailOptCC(report.To)) 297 report = c.pollEmailBug() 298 299 c.incomingEmail(report.Sender, syzTestGitBranchSamplePatch, 300 EmailOptFrom("test@requester.com"), EmailOptCC(report.To)) 301 c.expectNoEmail() 302 pollResp := c.client2.pollJobs(build.Manager) 303 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 304 } 305 306 const testErrorTitle = `upstream test error: WARNING in __queue_work` 307 308 func TestTestErrorPatch(t *testing.T) { 309 c := NewCtx(t) 310 defer c.Close() 311 312 build := testBuild(1) 313 c.client2.UploadBuild(build) 314 315 crash := testCrash(build, 2) 316 crash.Title = testErrorTitle 317 c.client2.ReportCrash(crash) 318 319 sender := c.pollEmailBug().Sender 320 c.incomingEmail(sender, "#syz upstream\n") 321 report := c.pollEmailBug() 322 323 c.incomingEmail(report.Sender, syzTestGitBranchSamplePatch, 324 EmailOptFrom("test@requester.com"), EmailOptCC(report.To)) 325 c.expectNoEmail() 326 pollResp := c.client2.pollJobs(build.Manager) 327 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 328 } 329 330 // Test on particular commit and without a patch. 331 func TestJobWithoutPatch(t *testing.T) { 332 c := NewCtx(t) 333 defer c.Close() 334 335 client := c.publicClient 336 337 build := testBuild(1) 338 client.UploadBuild(build) 339 340 crash := testCrash(build, 1) 341 crash.ReproOpts = []byte("repro opts") 342 crash.ReproSyz = []byte("repro syz") 343 client.ReportCrash(crash) 344 client.pollAndFailBisectJob(build.Manager) 345 sender := c.pollEmailBug().Sender 346 _, extBugID, err := email.RemoveAddrContext(sender) 347 c.expectOK(err) 348 349 // Patch testing should happen for bugs with fix commits too. 350 c.incomingEmail(sender, "#syz fix: some commit title\n") 351 352 c.incomingEmail(sender, "#syz test git://mygit.com/git.git 5e6a2eea\n", EmailOptMessageID(1)) 353 c.expectNoEmail() 354 pollResp := client.pollJobs(build.Manager) 355 c.expectNE(pollResp.ID, "") 356 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 357 testBuild := testBuild(2) 358 testBuild.KernelRepo = "git://mygit.com/git.git" 359 testBuild.KernelBranch = "" 360 testBuild.KernelCommit = "5e6a2eea5e6a2eea5e6a2eea5e6a2eea5e6a2eea" 361 jobDoneReq := &dashapi.JobDoneReq{ 362 ID: pollResp.ID, 363 Build: *testBuild, 364 } 365 client.JobDone(jobDoneReq) 366 { 367 _, dbBuild, _ := c.loadJob(pollResp.ID) 368 kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) 369 msg := c.pollEmailBug() 370 c.expectEQ(len(msg.Attachments), 0) 371 c.expectEQ(msg.Body, fmt.Sprintf(`Hello, 372 373 syzbot has tested the proposed patch and the reproducer did not trigger any issue: 374 375 Reported-and-tested-by: syzbot+%v@testapp.appspotmail.com 376 377 Tested on: 378 379 commit: 5e6a2eea kernel_commit_title2 380 git tree: git://mygit.com/git.git 381 kernel config: %[2]v 382 dashboard link: https://testapp.appspot.com/bug?extid=%[1]v 383 compiler: compiler2 384 385 Note: no patches were applied. 386 Note: testing is done by a robot and is best-effort only. 387 `, extBugID, kernelConfigLink)) 388 c.checkURLContents(kernelConfigLink, testBuild.KernelConfig) 389 } 390 391 pollResp = client.pollJobs(build.Manager) 392 c.expectEQ(pollResp.ID, "") 393 } 394 395 func TestReproRetestJob(t *testing.T) { 396 c := NewCtx(t) 397 defer c.Close() 398 399 client := c.publicClient 400 oldBuild := testBuild(1) 401 oldBuild.KernelRepo = "git://mygit.com/git.git" 402 oldBuild.KernelBranch = "main" 403 client.UploadBuild(oldBuild) 404 405 crash := testCrash(oldBuild, 1) 406 crash.ReproOpts = []byte("repro opts") 407 crash.ReproSyz = []byte("repro syz") 408 client.ReportCrash(crash) 409 sender := c.pollEmailBug().Sender 410 _, extBugID, err := email.RemoveAddrContext(sender) 411 c.expectOK(err) 412 413 crash2 := testCrash(oldBuild, 1) 414 crash2.ReproOpts = []byte("repro opts") 415 crash2.ReproSyz = []byte("repro syz") 416 crash2.ReproC = []byte("repro C") 417 client.ReportCrash(crash2) 418 c.pollEmailBug() 419 420 // Upload a newer build. 421 c.advanceTime(time.Minute) 422 build := testBuild(1) 423 build.ID = "new-build" 424 build.KernelRepo = "git://mygit.com/new-git.git" 425 build.KernelBranch = "new-main" 426 build.KernelConfig = []byte{0xAB, 0xCD, 0xEF} 427 client.UploadBuild(build) 428 429 c.advanceTime(time.Hour) 430 bug, _, _ := c.loadBug(extBugID) 431 c.expectEQ(bug.ReproLevel, ReproLevelC) 432 433 // Let's say that the C repro testing has failed. 434 c.advanceTime(c.config().Obsoleting.ReproRetestStart + time.Hour) 435 for i := 0; i < 2; i++ { 436 resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{TestPatches: true}) 437 c.expectEQ(resp.Type, dashapi.JobTestPatch) 438 c.expectEQ(resp.KernelRepo, build.KernelRepo) 439 c.expectEQ(resp.KernelBranch, build.KernelBranch) 440 c.expectEQ(resp.KernelConfig, build.KernelConfig) 441 c.expectEQ(resp.Patch, []uint8(nil)) 442 var done *dashapi.JobDoneReq 443 if resp.ReproC == nil { 444 // Pretend that the syz repro still works. 445 done = &dashapi.JobDoneReq{ 446 ID: resp.ID, 447 CrashTitle: crash.Title, 448 CrashLog: []byte("test crash log"), 449 CrashReport: []byte("test crash report"), 450 } 451 } else { 452 // Pretend that the C repro fails. 453 done = &dashapi.JobDoneReq{ 454 ID: resp.ID, 455 } 456 } 457 client.expectOK(client.JobDone(done)) 458 } 459 // Expect that the repro level is no longer ReproLevelC. 460 c.expectNoEmail() 461 bug, _, _ = c.loadBug(extBugID) 462 c.expectEQ(bug.HeadReproLevel, ReproLevelSyz) 463 // Let's also deprecate the syz repro. 464 c.advanceTime(c.config().Obsoleting.ReproRetestPeriod + time.Hour) 465 466 resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{TestPatches: true}) 467 c.expectEQ(resp.Type, dashapi.JobTestPatch) 468 c.expectEQ(resp.KernelBranch, build.KernelBranch) 469 c.expectEQ(resp.ReproC, []uint8(nil)) 470 c.expectEQ(resp.KernelConfig, build.KernelConfig) 471 done := &dashapi.JobDoneReq{ 472 ID: resp.ID, 473 } 474 client.expectOK(client.JobDone(done)) 475 // Expect that the repro level is no longer ReproLevelC. 476 bug, _, _ = c.loadBug(extBugID) 477 c.expectEQ(bug.HeadReproLevel, ReproLevelNone) 478 c.expectEQ(bug.ReproLevel, ReproLevelC) 479 // Expect that the bug gets deprecated. 480 notif := c.pollEmailBug() 481 if !strings.Contains(notif.Body, "Auto-closing this bug as obsolete") { 482 t.Fatalf("bad notification text: %q", notif.Body) 483 } 484 // Expect that the right obsoletion reason was set. 485 bug, _, _ = c.loadBug(extBugID) 486 c.expectEQ(bug.StatusReason, dashapi.InvalidatedByRevokedRepro) 487 } 488 489 func TestDelegatedManagerReproRetest(t *testing.T) { 490 c := NewCtx(t) 491 defer c.Close() 492 493 client := c.makeClient(clientMgrDecommission, keyMgrDecommission, true) 494 oldManager := notYetDecommManger 495 newManager := delegateToManager 496 497 oldBuild := testBuild(1) 498 oldBuild.KernelRepo = "git://delegated.repo/git.git" 499 oldBuild.KernelBranch = "main" 500 oldBuild.Manager = oldManager 501 client.UploadBuild(oldBuild) 502 503 crash := testCrash(oldBuild, 1) 504 crash.ReproOpts = []byte("repro opts") 505 crash.ReproSyz = []byte("repro syz") 506 crash.ReproC = []byte("repro C") 507 client.ReportCrash(crash) 508 sender := c.pollEmailBug().Sender 509 _, extBugID, err := email.RemoveAddrContext(sender) 510 c.expectOK(err) 511 512 // Deprecate the oldManager. 513 c.decommissionManager("test-mgr-decommission", oldManager, newManager) 514 515 // Upload a build for the new manager. 516 c.advanceTime(time.Minute) 517 build := testBuild(1) 518 build.ID = "new-build" 519 build.KernelRepo = "git://delegated.repo/new-git.git" 520 build.KernelBranch = "new-main" 521 build.KernelConfig = []byte{0xAB, 0xCD, 0xEF} 522 build.Manager = newManager 523 client.UploadBuild(build) 524 525 // Wait until the bug is upstreamed. 526 c.advanceTime(20 * 24 * time.Hour) 527 c.pollEmailBug() 528 c.pollEmailBug() 529 530 // Let's say that the C repro testing has failed. 531 c.advanceTime(c.config().Obsoleting.ReproRetestPeriod + time.Hour) 532 533 resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{TestPatches: true}) 534 c.expectEQ(resp.Type, dashapi.JobTestPatch) 535 c.expectEQ(resp.KernelRepo, build.KernelRepo) 536 c.expectEQ(resp.KernelBranch, build.KernelBranch) 537 c.expectEQ(resp.KernelConfig, build.KernelConfig) 538 c.expectEQ(resp.Patch, []uint8(nil)) 539 540 // Pretend that the C repro fails. 541 done := &dashapi.JobDoneReq{ 542 ID: resp.ID, 543 } 544 545 client.expectOK(client.JobDone(done)) 546 547 // If it has worked, the repro is revoked and the bug is obsoleted. 548 c.pollEmailBug() 549 bug, _, _ := c.loadBug(extBugID) 550 c.expectEQ(bug.HeadReproLevel, ReproLevelNone) 551 } 552 553 // Test on a restricted manager. 554 func TestJobRestrictedManager(t *testing.T) { 555 c := NewCtx(t) 556 defer c.Close() 557 558 client := c.publicClient 559 560 build := testBuild(1) 561 build.Manager = restrictedManager 562 client.UploadBuild(build) 563 564 crash := testCrash(build, 1) 565 crash.ReproSyz = []byte("repro syz") 566 client.ReportCrash(crash) 567 client.pollAndFailBisectJob(build.Manager) 568 sender := c.pollEmailBug().Sender 569 570 // Testing on a wrong repo must fail and no test jobs passed to manager. 571 c.incomingEmail(sender, "#syz test: git://mygit.com/git.git master\n", EmailOptMessageID(1)) 572 reply := c.pollEmailBug() 573 c.expectEQ(strings.Contains(reply.Body, "you should test only on restricted.git"), true) 574 pollResp := client.pollJobs(build.Manager) 575 c.expectEQ(pollResp.ID, "") 576 577 // Testing on the right repo must succeed. 578 c.incomingEmail(sender, "#syz test: git://restricted.git/restricted.git master\n", EmailOptMessageID(2)) 579 pollResp = client.pollJobs(build.Manager) 580 c.expectNE(pollResp.ID, "") 581 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 582 c.expectEQ(pollResp.Manager, build.Manager) 583 c.expectEQ(pollResp.KernelRepo, "git://restricted.git/restricted.git") 584 } 585 586 // Test that JobBisectFix is returned only after 30 days. 587 func TestBisectFixJob(t *testing.T) { 588 c := NewCtx(t) 589 defer c.Close() 590 591 // Upload a crash report. 592 build := testBuild(1) 593 c.client2.UploadBuild(build) 594 crash := testCrashWithRepro(build, 1) 595 c.client2.ReportCrash(crash) 596 c.client2.pollEmailBug() 597 598 // Receive the JobBisectCause. 599 resp := c.client2.pollJobs(build.Manager) 600 c.client2.expectNE(resp.ID, "") 601 c.client2.expectEQ(resp.Type, dashapi.JobBisectCause) 602 done := &dashapi.JobDoneReq{ 603 ID: resp.ID, 604 Error: []byte("testBisectFixJob:JobBisectCause"), 605 } 606 c.client2.expectOK(c.client2.JobDone(done)) 607 608 // Ensure no more jobs. 609 resp = c.client2.pollJobs(build.Manager) 610 c.client2.expectEQ(resp.ID, "") 611 612 // Advance time by 30 days and read out any notification emails. 613 { 614 c.advanceTime(30 * 24 * time.Hour) 615 msg := c.client2.pollEmailBug() 616 c.expectEQ(msg.Subject, "title1") 617 c.expectTrue(strings.Contains(msg.Body, "Sending this report to the next reporting stage.")) 618 619 msg = c.client2.pollEmailBug() 620 c.expectEQ(msg.Subject, "[syzbot] title1") 621 c.expectTrue(strings.Contains(msg.Body, "syzbot found the following issue")) 622 } 623 624 // Ensure that we get a JobBisectFix. 625 resp = c.client2.pollJobs(build.Manager) 626 c.client2.expectNE(resp.ID, "") 627 c.client2.expectEQ(resp.Type, dashapi.JobBisectFix) 628 done = &dashapi.JobDoneReq{ 629 ID: resp.ID, 630 Error: []byte("testBisectFixJob:JobBisectFix"), 631 } 632 c.client2.expectOK(c.client2.JobDone(done)) 633 } 634 635 // Test that JobBisectFix jobs are re-tried if crash occurs on ToT. 636 func TestBisectFixRetry(t *testing.T) { 637 c := NewCtx(t) 638 defer c.Close() 639 640 // Upload a crash report. 641 build := testBuild(1) 642 c.client2.UploadBuild(build) 643 crash := testCrashWithRepro(build, 1) 644 c.client2.ReportCrash(crash) 645 c.client2.pollEmailBug() 646 647 // Receive the JobBisectCause. 648 resp := c.client2.pollJobs(build.Manager) 649 c.client2.expectNE(resp.ID, "") 650 c.client2.expectEQ(resp.Type, dashapi.JobBisectCause) 651 done := &dashapi.JobDoneReq{ 652 ID: resp.ID, 653 Error: []byte("testBisectFixRetry:JobBisectCause"), 654 } 655 c.client2.expectOK(c.client2.JobDone(done)) 656 657 // Advance time by 30 days and read out any notification emails. 658 { 659 c.advanceTime(30 * 24 * time.Hour) 660 msg := c.client2.pollEmailBug() 661 c.expectEQ(msg.Subject, "title1") 662 c.expectTrue(strings.Contains(msg.Body, "Sending this report to the next reporting stage.")) 663 664 msg = c.client2.pollEmailBug() 665 c.expectEQ(msg.Subject, "[syzbot] title1") 666 c.expectTrue(strings.Contains(msg.Body, "syzbot found the following issue")) 667 } 668 669 // Ensure that we get a JobBisectFix. We send back a crashlog, no error, no commits. 670 resp = c.client2.pollJobs(build.Manager) 671 c.client2.expectNE(resp.ID, "") 672 c.client2.expectEQ(resp.Type, dashapi.JobBisectFix) 673 done = &dashapi.JobDoneReq{ 674 Build: dashapi.Build{ 675 ID: "build1", 676 }, 677 ID: resp.ID, 678 CrashLog: []byte("this is a crashlog"), 679 CrashReport: []byte("this is a crashreport"), 680 } 681 c.client2.expectOK(c.client2.JobDone(done)) 682 683 // Advance time by 30 days. No notification emails. 684 { 685 c.advanceTime(30 * 24 * time.Hour) 686 } 687 688 // Ensure that we get a JobBisectFix retry. 689 resp = c.client2.pollJobs(build.Manager) 690 c.client2.expectNE(resp.ID, "") 691 c.client2.expectEQ(resp.Type, dashapi.JobBisectFix) 692 done = &dashapi.JobDoneReq{ 693 ID: resp.ID, 694 Error: []byte("testBisectFixRetry:JobBisectFix"), 695 } 696 c.client2.expectOK(c.client2.JobDone(done)) 697 } 698 699 // Test that bisection results are not reported for bugs that are already marked as fixed. 700 func TestNotReportingAlreadyFixed(t *testing.T) { 701 c := NewCtx(t) 702 defer c.Close() 703 704 // Upload a crash report. 705 build := testBuild(1) 706 c.client2.UploadBuild(build) 707 crash := testCrashWithRepro(build, 1) 708 c.client2.ReportCrash(crash) 709 c.client2.pollEmailBug() 710 711 // Receive the JobBisectCause. 712 resp := c.client2.pollJobs(build.Manager) 713 c.client2.expectNE(resp.ID, "") 714 c.client2.expectEQ(resp.Type, dashapi.JobBisectCause) 715 done := &dashapi.JobDoneReq{ 716 ID: resp.ID, 717 Error: []byte("testBisectFixRetry:JobBisectCause"), 718 } 719 c.client2.expectOK(c.client2.JobDone(done)) 720 721 sender := "" 722 // Advance time by 30 days and read out any notification emails. 723 { 724 c.advanceTime(30 * 24 * time.Hour) 725 msg := c.client2.pollEmailBug() 726 c.expectEQ(msg.Subject, "title1") 727 c.expectTrue(strings.Contains(msg.Body, "Sending this report to the next reporting stage.")) 728 729 msg = c.client2.pollEmailBug() 730 c.expectEQ(msg.Subject, "[syzbot] title1") 731 c.expectTrue(strings.Contains(msg.Body, "syzbot found the following issue")) 732 sender = msg.Sender 733 } 734 735 // Poll for a BisectFix job. 736 resp = c.client2.pollJobs(build.Manager) 737 c.client2.expectNE(resp.ID, "") 738 c.client2.expectEQ(resp.Type, dashapi.JobBisectFix) 739 740 // Meanwhile, the bug is marked as fixed separately. 741 c.incomingEmail(sender, "#syz fix: kernel: add a fix", EmailOptCC(nil)) 742 743 { 744 // Email notification of "Your 'fix:' command is accepted, but please keep 745 // bugs@syzkaller.com mailing list in CC next time." 746 c.client2.pollEmailBug() 747 } 748 749 // At this point, send back the results for the BisectFix job also. 750 done = &dashapi.JobDoneReq{ 751 ID: resp.ID, 752 Build: *build, 753 Log: []byte("bisectfix log 4"), 754 CrashTitle: "bisectfix crash title 4", 755 CrashLog: []byte("bisectfix crash log 4"), 756 CrashReport: []byte("bisectfix crash report 4"), 757 Commits: []dashapi.Commit{ 758 { 759 Hash: "46e65cb4a0448942ec316b24d60446bbd5cc7827", 760 Title: "kernel: add a fix", 761 Author: "author@kernel.org", 762 AuthorName: "Author Kernelov", 763 CC: []string{ 764 "reviewer1@kernel.org", "\"Reviewer2\" <reviewer2@kernel.org>", 765 // These must be filtered out: 766 "syzbot@testapp.appspotmail.com", 767 "syzbot+1234@testapp.appspotmail.com", 768 "\"syzbot\" <syzbot+1234@testapp.appspotmail.com>", 769 }, 770 Date: time.Date(2000, 2, 9, 4, 5, 6, 7, time.UTC), 771 }, 772 }, 773 } 774 c.expectOK(c.client2.JobDone(done)) 775 776 // No reporting should come in at this point. If there is reporting, c.Close() 777 // will fail. 778 } 779 780 // Test that fix bisections are listed on the bug page if the bug.BisectFix 781 // is not BisectYes. 782 func TestFixBisectionsListed(t *testing.T) { 783 c := NewCtx(t) 784 defer c.Close() 785 786 // Upload a crash report. 787 build := testBuild(1) 788 c.client2.UploadBuild(build) 789 crash := testCrashWithRepro(build, 1) 790 c.client2.ReportCrash(crash) 791 c.client2.pollEmailBug() 792 793 // Receive the JobBisectCause. 794 resp := c.client2.pollJobs(build.Manager) 795 c.client2.expectNE(resp.ID, "") 796 c.client2.expectEQ(resp.Type, dashapi.JobBisectCause) 797 done := &dashapi.JobDoneReq{ 798 ID: resp.ID, 799 Error: []byte("testBisectFixRetry:JobBisectCause"), 800 } 801 c.client2.expectOK(c.client2.JobDone(done)) 802 803 // At this point, no fix bisections should be listed out. 804 var bugs []*Bug 805 keys, err := db.NewQuery("Bug").GetAll(c.ctx, &bugs) 806 c.expectEQ(err, nil) 807 c.expectEQ(len(bugs), 1) 808 url := fmt.Sprintf("/bug?id=%v", keys[0].StringID()) 809 content, err := c.GET(url) 810 c.expectEQ(err, nil) 811 c.expectTrue(!bytes.Contains(content, []byte("All fix bisections"))) 812 813 // Advance time by 30 days and read out any notification emails. 814 { 815 c.advanceTime(30 * 24 * time.Hour) 816 msg := c.client2.pollEmailBug() 817 c.expectEQ(msg.Subject, "title1") 818 c.expectTrue(strings.Contains(msg.Body, "Sending this report to the next reporting stage.")) 819 820 msg = c.client2.pollEmailBug() 821 c.expectEQ(msg.Subject, "[syzbot] title1") 822 c.expectTrue(strings.Contains(msg.Body, "syzbot found the following issue")) 823 } 824 825 // Ensure that we get a JobBisectFix. We send back a crashlog, no error, 826 // no commits. 827 resp = c.client2.pollJobs(build.Manager) 828 c.client2.expectNE(resp.ID, "") 829 c.client2.expectEQ(resp.Type, dashapi.JobBisectFix) 830 done = &dashapi.JobDoneReq{ 831 Build: dashapi.Build{ 832 ID: "build1", 833 }, 834 ID: resp.ID, 835 CrashTitle: "this is a crashtitle", 836 CrashLog: []byte("this is a crashlog"), 837 CrashReport: []byte("this is a crashreport"), 838 Log: []byte("this is a log"), 839 } 840 c.client2.expectOK(c.client2.JobDone(done)) 841 842 // Check the bug page and ensure that a bisection is listed out. 843 content, err = c.GET(url) 844 c.expectEQ(err, nil) 845 c.expectTrue(bytes.Contains(content, []byte("Fix bisection attempts"))) 846 847 // Advance time by 30 days. No notification emails. 848 { 849 c.advanceTime(30 * 24 * time.Hour) 850 } 851 852 // Ensure that we get a JobBisectFix retry. 853 resp = c.client2.pollJobs(build.Manager) 854 c.client2.expectNE(resp.ID, "") 855 c.client2.expectEQ(resp.Type, dashapi.JobBisectFix) 856 done = &dashapi.JobDoneReq{ 857 ID: resp.ID, 858 Error: []byte("testBisectFixRetry:JobBisectFix"), 859 } 860 c.client2.expectOK(c.client2.JobDone(done)) 861 862 // Check the bug page and ensure that no bisections are listed out. 863 content, err = c.GET(url) 864 c.expectEQ(err, nil) 865 c.expectTrue(!bytes.Contains(content, []byte("All fix bisections"))) 866 } 867 868 // Test that fix bisections do not occur if Repo has NoFixBisections set. 869 func TestFixBisectionsDisabled(t *testing.T) { 870 c := NewCtx(t) 871 defer c.Close() 872 873 // Upload a crash report. 874 build := testBuild(1) 875 build.Manager = noFixBisectionManager 876 c.client2.UploadBuild(build) 877 crash := testCrashWithRepro(build, 20) 878 c.client2.ReportCrash(crash) 879 c.client2.pollEmailBug() 880 881 // Receive the JobBisectCause. 882 resp := c.client2.pollJobs(build.Manager) 883 c.client2.expectNE(resp.ID, "") 884 c.client2.expectEQ(resp.Type, dashapi.JobBisectCause) 885 done := &dashapi.JobDoneReq{ 886 ID: resp.ID, 887 Error: []byte("testBisectFixRetry:JobBisectCause"), 888 } 889 c.client2.expectOK(c.client2.JobDone(done)) 890 891 // Advance time by 30 days and read out any notification emails. 892 { 893 c.advanceTime(30 * 24 * time.Hour) 894 msg := c.client2.pollEmailBug() 895 c.expectEQ(msg.Subject, "title20") 896 c.expectTrue(strings.Contains(msg.Body, "Sending this report to the next reporting stage.")) 897 898 msg = c.client2.pollEmailBug() 899 c.expectEQ(msg.Subject, "[syzbot] title20") 900 c.expectTrue(strings.Contains(msg.Body, "syzbot found the following issue")) 901 } 902 903 // Ensure that we do not get a JobBisectFix. 904 resp = c.client2.pollJobs(build.Manager) 905 c.client2.expectEQ(resp.ID, "") 906 } 907 908 func TestExternalPatchFlow(t *testing.T) { 909 c := NewCtx(t) 910 defer c.Close() 911 912 client := c.client 913 914 build := testBuild(1) 915 client.UploadBuild(build) 916 917 crash := testCrash(build, 2) 918 crash.Title = testErrorTitle 919 client.ReportCrash(crash) 920 921 // Confirm the report. 922 reports, err := client.ReportingPollBugs("test") 923 origReport := reports.Reports[0] 924 c.expectOK(err) 925 c.expectEQ(len(reports.Reports), 1) 926 927 reply, _ := client.ReportingUpdate(&dashapi.BugUpdate{ 928 ID: origReport.ID, 929 Status: dashapi.BugStatusOpen, 930 }) 931 client.expectEQ(reply.Error, false) 932 client.expectEQ(reply.OK, true) 933 934 // Create a new patch testing job. 935 ret, err := client.NewTestJob(&dashapi.TestPatchRequest{ 936 BugID: origReport.ID, 937 Link: "http://some-link.com/", 938 User: "developer@kernel.org", 939 Branch: "kernel-branch", 940 Repo: "git://git.git/git.git", 941 Patch: []byte(sampleGitPatch), 942 }) 943 c.expectOK(err) 944 c.expectEQ(ret.ErrorText, "") 945 946 // Make sure the job will be passed to the job processor. 947 pollResp := c.client2.pollJobs(build.Manager) 948 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 949 c.expectEQ(pollResp.KernelRepo, "git://git.git/git.git") 950 c.expectEQ(pollResp.KernelBranch, "kernel-branch") 951 c.expectEQ(pollResp.Patch, []byte(sampleGitPatch)) 952 953 // Emulate the completion of the job. 954 build2 := testBuild(2) 955 jobDoneReq := &dashapi.JobDoneReq{ 956 ID: pollResp.ID, 957 Build: *build2, 958 CrashTitle: "test crash title", 959 CrashLog: []byte("test crash log"), 960 CrashReport: []byte("test crash report"), 961 } 962 err = c.client2.JobDone(jobDoneReq) 963 c.expectOK(err) 964 965 // Verify that we do get the bug update about the completed request. 966 jobDoneUpdates, err := client.ReportingPollBugs("test") 967 c.expectOK(err) 968 c.expectEQ(len(jobDoneUpdates.Reports), 1) 969 970 newReport := jobDoneUpdates.Reports[0] 971 c.expectEQ(newReport.Type, dashapi.ReportTestPatch) 972 c.expectEQ(newReport.CrashTitle, "test crash title") 973 c.expectEQ(newReport.Report, []byte("test crash report")) 974 975 // Confirm the patch testing result. 976 reply, _ = client.ReportingUpdate(&dashapi.BugUpdate{ 977 ID: origReport.ID, 978 JobID: pollResp.ID, 979 Status: dashapi.BugStatusOpen, 980 }) 981 client.expectEQ(reply.Error, false) 982 client.expectEQ(reply.OK, true) 983 } 984 985 func TestExternalPatchTestError(t *testing.T) { 986 c := NewCtx(t) 987 defer c.Close() 988 989 client := c.client 990 991 build := testBuild(1) 992 client.UploadBuild(build) 993 994 crash := testCrash(build, 2) 995 crash.Title = testErrorTitle 996 client.ReportCrash(crash) 997 998 // Confirm the report. 999 reports, err := client.ReportingPollBugs("test") 1000 origReport := reports.Reports[0] 1001 c.expectOK(err) 1002 c.expectEQ(len(reports.Reports), 1) 1003 1004 reply, _ := client.ReportingUpdate(&dashapi.BugUpdate{ 1005 ID: origReport.ID, 1006 Status: dashapi.BugStatusOpen, 1007 }) 1008 client.expectEQ(reply.Error, false) 1009 client.expectEQ(reply.OK, true) 1010 1011 // Create a new patch testing job. 1012 ret, err := client.NewTestJob(&dashapi.TestPatchRequest{ 1013 BugID: origReport.ID, 1014 User: "developer@kernel.org", 1015 Branch: "kernel-branch", 1016 Repo: "invalid-repo", 1017 Patch: []byte(sampleGitPatch), 1018 }) 1019 c.expectOK(err) 1020 c.expectEQ(ret.ErrorText, `"invalid-repo" does not look like a valid git repo address.`) 1021 } 1022 1023 func TestExternalPatchCompletion(t *testing.T) { 1024 c := NewCtx(t) 1025 defer c.Close() 1026 1027 client := c.client 1028 1029 build := testBuild(1) 1030 build.KernelRepo = "git://git.git/git.git" 1031 client.UploadBuild(build) 1032 1033 crash := testCrash(build, 2) 1034 crash.Title = testErrorTitle 1035 client.ReportCrash(crash) 1036 1037 // Confirm the report. 1038 reports, err := client.ReportingPollBugs("test") 1039 origReport := reports.Reports[0] 1040 c.expectOK(err) 1041 c.expectEQ(len(reports.Reports), 1) 1042 1043 reply, _ := client.ReportingUpdate(&dashapi.BugUpdate{ 1044 ID: origReport.ID, 1045 Status: dashapi.BugStatusOpen, 1046 }) 1047 client.expectEQ(reply.Error, false) 1048 client.expectEQ(reply.OK, true) 1049 1050 // Create a new patch testing job. 1051 ret, err := client.NewTestJob(&dashapi.TestPatchRequest{ 1052 BugID: origReport.ID, 1053 User: "developer@kernel.org", 1054 Patch: []byte(sampleGitPatch), 1055 }) 1056 c.expectOK(err) 1057 c.expectEQ(ret.ErrorText, "") 1058 1059 // Make sure branch and repo are correct. 1060 pollResp := c.client2.pollJobs(build.Manager) 1061 c.expectEQ(pollResp.KernelRepo, build.KernelRepo) 1062 c.expectEQ(pollResp.KernelBranch, build.KernelBranch) 1063 } 1064 1065 func TestParallelJobs(t *testing.T) { 1066 c := NewCtx(t) 1067 defer c.Close() 1068 1069 client := c.client 1070 1071 build := testBuild(1) 1072 client.UploadBuild(build) 1073 1074 crash := testCrash(build, 2) 1075 crash.Title = testErrorTitle 1076 client.ReportCrash(crash) 1077 1078 // Confirm the report. 1079 reports, err := client.ReportingPollBugs("test") 1080 origReport := reports.Reports[0] 1081 c.expectOK(err) 1082 c.expectEQ(len(reports.Reports), 1) 1083 1084 reply, _ := client.ReportingUpdate(&dashapi.BugUpdate{ 1085 ID: origReport.ID, 1086 Status: dashapi.BugStatusOpen, 1087 }) 1088 client.expectEQ(reply.Error, false) 1089 client.expectEQ(reply.OK, true) 1090 1091 // Create a patch testing job. 1092 const ( 1093 repo1 = "git://git.git/git1.git" 1094 repo2 = "git://git.git/git2.git" 1095 ) 1096 testPatchReq := &dashapi.TestPatchRequest{ 1097 BugID: origReport.ID, 1098 Link: "http://some-link.com/", 1099 User: "developer@kernel.org", 1100 Branch: "kernel-branch", 1101 Repo: repo1, 1102 Patch: []byte(sampleGitPatch), 1103 } 1104 ret, err := client.NewTestJob(testPatchReq) 1105 c.expectOK(err) 1106 c.expectEQ(ret.ErrorText, "") 1107 1108 // Make sure the job will be passed to the job processor. 1109 pollResp := client.pollJobs(build.Manager) 1110 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 1111 c.expectEQ(pollResp.KernelRepo, repo1) 1112 1113 // This job is already taken, there are no other jobs. 1114 emptyPollResp := client.pollJobs(build.Manager) 1115 c.expectEQ(emptyPollResp, &dashapi.JobPollResp{}) 1116 1117 // Create another job. 1118 testPatchReq.Repo = repo2 1119 ret, err = client.NewTestJob(testPatchReq) 1120 c.expectOK(err) 1121 c.expectEQ(ret.ErrorText, "") 1122 1123 // Make sure the new job will be passed to the job processor. 1124 pollResp = client.pollJobs(build.Manager) 1125 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 1126 c.expectEQ(pollResp.KernelRepo, repo2) 1127 1128 // .. and then there'll be no other jobs. 1129 emptyPollResp = client.pollJobs(build.Manager) 1130 c.expectEQ(emptyPollResp, &dashapi.JobPollResp{}) 1131 1132 // Emulate a syz-ci restart. 1133 client.JobReset(&dashapi.JobResetReq{Managers: []string{build.Manager}}) 1134 1135 // .. and re-query both jobs. 1136 repos := []string{} 1137 for i := 0; i < 2; i++ { 1138 pollResp = client.pollJobs(build.Manager) 1139 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 1140 repos = append(repos, pollResp.KernelRepo) 1141 } 1142 assert.ElementsMatch(t, repos, []string{repo1, repo2}, "two patch testing requests are expected") 1143 1144 // .. but nothing else is to be expected. 1145 emptyPollResp = client.pollJobs(build.Manager) 1146 c.expectEQ(emptyPollResp, &dashapi.JobPollResp{}) 1147 1148 // Emulate the job's completion. 1149 build2 := testBuild(2) 1150 jobDoneReq := &dashapi.JobDoneReq{ 1151 ID: pollResp.ID, 1152 Build: *build2, 1153 CrashTitle: "test crash title", 1154 CrashLog: []byte("test crash log"), 1155 CrashReport: []byte("test crash report"), 1156 } 1157 err = client.JobDone(jobDoneReq) 1158 c.expectOK(err) 1159 client.pollBugs(1) 1160 1161 // .. and make sure it doesn't appear again. 1162 emptyPollResp = client.pollJobs(build.Manager) 1163 c.expectEQ(emptyPollResp, &dashapi.JobPollResp{}) 1164 } 1165 1166 // Test that JobBisectCause jobs are re-tried if there were infra problems. 1167 func TestJobCauseRetry(t *testing.T) { 1168 c := NewCtx(t) 1169 defer c.Close() 1170 1171 client := c.client2 1172 // Upload a crash report. 1173 build := testBuild(1) 1174 client.UploadBuild(build) 1175 crash := testCrashWithRepro(build, 1) 1176 client.ReportCrash(crash) 1177 client.pollEmailBug() 1178 1179 // Release the report to the second stage. 1180 c.advanceTime(15 * 24 * time.Hour) 1181 client.pollEmailBug() // "Sending report to the next stage" email. 1182 client.pollEmailBug() // New report. 1183 1184 // Emulate an infra failure. 1185 resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{ 1186 BisectCause: true, 1187 }) 1188 client.expectNE(resp.ID, "") 1189 client.expectEQ(resp.Type, dashapi.JobBisectCause) 1190 done := &dashapi.JobDoneReq{ 1191 ID: resp.ID, 1192 Error: []byte("infra problem"), 1193 Flags: dashapi.BisectResultInfraError, 1194 } 1195 client.expectOK(client.JobDone(done)) 1196 c.expectNoEmail() 1197 1198 // Ensure we don't recreate the job right away. 1199 c.advanceTime(24 * time.Hour) 1200 resp = client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{ 1201 BisectCause: true, 1202 }) 1203 client.expectEQ(resp.ID, "") 1204 1205 // Wait the end of the freeze period. 1206 c.advanceTime(7 * 24 * time.Hour) 1207 resp = client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{ 1208 BisectCause: true, 1209 }) 1210 client.expectNE(resp.ID, "") 1211 client.expectEQ(resp.Type, dashapi.JobBisectCause) 1212 1213 done = &dashapi.JobDoneReq{ 1214 ID: resp.ID, 1215 Build: *testBuild(2), 1216 Log: []byte("bisect log"), 1217 CrashTitle: "bisect crash title", 1218 CrashLog: []byte("bisect crash log"), 1219 CrashReport: []byte("bisect crash report"), 1220 Commits: []dashapi.Commit{ 1221 { 1222 Hash: "36e65cb4a0448942ec316b24d60446bbd5cc7827", 1223 Title: "kernel: add a bug", 1224 Author: "author@kernel.org", 1225 CC: []string{"user@domain.com"}, 1226 Date: time.Date(2000, 2, 9, 4, 5, 6, 7, time.UTC), 1227 }, 1228 }, 1229 } 1230 done.Build.ID = resp.ID 1231 c.expectOK(client.JobDone(done)) 1232 1233 msg := c.pollEmailBug() 1234 c.expectTrue(strings.Contains(msg.Body, "syzbot has bisected this issue to:")) 1235 } 1236 1237 // Test that we accept `#syz test` commands without arguments. 1238 func TestEmailTestCommandNoArgs(t *testing.T) { 1239 c := NewCtx(t) 1240 defer c.Close() 1241 1242 client := c.publicClient 1243 build := testBuild(1) 1244 build.KernelRepo = "git://git.git/git.git" 1245 build.KernelBranch = "kernel-branch" 1246 client.UploadBuild(build) 1247 1248 crash := testCrashWithRepro(build, 2) 1249 client.ReportCrash(crash) 1250 1251 sender := c.pollEmailBug().Sender 1252 mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email 1253 1254 c.incomingEmail(sender, "#syz test\n"+sampleGitPatch, 1255 EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList})) 1256 c.expectNoEmail() 1257 pollResp := client.pollJobs(build.Manager) 1258 c.expectEQ(pollResp.Type, dashapi.JobTestPatch) 1259 c.expectEQ(pollResp.KernelRepo, build.KernelRepo) 1260 c.expectEQ(pollResp.KernelBranch, build.KernelBranch) 1261 c.expectEQ(pollResp.Patch, []byte(sampleGitPatch)) 1262 } 1263 1264 func TestAliasPatchTestingJob(t *testing.T) { 1265 c := NewCtx(t) 1266 defer c.Close() 1267 1268 client := c.client 1269 1270 build := testBuild(1) 1271 client.UploadBuild(build) 1272 1273 crash := testCrash(build, 2) 1274 crash.Title = testErrorTitle 1275 client.ReportCrash(crash) 1276 1277 // Confirm the report. 1278 reports, err := client.ReportingPollBugs("test") 1279 origReport := reports.Reports[0] 1280 c.expectOK(err) 1281 1282 reply, _ := client.ReportingUpdate(&dashapi.BugUpdate{ 1283 ID: origReport.ID, 1284 Status: dashapi.BugStatusOpen, 1285 }) 1286 client.expectEQ(reply.Error, false) 1287 client.expectEQ(reply.OK, true) 1288 1289 // Create a new patch testing job. 1290 _, err = client.NewTestJob(&dashapi.TestPatchRequest{ 1291 BugID: origReport.ID, 1292 User: "developer@kernel.org", 1293 Branch: "some-branch", 1294 Repo: "repo10alias", 1295 Patch: []byte(sampleGitPatch), 1296 }) 1297 c.expectOK(err) 1298 1299 // Make sure branch and repo are correct. 1300 pollResp := c.client2.pollJobs(build.Manager) 1301 c.expectEQ(pollResp.KernelRepo, "git://syzkaller.org") 1302 c.expectEQ(pollResp.KernelBranch, "some-branch") 1303 }