aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-03-12 12:08:00 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-03-17 18:06:44 +0100
commit5958caeafcf3d467009ae984a9be8302bf852a50 (patch)
treefd0b1feed504a760374e5c0792178a2520792277
parente5207950cab65477fe2d63834abacd43df7d0f23 (diff)
dashboard/app: modernize tests
Use expectOK for checking errors more. Use pollEmailBug helper more. Add expectNE and use it.
-rw-r--r--dashboard/app/access_test.go12
-rw-r--r--dashboard/app/app_test.go8
-rw-r--r--dashboard/app/email_test.go56
-rw-r--r--dashboard/app/jobs_test.go71
-rw-r--r--dashboard/app/notifications_test.go8
-rw-r--r--dashboard/app/reporting_test.go34
-rw-r--r--dashboard/app/util_test.go12
7 files changed, 63 insertions, 138 deletions
diff --git a/dashboard/app/access_test.go b/dashboard/app/access_test.go
index c02ea1d63..c331fa242 100644
--- a/dashboard/app/access_test.go
+++ b/dashboard/app/access_test.go
@@ -73,13 +73,9 @@ func TestAccess(t *testing.T) {
// noteBugAccessLevel collects all entities associated with the extID bug.
noteBugAccessLevel := func(extID string, level AccessLevel) {
bug, _, err := findBugByReportingID(c.ctx, extID)
- if err != nil {
- t.Fatal(err)
- }
+ c.expectOK(err)
crash, _, err := findCrashForBug(c.ctx, bug)
- if err != nil {
- t.Fatal(err)
- }
+ c.expectOK(err)
bugID := bug.keyHash()
entities = append(entities, []entity{
{
@@ -147,9 +143,7 @@ func TestAccess(t *testing.T) {
// noteBuildccessLevel collects all entities associated with the kernel build buildID.
noteBuildccessLevel := func(ns, buildID string) {
build, err := loadBuild(c.ctx, ns, buildID)
- if err != nil {
- t.Fatal(err)
- }
+ c.expectOK(err)
entities = append(entities, entity{
level: config.Namespaces[ns].AccessLevel,
ref: build.ID,
diff --git a/dashboard/app/app_test.go b/dashboard/app/app_test.go
index 3987b024d..851410722 100644
--- a/dashboard/app/app_test.go
+++ b/dashboard/app/app_test.go
@@ -368,9 +368,7 @@ func TestPurgeOldCrashes(t *testing.T) {
}
bug, _, _ := c.loadBug(rep.ID)
crashes, _, err := queryCrashesForBug(c.ctx, bug.key(c.ctx), 10*totalReported)
- if err != nil {
- c.t.Fatal(err)
- }
+ c.expectOK(err)
// First, count how many crashes of different types we have.
// We should get all 3 reported crashes + some with repros and some without repros.
reported, norepro, repro := 0, 0, 0
@@ -396,9 +394,7 @@ func TestPurgeOldCrashes(t *testing.T) {
continue
}
idx, err := strconv.Atoi(string(crash.ReproOpts))
- if err != nil {
- c.t.Fatal(err)
- }
+ c.expectOK(err)
count := norepro
if crash.ReproSyz != 0 {
count = repro
diff --git a/dashboard/app/email_test.go b/dashboard/app/email_test.go
index 1fd6a81e8..012e50f12 100644
--- a/dashboard/app/email_test.go
+++ b/dashboard/app/email_test.go
@@ -28,15 +28,11 @@ func TestEmailReport(t *testing.T) {
// Report the crash over email and check all fields.
var sender0, extBugID0, body0 string
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
sender0 = msg.Sender
body0 = msg.Body
sender, extBugID, err := email.RemoveAddrContext(msg.Sender)
- if err != nil {
- t.Fatalf("failed to remove sender context: %v", err)
- }
+ c.expectOK(err)
extBugID0 = extBugID
_, dbCrash, dbBuild := c.loadBug(extBugID0)
crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log)
@@ -129,14 +125,10 @@ For more options, visit https://groups.google.com/d/optout.
c.client2.ReportCrash(crash)
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(msg.Sender, sender0)
sender, _, err := email.RemoveAddrContext(msg.Sender)
- if err != nil {
- t.Fatalf("failed to remove sender context: %v", err)
- }
+ c.expectOK(err)
_, dbCrash, dbBuild := c.loadBug(extBugID0)
reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz)
crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log)
@@ -181,17 +173,11 @@ report1
sender1, extBugID1 := "", ""
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
sender1 = msg.Sender
- if sender1 == sender0 {
- t.Fatalf("same ID in different reporting")
- }
+ c.expectNE(sender1, sender0)
sender, extBugID, err := email.RemoveAddrContext(msg.Sender)
- if err != nil {
- t.Fatalf("failed to remove sender context: %v", err)
- }
+ c.expectOK(err)
extBugID1 = extBugID
_, dbCrash, dbBuild := c.loadBug(extBugID1)
reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz)
@@ -260,14 +246,10 @@ Content-Type: text/plain
c.client2.ReportCrash(crash)
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(msg.Sender, sender1)
sender, _, err := email.RemoveAddrContext(msg.Sender)
- if err != nil {
- t.Fatalf("failed to remove sender context: %v", err)
- }
+ c.expectOK(err)
_, dbCrash, dbBuild := c.loadBug(extBugID1)
reproCLink := externalLink(c.ctx, textReproC, dbCrash.ReproC)
reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz)
@@ -321,9 +303,7 @@ Content-Type: text/plain
c.expectOK(c.POST("/_ah/mail/", incoming4))
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(msg.To, []string{"<foo@bar.com>"})
c.expectEQ(msg.Subject, "Re: title1")
c.expectEQ(msg.Headers["In-Reply-To"], []string{"<abcdef>"})
@@ -358,13 +338,9 @@ unknown command "bad-command"
// New crash must produce new bug in the first reporting.
c.client2.ReportCrash(crash)
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(msg.Subject, crash.Title+" (2)")
- if msg.Sender == sender0 {
- t.Fatalf("same reporting ID for new bug")
- }
+ c.expectNE(msg.Sender, sender0)
}
}
@@ -379,9 +355,7 @@ func TestEmailNoMaintainers(t *testing.T) {
crash := testCrash(build, 1)
c.client2.ReportCrash(crash)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- sender := (<-c.emailSink).Sender
+ sender := c.pollEmailBug().Sender
incoming1 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com
Date: Tue, 15 Aug 2017 14:59:00 -0700
@@ -437,9 +411,7 @@ func TestEmailDup(t *testing.T) {
// New crash must produce new bug in the first reporting.
c.client2.ReportCrash(crash2)
{
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(msg.Subject, crash2.Title+" (2)")
}
}
diff --git a/dashboard/app/jobs_test.go b/dashboard/app/jobs_test.go
index 66d7b399f..70dc8acb3 100644
--- a/dashboard/app/jobs_test.go
+++ b/dashboard/app/jobs_test.go
@@ -33,25 +33,19 @@ func TestJob(t *testing.T) {
crash.Maintainers = []string{"maintainer@kernel.org"}
c.client2.ReportCrash(crash)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- sender := (<-c.emailSink).Sender
+ sender := c.pollEmailBug().Sender
c.incomingEmail(sender, "#syz upstream\n")
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- sender = (<-c.emailSink).Sender
+ sender = c.pollEmailBug().Sender
_, extBugID, err := email.RemoveAddrContext(sender)
- if err != nil {
- t.Fatal(err)
- }
+ 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}))
- c.expectEQ(len(c.emailSink), 1)
- c.expectEQ(strings.Contains((<-c.emailSink).Body, "This crash does not have a reproducer"), true)
+ 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")
@@ -59,24 +53,23 @@ func TestJob(t *testing.T) {
crash.ReproC = []byte("repro C")
c.client2.ReportCrash(crash)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- c.expectEQ(strings.Contains((<-c.emailSink).Body, "syzbot has found a reproducer"), true)
+ 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}))
- c.expectEQ(len(c.emailSink), 1)
- c.expectEQ(strings.Contains((<-c.emailSink).Body, "want 2 args"), true)
+ 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}))
- c.expectEQ(len(c.emailSink), 1)
- c.expectEQ(strings.Contains((<-c.emailSink).Body, "want 2 args"), true)
+ 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}))
- c.expectEQ(len(c.emailSink), 1)
- c.expectEQ(strings.Contains((<-c.emailSink).Body, "does not look like a valid git repo"), true)
+ 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>"))
@@ -102,7 +95,7 @@ func TestJob(t *testing.T) {
pollResp, _ = c.client2.JobPoll([]string{"foobar"})
c.expectEQ(pollResp.ID, "")
pollResp, _ = c.client2.JobPoll([]string{build.Manager})
- c.expectEQ(pollResp.ID != "", true)
+ c.expectNE(pollResp.ID, "")
c.expectEQ(pollResp.Manager, build.Manager)
c.expectEQ(pollResp.KernelRepo, "git://git.git/git.git")
c.expectEQ(pollResp.KernelBranch, "kernel-branch")
@@ -125,14 +118,12 @@ func TestJob(t *testing.T) {
}
c.client2.JobDone(jobDoneReq)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
{
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.emailSink
+ 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)
@@ -171,13 +162,11 @@ patch: %[1]v
Error: []byte("failed to apply patch"),
}
c.client2.JobDone(jobDoneReq)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
{
dbJob, dbBuild := c.loadJob(pollResp.ID)
patchLink := externalLink(c.ctx, textPatch, dbJob.Patch)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
body := fmt.Sprintf(`Hello,
@@ -211,14 +200,12 @@ patch: %[1]v
Error: bytes.Repeat([]byte{'a', 'b', 'c'}, (maxInlineError+100)/3),
}
c.client2.JobDone(jobDoneReq)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
{
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.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
truncatedError := string(jobDoneReq.Error[len(jobDoneReq.Error)-maxInlineError:])
body := fmt.Sprintf(`Hello,
@@ -255,13 +242,11 @@ patch: %[3]v
Build: *build,
}
c.client2.JobDone(jobDoneReq)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
{
dbJob, dbBuild := c.loadJob(pollResp.ID)
patchLink := externalLink(c.ctx, textPatch, dbJob.Patch)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
body := fmt.Sprintf(`Hello,
@@ -302,14 +287,9 @@ func TestJobWithoutPatch(t *testing.T) {
crash.ReproOpts = []byte("repro opts")
crash.ReproSyz = []byte("repro syz")
c.client2.ReportCrash(crash)
-
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- sender := (<-c.emailSink).Sender
+ sender := c.pollEmailBug().Sender
_, extBugID, err := email.RemoveAddrContext(sender)
- if err != nil {
- t.Fatal(err)
- }
+ c.expectOK(err)
c.incomingEmail(sender, "#syz test: git://mygit.com/git.git 5e6a2eea\n", EmailOptMessageID(1))
pollResp, _ := c.client2.JobPoll([]string{build.Manager})
@@ -322,12 +302,10 @@ func TestJobWithoutPatch(t *testing.T) {
Build: *testBuild,
}
c.client2.JobDone(jobDoneReq)
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
{
_, dbBuild := c.loadJob(pollResp.ID)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
- msg := <-c.emailSink
+ msg := c.pollEmailBug()
c.expectEQ(len(msg.Attachments), 0)
body := fmt.Sprintf(`Hello,
@@ -366,10 +344,7 @@ func TestJobRestrictedManager(t *testing.T) {
crash := testCrash(build, 1)
crash.ReproSyz = []byte("repro syz")
c.client2.ReportCrash(crash)
-
- c.expectOK(c.GET("/email_poll"))
- c.expectEQ(len(c.emailSink), 1)
- sender := (<-c.emailSink).Sender
+ 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))
@@ -380,7 +355,7 @@ func TestJobRestrictedManager(t *testing.T) {
// Testing on the right repo must succeed.
c.incomingEmail(sender, "#syz test: git://restricted.git/restricted.git master\n", EmailOptMessageID(2))
pollResp, _ = c.client2.JobPoll([]string{build.Manager})
- c.expectEQ(pollResp.ID != "", true)
+ c.expectNE(pollResp.ID, "")
c.expectEQ(pollResp.Manager, build.Manager)
c.expectEQ(pollResp.KernelRepo, "git://restricted.git/restricted.git")
}
diff --git a/dashboard/app/notifications_test.go b/dashboard/app/notifications_test.go
index e6a7b6ba6..2223a2c33 100644
--- a/dashboard/app/notifications_test.go
+++ b/dashboard/app/notifications_test.go
@@ -36,9 +36,7 @@ func TestEmailNotifUpstreamEmbargo(t *testing.T) {
upstreamReport := c.pollEmailBug()
c.expectEQ(notifUpstream.Sender, report.Sender)
c.expectEQ(notifUpstream.Body, "Sending this report upstream.")
- if upstreamReport.Sender == report.Sender {
- t.Fatalf("upstream report from the same sender")
- }
+ c.expectNE(upstreamReport.Sender, report.Sender)
c.expectEQ(upstreamReport.To, []string{"bugs@syzkaller.com", "default@maintainers.com"})
}
@@ -67,9 +65,7 @@ func TestEmailNotifUpstreamSkip(t *testing.T) {
upstreamReport := c.pollEmailBug()
c.expectEQ(notifUpstream.Sender, report.Sender)
c.expectEQ(notifUpstream.Body, "Sending this report upstream.")
- if upstreamReport.Sender == report.Sender {
- t.Fatalf("upstream report from the same sender")
- }
+ c.expectNE(upstreamReport.Sender, report.Sender)
c.expectEQ(upstreamReport.To, []string{"bugs@syzkaller.com", "default@maintainers.com"})
}
diff --git a/dashboard/app/reporting_test.go b/dashboard/app/reporting_test.go
index 655bca8a3..74899b400 100644
--- a/dashboard/app/reporting_test.go
+++ b/dashboard/app/reporting_test.go
@@ -9,7 +9,6 @@ import (
"testing"
"time"
- "github.com/google/go-cmp/cmp"
"github.com/google/syzkaller/dashboard/dashapi"
)
@@ -37,9 +36,7 @@ func TestReportBug(t *testing.T) {
resp, _ = c.client.ReportingPollBugs("test")
c.expectEQ(len(resp.Reports), 1)
rep := resp.Reports[0]
- if rep.ID == "" {
- t.Fatalf("empty report ID")
- }
+ c.expectNE(rep.ID, "")
_, dbCrash, dbBuild := c.loadBug(rep.ID)
want := &dashapi.BugReport{
Namespace: "test1",
@@ -66,9 +63,7 @@ func TestReportBug(t *testing.T) {
NumCrashes: 1,
HappenedOn: []string{"repo1 branch1"},
}
- if diff := cmp.Diff(want, rep); diff != "" {
- t.Fatal(diff)
- }
+ c.expectEQ(want, rep)
// Since we did not update bug status yet, should get the same report again.
c.expectEQ(c.client.pollBug(), want)
@@ -80,18 +75,14 @@ func TestReportBug(t *testing.T) {
want.ReproSyz = []byte(syzReproPrefix + "#some opts\ngetpid()")
c.client.ReportCrash(crash1)
rep1 := c.client.pollBug()
- if want.CrashID == rep1.CrashID {
- t.Fatal("get the same CrashID for new crash")
- }
+ c.expectNE(want.CrashID, rep1.CrashID)
_, dbCrash, _ = c.loadBug(rep.ID)
want.CrashID = rep1.CrashID
want.NumCrashes = 2
want.ReproSyzLink = externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz)
want.LogLink = externalLink(c.ctx, textCrashLog, dbCrash.Log)
want.ReportLink = externalLink(c.ctx, textCrashReport, dbCrash.Report)
- if diff := cmp.Diff(want, rep1); diff != "" {
- t.Fatal(diff)
- }
+ c.expectEQ(want, rep1)
reply, _ := c.client.ReportingUpdate(&dashapi.BugUpdate{
ID: rep.ID,
@@ -118,17 +109,14 @@ func TestReportBug(t *testing.T) {
// Check that we get the report in the second reporting.
rep2 := c.client.pollBug()
- if rep2.ID == "" || rep2.ID == rep.ID {
- t.Fatalf("bad report ID: %q", rep2.ID)
- }
+ c.expectNE(rep2.ID, "")
+ c.expectNE(rep2.ID, rep.ID)
want.ID = rep2.ID
want.First = true
want.Moderation = false
want.Config = []byte(`{"Index":2}`)
want.NumCrashes = 3
- if diff := cmp.Diff(want, rep2); diff != "" {
- t.Fatal(diff)
- }
+ c.expectEQ(want, rep2)
// Check that that we can't upstream the bug in the final reporting.
reply, _ = c.client.ReportingUpdate(&dashapi.BugUpdate{
@@ -187,9 +175,7 @@ func TestInvalidBug(t *testing.T) {
// Now it should be reported again.
rep = c.client.pollBug()
- if rep.ID == "" {
- t.Fatalf("empty report ID")
- }
+ c.expectNE(rep.ID, "")
_, dbCrash, dbBuild := c.loadBug(rep.ID)
want := &dashapi.BugReport{
Namespace: "test1",
@@ -217,9 +203,7 @@ func TestInvalidBug(t *testing.T) {
NumCrashes: 1,
HappenedOn: []string{"repo1 branch1"},
}
- if diff := cmp.Diff(want, rep); diff != "" {
- t.Fatal(diff)
- }
+ c.expectEQ(want, rep)
c.client.ReportFailedRepro(testCrashID(crash1))
}
diff --git a/dashboard/app/util_test.go b/dashboard/app/util_test.go
index 14722c90f..2f9d959c3 100644
--- a/dashboard/app/util_test.go
+++ b/dashboard/app/util_test.go
@@ -24,6 +24,7 @@ import (
"testing"
"time"
+ "github.com/google/go-cmp/cmp"
"github.com/google/syzkaller/dashboard/dashapi"
"golang.org/x/net/context"
"google.golang.org/appengine"
@@ -96,8 +97,14 @@ func (c *Ctx) expectForbidden(err error) {
}
func (c *Ctx) expectEQ(got, want interface{}) {
- if !reflect.DeepEqual(got, want) {
- c.t.Fatalf("\n%v: got %#v, want %#v", caller(0), got, want)
+ if diff := cmp.Diff(got, want); diff != "" {
+ c.t.Fatalf("\n%v: %v", caller(0), diff)
+ }
+}
+
+func (c *Ctx) expectNE(got, want interface{}) {
+ if reflect.DeepEqual(got, want) {
+ c.t.Fatalf("\n%v: equal: %#v", caller(0), got)
}
}
@@ -124,6 +131,7 @@ func (c *Ctx) Close() {
for _, key := range keys {
c.expectOK(c.GET(fmt.Sprintf("/bug?id=%v", key.StringID())))
}
+ // No pending emails (tests need to consume them).
c.expectOK(c.GET("/email_poll"))
for len(c.emailSink) != 0 {
c.t.Errorf("ERROR: leftover email: %v", (<-c.emailSink).Body)