OLD | NEW |
1 package main | 1 package main |
2 | 2 |
3 import ( | 3 import ( |
4 "encoding/json" | 4 "encoding/json" |
5 "flag" | 5 "flag" |
6 "fmt" | 6 "fmt" |
7 "html/template" | 7 "html/template" |
8 "io/ioutil" | 8 "io/ioutil" |
9 "net/http" | 9 "net/http" |
10 "os" | 10 "os" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 ) | 63 ) |
64 | 64 |
65 // ResponseEnvelope wraps all responses. Some fields might be empty depending | 65 // ResponseEnvelope wraps all responses. Some fields might be empty depending |
66 // on context or whether there was an error or not. | 66 // on context or whether there was an error or not. |
67 type ResponseEnvelope struct { | 67 type ResponseEnvelope struct { |
68 Data *interface{} `json:"data"` | 68 Data *interface{} `json:"data"` |
69 Err *string `json:"err"` | 69 Err *string `json:"err"` |
70 Status int `json:"status"` | 70 Status int `json:"status"` |
71 } | 71 } |
72 | 72 |
73 var analyzer *analysis.Analyzer = nil | 73 var ( |
| 74 » analyzer *analysis.Analyzer = nil |
| 75 » ignoreStore types.IgnoreStore |
| 76 ) |
74 | 77 |
75 // ***************************************************************************** | 78 // ***************************************************************************** |
76 // ***************************************************************************** | 79 // ***************************************************************************** |
77 // New polymer based UI code begin. | 80 // New polymer based UI code begin. |
78 // ***************************************************************************** | 81 // ***************************************************************************** |
79 // ***************************************************************************** | 82 // ***************************************************************************** |
80 | 83 |
81 // polyMainHandler is the main page for the Polymer based frontend. | 84 // polyMainHandler is the main page for the Polymer based frontend. |
82 func polyMainHandler(w http.ResponseWriter, r *http.Request) { | 85 func polyMainHandler(w http.ResponseWriter, r *http.Request) { |
83 glog.Infof("Poly Main Handler: %q\n", r.URL.Path) | 86 glog.Infof("Poly Main Handler: %q\n", r.URL.Path) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 util.ReportError(w, r, err, "Failed to load test information") | 131 util.ReportError(w, r, err, "Failed to load test information") |
129 return | 132 return |
130 } | 133 } |
131 w.Header().Set("Content-Type", "application/json") | 134 w.Header().Set("Content-Type", "application/json") |
132 enc := json.NewEncoder(w) | 135 enc := json.NewEncoder(w) |
133 if err := enc.Encode(res); err != nil { | 136 if err := enc.Encode(res); err != nil { |
134 util.ReportError(w, r, err, "Failed to encode result") | 137 util.ReportError(w, r, err, "Failed to encode result") |
135 } | 138 } |
136 } | 139 } |
137 | 140 |
138 // IgnoreRule is the GUI struct for dealing with Ignore rules. | |
139 type IgnoreRule struct { | |
140 ID string `json:"id"` | |
141 Name string `json:"name"` | |
142 Expires time.Time `json:"expires"` | |
143 Query string `json:"query"` | |
144 Note string `json:"note"` | |
145 Count int `json:"count"` | |
146 } | |
147 | |
148 // ignores is an in memory database of ignore rules. | |
149 // | |
150 // TODO replace with a database. | |
151 var ignores = []*IgnoreRule{ | |
152 &IgnoreRule{ | |
153 ID: "1", | |
154 Name: "jcgregorio@google.com", | |
155 Expires: time.Now().Add(time.Hour), | |
156 Query: "config=gpu", | |
157 Note: "Because", | |
158 Count: 354, | |
159 }, | |
160 &IgnoreRule{ | |
161 ID: "2", | |
162 Name: "jcgregorio@google.com", | |
163 Expires: time.Now().Add(2 * time.Hour * 24), | |
164 Query: "arch=x86&bench_type=playback&config=8888&extra_config=
GDI&os=Android", | |
165 Note: "Lorem ipsum dolor sit amet, consetetur sadipscing elit
r, sed diam nonumy eirmod", | |
166 Count: 12, | |
167 }, | |
168 } | |
169 | |
170 // deleteIgnoreRule deletes an Ignore rule. | |
171 // | |
172 // TODO replace with database action. | |
173 func deleteIgnoreRule(id string) { | |
174 for i, r := range ignores { | |
175 if r.ID == id { | |
176 ignores = append(ignores[:i], ignores[i+1:]...) | |
177 break | |
178 } | |
179 } | |
180 } | |
181 | |
182 // addIgnoreRule adds the IgnoreRule to the database. | |
183 // | |
184 // TODO replace with database action. | |
185 func addIgnoreRule(ig *IgnoreRule) { | |
186 ignores = append(ignores, ig) | |
187 } | |
188 | |
189 // polyIgnoresJSONHandler returns the current ignore rules in JSON format. | 141 // polyIgnoresJSONHandler returns the current ignore rules in JSON format. |
190 func polyIgnoresJSONHandler(w http.ResponseWriter, r *http.Request) { | 142 func polyIgnoresJSONHandler(w http.ResponseWriter, r *http.Request) { |
191 w.Header().Set("Content-Type", "application/json") | 143 w.Header().Set("Content-Type", "application/json") |
| 144 ignores, err := analyzer.ListIgnoreRules() |
| 145 if err != nil { |
| 146 util.ReportError(w, r, err, "Failed to retrieve ignored traces."
) |
| 147 } |
| 148 |
| 149 // TODO(stephana): Wrap in response envelope if it makes sense ! |
192 enc := json.NewEncoder(w) | 150 enc := json.NewEncoder(w) |
193 if err := enc.Encode(ignores); err != nil { | 151 if err := enc.Encode(ignores); err != nil { |
194 util.ReportError(w, r, err, "Failed to encode result") | 152 util.ReportError(w, r, err, "Failed to encode result") |
195 } | 153 } |
196 } | 154 } |
197 | 155 |
198 func polyIgnoresDeleteHandler(w http.ResponseWriter, r *http.Request) { | 156 func polyIgnoresDeleteHandler(w http.ResponseWriter, r *http.Request) { |
199 user := login.LoggedInAs(r) | 157 user := login.LoggedInAs(r) |
200 if user == "" { | 158 if user == "" { |
201 util.ReportError(w, r, fmt.Errorf("Not logged in."), "You must b
e logged in to add an ignore rule.") | 159 util.ReportError(w, r, fmt.Errorf("Not logged in."), "You must b
e logged in to add an ignore rule.") |
202 return | 160 return |
203 } | 161 } |
204 » id := mux.Vars(r)["id"] | 162 » id, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 0) |
205 » deleteIgnoreRule(id) | 163 » if err != nil { |
206 » w.Header().Set("Content-Type", "application/json") | 164 » » util.ReportError(w, r, err, "ID must be valid integer.") |
207 » enc := json.NewEncoder(w) | 165 » » return |
208 » if err := enc.Encode(ignores); err != nil { | 166 » } |
209 » » util.ReportError(w, r, err, "Failed to encode result") | 167 |
| 168 » if err := analyzer.DeleteIgnoreRule(int(id), user); err != nil { |
| 169 » » util.ReportError(w, r, err, "Unable to delete ignore rule.") |
| 170 » } else { |
| 171 » » // If delete worked just list the current ignores and return the
m. |
| 172 » » polyIgnoresJSONHandler(w, r) |
210 } | 173 } |
211 } | 174 } |
212 | 175 |
213 type IngoresAddRequest struct { | 176 type IgnoresAddRequest struct { |
214 Duration string `json:"duration"` | 177 Duration string `json:"duration"` |
215 Filter string `json:"filter"` | 178 Filter string `json:"filter"` |
216 Note string `json:"note"` | 179 Note string `json:"note"` |
217 } | 180 } |
218 | 181 |
219 var durationRe = regexp.MustCompile("([0-9]+)([smhdw])") | 182 var durationRe = regexp.MustCompile("([0-9]+)([smhdw])") |
220 | 183 |
221 // polyIgnoresAddHandler is for adding a new ignore rule. | 184 // polyIgnoresAddHandler is for adding a new ignore rule. |
222 func polyIgnoresAddHandler(w http.ResponseWriter, r *http.Request) { | 185 func polyIgnoresAddHandler(w http.ResponseWriter, r *http.Request) { |
223 user := login.LoggedInAs(r) | 186 user := login.LoggedInAs(r) |
224 if user == "" { | 187 if user == "" { |
225 util.ReportError(w, r, fmt.Errorf("Not logged in."), "You must b
e logged in to add an ignore rule.") | 188 util.ReportError(w, r, fmt.Errorf("Not logged in."), "You must b
e logged in to add an ignore rule.") |
226 return | 189 return |
227 } | 190 } |
228 » req := &IngoresAddRequest{} | 191 » req := &IgnoresAddRequest{} |
229 if err := parseJson(r, req); err != nil { | 192 if err := parseJson(r, req); err != nil { |
230 » » util.ReportError(w, r, err, "Failed to decode result") | 193 » » util.ReportError(w, r, err, "Failed to parse submitted data.") |
231 return | 194 return |
232 } | 195 } |
233 parsed := durationRe.FindStringSubmatch(req.Duration) | 196 parsed := durationRe.FindStringSubmatch(req.Duration) |
234 if len(parsed) != 3 { | 197 if len(parsed) != 3 { |
235 util.ReportError(w, r, fmt.Errorf("Rejected duration: %s", req.D
uration), "Failed to parse duration") | 198 util.ReportError(w, r, fmt.Errorf("Rejected duration: %s", req.D
uration), "Failed to parse duration") |
236 return | 199 return |
237 } | 200 } |
238 // TODO break out the following into its own func, add tests. | 201 // TODO break out the following into its own func, add tests. |
239 n, err := strconv.ParseInt(parsed[1], 10, 32) | 202 n, err := strconv.ParseInt(parsed[1], 10, 32) |
240 if err != nil { | 203 if err != nil { |
241 util.ReportError(w, r, err, "Failed to parse duration") | 204 util.ReportError(w, r, err, "Failed to parse duration") |
242 return | 205 return |
243 } | 206 } |
244 d := time.Second | 207 d := time.Second |
245 switch parsed[2][0] { | 208 switch parsed[2][0] { |
246 case 's': | 209 case 's': |
247 d = time.Duration(n) * time.Second | 210 d = time.Duration(n) * time.Second |
248 case 'm': | 211 case 'm': |
249 d = time.Duration(n) * time.Minute | 212 d = time.Duration(n) * time.Minute |
250 case 'h': | 213 case 'h': |
251 d = time.Duration(n) * time.Hour | 214 d = time.Duration(n) * time.Hour |
252 case 'd': | 215 case 'd': |
253 d = time.Duration(n) * 24 * time.Hour | 216 d = time.Duration(n) * 24 * time.Hour |
254 case 'w': | 217 case 'w': |
255 d = time.Duration(n) * 7 * 24 * time.Hour | 218 d = time.Duration(n) * 7 * 24 * time.Hour |
256 } | 219 } |
257 » ig := &IgnoreRule{ | 220 » ignoreRule := types.NewIgnoreRule(user, time.Now().Add(d), req.Filter, r
eq.Note) |
258 » » ID: "foo", | 221 » if err != nil { |
259 » » Name: user, | 222 » » util.ReportError(w, r, err, "Failed to create ignore rule.") |
260 » » Expires: time.Now().Add(d), | 223 » » return |
261 » » Query: req.Filter, | |
262 » » Note: req.Note, | |
263 } | 224 } |
264 » addIgnoreRule(ig) | 225 |
265 » w.Header().Set("Content-Type", "application/json") | 226 » if err := analyzer.AddIgnoreRule(ignoreRule); err != nil { |
266 » enc := json.NewEncoder(w) | 227 » » util.ReportError(w, r, err, "Failed to create ignore rule.") |
267 » if err := enc.Encode(ignores); err != nil { | 228 » » return |
268 » » util.ReportError(w, r, err, "Failed to encode result") | |
269 } | 229 } |
| 230 |
| 231 polyIgnoresJSONHandler(w, r) |
270 } | 232 } |
271 | 233 |
272 // polyIgnoresHandler is for setting up ignores rules. | 234 // polyIgnoresHandler is for setting up ignores rules. |
273 func polyIgnoresHandler(w http.ResponseWriter, r *http.Request) { | 235 func polyIgnoresHandler(w http.ResponseWriter, r *http.Request) { |
274 glog.Infof("Poly Ignores Handler: %q\n", r.URL.Path) | 236 glog.Infof("Poly Ignores Handler: %q\n", r.URL.Path) |
275 w.Header().Set("Content-Type", "text/html") | 237 w.Header().Set("Content-Type", "text/html") |
276 if *local { | 238 if *local { |
277 loadTemplates() | 239 loadTemplates() |
278 } | 240 } |
279 if err := ignoresTemplate.Execute(w, struct{}{}); err != nil { | 241 if err := ignoresTemplate.Execute(w, struct{}{}); err != nil { |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 diffStore, err := filediffstore.NewFileDiffStore(client, *imageDir, *gsB
ucketName, filediffstore.DEFAULT_GS_IMG_DIR_NAME, cacheFactory, filediffstore.RE
COMMENDED_WORKER_POOL_SIZE) | 509 diffStore, err := filediffstore.NewFileDiffStore(client, *imageDir, *gsB
ucketName, filediffstore.DEFAULT_GS_IMG_DIR_NAME, cacheFactory, filediffstore.RE
COMMENDED_WORKER_POOL_SIZE) |
548 if err != nil { | 510 if err != nil { |
549 glog.Fatalf("Allocating DiffStore failed: %s", err) | 511 glog.Fatalf("Allocating DiffStore failed: %s", err) |
550 } | 512 } |
551 conf, err := database.ConfigFromFlagsAndMetadata(*local, db.MigrationSte
ps()) | 513 conf, err := database.ConfigFromFlagsAndMetadata(*local, db.MigrationSte
ps()) |
552 if err != nil { | 514 if err != nil { |
553 glog.Fatal(err) | 515 glog.Fatal(err) |
554 } | 516 } |
555 vdb := database.NewVersionedDB(conf) | 517 vdb := database.NewVersionedDB(conf) |
556 expStore := expstorage.NewCachingExpectationStore(expstorage.NewSQLExpec
tationStore(vdb)) | 518 expStore := expstorage.NewCachingExpectationStore(expstorage.NewSQLExpec
tationStore(vdb)) |
| 519 ignoreStore = types.NewSQLIgnoreStore(vdb) |
557 tileStore := filetilestore.NewFileTileStore(*tileStoreDir, "golden", -1) | 520 tileStore := filetilestore.NewFileTileStore(*tileStoreDir, "golden", -1) |
558 | 521 |
559 // Initialize the Analyzer | 522 // Initialize the Analyzer |
560 imgFS := NewURLAwareFileServer(*imageDir, IMAGE_URL_PREFIX) | 523 imgFS := NewURLAwareFileServer(*imageDir, IMAGE_URL_PREFIX) |
561 » analyzer = analysis.NewAnalyzer(expStore, tileStore, diffStore, imgFS.Ge
tURL, 10*time.Minute) | 524 » analyzer = analysis.NewAnalyzer(expStore, tileStore, diffStore, ignoreSt
ore, imgFS.GetURL, 10*time.Minute) |
562 | 525 |
563 router := mux.NewRouter() | 526 router := mux.NewRouter() |
564 | 527 |
565 // Wire up the resources. We use the 'rest' prefix to avoid any name | 528 // Wire up the resources. We use the 'rest' prefix to avoid any name |
566 // clashes witht the static files being served. | 529 // clashes witht the static files being served. |
567 router.HandleFunc("/rest/counts", autogzip.HandleFunc(tileCountsHandler)
).Methods("GET") | 530 router.HandleFunc("/rest/counts", autogzip.HandleFunc(tileCountsHandler)
).Methods("GET") |
568 router.HandleFunc("/rest/triage", autogzip.HandleFunc(listTestDetailsHan
dler)).Methods("GET") | 531 router.HandleFunc("/rest/triage", autogzip.HandleFunc(listTestDetailsHan
dler)).Methods("GET") |
569 router.HandleFunc("/rest/triage/{testname}", autogzip.HandleFunc(testDet
ailsHandler)).Methods("GET") | 532 router.HandleFunc("/rest/triage/{testname}", autogzip.HandleFunc(testDet
ailsHandler)).Methods("GET") |
570 router.HandleFunc("/rest/triage", autogzip.HandleFunc(triageDigestsHandl
er)).Methods("POST") | 533 router.HandleFunc("/rest/triage", autogzip.HandleFunc(triageDigestsHandl
er)).Methods("POST") |
571 router.HandleFunc("/rest/status", autogzip.HandleFunc(statusHandler)).Me
thods("GET") | 534 router.HandleFunc("/rest/status", autogzip.HandleFunc(statusHandler)).Me
thods("GET") |
(...skipping 24 matching lines...) Expand all Loading... |
596 // Everything else is served out of the static directory. | 559 // Everything else is served out of the static directory. |
597 router.PathPrefix("/").Handler(http.FileServer(http.Dir(*staticDir))) | 560 router.PathPrefix("/").Handler(http.FileServer(http.Dir(*staticDir))) |
598 | 561 |
599 // Send all requests to the router | 562 // Send all requests to the router |
600 http.Handle("/", router) | 563 http.Handle("/", router) |
601 | 564 |
602 // Start the server | 565 // Start the server |
603 glog.Infoln("Serving on http://127.0.0.1" + *port) | 566 glog.Infoln("Serving on http://127.0.0.1" + *port) |
604 glog.Fatal(http.ListenAndServe(*port, nil)) | 567 glog.Fatal(http.ListenAndServe(*port, nil)) |
605 } | 568 } |
OLD | NEW |