Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Unified Diff: golden/go/skiacorrectness/main.go

Issue 650253003: Added HTTP endpoints for Correctness counts (Closed) Base URL: https://skia.googlesource.com/buildbot@master
Patch Set: Fixed typos Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: golden/go/skiacorrectness/main.go
diff --git a/golden/go/skiacorrectness/main.go b/golden/go/skiacorrectness/main.go
index 3b23b3161c47f6e0b40804b5695b035521126f64..bc37cc151dbe88cd9279c68250a36c054ecb3c30 100644
--- a/golden/go/skiacorrectness/main.go
+++ b/golden/go/skiacorrectness/main.go
@@ -1,32 +1,137 @@
package main
import (
+ "encoding/json"
"flag"
+ "fmt"
"net/http"
-)
+ "time"
-import (
"github.com/golang/glog"
+ "github.com/gorilla/mux"
+
+ // "skia.googlesource.com/buildbot.git/golden/go/analysis"
jcgregorio 2014/10/17 18:07:52 leftover?
stephana 2014/10/17 20:01:45 Yes. Thank you. Removed.
+ "skia.googlesource.com/buildbot.git/go/database"
+ "skia.googlesource.com/buildbot.git/golden/go/analysis"
+ "skia.googlesource.com/buildbot.git/golden/go/db"
+ "skia.googlesource.com/buildbot.git/golden/go/expstorage"
+ "skia.googlesource.com/buildbot.git/golden/go/filediffstore"
+ "skia.googlesource.com/buildbot.git/perf/go/filetilestore"
)
// flags
var (
- port = flag.String("port", ":9000", "HTTP service address (e.g., ':9000')")
- staticDir = flag.String("static", "./app", "Directory with static content to serve")
-
-// TODO (stephana): Just ideas to be sorted out later
-// tempDir = flag.String("temp", "./.cache",
-// "Directory to store temporary file and application cache")
+ port = flag.String("port", ":9000", "HTTP service address (e.g., ':9000')")
+ local = flag.Bool("local", false, "Running locally if true. As opposed to in production.")
+ staticDir = flag.String("static_dir", "./app", "Directory with static content to serve")
+ tileStoreDir = flag.String("tile_store_dir", "/tmp/tileStore", "What directory to look for tiles in.")
+ imageDiffDir = flag.String("image_diff_dir", "/tmp/imagediffdir", "What directory to store diff images in.")
+ gsBucketName = flag.String("gs_bucket", "chromium-skia-gm", "Name of the google storage bucket that holds uploaded images.")
+ mysqlConnStr = flag.String("mysql_conn", "", "MySQL connection string for backend database. If 'local' is false the password in this string will be substituted via the metadata server.")
+ sqlitePath = flag.String("sqlite_path", "./golden.db", "Filepath of the embedded SQLite database. Requires 'local' to be set to true and 'mysql_conn' to be empty to take effect.")
)
+// Response envelope. All responses follow this format. Some fields might
+// be empty depending on context.
+type ResponseEnvelope struct {
+ Data *interface{} `json:"data"`
+ Err *string `json:"err"`
+ Status int `json:"status"`
+}
+
+type RestResources struct {
+ analizer *analysis.Analyzer
+}
+
+func NewRestResources(a *analysis.Analyzer) *RestResources {
+ return &RestResources{
+ analizer: a,
+ }
+}
+
+// Get the aggregated counts
+func (rr *RestResources) GetTileCountsHandler(w http.ResponseWriter, r *http.Request) {
jcgregorio 2014/10/17 18:07:52 sendResponse looks useful, but I'm not sure about
stephana 2014/10/17 20:01:45 I added RestResources as a container for the varia
jcgregorio 2014/10/17 20:12:16 As for global, that's not too much of a concern si
+ result, err := rr.analizer.GetTileCounts()
+ if err != nil {
+ sendErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ sendResponse(w, result, http.StatusOK)
+}
+
+// Process a diff request send via HTTP.
+func (rr *RestResources) GetTestCountsHandler(w http.ResponseWriter, r *http.Request) {
+ testName := mux.Vars(r)["testname"]
+ result, err := rr.analizer.GetTestCounts(testName)
+ if err != nil {
+ sendErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ sendResponse(w, result, http.StatusOK)
+}
+
+// Send an error response with the given error message.
+func sendErrorResponse(w http.ResponseWriter, errorMsg string, status int) {
+ resp := ResponseEnvelope{nil, &errorMsg, status}
+ sendJson(w, &resp)
+}
+
+// Send a non-error response with the given data.
+func sendResponse(w http.ResponseWriter, data interface{}, status int) {
+ resp := ResponseEnvelope{&data, nil, status}
+ sendJson(w, &resp)
+}
+
+// Parse JSON input and validate it.
+// TODO (stephana): Validation is still missing. It's not sufficient
+// to just parse the JSON. Could be done with Json schemas.
+func parseJson(r *http.Request, v interface{}) error {
jcgregorio 2014/10/17 18:07:52 Doesn't appear to be used?
stephana 2014/10/17 20:01:45 Agreed that's a remainder from another version. Re
+ // TODO: validate the JSON against a schema. Might not be necessary !
+ decoder := json.NewDecoder(r.Body)
+ return decoder.Decode(v)
+}
+
+// Sends the response envelope rendered as JSON.
+func sendJson(w http.ResponseWriter, resp *ResponseEnvelope) {
+ jsonBytes, err := json.Marshal(resp)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(jsonBytes)))
jcgregorio 2014/10/17 18:07:52 Content-Length isn't necessary.
stephana 2014/10/17 20:01:45 Removed.
+ w.Write(jsonBytes)
+}
+
func main() {
// parse the arguments
flag.Parse()
+ // Get the expecations storage, the filediff storage and the tilestore.
+ diffStore := filediffstore.NewFileDiffStore(nil, *imageDiffDir, *gsBucketName)
+ vdb := database.NewVersionedDB(db.GetDatabaseConfig(*mysqlConnStr, *sqlitePath, *local))
+ expStore := expstorage.NewSQLExpectationStore(vdb)
+ tileStore := filetilestore.NewFileTileStore(*tileStoreDir, "golden", -1)
+
+ // Create the analyer and plug it into the rest resources.
+ analyzer := analysis.NewAnalyzer(expStore, tileStore, diffStore, 5*time.Minute)
+ resources := NewRestResources(analyzer)
+
+ router := mux.NewRouter()
+
+ // Wire up the resources. We use the 'rest' prefix to avoid any name
+ // clashes witht the static files being served.
+ router.HandleFunc("/rest/tilecounts", resources.GetTileCountsHandler)
jcgregorio 2014/10/17 18:07:52 Consider adding autogzip for JSON responses: htt
stephana 2014/10/17 20:01:45 I actually had that and removed it. I think we sho
+ router.HandleFunc("/rest/tilecounts/{testname}", resources.GetTestCountsHandler)
+
// // Static file handling
- http.Handle("/", http.FileServer(http.Dir(*staticDir)))
+ router.Handle("/", http.FileServer(http.Dir(*staticDir)))
- // Wire up the resources
+ // Send all requests to the router
+ http.Handle("/", router)
// Start the server
glog.Infoln("Serving on http://127.0.0.1" + *port)

Powered by Google App Engine
This is Rietveld 408576698