github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/dashboard/app/subsystem_test.go (about) 1 // Copyright 2023 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 "fmt" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/google/syzkaller/dashboard/dashapi" 13 "github.com/google/syzkaller/pkg/email" 14 "github.com/google/syzkaller/pkg/subsystem" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 const subsystemTestNs = "test1" 19 20 func TestSubsytemMaintainers(t *testing.T) { 21 c := NewCtx(t) 22 defer c.Close() 23 24 // This also indirectly tests getSubsystemService. 25 assert.ElementsMatch(t, 26 subsystemMaintainers(c.ctx, subsystemTestNs, "subsystemA"), 27 []string{ 28 "subsystemA@list.com", "subsystemA@person.com", 29 }, 30 ) 31 assert.ElementsMatch(t, subsystemMaintainers(c.ctx, subsystemTestNs, "does-not-exist"), []string{}) 32 } 33 34 func TestPeriodicSubsystemRefresh(t *testing.T) { 35 c := NewCtx(t) 36 defer c.Close() 37 38 client := c.client 39 ns := subsystemTestNs 40 41 build := testBuild(1) 42 client.UploadBuild(build) 43 44 // Create a bug without any subsystems. 45 c.setSubsystems(ns, nil, 1) 46 crash := testCrash(build, 1) 47 crash.Title = "WARNING: abcd" 48 crash.GuiltyFiles = []string{"test.c"} 49 client.ReportCrash(crash) 50 rep := client.pollBug() 51 extID := rep.ID 52 53 // Initially there should be no subsystems. 54 expectLabels(t, client, extID) 55 56 // Update subsystems. 57 item := &subsystem.Subsystem{ 58 Name: "first", 59 PathRules: []subsystem.PathRule{{IncludeRegexp: `test\.c`}}, 60 } 61 // Keep revision the same. 62 c.setSubsystems(ns, []*subsystem.Subsystem{item}, 1) 63 64 // Refresh subsystems. 65 c.advanceTime(time.Hour) 66 _, err := c.AuthGET(AccessUser, "/cron/refresh_subsystems") 67 c.expectOK(err) 68 expectLabels(t, client, extID) // Not enough time has passed yet. 69 70 // Wait until the refresh period is over. 71 c.advanceTime(openBugsUpdateTime) 72 73 _, err = c.AuthGET(AccessUser, "/cron/refresh_subsystems") 74 c.expectOK(err) 75 expectLabels(t, client, extID, "subsystems:first") 76 } 77 78 func TestOpenBugRevRefresh(t *testing.T) { 79 c := NewCtx(t) 80 defer c.Close() 81 82 client := c.client 83 ns := subsystemTestNs 84 85 build := testBuild(1) 86 client.UploadBuild(build) 87 88 // Create a bug without any subsystems. 89 c.setSubsystems(ns, nil, 0) 90 crash := testCrash(build, 1) 91 crash.GuiltyFiles = []string{"test.c"} 92 client.ReportCrash(crash) 93 rep := client.pollBug() 94 extID := rep.ID 95 96 // Initially there should be no subsystems. 97 expectLabels(t, client, extID) 98 99 // Update subsystems. 100 c.advanceTime(time.Hour) 101 item := &subsystem.Subsystem{ 102 Name: "first", 103 PathRules: []subsystem.PathRule{{IncludeRegexp: `test\.c`}}, 104 } 105 // Update the revision number as well. 106 c.setSubsystems(ns, []*subsystem.Subsystem{item}, 1) 107 108 // Refresh subsystems. 109 _, err := c.AuthGET(AccessUser, "/cron/refresh_subsystems") 110 c.expectOK(err) 111 expectLabels(t, client, extID, "subsystems:first") 112 } 113 114 func TestClosedBugSubsystemRefresh(t *testing.T) { 115 c := NewCtx(t) 116 defer c.Close() 117 118 client := c.client 119 ns := subsystemTestNs 120 121 build := testBuild(1) 122 client.UploadBuild(build) 123 124 // Create a bug without any subsystems. 125 c.setSubsystems(ns, nil, 0) 126 crash := testCrash(build, 1) 127 crash.GuiltyFiles = []string{"test.c"} 128 client.ReportCrash(crash) 129 rep := client.pollBug() 130 extID := rep.ID 131 132 // "Fix" the bug. 133 reply, _ := c.client.ReportingUpdate(&dashapi.BugUpdate{ 134 ID: rep.ID, 135 Status: dashapi.BugStatusOpen, 136 FixCommits: []string{"foo: fix the crash"}, 137 }) 138 c.expectEQ(reply.OK, true) 139 build2 := testBuild(2) 140 build2.Manager = build.Manager 141 build2.Commits = []string{"foo: fix the crash"} 142 client.UploadBuild(build2) 143 client.pollNotifs(0) 144 bug, _, _ := c.loadBug(rep.ID) 145 c.expectEQ(bug.Status, BugStatusFixed) 146 147 // Initially there should be no subsystems. 148 expectLabels(t, client, extID) 149 150 // Update subsystems. 151 c.advanceTime(time.Hour) 152 item := &subsystem.Subsystem{ 153 Name: "first", 154 PathRules: []subsystem.PathRule{{IncludeRegexp: `test\.c`}}, 155 } 156 c.setSubsystems(ns, []*subsystem.Subsystem{item}, 1) 157 158 // Refresh subsystems. 159 c.advanceTime(time.Hour) 160 _, err := c.AuthGET(AccessUser, "/cron/refresh_subsystems") 161 c.expectOK(err) 162 expectLabels(t, client, extID, "subsystems:first") 163 } 164 165 func TestInvalidBugSubsystemRefresh(t *testing.T) { 166 c := NewCtx(t) 167 defer c.Close() 168 169 client := c.client 170 build := testBuild(1) 171 client.UploadBuild(build) 172 173 // Create a bug without any subsystems. 174 c.setSubsystems(subsystemTestNs, nil, 0) 175 crash := testCrash(build, 1) 176 crash.GuiltyFiles = []string{"test.c"} 177 client.ReportCrash(crash) 178 rep := client.pollBug() 179 extID := rep.ID 180 181 // Invalidate the bug. 182 reply, _ := c.client.ReportingUpdate(&dashapi.BugUpdate{ 183 ID: rep.ID, 184 Status: dashapi.BugStatusInvalid, 185 }) 186 c.expectEQ(reply.OK, true) 187 bug, _, _ := c.loadBug(rep.ID) 188 c.expectEQ(bug.Status, BugStatusInvalid) 189 190 // Initially there should be no subsystems. 191 expectLabels(t, client, extID) 192 193 // Update subsystems. 194 c.advanceTime(time.Hour) 195 item := &subsystem.Subsystem{ 196 Name: "first", 197 PathRules: []subsystem.PathRule{{IncludeRegexp: `test\.c`}}, 198 } 199 c.setSubsystems(subsystemTestNs, []*subsystem.Subsystem{item}, 1) 200 201 // Refresh subsystems. 202 c.advanceTime(time.Hour) 203 _, err := c.AuthGET(AccessUser, "/cron/refresh_subsystems") 204 c.expectOK(err) 205 expectLabels(t, client, extID, "subsystems:first") 206 } 207 208 func TestUserSubsystemsRefresh(t *testing.T) { 209 c := NewCtx(t) 210 defer c.Close() 211 212 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 213 ns := "access-public-email" 214 215 build := testBuild(1) 216 client.UploadBuild(build) 217 218 // Create a bug with subsystemA. 219 crash := testCrash(build, 1) 220 crash.GuiltyFiles = []string{"a.c"} 221 client.ReportCrash(crash) 222 c.incomingEmail(c.pollEmailBug().Sender, "#syz upstream\n") 223 224 sender := c.pollEmailBug().Sender 225 _, extID, err := email.RemoveAddrContext(sender) 226 c.expectOK(err) 227 228 // Make sure we've set the right subsystem. 229 expectLabels(t, client, extID, "subsystems:subsystemA") 230 231 // Manually set another subsystem. 232 c.incomingEmail(sender, "#syz set subsystems: subsystemB\n", 233 EmailOptFrom("test@requester.com")) 234 expectLabels(t, client, extID, "subsystems:subsystemB") 235 236 // Refresh subsystems. 237 c.advanceTime(openBugsUpdateTime + time.Hour) 238 _, err = c.AuthGET(AccessUser, "/cron/refresh_subsystems") 239 c.expectOK(err) 240 241 // The subsystems must stay the same. 242 expectLabels(t, client, extID, "subsystems:subsystemB") 243 244 // Bump the subsystem revision and refresh subsystems. 245 c.setSubsystems(ns, testSubsystems, 2) 246 c.advanceTime(time.Hour) 247 _, err = c.AuthGET(AccessUser, "/cron/refresh_subsystems") 248 c.expectOK(err) 249 250 // The subsystem must still stay the same. 251 expectLabels(t, client, extID, "subsystems:subsystemB") 252 } 253 254 func TestNoUserSubsystemOverwrite(t *testing.T) { 255 c := NewCtx(t) 256 defer c.Close() 257 258 client := c.makeClient(clientPublicEmail, keyPublicEmail, true) 259 260 build := testBuild(1) 261 client.UploadBuild(build) 262 263 // Create a bug without subsystems. 264 crash := testCrash(build, 1) 265 client.ReportCrash(crash) 266 c.incomingEmail(c.pollEmailBug().Sender, "#syz upstream\n") 267 268 sender := c.pollEmailBug().Sender 269 _, extID, err := email.RemoveAddrContext(sender) 270 c.expectOK(err) 271 272 // Manually set subsystemA. 273 c.incomingEmail(sender, "#syz set subsystems: subsystemA\n", 274 EmailOptFrom("test@requester.com")) 275 expectLabels(t, client, extID, "subsystems:subsystemA") 276 277 // Now we find a reproducer that indicates it's subsystemB. 278 279 crash.GuiltyFiles = []string{"b.c"} 280 crash.ReproOpts = []byte("some opts") 281 crash.ReproSyz = []byte("getpid()") 282 client.ReportCrash(crash) 283 c.pollEmailBug() 284 285 // Make sure subsystem stayed unchanged. 286 expectLabels(t, client, extID, "subsystems:subsystemA") 287 } 288 289 // nolint: goconst 290 func TestPeriodicSubsystemReminders(t *testing.T) { 291 c := NewCtx(t) 292 defer c.Close() 293 294 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 295 build := testBuild(1) 296 client.UploadBuild(build) 297 298 bugToExtID := map[string]string{} 299 300 // WARNING: a first (3 crashes) 301 aFirst := testCrash(build, 1) 302 aFirst.Title = `WARNING: a first` 303 aFirst.GuiltyFiles = []string{"a.c"} 304 client.ReportCrash(aFirst) 305 bugToExtID[aFirst.Title] = client.pollEmailExtID() 306 for i := 0; i < 2; i++ { 307 client.ReportCrash(aFirst) 308 c.advanceTime(time.Hour) 309 } 310 311 // WARNING: a second (1 crash) 312 aSecond := testCrash(build, 1) 313 aSecond.Title = `WARNING: a second` 314 aSecond.GuiltyFiles = []string{"a.c"} 315 client.ReportCrash(aSecond) 316 bugToExtID[aSecond.Title] = client.pollEmailExtID() 317 c.advanceTime(time.Hour) 318 319 // WARNING: b first (1 crashes) 320 bFirst := testCrash(build, 1) 321 bFirst.Title = `WARNING: b first` 322 bFirst.GuiltyFiles = []string{"b.c"} 323 client.ReportCrash(bFirst) 324 bugToExtID[bFirst.Title] = client.pollEmailExtID() 325 c.advanceTime(time.Hour) 326 327 // WARNING: b first (5 crashes) 328 bSecond := testCrash(build, 1) 329 bSecond.Title = `WARNING: b second` 330 bSecond.GuiltyFiles = []string{"b.c"} 331 client.ReportCrash(bSecond) 332 bugToExtID[bSecond.Title] = client.pollEmailExtID() 333 for i := 0; i < 4; i++ { 334 client.ReportCrash(bSecond) 335 c.advanceTime(time.Hour) 336 } 337 338 // Report bugs once more to pretend they're still valid. 339 c.advanceTime(time.Hour * 24 * 14) 340 client.ReportCrash(aFirst) 341 client.ReportCrash(bFirst) 342 client.ReportCrash(aSecond) 343 client.ReportCrash(bSecond) 344 c.advanceTime(time.Hour) 345 346 // Make sure we don't report crashes at other reporting stages. 347 crash := testCrash(build, 1) 348 crash.Title = `WARNING: a third, keep in moderation` // see the config in app_test.go 349 crash.GuiltyFiles = []string{"a.c"} 350 client.ReportCrash(crash) 351 client.pollBug() 352 c.advanceTime(time.Hour) 353 354 _, err := c.GET("/cron/subsystem_reports") 355 c.expectOK(err) 356 357 // Expect the reminder for subsystemA. 358 reply := client.pollEmailBug() 359 c.expectEQ(reply.Subject, "[moderation] Monthly subsystemA report (Jan 2000)") 360 c.expectEQ(reply.To, []string{"moderation@syzkaller.com"}) 361 c.expectEQ(reply.Cc, []string(nil)) 362 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 363 364 This is a 30-day syzbot report for the subsystemA subsystem. 365 All related reports/information can be found at: 366 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 367 368 During the period, 2 new issues were detected and 0 were fixed. 369 In total, 2 issues are still open. 370 371 Some of the still happening issues: 372 373 Ref Crashes Repro Title 374 <1> 4 No WARNING: a first 375 https://testapp.appspot.com/bug?extid=%[1]v 376 <2> 2 No WARNING: a second 377 https://testapp.appspot.com/bug?extid=%[2]v 378 379 The report will be sent to: [subsystemA@list.com subsystemA@person.com]. 380 381 --- 382 This report is generated by a bot. It may contain errors. 383 See https://goo.gl/tpsmEJ for more information about syzbot. 384 syzbot engineers can be reached at syzkaller@googlegroups.com. 385 386 To disable reminders for individual bugs, reply with the following command: 387 #syz set <Ref> no-reminders 388 389 To change bug's subsystems, reply with: 390 #syz set <Ref> subsystems: new-subsystem 391 392 If the report looks fine to you, reply with: 393 #syz upstream 394 395 To regenerate the report, reply with: 396 #syz regenerate 397 398 You may send multiple commands in a single email message. 399 `, bugToExtID["WARNING: a first"], bugToExtID["WARNING: a second"])) 400 401 // Expect the reminder for subsystemB. 402 reply = client.pollEmailBug() 403 c.expectEQ(reply.Subject, "[moderation] Monthly subsystemB report (Jan 2000)") 404 c.expectEQ(reply.To, []string{"moderation@syzkaller.com"}) 405 c.expectEQ(reply.Cc, []string(nil)) 406 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemB maintainers/developers, 407 408 This is a 30-day syzbot report for the subsystemB subsystem. 409 All related reports/information can be found at: 410 https://testapp.appspot.com/subsystem-reminders/s/subsystemB 411 412 During the period, 2 new issues were detected and 0 were fixed. 413 In total, 2 issues are still open. 414 415 Some of the still happening issues: 416 417 Ref Crashes Repro Title 418 <1> 6 No WARNING: b second 419 https://testapp.appspot.com/bug?extid=%[1]v 420 <2> 2 No WARNING: b first 421 https://testapp.appspot.com/bug?extid=%[2]v 422 423 The report will be sent to: [subsystemB@list.com subsystemB@person.com]. 424 425 --- 426 This report is generated by a bot. It may contain errors. 427 See https://goo.gl/tpsmEJ for more information about syzbot. 428 syzbot engineers can be reached at syzkaller@googlegroups.com. 429 430 To disable reminders for individual bugs, reply with the following command: 431 #syz set <Ref> no-reminders 432 433 To change bug's subsystems, reply with: 434 #syz set <Ref> subsystems: new-subsystem 435 436 If the report looks fine to you, reply with: 437 #syz upstream 438 439 To regenerate the report, reply with: 440 #syz regenerate 441 442 You may send multiple commands in a single email message. 443 `, bugToExtID["WARNING: b second"], bugToExtID["WARNING: b first"])) 444 445 // Wait the next pair of reminders. 446 c.advanceTime(time.Hour * 24 * 31) 447 _, err = c.GET("/cron/subsystem_reports") 448 c.expectOK(err) 449 } 450 451 func TestSubsystemRemindersModeration(t *testing.T) { 452 c := NewCtx(t) 453 defer c.Close() 454 455 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 456 build := testBuild(1) 457 client.UploadBuild(build) 458 bugToExtID := map[string]string{} 459 460 aFirst := testCrash(build, 1) 461 aFirst.Title = `WARNING: a first` 462 aFirst.GuiltyFiles = []string{"a.c"} 463 client.ReportCrash(aFirst) 464 bugToExtID[aFirst.Title] = client.pollEmailExtID() 465 c.advanceTime(time.Hour) 466 467 aSecond := testCrash(build, 1) 468 aSecond.Title = `WARNING: a second` 469 aSecond.GuiltyFiles = []string{"a.c"} 470 client.ReportCrash(aSecond) 471 bugToExtID[aSecond.Title] = client.pollEmailExtID() 472 c.advanceTime(time.Hour) 473 474 // Report them again. 475 c.advanceTime(time.Hour * 24 * 14) 476 client.ReportCrash(aFirst) 477 client.ReportCrash(aSecond) 478 479 _, err := c.GET("/cron/subsystem_reports") 480 c.expectOK(err) 481 482 // Expect the reminder for subsystemA. 483 replyA := client.pollEmailBug() 484 c.expectEQ(replyA.Subject, "[moderation] Monthly subsystemA report (Jan 2000)") 485 486 // Moderate the subsystemA list. 487 c.advanceTime(time.Hour) 488 c.incomingEmail(replyA.Sender, "#syz upstream\n") 489 // Also emulate the second email that would come from the mailing list. 490 // The email should be silently ignored. 491 c.incomingEmail(replyA.Sender, "#syz upstream\n", 492 EmailOptFrom("moderation@syzkaller.com"), EmailOptOrigFrom("user@user.com")) 493 494 // Expect the normal report. 495 reply := client.pollEmailBug() 496 c.expectEQ(reply.Subject, "[syzbot] Monthly subsystemA report (Jan 2000)") 497 c.expectEQ(reply.To, []string{"bugs@syzkaller.com", "subsystemA@list.com", "subsystemA@person.com"}) 498 c.expectEQ(reply.Cc, []string(nil)) 499 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 500 501 This is a 30-day syzbot report for the subsystemA subsystem. 502 All related reports/information can be found at: 503 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 504 505 During the period, 2 new issues were detected and 0 were fixed. 506 In total, 2 issues are still open. 507 508 Some of the still happening issues: 509 510 Ref Crashes Repro Title 511 <1> 2 No WARNING: a first 512 https://testapp.appspot.com/bug?extid=%[1]v 513 <2> 2 No WARNING: a second 514 https://testapp.appspot.com/bug?extid=%[2]v 515 516 --- 517 This report is generated by a bot. It may contain errors. 518 See https://goo.gl/tpsmEJ for more information about syzbot. 519 syzbot engineers can be reached at syzkaller@googlegroups.com. 520 521 To disable reminders for individual bugs, reply with the following command: 522 #syz set <Ref> no-reminders 523 524 To change bug's subsystems, reply with: 525 #syz set <Ref> subsystems: new-subsystem 526 527 You may send multiple commands in a single email message. 528 `, bugToExtID["WARNING: a first"], bugToExtID["WARNING: a second"])) 529 } 530 531 func TestSubsystemReportGeneration(t *testing.T) { 532 c := NewCtx(t) 533 defer c.Close() 534 535 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 536 build := testBuild(1) 537 client.UploadBuild(build) 538 bugToExtID := map[string]string{} 539 540 // This crash will be too old. 541 crash := testCrash(build, 1) 542 crash.Title = `WARNING: old crash` 543 crash.GuiltyFiles = []string{"a.c"} 544 client.ReportCrash(crash) 545 client.pollEmailBug() 546 c.advanceTime(time.Hour * 24 * 40) 547 548 // Emulate one fixed bug. 549 aFixed := testCrash(build, 1) 550 aFixed.Title = `WARNING: fixed bug` 551 aFixed.GuiltyFiles = []string{"a.c"} 552 client.ReportCrash(aFixed) 553 bugToExtID[aFixed.Title] = client.pollEmailExtID() 554 c.advanceTime(time.Hour) 555 updReply, _ := client.ReportingUpdate(&dashapi.BugUpdate{ 556 ID: bugToExtID[aFixed.Title], 557 Status: dashapi.BugStatusOpen, 558 FixCommits: []string{"foo: fix1"}, 559 }) 560 c.expectEQ(updReply.OK, true) 561 c.expectOK(client.UploadCommits([]dashapi.Commit{ 562 {Hash: "hash1", Title: "foo: fix1", Date: timeNow(c.ctx)}, 563 })) 564 565 allCrashes := []*dashapi.Crash{} 566 567 // Report 4 crashes with a reproducer. 568 var biggestReproCrash *dashapi.Crash 569 for i := 2; i <= 5; i++ { 570 crash := testCrash(build, 1) 571 crash.Title = fmt.Sprintf(`WARNING: has repro %d`, i+1) 572 crash.GuiltyFiles = []string{"a.c"} 573 client.ReportCrash(crash) 574 bugToExtID[crash.Title] = client.pollEmailExtID() 575 c.advanceTime(time.Hour) 576 577 crash.ReproOpts = []byte("some opts") 578 crash.ReproSyz = []byte("getpid()") 579 client.ReportCrash(crash) 580 client.pollEmailBug() 581 c.advanceTime(time.Hour) 582 583 for j := 3; j <= i; j++ { 584 client.ReportCrash(crash) 585 c.advanceTime(time.Hour) 586 } 587 allCrashes = append(allCrashes, crash) 588 biggestReproCrash = crash 589 } 590 591 // Report 5 crashes without a reproducer. 592 for i := 1; i <= 5; i++ { 593 crash := testCrash(build, 1) 594 crash.Title = fmt.Sprintf(`WARNING: no repro %d`, i+1) 595 crash.GuiltyFiles = []string{"a.c"} 596 client.ReportCrash(crash) 597 bugToExtID[crash.Title] = client.pollEmailExtID() 598 c.advanceTime(time.Hour) 599 600 for j := 2; j <= i; j++ { 601 client.ReportCrash(crash) 602 c.advanceTime(time.Hour) 603 } 604 allCrashes = append(allCrashes, crash) 605 } 606 607 c.advanceTime(time.Hour * 24 * 14) 608 for _, crash := range allCrashes { 609 client.ReportCrash(crash) 610 c.advanceTime(time.Hour) 611 } 612 613 // Now query the report. 614 _, err := c.GET("/cron/subsystem_reports") 615 c.expectOK(err) 616 617 reply := client.pollEmailBug() 618 c.expectEQ(reply.Subject, "[moderation] Monthly subsystemA report (Feb 2000)") 619 c.expectEQ(reply.To, []string{"moderation@syzkaller.com"}) 620 c.expectEQ(reply.Cc, []string(nil)) 621 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 622 623 This is a 30-day syzbot report for the subsystemA subsystem. 624 All related reports/information can be found at: 625 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 626 627 During the period, 9 new issues were detected and 1 were fixed. 628 In total, 10 issues are still open and 1 has been fixed so far. 629 630 Some of the still happening issues: 631 632 Ref Crashes Repro Title 633 <1> 6 Yes WARNING: has repro 6 634 https://testapp.appspot.com/bug?extid=%[1]v 635 <2> 6 No WARNING: no repro 6 636 https://testapp.appspot.com/bug?extid=%[2]v 637 <3> 5 Yes WARNING: has repro 5 638 https://testapp.appspot.com/bug?extid=%[3]v 639 <4> 5 No WARNING: no repro 5 640 https://testapp.appspot.com/bug?extid=%[4]v 641 <5> 4 Yes WARNING: has repro 4 642 https://testapp.appspot.com/bug?extid=%[5]v 643 <6> 3 Yes WARNING: has repro 3 644 https://testapp.appspot.com/bug?extid=%[6]v 645 646 The report will be sent to: [subsystemA@list.com subsystemA@person.com]. 647 648 --- 649 This report is generated by a bot. It may contain errors. 650 See https://goo.gl/tpsmEJ for more information about syzbot. 651 syzbot engineers can be reached at syzkaller@googlegroups.com. 652 653 To disable reminders for individual bugs, reply with the following command: 654 #syz set <Ref> no-reminders 655 656 To change bug's subsystems, reply with: 657 #syz set <Ref> subsystems: new-subsystem 658 659 If the report looks fine to you, reply with: 660 #syz upstream 661 662 To regenerate the report, reply with: 663 #syz regenerate 664 665 You may send multiple commands in a single email message. 666 `, 667 bugToExtID["WARNING: has repro 6"], 668 bugToExtID["WARNING: no repro 6"], 669 bugToExtID["WARNING: has repro 5"], 670 bugToExtID["WARNING: no repro 5"], 671 bugToExtID["WARNING: has repro 4"], 672 bugToExtID["WARNING: has repro 3"], 673 )) 674 675 // Add one more crash and regenerate. 676 client.ReportCrash(biggestReproCrash) 677 c.advanceTime(time.Hour) 678 679 c.incomingEmail(reply.Sender, "#syz regenerate\n") 680 c.advanceTime(time.Hour) 681 682 _, err = c.GET("/cron/subsystem_reports") 683 c.expectOK(err) 684 685 secondReply := client.pollEmailBug() 686 c.expectEQ(secondReply.Subject, "[moderation] Monthly subsystemA report (Feb 2000)") 687 c.expectNE(reply.Sender, secondReply.Sender) 688 c.expectTrue(strings.Contains(secondReply.Body, `7 Yes WARNING: has repro 6`)) 689 } 690 691 func TestSubsystemRemindersNoReport(t *testing.T) { 692 c := NewCtx(t) 693 defer c.Close() 694 695 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 696 build := testBuild(1) 697 client.UploadBuild(build) 698 699 cFirst := testCrash(build, 1) 700 cFirst.Title = `WARNING: c first` 701 cFirst.GuiltyFiles = []string{"c.c"} 702 client.ReportCrash(cFirst) 703 client.pollEmailBug() 704 c.advanceTime(time.Hour) 705 706 cSecond := testCrash(build, 1) 707 cSecond.Title = `WARNING: c second` 708 cSecond.GuiltyFiles = []string{"c.c"} 709 client.ReportCrash(cSecond) 710 client.pollEmailBug() 711 c.advanceTime(time.Hour) 712 713 // Report them again. 714 c.advanceTime(time.Hour * 24 * 14) 715 client.ReportCrash(cFirst) 716 client.ReportCrash(cSecond) 717 718 _, err := c.GET("/cron/subsystem_reports") 719 c.expectOK(err) 720 721 // Expect no reminders for subsystemC. 722 client.expectNoEmail() 723 } 724 725 // nolint: goconst 726 func TestNoRemindersWithDiscussions(t *testing.T) { 727 c := NewCtx(t) 728 defer c.Close() 729 730 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 731 build := testBuild(1) 732 client.UploadBuild(build) 733 734 bugToExtID := map[string]string{} 735 736 // WARNING: a first 737 aFirst := testCrash(build, 1) 738 aFirst.Title = `WARNING: a first` 739 aFirst.GuiltyFiles = []string{"a.c"} 740 client.ReportCrash(aFirst) 741 bugToExtID[aFirst.Title] = client.pollEmailExtID() 742 c.advanceTime(time.Hour) 743 744 // WARNING: a second (1 crash) 745 aSecond := testCrash(build, 1) 746 aSecond.Title = `WARNING: a second` 747 aSecond.GuiltyFiles = []string{"a.c"} 748 client.ReportCrash(aSecond) 749 bugToExtID[aSecond.Title] = client.pollEmailExtID() 750 c.advanceTime(time.Hour) 751 752 // WARNING: a third (1 crash) 753 aThird := testCrash(build, 1) 754 aThird.Title = `WARNING: a third` 755 aThird.GuiltyFiles = []string{"a.c"} 756 client.ReportCrash(aThird) 757 bugToExtID[aThird.Title] = client.pollEmailExtID() 758 c.advanceTime(time.Hour) 759 760 // Report bugs once more to pretend they're still valid. 761 c.advanceTime(time.Hour * 24 * 10) 762 client.ReportCrash(aFirst) 763 client.ReportCrash(aSecond) 764 client.ReportCrash(aThird) 765 766 // Add a recent discussion to the second bug. 767 c.expectOK(client.SaveDiscussion(&dashapi.SaveDiscussionReq{ 768 Discussion: &dashapi.Discussion{ 769 ID: "123", 770 Source: dashapi.DiscussionLore, 771 Type: dashapi.DiscussionReport, 772 Subject: "Some discussion", 773 BugIDs: []string{bugToExtID[aSecond.Title]}, 774 Messages: []dashapi.DiscussionMessage{ 775 { 776 ID: "123", 777 External: true, 778 Time: timeNow(c.ctx), 779 }, 780 }, 781 }, 782 })) 783 c.advanceTime(time.Hour) 784 785 _, err := c.GET("/cron/subsystem_reports") 786 c.expectOK(err) 787 788 reply := client.pollEmailBug() 789 // Verify that the second bug is not present. 790 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 791 792 This is a 30-day syzbot report for the subsystemA subsystem. 793 All related reports/information can be found at: 794 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 795 796 During the period, 3 new issues were detected and 0 were fixed. 797 In total, 3 issues are still open. 798 799 Some of the still happening issues: 800 801 Ref Crashes Repro Title 802 <1> 2 No WARNING: a first 803 https://testapp.appspot.com/bug?extid=%[1]v 804 <2> 2 No WARNING: a third 805 https://testapp.appspot.com/bug?extid=%[2]v 806 807 The report will be sent to: [subsystemA@list.com subsystemA@person.com]. 808 809 --- 810 This report is generated by a bot. It may contain errors. 811 See https://goo.gl/tpsmEJ for more information about syzbot. 812 syzbot engineers can be reached at syzkaller@googlegroups.com. 813 814 To disable reminders for individual bugs, reply with the following command: 815 #syz set <Ref> no-reminders 816 817 To change bug's subsystems, reply with: 818 #syz set <Ref> subsystems: new-subsystem 819 820 If the report looks fine to you, reply with: 821 #syz upstream 822 823 To regenerate the report, reply with: 824 #syz regenerate 825 826 You may send multiple commands in a single email message. 827 `, bugToExtID["WARNING: a first"], bugToExtID["WARNING: a third"])) 828 } 829 830 // nolint: goconst 831 func TestSkipSubsystemReminders(t *testing.T) { 832 c := NewCtx(t) 833 defer c.Close() 834 835 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 836 build := testBuild(1) 837 client.UploadBuild(build) 838 839 bugToExtID := map[string]string{} 840 841 // WARNING: a first 842 aFirst := testCrash(build, 1) 843 aFirst.Title = `WARNING: a first` 844 aFirst.GuiltyFiles = []string{"a.c"} 845 client.ReportCrash(aFirst) 846 bugToExtID[aFirst.Title] = client.pollEmailExtID() 847 c.advanceTime(time.Hour) 848 849 // WARNING: a second (1 crash) 850 aSecond := testCrash(build, 1) 851 aSecond.Title = `WARNING: a second` 852 aSecond.GuiltyFiles = []string{"a.c"} 853 client.ReportCrash(aSecond) 854 bugToExtID[aSecond.Title] = client.pollEmailExtID() 855 c.advanceTime(time.Hour) 856 857 // WARNING: a third (1 crash) 858 aThird := testCrash(build, 1) 859 aThird.Title = `WARNING: a third` 860 aThird.GuiltyFiles = []string{"a.c"} 861 client.ReportCrash(aThird) 862 bugToExtID[aThird.Title] = client.pollEmailExtID() 863 c.advanceTime(time.Hour) 864 865 // WARNING: a fourth (1 crash) 866 aFourth := testCrash(build, 1) 867 aFourth.Title = `WARNING: a fourth` 868 aFourth.GuiltyFiles = []string{"a.c"} 869 client.ReportCrash(aFourth) 870 bugToExtID[aFourth.Title] = client.pollEmailExtID() 871 c.advanceTime(time.Hour) 872 873 // Report bugs once more to pretend they're still valid. 874 c.advanceTime(time.Hour * 24 * 14) 875 client.ReportCrash(aFirst) 876 client.ReportCrash(aSecond) 877 client.ReportCrash(aThird) 878 client.ReportCrash(aFourth) 879 c.advanceTime(time.Hour) 880 881 _, err := c.GET("/cron/subsystem_reports") 882 c.expectOK(err) 883 884 // Expect the reminder for subsystemA. 885 reply := client.pollEmailBug() 886 c.expectEQ(reply.Subject, "[moderation] Monthly subsystemA report (Jan 2000)") 887 c.expectEQ(reply.To, []string{"moderation@syzkaller.com"}) 888 c.expectEQ(reply.Cc, []string(nil)) 889 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 890 891 This is a 30-day syzbot report for the subsystemA subsystem. 892 All related reports/information can be found at: 893 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 894 895 During the period, 4 new issues were detected and 0 were fixed. 896 In total, 4 issues are still open. 897 898 Some of the still happening issues: 899 900 Ref Crashes Repro Title 901 <1> 2 No WARNING: a first 902 https://testapp.appspot.com/bug?extid=%[1]v 903 <2> 2 No WARNING: a fourth 904 https://testapp.appspot.com/bug?extid=%[4]v 905 <3> 2 No WARNING: a second 906 https://testapp.appspot.com/bug?extid=%[2]v 907 <4> 2 No WARNING: a third 908 https://testapp.appspot.com/bug?extid=%[3]v 909 910 The report will be sent to: [subsystemA@list.com subsystemA@person.com]. 911 912 --- 913 This report is generated by a bot. It may contain errors. 914 See https://goo.gl/tpsmEJ for more information about syzbot. 915 syzbot engineers can be reached at syzkaller@googlegroups.com. 916 917 To disable reminders for individual bugs, reply with the following command: 918 #syz set <Ref> no-reminders 919 920 To change bug's subsystems, reply with: 921 #syz set <Ref> subsystems: new-subsystem 922 923 If the report looks fine to you, reply with: 924 #syz upstream 925 926 To regenerate the report, reply with: 927 #syz regenerate 928 929 You may send multiple commands in a single email message. 930 `, bugToExtID["WARNING: a first"], bugToExtID["WARNING: a second"], 931 bugToExtID["WARNING: a third"], bugToExtID["WARNING: a fourth"])) 932 933 c.incomingEmail(reply.Sender, `> In total, 4 issues are still open. 934 > 935 > Some of the still happening issues: 936 > 937 > Ref Crashes Repro Title 938 > <1> 2 No WARNING: a first 939 > https://testapp.appspot.com/bug?extid=%[1]v 940 > <2> 2 No WARNING: a fourth 941 > https://testapp.appspot.com/bug?extid=%[4]v 942 #syz set <2> no-reminders 943 > <3> 2 No WARNING: a second 944 > https://testapp.appspot.com/bug?extid=%[2]v 945 > <4> 2 No WARNING: a third 946 > https://testapp.appspot.com/bug?extid=%[3]v 947 #syz set <4> no-reminders 948 `) 949 950 // Prepare for the next monthly report. 951 c.advanceTime(time.Hour * 24 * 31) 952 client.ReportCrash(aFirst) 953 client.ReportCrash(aSecond) 954 client.ReportCrash(aThird) 955 client.ReportCrash(aFourth) 956 c.advanceTime(time.Hour) 957 958 _, err = c.GET("/cron/subsystem_reports") 959 c.expectOK(err) 960 961 reply = client.pollEmailBug() 962 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 963 964 This is a 30-day syzbot report for the subsystemA subsystem. 965 All related reports/information can be found at: 966 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 967 968 During the period, 0 new issues were detected and 0 were fixed. 969 In total, 4 issues are still open. 970 971 Some of the still happening issues: 972 973 Ref Crashes Repro Title 974 <1> 3 No WARNING: a first 975 https://testapp.appspot.com/bug?extid=%[1]v 976 <2> 3 No WARNING: a second 977 https://testapp.appspot.com/bug?extid=%[2]v 978 979 The report will be sent to: [subsystemA@list.com subsystemA@person.com]. 980 981 --- 982 This report is generated by a bot. It may contain errors. 983 See https://goo.gl/tpsmEJ for more information about syzbot. 984 syzbot engineers can be reached at syzkaller@googlegroups.com. 985 986 To disable reminders for individual bugs, reply with the following command: 987 #syz set <Ref> no-reminders 988 989 To change bug's subsystems, reply with: 990 #syz set <Ref> subsystems: new-subsystem 991 992 If the report looks fine to you, reply with: 993 #syz upstream 994 995 To regenerate the report, reply with: 996 #syz regenerate 997 998 You may send multiple commands in a single email message. 999 `, bugToExtID["WARNING: a first"], bugToExtID["WARNING: a second"])) 1000 } 1001 1002 // nolint: goconst 1003 func TestRemindersPriority(t *testing.T) { 1004 c := NewCtx(t) 1005 defer c.Close() 1006 1007 client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true) 1008 cc := EmailOptCC([]string{"bugs@syzkaller.com", "default@maintainers.com"}) 1009 build := testBuild(1) 1010 client.UploadBuild(build) 1011 1012 // WARNING: a first, low prio, has repro 1013 aFirst := testCrash(build, 1) 1014 aFirst.Title = `WARNING: a first` 1015 aFirst.GuiltyFiles = []string{"a.c"} 1016 aFirst.ReproOpts = []byte("some opts") 1017 aFirst.ReproSyz = []byte("getpid()") 1018 client.ReportCrash(aFirst) 1019 sender, firstExtID := client.pollEmailAndExtID() 1020 c.incomingEmail(sender, "#syz set prio: low\n", 1021 EmailOptFrom("test@requester.com"), cc) 1022 c.advanceTime(time.Hour) 1023 1024 // WARNING: a second, normal prio 1025 aSecond := testCrash(build, 1) 1026 aSecond.Title = `WARNING: a second` 1027 aSecond.GuiltyFiles = []string{"a.c"} 1028 client.ReportCrash(aSecond) 1029 secondExtID := client.pollEmailExtID() 1030 c.advanceTime(time.Hour) 1031 1032 // WARNING: a third, high prio 1033 aThird := testCrash(build, 1) 1034 aThird.Title = `WARNING: a third` 1035 aThird.GuiltyFiles = []string{"a.c"} 1036 client.ReportCrash(aThird) 1037 sender, thirdExtID := client.pollEmailAndExtID() 1038 c.incomingEmail(sender, "#syz set prio: high\n", 1039 EmailOptFrom("test@requester.com"), cc) 1040 c.advanceTime(time.Hour) 1041 1042 // Report bugs once more to pretend they're still valid. 1043 c.advanceTime(time.Hour * 24 * 10) 1044 client.ReportCrash(aFirst) 1045 client.ReportCrash(aSecond) 1046 client.ReportCrash(aThird) 1047 1048 _, err := c.GET("/cron/subsystem_reports") 1049 c.expectOK(err) 1050 1051 reply := client.pollEmailBug() 1052 // Verify that the second bug is not present. 1053 c.expectEQ(reply.Body, fmt.Sprintf(`Hello subsystemA maintainers/developers, 1054 1055 This is a 30-day syzbot report for the subsystemA subsystem. 1056 All related reports/information can be found at: 1057 https://testapp.appspot.com/subsystem-reminders/s/subsystemA 1058 1059 During the period, 2 new issues were detected and 0 were fixed. 1060 In total, 2 issues are still open. 1061 There is also 1 low-priority issue. 1062 1063 Some of the still happening issues: 1064 1065 Ref Crashes Repro Title 1066 <1> 2 No WARNING: a third 1067 https://testapp.appspot.com/bug?extid=%[1]v 1068 <2> 2 No WARNING: a second 1069 https://testapp.appspot.com/bug?extid=%[2]v 1070 1071 The report will be sent to: [subsystemA@list.com subsystemA@person.com]. 1072 1073 --- 1074 This report is generated by a bot. It may contain errors. 1075 See https://goo.gl/tpsmEJ for more information about syzbot. 1076 syzbot engineers can be reached at syzkaller@googlegroups.com. 1077 1078 To disable reminders for individual bugs, reply with the following command: 1079 #syz set <Ref> no-reminders 1080 1081 To change bug's subsystems, reply with: 1082 #syz set <Ref> subsystems: new-subsystem 1083 1084 If the report looks fine to you, reply with: 1085 #syz upstream 1086 1087 To regenerate the report, reply with: 1088 #syz regenerate 1089 1090 You may send multiple commands in a single email message. 1091 `, thirdExtID, secondExtID, firstExtID)) 1092 }