From 0f51729bc4b8b7bdf4767eb88d2c124183639dde Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 13 Feb 2019 14:57:30 +0100 Subject: dashboard/app: record last activity and fix times It would be useful to record last activity time for bugs (e.g. for pings) and when a fix is provided for statistics purposes. Fixes #673 --- dashboard/app/api.go | 1 + dashboard/app/entities.go | 2 ++ dashboard/app/fix_test.go | 39 +++++++++++++++++++++++++++++++++++++++ dashboard/app/jobs.go | 42 +++++++++++++++++++++--------------------- dashboard/app/jobs_test.go | 1 + dashboard/app/reporting.go | 2 ++ 6 files changed, 66 insertions(+), 21 deletions(-) diff --git a/dashboard/app/api.go b/dashboard/app/api.go index 5c84ad75e..5de4178f0 100644 --- a/dashboard/app/api.go +++ b/dashboard/app/api.go @@ -410,6 +410,7 @@ func addCommitsToBug(c context.Context, bug *Bug, manager string, managers []str } if len(fixCommits) != 0 && !reflect.DeepEqual(bug.Commits, fixCommits) { bug.Commits = fixCommits + bug.FixTime = now bug.PatchedOn = nil } bug.PatchedOn = append(bug.PatchedOn, manager) diff --git a/dashboard/app/entities.go b/dashboard/app/entities.go index 152a12506..3ffe09b7d 100644 --- a/dashboard/app/entities.go +++ b/dashboard/app/entities.go @@ -78,6 +78,8 @@ type Bug struct { LastTime time.Time LastSavedCrash time.Time LastReproTime time.Time + FixTime time.Time // when we become aware of the fixing commit + LastActivity time.Time // last time we observed any activity related to the bug Closed time.Time Reporting []BugReporting Commits []string diff --git a/dashboard/app/fix_test.go b/dashboard/app/fix_test.go index 420d28149..b0c7bee2b 100644 --- a/dashboard/app/fix_test.go +++ b/dashboard/app/fix_test.go @@ -159,9 +159,15 @@ func TestReFixed(t *testing.T) { builderPollResp, _ := c.client.BuilderPoll(build1.Manager) c.expectEQ(len(builderPollResp.PendingCommits), 0) + c.advanceTime(time.Hour) rep := c.client.pollBug() + bug, _, _ := c.loadBug(rep.ID) + c.expectEQ(bug.LastActivity, c.mockedTime) + c.expectEQ(bug.FixTime, time.Time{}) + // Specify fixing commit for the bug. + c.advanceTime(time.Hour) reply, _ := c.client.ReportingUpdate(&dashapi.BugUpdate{ ID: rep.ID, Status: dashapi.BugStatusOpen, @@ -169,12 +175,45 @@ func TestReFixed(t *testing.T) { }) c.expectEQ(reply.OK, true) + bug, _, _ = c.loadBug(rep.ID) + c.expectEQ(bug.LastActivity, c.mockedTime) + c.expectEQ(bug.FixTime, c.mockedTime) + + c.advanceTime(time.Hour) + reply, _ = c.client.ReportingUpdate(&dashapi.BugUpdate{ + ID: rep.ID, + Status: dashapi.BugStatusOpen, + FixCommits: []string{"the right one"}, + }) + c.expectEQ(reply.OK, true) + + bug, _, _ = c.loadBug(rep.ID) + c.expectEQ(bug.LastActivity, c.mockedTime) + c.expectEQ(bug.FixTime, c.mockedTime) + + // No updates, just check that LastActivity time is updated, FixTime preserved. + fixTime := c.mockedTime + c.advanceTime(time.Hour) + reply, _ = c.client.ReportingUpdate(&dashapi.BugUpdate{ + ID: rep.ID, + Status: dashapi.BugStatusOpen, + }) + c.expectEQ(reply.OK, true) + bug, _, _ = c.loadBug(rep.ID) + c.expectEQ(bug.LastActivity, c.mockedTime) + c.expectEQ(bug.FixTime, fixTime) + + // Send the same fixing commit, check that LastActivity time is updated, FixTime preserved. + c.advanceTime(time.Hour) reply, _ = c.client.ReportingUpdate(&dashapi.BugUpdate{ ID: rep.ID, Status: dashapi.BugStatusOpen, FixCommits: []string{"the right one"}, }) c.expectEQ(reply.OK, true) + bug, _, _ = c.loadBug(rep.ID) + c.expectEQ(bug.LastActivity, c.mockedTime) + c.expectEQ(bug.FixTime, fixTime) builderPollResp, _ = c.client.BuilderPoll(build1.Manager) c.expectEQ(len(builderPollResp.PendingCommits), 1) diff --git a/dashboard/app/jobs.go b/dashboard/app/jobs.go index 808c79182..7427f05dd 100644 --- a/dashboard/app/jobs.go +++ b/dashboard/app/jobs.go @@ -40,33 +40,33 @@ func handleTestRequest(c context.Context, bugID, user, extID, link, patch, repo, return fmt.Sprintf("can't find the associated bug (do you have %v in To/CC?)", myEmail) } bugReporting, _ := bugReportingByID(bug, bugID) - reply, err := addTestJob(c, bug, bugKey, bugReporting, user, extID, link, patch, repo, branch, jobCC) + now := timeNow(c) + reply, err := addTestJob(c, bug, bugKey, bugReporting, user, extID, link, patch, repo, branch, jobCC, now) if err != nil { log.Errorf(c, "test request failed: %v", err) if reply == "" { reply = internalError } } - // Update bug CC list in any case. - if !stringsInList(strings.Split(bugReporting.CC, "|"), jobCC) { - tx := func(c context.Context) error { - bug := new(Bug) - if err := datastore.Get(c, bugKey, bug); err != nil { - return err - } - bugReporting = bugReportingByName(bug, bugReporting.Name) - bugCC := strings.Split(bugReporting.CC, "|") - merged := email.MergeEmailLists(bugCC, jobCC) - bugReporting.CC = strings.Join(merged, "|") - if _, err := datastore.Put(c, bugKey, bug); err != nil { - return fmt.Errorf("failed to put bug: %v", err) - } - return nil + // Update bug CC and last activity time. + tx := func(c context.Context) error { + bug := new(Bug) + if err := datastore.Get(c, bugKey, bug); err != nil { + return err } - if err := datastore.RunInTransaction(c, tx, nil); err != nil { - // We've already stored the job, so just log the error. - log.Errorf(c, "failed to update bug: %v", err) + bug.LastActivity = now + bugReporting = bugReportingByName(bug, bugReporting.Name) + bugCC := strings.Split(bugReporting.CC, "|") + merged := email.MergeEmailLists(bugCC, jobCC) + bugReporting.CC = strings.Join(merged, "|") + if _, err := datastore.Put(c, bugKey, bug); err != nil { + return fmt.Errorf("failed to put bug: %v", err) } + return nil + } + if err := datastore.RunInTransaction(c, tx, nil); err != nil { + // We've already stored the job, so just log the error. + log.Errorf(c, "failed to update bug: %v", err) } if link != "" { reply = "" // don't send duplicate error reply @@ -75,7 +75,7 @@ func handleTestRequest(c context.Context, bugID, user, extID, link, patch, repo, } func addTestJob(c context.Context, bug *Bug, bugKey *datastore.Key, bugReporting *BugReporting, - user, extID, link, patch, repo, branch string, jobCC []string) (string, error) { + user, extID, link, patch, repo, branch string, jobCC []string, now time.Time) (string, error) { crash, crashKey, err := findCrashForBug(c, bug) if err != nil { return "", err @@ -103,7 +103,7 @@ func addTestJob(c context.Context, bug *Bug, bugKey *datastore.Key, bugReporting } job := &Job{ - Created: timeNow(c), + Created: now, User: user, CC: jobCC, Reporting: bugReporting.Name, diff --git a/dashboard/app/jobs_test.go b/dashboard/app/jobs_test.go index d5ad69d92..66d7b399f 100644 --- a/dashboard/app/jobs_test.go +++ b/dashboard/app/jobs_test.go @@ -85,6 +85,7 @@ func TestJob(t *testing.T) { pollResp, _ := c.client2.JobPoll([]string{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"})) diff --git a/dashboard/app/reporting.go b/dashboard/app/reporting.go index fafd9c8a3..32d3fc8e6 100644 --- a/dashboard/app/reporting.go +++ b/dashboard/app/reporting.go @@ -512,6 +512,7 @@ func incomingCommandTx(c context.Context, now time.Time, cmd *dashapi.BugUpdate, sort.Strings(cmd.FixCommits) if !reflect.DeepEqual(bug.Commits, cmd.FixCommits) { bug.Commits = cmd.FixCommits + bug.FixTime = now bug.PatchedOn = nil } } @@ -546,6 +547,7 @@ func incomingCommandTx(c context.Context, now time.Time, cmd *dashapi.BugUpdate, if bug.Status != BugStatusDup { bug.DupOf = "" } + bug.LastActivity = now if _, err := datastore.Put(c, bugKey, bug); err != nil { return false, internalError, fmt.Errorf("failed to put bug: %v", err) } -- cgit mrf-deployment