blob: b6614d3ffc6bdb77c52f56ae94c0e15f0de06966 [file] [log] [blame]
// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// +build aetest
package dash
import (
"bytes"
"fmt"
"strings"
"testing"
"github.com/google/syzkaller/dashboard/dashapi"
"github.com/google/syzkaller/pkg/email"
)
func TestJob(t *testing.T) {
c := NewCtx(t)
defer c.Close()
build := testBuild(1)
c.client2.UploadBuild(build)
patch := `--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
- current->kasan_depth++;
+ current->kasan_depth--;
`
// Report crash without repro, check that test requests are not accepted.
crash := testCrash(build, 1)
crash.Maintainers = []string{"maintainer@kernel.org"}
c.client2.ReportCrash(crash)
sender := c.pollEmailBug().Sender
c.incomingEmail(sender, "#syz upstream\n")
sender = c.pollEmailBug().Sender
_, extBugID, err := email.RemoveAddrContext(sender)
c.expectOK(err)
mailingList := config.Namespaces["test2"].Reporting[1].Config.(*EmailConfig).Email
c.incomingEmail(sender, "bla-bla-bla", EmailOptFrom("maintainer@kernel.org"),
EmailOptCC([]string{mailingList, "kernel@mailing.list"}))
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
body := c.pollEmailBug().Body
c.expectEQ(strings.Contains(body, "This crash does not have a reproducer"), true)
// Report crash with repro.
crash.ReproOpts = []byte("repro opts")
crash.ReproSyz = []byte("repro syz")
crash.ReproC = []byte("repro C")
c.client2.ReportCrash(crash)
c.client2.pollAndFailBisectJob(build.Manager)
body = c.pollEmailBug().Body
c.expectEQ(strings.Contains(body, "syzbot has found a reproducer"), true)
c.incomingEmail(sender, "#syz test: repo",
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
body = c.pollEmailBug().Body
c.expectEQ(strings.Contains(body, "want 2 args"), true)
c.incomingEmail(sender, "#syz test: repo branch commit",
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
body = c.pollEmailBug().Body
c.expectEQ(strings.Contains(body, "want 2 args"), true)
c.incomingEmail(sender, "#syz test: repo branch",
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
body = c.pollEmailBug().Body
c.expectEQ(strings.Contains(body, "does not look like a valid git repo"), true)
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptFrom("\"foo\" <blAcklisteD@dOmain.COM>"))
c.expectNoEmail()
pollResp := c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.ID, "")
// This submits actual test request.
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptMessageID(1), EmailOptFrom("test@requester.com"),
EmailOptCC([]string{"somebody@else.com"}))
c.expectNoEmail()
// A dup of the same request with the same Message-ID.
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch,
EmailOptMessageID(1), EmailOptFrom("test@requester.com"),
EmailOptCC([]string{"somebody@else.com"}))
c.expectNoEmail()
pollResp = c.client2.pollJobs("foobar")
c.expectEQ(pollResp.ID, "")
pollResp = c.client2.pollJobs(build.Manager)
c.expectNE(pollResp.ID, "")
c.expectEQ(pollResp.Type, dashapi.JobTestPatch)
c.expectEQ(pollResp.Manager, build.Manager)
c.expectEQ(pollResp.KernelRepo, "git://git.git/git.git")
c.expectEQ(pollResp.KernelBranch, "kernel-branch")
c.expectEQ(pollResp.KernelConfig, build.KernelConfig)
c.expectEQ(pollResp.SyzkallerCommit, build.SyzkallerCommit)
c.expectEQ(pollResp.Patch, []byte(patch))
c.expectEQ(pollResp.ReproOpts, []byte("repro opts"))
c.expectEQ(pollResp.ReproSyz, []byte("repro syz"))
c.expectEQ(pollResp.ReproC, []byte("repro C"))
pollResp2 := c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp2, pollResp)
jobDoneReq := &dashapi.JobDoneReq{
ID: pollResp.ID,
Build: *build,
CrashTitle: "test crash title",
CrashLog: []byte("test crash log"),
CrashReport: []byte("test crash report"),
}
c.client2.JobDone(jobDoneReq)
{
dbJob, dbBuild, _ := c.loadJob(pollResp.ID)
patchLink := externalLink(c.ctx, textPatch, dbJob.Patch)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
logLink := externalLink(c.ctx, textCrashLog, dbJob.CrashLog)
msg := c.pollEmailBug()
to := email.MergeEmailLists([]string{"test@requester.com", "somebody@else.com", mailingList})
c.expectEQ(msg.To, to)
c.expectEQ(msg.Subject, "Re: "+crash.Title)
c.expectEQ(len(msg.Attachments), 0)
c.expectEQ(msg.Body, fmt.Sprintf(`Hello,
syzbot has tested the proposed patch but the reproducer still triggered crash:
test crash title
test crash report
Tested on:
commit: 11111111 kernel_commit_title1
git tree: repo1 branch1
console output: %[3]v
kernel config: %[2]v
compiler: compiler1
patch: %[1]v
`, patchLink, kernelConfigLink, logLink))
c.checkURLContents(patchLink, []byte(patch))
c.checkURLContents(kernelConfigLink, build.KernelConfig)
c.checkURLContents(logLink, jobDoneReq.CrashLog)
}
// Testing fails with an error.
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch, EmailOptMessageID(2))
pollResp = c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.Type, dashapi.JobTestPatch)
jobDoneReq = &dashapi.JobDoneReq{
ID: pollResp.ID,
Build: *build,
Error: []byte("failed to apply patch"),
}
c.client2.JobDone(jobDoneReq)
{
dbJob, dbBuild, _ := c.loadJob(pollResp.ID)
patchLink := externalLink(c.ctx, textPatch, dbJob.Patch)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
c.expectEQ(msg.Body, fmt.Sprintf(`Hello,
syzbot tried to test the proposed patch but build/boot failed:
failed to apply patch
Tested on:
commit: 11111111 kernel_commit_title1
git tree: repo1 branch1
kernel config: %[2]v
compiler: compiler1
patch: %[1]v
`, patchLink, kernelConfigLink))
c.checkURLContents(patchLink, []byte(patch))
c.checkURLContents(kernelConfigLink, build.KernelConfig)
}
// Testing fails with a huge error that can't be inlined in email.
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch, EmailOptMessageID(3))
pollResp = c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.Type, dashapi.JobTestPatch)
jobDoneReq = &dashapi.JobDoneReq{
ID: pollResp.ID,
Build: *build,
Error: bytes.Repeat([]byte{'a', 'b', 'c'}, (maxInlineError+100)/3),
}
c.client2.JobDone(jobDoneReq)
{
dbJob, dbBuild, _ := c.loadJob(pollResp.ID)
patchLink := externalLink(c.ctx, textPatch, dbJob.Patch)
errorLink := externalLink(c.ctx, textError, dbJob.Error)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
truncatedError := string(jobDoneReq.Error[len(jobDoneReq.Error)-maxInlineError:])
c.expectEQ(msg.Body, fmt.Sprintf(`Hello,
syzbot tried to test the proposed patch but build/boot failed:
%[1]v
Error text is too large and was truncated, full error text is at:
%[2]v
Tested on:
commit: 11111111 kernel_commit_title1
git tree: repo1 branch1
kernel config: %[4]v
compiler: compiler1
patch: %[3]v
`, truncatedError, errorLink, patchLink, kernelConfigLink))
c.checkURLContents(patchLink, []byte(patch))
c.checkURLContents(errorLink, jobDoneReq.Error)
c.checkURLContents(kernelConfigLink, build.KernelConfig)
}
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+patch, EmailOptMessageID(4))
pollResp = c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.Type, dashapi.JobTestPatch)
jobDoneReq = &dashapi.JobDoneReq{
ID: pollResp.ID,
Build: *build,
}
c.client2.JobDone(jobDoneReq)
{
dbJob, dbBuild, _ := c.loadJob(pollResp.ID)
patchLink := externalLink(c.ctx, textPatch, dbJob.Patch)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
c.expectEQ(msg.Body, fmt.Sprintf(`Hello,
syzbot has tested the proposed patch and the reproducer did not trigger crash:
Reported-and-tested-by: syzbot+%v@testapp.appspotmail.com
Tested on:
commit: 11111111 kernel_commit_title1
git tree: repo1 branch1
kernel config: %[3]v
compiler: compiler1
patch: %[2]v
Note: testing is done by a robot and is best-effort only.
`, extBugID, patchLink, kernelConfigLink))
c.checkURLContents(patchLink, []byte(patch))
c.checkURLContents(kernelConfigLink, build.KernelConfig)
}
pollResp = c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.ID, "")
}
// Test on particular commit and without a patch.
func TestJobWithoutPatch(t *testing.T) {
c := NewCtx(t)
defer c.Close()
build := testBuild(1)
c.client2.UploadBuild(build)
crash := testCrash(build, 1)
crash.ReproOpts = []byte("repro opts")
crash.ReproSyz = []byte("repro syz")
c.client2.ReportCrash(crash)
c.client2.pollAndFailBisectJob(build.Manager)
sender := c.pollEmailBug().Sender
_, extBugID, err := email.RemoveAddrContext(sender)
c.expectOK(err)
c.incomingEmail(sender, "#syz test git://mygit.com/git.git 5e6a2eea\n", EmailOptMessageID(1))
pollResp := c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.Type, dashapi.JobTestPatch)
testBuild := testBuild(2)
testBuild.KernelRepo = "git://mygit.com/git.git"
testBuild.KernelBranch = ""
testBuild.KernelCommit = "5e6a2eea5e6a2eea5e6a2eea5e6a2eea5e6a2eea"
jobDoneReq := &dashapi.JobDoneReq{
ID: pollResp.ID,
Build: *testBuild,
}
c.client2.JobDone(jobDoneReq)
{
_, dbBuild, _ := c.loadJob(pollResp.ID)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
c.expectEQ(msg.Body, fmt.Sprintf(`Hello,
syzbot has tested the proposed patch and the reproducer did not trigger crash:
Reported-and-tested-by: syzbot+%v@testapp.appspotmail.com
Tested on:
commit: 5e6a2eea kernel_commit_title2
git tree: git://mygit.com/git.git
kernel config: %[2]v
compiler: compiler2
Note: testing is done by a robot and is best-effort only.
`, extBugID, kernelConfigLink))
c.checkURLContents(kernelConfigLink, testBuild.KernelConfig)
}
pollResp = c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.ID, "")
}
// Test on a restricted manager.
func TestJobRestrictedManager(t *testing.T) {
c := NewCtx(t)
defer c.Close()
build := testBuild(1)
build.Manager = "restricted-manager"
c.client2.UploadBuild(build)
crash := testCrash(build, 1)
crash.ReproSyz = []byte("repro syz")
c.client2.ReportCrash(crash)
c.client2.pollAndFailBisectJob(build.Manager)
sender := c.pollEmailBug().Sender
// Testing on a wrong repo must fail and no test jobs passed to manager.
c.incomingEmail(sender, "#syz test: git://mygit.com/git.git master\n", EmailOptMessageID(1))
c.expectEQ(strings.Contains((<-c.emailSink).Body, "you should test only on restricted.git"), true)
pollResp := c.client2.pollJobs(build.Manager)
c.expectEQ(pollResp.ID, "")
// Testing on the right repo must succeed.
c.incomingEmail(sender, "#syz test: git://restricted.git/restricted.git master\n", EmailOptMessageID(2))
pollResp = c.client2.pollJobs(build.Manager)
c.expectNE(pollResp.ID, "")
c.expectEQ(pollResp.Type, dashapi.JobTestPatch)
c.expectEQ(pollResp.Manager, build.Manager)
c.expectEQ(pollResp.KernelRepo, "git://restricted.git/restricted.git")
}