Skip to content

Commit 13d6fbb

Browse files
committed
dashboard/app: filter coverage by minspread
Coverage spread is the max_coverage-min_coverage for the time period. Minspread 0 means show all records. Minspread 10 means show only the records where coverage was floating +/- 5%.
1 parent a2ada0e commit 13d6fbb

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

dashboard/app/coverage.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func GetCoverageDBClient(ctx context.Context) spannerclient.SpannerClient {
5050

5151
type funcStyleBodyJS func(
5252
ctx context.Context, client spannerclient.SpannerClient,
53-
scope *coveragedb.SelectScope, onlyUnique bool, sss, managers []string,
53+
scope *coveragedb.SelectScope, onlyUnique bool, sss, managers []string, dataFilters cover.Format,
5454
) (template.CSS, template.HTML, template.HTML, error)
5555

5656
func handleCoverageHeatmap(c context.Context, w http.ResponseWriter, r *http.Request) error {
@@ -121,6 +121,11 @@ func handleHeatmap(c context.Context, w http.ResponseWriter, r *http.Request, f
121121

122122
onlyUnique := r.FormValue("unique-only") == "1"
123123

124+
minSpread, err := strconv.Atoi("0" + r.FormValue("minspread"))
125+
if err != nil {
126+
return fmt.Errorf("minspread should be integer")
127+
}
128+
124129
var style template.CSS
125130
var body, js template.HTML
126131
if style, body, js, err = f(c, GetCoverageDBClient(c),
@@ -130,7 +135,11 @@ func handleHeatmap(c context.Context, w http.ResponseWriter, r *http.Request, f
130135
Manager: manager,
131136
Periods: periods,
132137
},
133-
onlyUnique, subsystems, managers); err != nil {
138+
onlyUnique, subsystems, managers,
139+
cover.Format{
140+
FilterMinSpread: minSpread,
141+
OrderByInstrumentedDrop: minSpread != 0,
142+
}); err != nil {
134143
return fmt.Errorf("failed to generate heatmap: %w", err)
135144
}
136145
return serveTemplate(w, "custom_content.html", struct {

pkg/cover/heatmap.go

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
_ "embed"
1010
"fmt"
1111
"html/template"
12+
"slices"
1213
"sort"
1314
"strings"
1415

@@ -21,7 +22,8 @@ import (
2122
type templateHeatmapRow struct {
2223
Items []*templateHeatmapRow
2324
Name string
24-
Coverage []int64
25+
Coverage []int64 // in percents
26+
Covered []int64 // in lines count
2527
IsDir bool
2628
Depth int
2729
LastDayInstrumented int64
@@ -41,6 +43,33 @@ type templateHeatmap struct {
4143
Managers []string
4244
}
4345

46+
// Filter removes the records where predicate is true.
47+
func (th *templateHeatmap) Filter(pred func(*templateHeatmapRow) bool) {
48+
th.Root.filter(pred)
49+
}
50+
51+
func (th *templateHeatmap) Sort(pred func(*templateHeatmapRow, *templateHeatmapRow) int) {
52+
th.Root.sort(pred)
53+
}
54+
55+
func (thm *templateHeatmapRow) filter(pred func(*templateHeatmapRow) bool) {
56+
var filteredItems []*templateHeatmapRow
57+
for _, item := range thm.Items {
58+
item.filter(pred)
59+
if pred(item) {
60+
filteredItems = append(filteredItems, item)
61+
}
62+
}
63+
thm.Items = filteredItems
64+
}
65+
66+
func (thm *templateHeatmapRow) sort(pred func(*templateHeatmapRow, *templateHeatmapRow) int) {
67+
for _, item := range thm.Items {
68+
item.sort(pred)
69+
}
70+
slices.SortFunc(thm.Items, pred)
71+
}
72+
4473
func (thm *templateHeatmapRow) addParts(depth int, pathLeft []string, filePath string, instrumented, covered int64,
4574
timePeriod coveragedb.TimePeriod) {
4675
thm.instrumented[timePeriod] += instrumented
@@ -94,6 +123,7 @@ func (thm *templateHeatmapRow) prepareDataFor(pageColumns []pageColumnTarget, sk
94123
dateCoverage = percent(thm.covered[tp], thm.instrumented[tp])
95124
}
96125
thm.Coverage = append(thm.Coverage, dateCoverage)
126+
thm.Covered = append(thm.Covered, thm.covered[tp])
97127
thm.Tooltips = append(thm.Tooltips, fmt.Sprintf("Instrumented:\t%d blocks\nCovered:\t%d blocks",
98128
thm.instrumented[tp], thm.covered[tp]))
99129
if !thm.IsDir {
@@ -179,22 +209,30 @@ func stylesBodyJSTemplate(templData *templateHeatmap,
179209
template.HTML(js.Bytes()), nil
180210
}
181211

212+
type Format struct {
213+
FilterMinSpread int
214+
OrderByInstrumentedDrop bool
215+
// TODO(tarasmadan): move onlyUnique here as a filter
216+
}
217+
182218
func DoHeatMapStyleBodyJS(
183219
ctx context.Context, client spannerclient.SpannerClient, scope *coveragedb.SelectScope, onlyUnique bool,
184-
sss, managers []string) (template.CSS, template.HTML, template.HTML, error) {
220+
sss, managers []string, dataFilters Format) (template.CSS, template.HTML, template.HTML, error) {
185221
covAndDates, err := coveragedb.FilesCoverageWithDetails(ctx, client, scope, onlyUnique)
186222
if err != nil {
187223
return "", "", "", fmt.Errorf("failed to FilesCoverageWithDetails: %w", err)
188224
}
189225
templData := filesCoverageToTemplateData(covAndDates, onlyUnique)
190226
templData.Subsystems = sss
191227
templData.Managers = managers
228+
FormatResult(templData, dataFilters)
229+
192230
return stylesBodyJSTemplate(templData)
193231
}
194232

195233
func DoSubsystemsHeatMapStyleBodyJS(
196234
ctx context.Context, client spannerclient.SpannerClient, scope *coveragedb.SelectScope, onlyUnique bool,
197-
sss, managers []string) (template.CSS, template.HTML, template.HTML, error) {
235+
sss, managers []string, format Format) (template.CSS, template.HTML, template.HTML, error) {
198236
covWithDetails, err := coveragedb.FilesCoverageWithDetails(ctx, client, scope, onlyUnique)
199237
if err != nil {
200238
panic(err)
@@ -215,9 +253,28 @@ func DoSubsystemsHeatMapStyleBodyJS(
215253
}
216254
templData := filesCoverageToTemplateData(ssCovAndDates, onlyUnique)
217255
templData.Managers = managers
256+
FormatResult(templData, format)
218257
return stylesBodyJSTemplate(templData)
219258
}
220259

260+
func FormatResult(thm *templateHeatmap, format Format) {
261+
if format.FilterMinSpread > 0 {
262+
thm.Filter(func(row *templateHeatmapRow) bool {
263+
if row.IsDir && len(row.Items) > 0 {
264+
return true
265+
}
266+
return row.Coverage[len(row.Coverage)-1]-slices.Min(row.Coverage) >= int64(format.FilterMinSpread)
267+
})
268+
}
269+
if format.OrderByInstrumentedDrop {
270+
thm.Sort(func(row1 *templateHeatmapRow, row2 *templateHeatmapRow) int {
271+
row1InstrDrop := slices.Max(row1.Covered) - row1.Covered[len(row1.Covered)-1]
272+
row2InstrDrop := slices.Max(row2.Covered) - row2.Covered[len(row2.Covered)-1]
273+
return int(row2InstrDrop - row1InstrDrop)
274+
})
275+
}
276+
}
277+
221278
func approximateInstrumented(points int64) string {
222279
dim := "_"
223280
if points > 10000 {

pkg/cover/heatmap_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
4545
{
4646
Name: "file1",
4747
Coverage: []int64{100},
48+
Covered: []int64{1},
4849
IsDir: false,
4950
Depth: 0,
5051
LastDayInstrumented: 1,
@@ -57,6 +58,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
5758
},
5859
Name: "",
5960
Coverage: []int64{100},
61+
Covered: []int64{1},
6062
IsDir: true,
6163
Depth: 0,
6264
LastDayInstrumented: 1,
@@ -93,6 +95,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
9395
{
9496
Name: "file1",
9597
Coverage: []int64{100, 0},
98+
Covered: []int64{1, 0},
9699
IsDir: false,
97100
Depth: 1,
98101
LastDayInstrumented: 0,
@@ -107,6 +110,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
107110
{
108111
Name: "file2",
109112
Coverage: []int64{0, 0},
113+
Covered: []int64{0, 0},
110114
IsDir: false,
111115
Depth: 1,
112116
LastDayInstrumented: 1,
@@ -121,6 +125,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
121125
},
122126
Name: "dir",
123127
Coverage: []int64{100, 0},
128+
Covered: []int64{1, 0},
124129
IsDir: true,
125130
Depth: 0,
126131
LastDayInstrumented: 1,
@@ -132,6 +137,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
132137
},
133138
Name: "",
134139
Coverage: []int64{100, 0},
140+
Covered: []int64{1, 0},
135141
LastDayInstrumented: 1,
136142
Tooltips: []string{
137143
"Instrumented:\t1 blocks\nCovered:\t1 blocks",
@@ -157,6 +163,7 @@ func TestFilesCoverageToTemplateData(t *testing.T) {
157163
want: &templateHeatmap{
158164
Root: &templateHeatmapRow{
159165
Coverage: []int64{0},
166+
Covered: []int64{0},
160167
IsDir: true,
161168
LastDayInstrumented: 1,
162169
Tooltips: []string{"Instrumented:\t1 blocks\nCovered:\t0 blocks"},

0 commit comments

Comments
 (0)