@@ -5,12 +5,14 @@ package main
55
66import (
77 "context"
8+ "errors"
89 "fmt"
910 "html/template"
1011 "net/http"
1112 "os"
1213 "slices"
1314 "strconv"
15+ "strings"
1416
1517 "cloud.google.com/go/civil"
1618 "github.com/google/syzkaller/pkg/cover"
@@ -56,22 +58,135 @@ type funcStyleBodyJS func(
5658 scope * coveragedb.SelectScope , onlyUnique bool , sss , managers []string , dataFilters cover.Format ,
5759) (template.CSS , template.HTML , template.HTML , error )
5860
59- func handleCoverageHeatmap (c context.Context , w http.ResponseWriter , r * http.Request ) error {
60- if r .FormValue ("jsonl" ) == "1" {
61- hdr , err := commonHeader (c , r , w , "" )
62- if err != nil {
63- return err
61+ type coverageHeatmapParams struct {
62+ manager string
63+ subsystem string
64+ onlyUnique bool
65+ periodType string
66+ nPeriods int
67+ dateTo civil.Date
68+ cover.Format
69+ }
70+
71+ const minPeriodsOnThePage = 1
72+ const maxPeriodsOnThePage = 12
73+
74+ func makeHeatmapParams (ctx context.Context , r * http.Request ) (* coverageHeatmapParams , error ) {
75+ minCoverLinesDrop , err := getIntParam (r , covPageParams [MinCoverLinesDrop ], 0 )
76+ if err != nil {
77+ return nil , err
78+ }
79+ onlyUnique , err := getBoolParam (r , covPageParams [UniqueOnly ], false )
80+ if err != nil {
81+ return nil , err
82+ }
83+ orderByCoverDrop , err := getBoolParam (r , covPageParams [OrderByCoverDrop ], false )
84+ if err != nil {
85+ return nil , err
86+ }
87+ periodType , err := getStringParam (r , covPageParams [PeriodType ], coveragedb .DayPeriod )
88+ if err != nil {
89+ return nil , err
90+ }
91+ if ! slices .Contains (coveragedb .AllPeriods , periodType ) {
92+ return nil , fmt .Errorf ("only {%s} are allowed, but received %s instead, %w" ,
93+ strings .Join (coveragedb .AllPeriods , ", " ), periodType , ErrClientBadRequest )
94+ }
95+
96+ nPeriods , err := getIntParam (r , covPageParams [PeriodCount ], 4 )
97+ if err != nil || nPeriods > maxPeriodsOnThePage || nPeriods < minPeriodsOnThePage {
98+ return nil , fmt .Errorf ("periods_count is wrong, expected [%d, %d]: %w" ,
99+ minPeriodsOnThePage , maxPeriodsOnThePage , err )
100+ }
101+
102+ dateTo := civil .DateOf (timeNow (ctx ))
103+ if customDate := r .FormValue (covPageParams [DateTo ]); customDate != "" {
104+ if dateTo , err = civil .ParseDate (customDate ); err != nil {
105+ return nil , fmt .Errorf ("civil.ParseDate(%s): %w" , customDate , err )
64106 }
107+ }
108+
109+ return & coverageHeatmapParams {
110+ manager : r .FormValue (covPageParams [ManagerName ]),
111+ subsystem : r .FormValue (covPageParams [SubsystemName ]),
112+ onlyUnique : onlyUnique ,
113+ periodType : periodType ,
114+ nPeriods : nPeriods ,
115+ dateTo : dateTo ,
116+ Format : cover.Format {
117+ DropCoveredLines0 : onlyUnique ,
118+ OrderByCoveredLinesDrop : orderByCoverDrop ,
119+ FilterMinCoveredLinesDrop : minCoverLinesDrop ,
120+ },
121+ }, nil
122+ }
123+
124+ func getIntParam (r * http.Request , name string , orDefault ... int ) (int , error ) {
125+ if r .FormValue (name ) == "" {
126+ if len (orDefault ) > 0 {
127+ return orDefault [0 ], nil
128+ }
129+ return 0 , errors .New ("missing parameter " + name )
130+ }
131+ res , err := strconv .Atoi (r .FormValue (name ))
132+ if err != nil {
133+ return 0 , fmt .Errorf ("strconv.Atoi(%s): %w" , name , err )
134+ }
135+ return res , nil
136+ }
137+
138+ func getBoolParam (r * http.Request , name string , orDefault ... bool ) (bool , error ) {
139+ if r .FormValue (name ) == "" {
140+ if len (orDefault ) > 0 {
141+ return orDefault [0 ], nil
142+ }
143+ return false , errors .New ("missing parameter " + name )
144+ }
145+ res , err := strconv .ParseBool (r .FormValue (name ))
146+ if err != nil {
147+ return false , fmt .Errorf ("strconv.ParseBool(%s): %w" , name , err )
148+ }
149+ return res , nil
150+ }
151+
152+ func getStringParam (r * http.Request , name string , orDefault ... string ) (string , error ) {
153+ if r .FormValue (name ) == "" {
154+ if len (orDefault ) > 0 {
155+ return orDefault [0 ], nil
156+ }
157+ return "" , errors .New ("missing parameter " + name )
158+ }
159+ return r .FormValue (name ), nil
160+ }
161+
162+ func handleCoverageHeatmap (c context.Context , w http.ResponseWriter , r * http.Request ) error {
163+ hdr , err := commonHeader (c , r , w , "" )
164+ if err != nil {
165+ return err
166+ }
167+ params , err := makeHeatmapParams (c , r )
168+ if err != nil {
169+ return fmt .Errorf ("%s: %w" , err .Error (), ErrClientBadRequest )
170+ }
171+ if requestJSONL , _ := getBoolParam (r , "jsonl" , false ); requestJSONL {
65172 ns := hdr .Namespace
66173 repo , _ := getNsConfig (c , ns ).mainRepoBranch ()
67174 w .Header ().Set ("Content-Type" , "application/json" )
68- return writeExtAPICoverageFor (c , w , ns , repo )
175+ return writeExtAPICoverageFor (c , w , ns , repo , params )
69176 }
70- return handleHeatmap (c , w , r , cover .DoHeatMapStyleBodyJS )
177+ return handleHeatmap (c , w , hdr , params , cover .DoHeatMapStyleBodyJS )
71178}
72179
73180func handleSubsystemsCoverageHeatmap (c context.Context , w http.ResponseWriter , r * http.Request ) error {
74- return handleHeatmap (c , w , r , cover .DoSubsystemsHeatMapStyleBodyJS )
181+ hdr , err := commonHeader (c , r , w , "" )
182+ if err != nil {
183+ return err
184+ }
185+ params , err := makeHeatmapParams (c , r )
186+ if err != nil {
187+ return fmt .Errorf ("%s: %w" , err .Error (), ErrClientBadRequest )
188+ }
189+ return handleHeatmap (c , w , hdr , params , cover .DoSubsystemsHeatMapStyleBodyJS )
75190}
76191
77192type covPageParam int
@@ -127,46 +242,14 @@ func coveragePageLink(ns, periodType, dateTo string, minDrop, periodCount int, o
127242 return url
128243}
129244
130- func handleHeatmap (c context.Context , w http.ResponseWriter , r * http.Request , f funcStyleBodyJS ) error {
131- hdr , err := commonHeader (c , r , w , "" )
132- if err != nil {
133- return err
134- }
245+ func handleHeatmap (c context.Context , w http.ResponseWriter , hdr * uiHeader , p * coverageHeatmapParams ,
246+ f funcStyleBodyJS ) error {
135247 nsConfig := getNsConfig (c , hdr .Namespace )
136248 if nsConfig .Coverage == nil {
137249 return ErrClientNotFound
138250 }
139- ss := r .FormValue (covPageParams [SubsystemName ])
140- manager := r .FormValue (covPageParams [ManagerName ])
141-
142- periodType := r .FormValue (covPageParams [PeriodType ])
143- if periodType == "" {
144- periodType = coveragedb .DayPeriod
145- }
146- if periodType != coveragedb .DayPeriod &&
147- periodType != coveragedb .MonthPeriod &&
148- periodType != coveragedb .QuarterPeriod {
149- return fmt .Errorf ("only 'day', 'month' and 'quarter' are allowed, but received %s instead, %w" ,
150- periodType , ErrClientBadRequest )
151- }
152-
153- periodCount := r .FormValue (covPageParams [PeriodCount ])
154- if periodCount == "" {
155- periodCount = "4"
156- }
157- nPeriods , err := strconv .Atoi (periodCount )
158- if err != nil || nPeriods > 12 || nPeriods < 1 {
159- return fmt .Errorf ("periods_count is wrong, expected [1, 12]: %w" , err )
160- }
161-
162- dateTo := civil .DateOf (timeNow (c ))
163- if customDate := r .FormValue (covPageParams [DateTo ]); customDate != "" {
164- if dateTo , err = civil .ParseDate (customDate ); err != nil {
165- return fmt .Errorf ("civil.ParseDate(%s): %w" , customDate , err )
166- }
167- }
168251
169- periods , err := coveragedb .GenNPeriodsTill (nPeriods , dateTo , periodType )
252+ periods , err := coveragedb .GenNPeriodsTill (p . nPeriods , p . dateTo , p . periodType )
170253 if err != nil {
171254 return fmt .Errorf ("%s: %w" , err .Error (), ErrClientBadRequest )
172255 }
@@ -182,29 +265,17 @@ func handleHeatmap(c context.Context, w http.ResponseWriter, r *http.Request, f
182265 slices .Sort (managers )
183266 slices .Sort (subsystems )
184267
185- onlyUnique := r .FormValue (covPageParams [UniqueOnly ]) == "1"
186- orderByCoverLinesDrop := r .FormValue (covPageParams [OrderByCoverDrop ]) == "1"
187- // Prefixing "0" we don't fail on empty string.
188- minCoverLinesDrop , err := strconv .Atoi ("0" + r .FormValue (covPageParams [MinCoverLinesDrop ]))
189- if err != nil {
190- return fmt .Errorf (covPageParams [MinCoverLinesDrop ] + " should be integer" )
191- }
192-
193268 var style template.CSS
194269 var body , js template.HTML
195270 if style , body , js , err = f (c , getCoverageDBClient (c ),
196271 & coveragedb.SelectScope {
197272 Ns : hdr .Namespace ,
198- Subsystem : ss ,
199- Manager : manager ,
273+ Subsystem : p . subsystem ,
274+ Manager : p . manager ,
200275 Periods : periods ,
201276 },
202- onlyUnique , subsystems , managers ,
203- cover.Format {
204- FilterMinCoveredLinesDrop : minCoverLinesDrop ,
205- OrderByCoveredLinesDrop : orderByCoverLinesDrop ,
206- DropCoveredLines0 : onlyUnique ,
207- }); err != nil {
277+ p .onlyUnique , subsystems , managers , p .Format ,
278+ ); err != nil {
208279 return fmt .Errorf ("failed to generate heatmap: %w" , err )
209280 }
210281 return serveTemplate (w , "custom_content.html" , struct {
@@ -261,7 +332,7 @@ func handleFileCoverage(c context.Context, w http.ResponseWriter, r *http.Reques
261332 if err != nil {
262333 return fmt .Errorf ("coveragedb.MakeTimePeriod: %w" , err )
263334 }
264- onlyUnique := r . FormValue ( covPageParams [UniqueOnly ]) == "1"
335+ onlyUnique , _ := getBoolParam ( r , covPageParams [UniqueOnly ], false )
265336 mainNsRepo , _ := nsConfig .mainRepoBranch ()
266337 client := getCoverageDBClient (c )
267338 if client == nil {
0 commit comments