| 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 |