diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2025-04-08 16:29:16 +0200 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2025-04-10 10:37:46 +0000 |
| commit | f68248c3be1d60bb978ff7034234d9e32597ee1b (patch) | |
| tree | 2d87ea956abd579dca52eae07bc325ac7c2445dd /syz-cluster | |
| parent | c8f1c38aba5ba9a902386908635f6e69c85cfb01 (diff) | |
syz-cluster: display the number of findings per series
It will help identify the series to highlight.
Diffstat (limited to 'syz-cluster')
| -rw-r--r-- | syz-cluster/dashboard/templates/index.html | 2 | ||||
| -rw-r--r-- | syz-cluster/pkg/db/series_repo.go | 110 | ||||
| -rw-r--r-- | syz-cluster/pkg/db/series_repo_test.go | 24 |
3 files changed, 100 insertions, 36 deletions
diff --git a/syz-cluster/dashboard/templates/index.html b/syz-cluster/dashboard/templates/index.html index f51e5d34f..c87285b58 100644 --- a/syz-cluster/dashboard/templates/index.html +++ b/syz-cluster/dashboard/templates/index.html @@ -54,7 +54,7 @@ <td>{{.Series.AuthorEmail}}</td> <td> {{if .Session}} - {{.Session.Status}} + {{.Session.Status}} {{if gt .Findings 0}}<b>[{{.Findings}} findings]</b>{{end}} {{else}} - {{end}} diff --git a/syz-cluster/pkg/db/series_repo.go b/syz-cluster/pkg/db/series_repo.go index 554a32b00..5f414b7cc 100644 --- a/syz-cluster/pkg/db/series_repo.go +++ b/syz-cluster/pkg/db/series_repo.go @@ -127,8 +127,9 @@ func (repo *SeriesRepository) Count(ctx context.Context) (int, error) { } type SeriesWithSession struct { - Series *Series - Session *Session + Series *Series + Session *Session + Findings int } type SeriesFilter struct { @@ -191,37 +192,96 @@ func (repo *SeriesRepository) ListLatest(ctx context.Context, filter SeriesFilte } // Now query Sessions. - var keys []string var ret []*SeriesWithSession - idToSeries := map[string]*SeriesWithSession{} for _, series := range seriesList { + obj := &SeriesWithSession{Series: series} + ret = append(ret, obj) + } + + // And the rest of the data. + err = repo.querySessions(ctx, ro, ret) + if err != nil { + return nil, fmt.Errorf("failed to query sessions: %w", err) + } + err = repo.queryFindingCounts(ctx, ro, ret) + if err != nil { + return nil, fmt.Errorf("failed to query finding counts: %w", err) + } + return ret, nil +} + +func (repo *SeriesRepository) querySessions(ctx context.Context, ro *spanner.ReadOnlyTransaction, + seriesList []*SeriesWithSession) error { + idToSeries := map[string]*SeriesWithSession{} + var keys []string + for _, item := range seriesList { + series := item.Series + idToSeries[series.ID] = item if !series.LatestSessionID.IsNull() { keys = append(keys, series.LatestSessionID.String()) } - obj := &SeriesWithSession{Series: series} - ret = append(ret, obj) - idToSeries[series.ID] = obj - } - if len(keys) > 0 { - iter := ro.Query(ctx, spanner.Statement{ - SQL: "SELECT * FROM Sessions WHERE ID IN UNNEST(@ids)", - Params: map[string]interface{}{ - "ids": keys, - }, - }) - defer iter.Stop() - sessions, err := readEntities[Session](iter) - if err != nil { - return nil, err + } + if len(keys) == 0 { + return nil + } + iter := ro.Query(ctx, spanner.Statement{ + SQL: "SELECT * FROM Sessions WHERE ID IN UNNEST(@ids)", + Params: map[string]interface{}{ + "ids": keys, + }, + }) + defer iter.Stop() + sessions, err := readEntities[Session](iter) + if err != nil { + return err + } + for _, session := range sessions { + obj := idToSeries[session.SeriesID] + if obj != nil { + obj.Session = session } - for _, session := range sessions { - obj := idToSeries[session.SeriesID] - if obj != nil { - obj.Session = session - } + } + return nil +} + +func (repo *SeriesRepository) queryFindingCounts(ctx context.Context, ro *spanner.ReadOnlyTransaction, + seriesList []*SeriesWithSession) error { + var keys []string + sessionToSeries := map[string]*SeriesWithSession{} + for _, series := range seriesList { + if series.Session == nil || series.Session.Status() != SessionStatusFinished { + continue } + keys = append(keys, series.Session.ID) + sessionToSeries[series.Session.ID] = series } - return ret, nil + if len(keys) == 0 { + return nil + } + + type findingCount struct { + SessionID string `spanner:"SessionID"` + Count int64 `spanner:"Count"` + } + + stmt := spanner.Statement{ + SQL: "SELECT `SessionID`, COUNT(`ID`) as `Count` FROM `Findings` " + + "WHERE `SessionID` IN UNNEST(@ids) GROUP BY `SessionID`", + Params: map[string]interface{}{ + "ids": keys, + }, + } + iter := repo.client.Single().Query(ctx, stmt) + defer iter.Stop() + + list, err := readEntities[findingCount](iter) + if err != nil { + return err + } + for _, item := range list { + sessionToSeries[item.SessionID].Findings = int(item.Count) + } + return nil } // golint sees too much similarity with SessionRepository's ListForSeries, but in reality there's not. diff --git a/syz-cluster/pkg/db/series_repo_test.go b/syz-cluster/pkg/db/series_repo_test.go index 694893514..ca84b70a8 100644 --- a/syz-cluster/pkg/db/series_repo_test.go +++ b/syz-cluster/pkg/db/series_repo_test.go @@ -125,30 +125,34 @@ func TestSeriesRepositoryList(t *testing.T) { }) // Start one session to test filtering by status. - sessionRepo := NewSessionRepository(client) series2, err := repo.GetByExtID(ctx, "series-2") assert.NoError(t, err) - session := &Session{ - SeriesID: series2.ID, - CreatedAt: time.Now(), - } - err = sessionRepo.Insert(ctx, session) - assert.NoError(t, err) + dtd := &dummyTestData{t, ctx, client} + session := dtd.dummySession(series2) + dtd.addSessionTest(session, "test") t.Run("filter_status_waiting", func(t *testing.T) { list, err := repo.ListLatest(ctx, SeriesFilter{Status: SessionStatusWaiting}, time.Time{}) assert.NoError(t, err) assert.Len(t, list, 1) }) - err = sessionRepo.Start(ctx, session.ID) - assert.NoError(t, err) - + dtd.startSession(session) t.Run("filter_status_in_progress", func(t *testing.T) { list, err := repo.ListLatest(ctx, SeriesFilter{Status: SessionStatusInProgress}, time.Time{}) assert.NoError(t, err) assert.Len(t, list, 1) }) + + dtd.addSessionTest(session, "test") + dtd.addFinding(session, "title", "test") + dtd.finishSession(session) + t.Run("query_finding_count", func(t *testing.T) { + list, err := repo.ListLatest(ctx, SeriesFilter{Status: SessionStatusFinished}, time.Time{}) + assert.NoError(t, err) + assert.Len(t, list, 1) + assert.Equal(t, 1, list[0].Findings, "there must be just one finding") + }) } func TestSeriesRepositoryUpdate(t *testing.T) { |
