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