diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2023-05-10 19:38:27 +0200 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2023-05-12 13:24:58 +0200 |
| commit | ecca8a243762a781257ba0b65291bca940e13e9c (patch) | |
| tree | 6a3ae8f113f81af4f43b9f9eae0ff21256496c97 | |
| parent | 76821f5baf47294314823eb4df0e05ceb8242d74 (diff) | |
dashboard: display bug origin tree testing results
Display them as a collapsible block on the bug info page. Use colors to
distinguish results.
| -rw-r--r-- | dashboard/app/bug.html | 3 | ||||
| -rw-r--r-- | dashboard/app/jobs.go | 9 | ||||
| -rw-r--r-- | dashboard/app/main.go | 14 | ||||
| -rw-r--r-- | dashboard/app/templates.html | 41 | ||||
| -rw-r--r-- | dashboard/app/tree.go | 70 | ||||
| -rw-r--r-- | dashboard/app/tree_test.go | 7 | ||||
| -rw-r--r-- | dashboard/dashapi/dashapi.go | 1 | ||||
| -rw-r--r-- | pkg/html/pages/style.css | 12 |
8 files changed, 148 insertions, 9 deletions
diff --git a/dashboard/app/bug.html b/dashboard/app/bug.html index 3078eee42..4d499bebf 100644 --- a/dashboard/app/bug.html +++ b/dashboard/app/bug.html @@ -53,7 +53,8 @@ Page with details about a single bug. {{if eq $item.Type "bug_list"}}{{template "bug_list" $item.Value}}{{end}} {{if eq $item.Type "job_list"}}{{template "job_list" $item.Value}}{{end}} {{if eq $item.Type "discussion_list"}}{{template "discussion_list" $item.Value}}{{end}} - </div> + {{if eq $item.Type "test_results"}}{{template "test_results" $item.Value}}{{end}} + </div> </div> {{end}} diff --git a/dashboard/app/jobs.go b/dashboard/app/jobs.go index f65f224b7..57816930b 100644 --- a/dashboard/app/jobs.go +++ b/dashboard/app/jobs.go @@ -1380,16 +1380,16 @@ func jobID2Key(c context.Context, id string) (*db.Key, error) { return jobKey, nil } -func fetchJob(c context.Context, key string) (*Job, error) { +func fetchJob(c context.Context, key string) (*Job, *db.Key, error) { jobKey, err := db.DecodeKey(key) if err != nil { - return nil, err + return nil, nil, err } job := new(Job) if err := db.Get(c, jobKey, job); err != nil { - return nil, fmt.Errorf("failed to get job: %v", err) + return nil, nil, fmt.Errorf("failed to get job: %v", err) } - return job, nil + return job, jobKey, nil } func makeJobInfo(c context.Context, job *Job, jobKey *db.Key, bug *Bug, build *Build, @@ -1423,6 +1423,7 @@ func makeJobInfo(c context.Context, job *Job, jobKey *db.Key, bug *Bug, build *B ErrorLink: textLink(textError, job.Error), Reported: job.Reported, TreeOrigin: job.TreeOrigin, + OnMergeBase: job.MergeBaseRepo != "", } if !job.Finished.IsZero() { info.Duration = job.Finished.Sub(job.LastStarted) diff --git a/dashboard/app/main.go b/dashboard/app/main.go index df7fb3023..35864b4df 100644 --- a/dashboard/app/main.go +++ b/dashboard/app/main.go @@ -254,6 +254,7 @@ const ( sectionBugList = "bug_list" sectionJobList = "job_list" sectionDiscussionList = "discussion_list" + sectionTestResults = "test_results" ) type uiCollapsible struct { @@ -746,6 +747,18 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error Value: discussions, }) } + treeTestJobs, err := treeTestJobs(c, bug) + if err != nil { + return err + } + if len(treeTestJobs) > 0 { + sections = append(sections, &uiCollapsible{ + Title: fmt.Sprintf("Bug presence on other trees (%d)", len(treeTestJobs)), + Show: true, + Type: sectionTestResults, + Value: treeTestJobs, + }) + } similar, err := loadSimilarBugsUI(c, r, bug, state) if err != nil { return err @@ -758,7 +771,6 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error Value: similar, }) } - var bisectCause *uiJob if bug.BisectCause > BisectPending { bisectCause, err = getUIJob(c, bug, JobBisectCause) diff --git a/dashboard/app/templates.html b/dashboard/app/templates.html index 001eec25e..2c84878d7 100644 --- a/dashboard/app/templates.html +++ b/dashboard/app/templates.html @@ -544,3 +544,44 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the </table> {{end}} {{end}} + +{{/* List of test results, invoked with []*dashapi.JobInfo */}} +{{define "test_results"}} +{{if .}} +<table class="list_table"> + <thead> + <tr> + <th>Date</th> + <th>Name</th> + <th>Commit</th> + <th>Repro</th> + <th>Result</th> + </tr> + </thead> + <tbody> + {{range $item := .}} + <tr> + <td>{{formatDate $item.Finished}}</td> + <td>{{$item.KernelAlias}} {{if $item.OnMergeBase}}(merge base){{else}}(ToT){{end}}</td> + <td class="stat">{{link $item.KernelCommitLink (formatTagHash $item.KernelCommit)}}</td> + <td> + {{if $item.ReproCLink}}<a href="{{$item.ReproCLink}}">C</a> + {{else if $item.ReproSyzLink}}<a href="{{$item.ReproSyzLink}}">C</a>{{end}} + </td> + {{if ne $item.CrashTitle ""}} + <td class="status-crashed"> + {{link $item.CrashReportLink "[report]"}} <i>{{$item.CrashTitle}}</i> + </td> + {{else if ne $item.ErrorLink ""}} + <td class="status-error"> + Failed due to {{link $item.ErrorLink "an error"}}; will retry later + </td> + {{else}} + <td class="status-ok">Didn't crash</td> + {{end}} + </tr> + {{end}} + </tbody> +</table> +{{end}} +{{end}} diff --git a/dashboard/app/tree.go b/dashboard/app/tree.go index 50b35186a..0ac434c9a 100644 --- a/dashboard/app/tree.go +++ b/dashboard/app/tree.go @@ -10,10 +10,13 @@ package main import ( "fmt" + "sort" + "sync" "time" "github.com/google/syzkaller/dashboard/dashapi" "golang.org/x/net/context" + "golang.org/x/sync/errgroup" db "google.golang.org/appengine/v2/datastore" "google.golang.org/appengine/v2/log" ) @@ -447,7 +450,7 @@ func (ctx *bugTreeContext) doRunRepro(repo KernelRepo, result expectedResult, ru } func (ctx *bugTreeContext) ensureRepeatPeriod(jobKey string, period time.Duration) pollTreeJobResult { - job, err := fetchJob(ctx.c, jobKey) + job, _, err := fetchJob(ctx.c, jobKey) if err != nil { return pollResultError(err) } @@ -479,7 +482,7 @@ func (ctx *bugTreeContext) findResult(repo KernelRepo, result expectedResult, ru if key == "" { continue } - job, err := fetchJob(ctx.c, key) + job, _, err := fetchJob(ctx.c, key) if err != nil { return pollResultError(err) } @@ -605,7 +608,7 @@ func (test *BugTreeTest) applyPending(c context.Context) error { if test.Pending == "" { return nil } - job, err := fetchJob(c, test.Pending) + job, _, err := fetchJob(c, test.Pending) if err != nil { return err } @@ -631,6 +634,67 @@ func (test *BugTreeTest) applyPending(c context.Context) error { return nil } +// treeTestJobs fetches relevant tree testing results. +func treeTestJobs(c context.Context, bug *Bug) ([]*dashapi.JobInfo, error) { + g, _ := errgroup.WithContext(context.Background()) + jobIDs := make(chan string) + + var ret []*dashapi.JobInfo + var mu sync.Mutex + + // The underlying code makes a number of queries, so let's do it in parallel to speed up processing. + const threads = 3 + for i := 0; i < threads; i++ { + g.Go(func() error { + for id := range jobIDs { + job, jobKey, err := fetchJob(c, id) + if err != nil { + return err + } + build, err := loadBuild(c, job.Namespace, job.BuildID) + if err != nil { + return err + } + crashKey := db.NewKey(c, "Crash", "", job.CrashID, bug.key(c)) + crash := new(Crash) + if err := db.Get(c, crashKey, crash); err != nil { + return fmt.Errorf("failed to get crash: %v", err) + } + info := makeJobInfo(c, job, jobKey, bug, build, crash) + mu.Lock() + ret = append(ret, info) + mu.Unlock() + } + return nil + }) + } + for _, info := range bug.TreeTests.List { + if info.FirstOK != "" { + jobIDs <- info.FirstOK + } + if info.FirstCrash != "" { + jobIDs <- info.FirstCrash + } + if info.Error != "" { + jobIDs <- info.Error + } + } + // Wait until we have all information. + close(jobIDs) + err := g.Wait() + if err != nil { + return nil, err + } + // Sort structures to keep output consistent. + sort.Slice(ret, func(i, j int) bool { + if ret[i].KernelAlias != ret[j].KernelAlias { + return ret[i].KernelAlias < ret[j].KernelAlias + } + return ret[i].Finished.Before(ret[j].Finished) + }) + return ret, nil +} + type repoNode struct { repo KernelRepo edges []repoEdge diff --git a/dashboard/app/tree_test.go b/dashboard/app/tree_test.go index 9ebcf64dd..1464ea5f4 100644 --- a/dashboard/app/tree_test.go +++ b/dashboard/app/tree_test.go @@ -43,6 +43,9 @@ func TestTreeOriginDownstream(t *testing.T) { c.expectEQ(ctx.entries[0].jobsDone, 1) c.expectEQ(ctx.entries[1].jobsDone, 1) c.expectEQ(ctx.entries[2].jobsDone, 1) + // Test that we can render the bug page. + _, err := c.GET(ctx.bugLink()) + c.expectEQ(err, nil) } func TestTreeOriginLts(t *testing.T) { @@ -730,6 +733,10 @@ func (ctx *treeTestCtx) ensureLabels(labels ...string) { ctx.ctx.expectEQ(labels, bugLabels) } +func (ctx *treeTestCtx) bugLink() string { + return fmt.Sprintf("/bug?id=%v", ctx.bug.key(ctx.ctx.ctx).StringID()) +} + type treeTestEntry struct { alias string mergeAlias string diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go index 91b6a4a0d..9f90467ef 100644 --- a/dashboard/dashapi/dashapi.go +++ b/dashboard/dashapi/dashapi.go @@ -865,6 +865,7 @@ type JobInfo struct { Commits []*Commit // for inconclusive bisection Reported bool TreeOrigin bool + OnMergeBase bool } func (dash *Dashboard) Query(method string, req, reply interface{}) error { diff --git a/pkg/html/pages/style.css b/pkg/html/pages/style.css index 3bff3a9ed..8ced887ba 100644 --- a/pkg/html/pages/style.css +++ b/pkg/html/pages/style.css @@ -207,6 +207,18 @@ table td, table th { font-size: 75%; } +.list_table .status-crashed { + background-color: #FF8674; +} + +.list_table .status-ok { + background-color: lightgreen; +} + +.list_table .status-error { + background-color: lightgray; +} + .bug-label { background: white; border: 1pt solid black; |
