/** Conditions to test. Traces ------ id | config | test name | corpus(source_type) | digests a 8888 foo gm aaa+, bbb- b 565 foo gm ccc?, ddd? c gpu foo gm eee+ d 8888 bar gm fff-, ggg? e 8888 quux image jjj? Expectations ------------ foo aaa pos foo bbb neg foo ccc unt foo ddd unt foo eee pos bar fff neg Ignores ------- config=565 Note no entry for quux or ggg, meaning untriaged. Test the following conditions and make sure you get the expected test summaries. source_type=gm foo - pos(aaa, eee):2 neg(bbb):1 bar - neg(fff):1 unt(ggg):1 source_type=gm includeIgnores=true foo - pos(aaa, eee):2 neg(bbb):1 unt(ccc, ddd):2 bar - neg(fff):1 unt(ggg):1 source_type=gm includeIgnores=true testName=foo foo - pos(aaa, eee):2 neg(bbb):1 unt(ccc, ddd):2 testname = foo foo - pos(aaa, eee):2 neg(bbb):1 testname = quux quux - unt(jjj):1 config=565&config=8888 foo - pos(aaa):1 neg(bbb):1 bar - neg(fff):1 unt(ggg):1 quux - unt(jjj):1 config=565&config=8888 head=true foo - neg(bbb):1 bar - unt(ggg):1 quux - unt(jjj):1 config=gpu foo - pos(eee):1 config=unknown <empty> */ func TestCalcSummaries(t *testing.T) { tile := &tiling.Tile{ Traces: map[string]tiling.Trace{ "a": &types.GoldenTrace{ Values: []string{"aaa", "bbb"}, Params_: map[string]string{ "name": "foo", "config": "8888", "source_type": "gm"}, }, "b": &types.GoldenTrace{ Values: []string{"ccc", "ddd"}, Params_: map[string]string{ "name": "foo", "config": "565", "source_type": "gm"}, }, "c": &types.GoldenTrace{ Values: []string{"eee", types.MISSING_DIGEST}, Params_: map[string]string{ "name": "foo", "config": "gpu", "source_type": "gm"}, }, "d": &types.GoldenTrace{ Values: []string{"fff", "ggg"}, Params_: map[string]string{ "name": "bar", "config": "8888", "source_type": "gm"}, }, "e": &types.GoldenTrace{ Values: []string{"jjj", types.MISSING_DIGEST}, Params_: map[string]string{ "name": "quux", "config": "8888", "source_type": "image"}, }, }, Commits: []*tiling.Commit{ &tiling.Commit{ CommitTime: 42, Hash: "ffffffffffffffffffffffffffffffffffffffff", Author: "*****@*****.**", }, &tiling.Commit{ CommitTime: 45, Hash: "gggggggggggggggggggggggggggggggggggggggg", Author: "*****@*****.**", }, }, Scale: 0, TileIndex: 0, } eventBus := eventbus.New(nil) storages := &storage.Storage{ DiffStore: mocks.MockDiffStore{}, ExpectationsStore: expstorage.NewMemExpectationsStore(eventBus), IgnoreStore: ignore.NewMemIgnoreStore(), MasterTileBuilder: mocks.NewMockTileBuilderFromTile(t, tile), NCommits: 50, EventBus: eventBus, DigestStore: &mocks.MockDigestStore{FirstSeen: time.Now().Unix() + 1000, OkValue: true}, } assert.Nil(t, storages.ExpectationsStore.AddChange(map[string]types.TestClassification{ "foo": map[string]types.Label{ "aaa": types.POSITIVE, "bbb": types.NEGATIVE, "ccc": types.UNTRIAGED, "ddd": types.UNTRIAGED, "eee": types.POSITIVE, }, "bar": map[string]types.Label{ "fff": types.NEGATIVE, }, }, "*****@*****.**")) ta, _ := tally.New(storages) assert.Nil(t, storages.IgnoreStore.Create(&ignore.IgnoreRule{ ID: 1, Name: "foo", Expires: time.Now().Add(time.Hour), Query: "config=565", })) blamer, err := blame.New(storages) assert.Nil(t, err) summaries, err := New(storages, ta, blamer) assert.Nil(t, err) sum, err := summaries.CalcSummaries(nil, "source_type=gm", false, false) if err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 2, len(sum)) triageCountsCorrect(t, sum, "foo", 2, 1, 0) triageCountsCorrect(t, sum, "bar", 0, 1, 1) assert.Equal(t, []string{}, sum["foo"].UntHashes) assert.Equal(t, []string{"ggg"}, sum["bar"].UntHashes) if sum, err = summaries.CalcSummaries(nil, "source_type=gm", true, false); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 2, len(sum)) triageCountsCorrect(t, sum, "foo", 2, 1, 2) triageCountsCorrect(t, sum, "bar", 0, 1, 1) assert.Equal(t, sum["foo"].UntHashes, []string{"ccc", "ddd"}) assert.Equal(t, sum["bar"].UntHashes, []string{"ggg"}) if sum, err = summaries.CalcSummaries([]string{"foo"}, "source_type=gm", true, false); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 1, len(sum)) triageCountsCorrect(t, sum, "foo", 2, 1, 2) assert.Equal(t, sum["foo"].UntHashes, []string{"ccc", "ddd"}) if sum, err = summaries.CalcSummaries([]string{"foo"}, "", false, false); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 1, len(sum)) triageCountsCorrect(t, sum, "foo", 2, 1, 0) assert.Equal(t, sum["foo"].UntHashes, []string{}) if sum, err = summaries.CalcSummaries(nil, "config=8888&config=565", false, false); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 3, len(sum)) triageCountsCorrect(t, sum, "foo", 1, 1, 0) triageCountsCorrect(t, sum, "bar", 0, 1, 1) triageCountsCorrect(t, sum, "quux", 0, 0, 1) assert.Equal(t, sum["foo"].UntHashes, []string{}) assert.Equal(t, sum["bar"].UntHashes, []string{"ggg"}) assert.Equal(t, sum["quux"].UntHashes, []string{"jjj"}) if sum, err = summaries.CalcSummaries(nil, "config=8888&config=565", false, true); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 3, len(sum)) triageCountsCorrect(t, sum, "foo", 0, 1, 0) triageCountsCorrect(t, sum, "bar", 0, 0, 1) triageCountsCorrect(t, sum, "quux", 0, 0, 1) assert.Equal(t, sum["foo"].UntHashes, []string{}) assert.Equal(t, sum["bar"].UntHashes, []string{"ggg"}) assert.Equal(t, sum["quux"].UntHashes, []string{"jjj"}) if sum, err = summaries.CalcSummaries(nil, "config=gpu", false, false); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 1, len(sum)) triageCountsCorrect(t, sum, "foo", 1, 0, 0) assert.Equal(t, sum["foo"].UntHashes, []string{}) if sum, err = summaries.CalcSummaries(nil, "config=unknown", false, false); err != nil { t.Fatalf("Failed to calc: %s", err) } assert.Equal(t, 0, len(sum)) }
func main() { defer common.LogPanic() var err error mainTimer := timer.New("main init") // Setup DB flags. dbConf := database.ConfigFromFlags(db.PROD_DB_HOST, db.PROD_DB_PORT, database.USER_RW, db.PROD_DB_NAME, db.MigrationSteps()) // Global init to initialize common.InitWithMetrics("skiacorrectness", graphiteServer) v, err := skiaversion.GetVersion() if err != nil { glog.Fatalf("Unable to retrieve version: %s", err) } glog.Infof("Version %s, built at %s", v.Commit, v.Date) // Enable the memory profiler if memProfile was set. // TODO(stephana): This should be moved to a HTTP endpoint that // only responds to internal IP addresses/ports. if *memProfile > 0 { time.AfterFunc(*memProfile, func() { glog.Infof("Writing Memory Profile") f, err := ioutil.TempFile("./", "memory-profile") if err != nil { glog.Fatalf("Unable to create memory profile file: %s", err) } if err := pprof.WriteHeapProfile(f); err != nil { glog.Fatalf("Unable to write memory profile file: %v", err) } util.Close(f) glog.Infof("Memory profile written to %s", f.Name()) os.Exit(0) }) } if *cpuProfile > 0 { glog.Infof("Writing CPU Profile") f, err := ioutil.TempFile("./", "cpu-profile") if err != nil { glog.Fatalf("Unable to create cpu profile file: %s", err) } if err := pprof.StartCPUProfile(f); err != nil { glog.Fatalf("Unable to write cpu profile file: %v", err) } time.AfterFunc(*cpuProfile, func() { pprof.StopCPUProfile() util.Close(f) glog.Infof("CPU profile written to %s", f.Name()) os.Exit(0) }) } // Init this module. Init() // Initialize submodules. filediffstore.Init() // Set up login // TODO (stephana): Factor out to go/login/login.go and removed hard coded // values. var cookieSalt = "notverysecret" var clientID = "31977622648-ubjke2f3staq6ouas64r31h8f8tcbiqp.apps.googleusercontent.com" var clientSecret = "rK-kRY71CXmcg0v9I9KIgWci" var useRedirectURL = fmt.Sprintf("http://localhost%s/oauth2callback/", *port) if !*local { cookieSalt = metadata.Must(metadata.ProjectGet(metadata.COOKIESALT)) clientID = metadata.Must(metadata.ProjectGet(metadata.CLIENT_ID)) clientSecret = metadata.Must(metadata.ProjectGet(metadata.CLIENT_SECRET)) useRedirectURL = *redirectURL } login.Init(clientID, clientSecret, useRedirectURL, cookieSalt, login.DEFAULT_SCOPE, *authWhiteList, *local) // get the Oauthclient if necessary. client := getOAuthClient(*oauthCacheFile) // Set up the cache implementation to use. cacheFactory := filediffstore.MemCacheFactory if *redisHost != "" { cacheFactory = func(uniqueId string, codec util.LRUCodec) util.LRUCache { return redisutil.NewRedisLRUCache(*redisHost, *redisDB, uniqueId, codec) } } // Get the expecations storage, the filediff storage and the tilestore. diffStore, err := filediffstore.NewFileDiffStore(client, *imageDir, *gsBucketName, filediffstore.DEFAULT_GS_IMG_DIR_NAME, cacheFactory, filediffstore.RECOMMENDED_WORKER_POOL_SIZE) if err != nil { glog.Fatalf("Allocating DiffStore failed: %s", err) } if !*local { if err := dbConf.GetPasswordFromMetadata(); err != nil { glog.Fatal(err) } } vdb, err := dbConf.NewVersionedDB() if err != nil { glog.Fatal(err) } if !vdb.IsLatestVersion() { glog.Fatal("Wrong DB version. Please updated to latest version.") } digestStore, err := digeststore.New(*storageDir) if err != nil { glog.Fatal(err) } eventBus := eventbus.New(nil) storages = &storage.Storage{ DiffStore: diffStore, ExpectationsStore: expstorage.NewCachingExpectationStore(expstorage.NewSQLExpectationStore(vdb), eventBus), IgnoreStore: ignore.NewSQLIgnoreStore(vdb), TileStore: filetilestore.NewFileTileStore(*tileStoreDir, config.DATASET_GOLD, 2*time.Minute), DigestStore: digestStore, NCommits: *nCommits, EventBus: eventBus, TrybotResults: trybot.NewTrybotResultStorage(vdb), RietveldAPI: rietveld.New(*rietveldURL, nil), } if err := history.Init(storages, *nTilesToBackfill); err != nil { glog.Fatalf("Unable to initialize history package: %s", err) } if blamer, err = blame.New(storages); err != nil { glog.Fatalf("Unable to create blamer: %s", err) } if err := ignore.Init(storages.IgnoreStore); err != nil { glog.Fatalf("Failed to start monitoring for expired ignore rules: %s", err) } // Enable the experimental features. tallies, err = tally.New(storages) if err != nil { glog.Fatalf("Failed to build tallies: %s", err) } paramsetSum = paramsets.New(tallies, storages) if !*local { *issueTrackerKey = metadata.Must(metadata.ProjectGet(metadata.APIKEY)) } issueTracker = issues.NewIssueTracker(*issueTrackerKey) summaries, err = summary.New(storages, tallies, blamer) if err != nil { glog.Fatalf("Failed to build summary: %s", err) } statusWatcher, err = status.New(storages) if err != nil { glog.Fatalf("Failed to initialize status watcher: %s", err) } imgFS := NewURLAwareFileServer(*imageDir, IMAGE_URL_PREFIX) pathToURLConverter = imgFS.GetURL if err := warmer.Init(storages, summaries, tallies); err != nil { glog.Fatalf("Failed to initialize the warmer: %s", err) } mainTimer.Stop() // Everything is wired up at this point. Run the self tests if requested. if *selfTest { search.SelfTest(storages, tallies, blamer, paramsetSum) } router := mux.NewRouter() // Set up the resource to serve the image files. router.PathPrefix(IMAGE_URL_PREFIX).Handler(imgFS.Handler) // New Polymer based UI endpoints. router.PathPrefix("/res/").HandlerFunc(makeResourceHandler()) // TODO(stephana): Remove the 'poly' prefix from all the handlers and clean // up main2.go by either merging it it into main.go or making it clearer that // it contains all the handlers. Make it clearer what variables are shared // between the different file. // All the handlers will be prefixed with poly to differentiate it from the // angular code until the angular code is removed. router.HandleFunc(OAUTH2_CALLBACK_PATH, login.OAuth2CallbackHandler) router.HandleFunc("/", byBlameHandler).Methods("GET") router.HandleFunc("/list", templateHandler("list.html")).Methods("GET") router.HandleFunc("/_/details", polyDetailsHandler).Methods("GET") router.HandleFunc("/_/diff", polyDiffJSONDigestHandler).Methods("GET") router.HandleFunc("/_/hashes", polyAllHashesHandler).Methods("GET") router.HandleFunc("/_/ignores", polyIgnoresJSONHandler).Methods("GET") router.HandleFunc("/_/ignores/add/", polyIgnoresAddHandler).Methods("POST") router.HandleFunc("/_/ignores/del/{id}", polyIgnoresDeleteHandler).Methods("POST") router.HandleFunc("/_/ignores/save/{id}", polyIgnoresUpdateHandler).Methods("POST") router.HandleFunc("/_/list", polyListTestsHandler).Methods("GET") router.HandleFunc("/_/paramset", polyParamsHandler).Methods("GET") router.HandleFunc("/_/nxn", nxnJSONHandler).Methods("GET") // TODO(stephana): Once /_/search3 is stable it will replace /_/search and the // /search*.html pages will be consolidated into one. router.HandleFunc("/_/search", polySearchJSONHandler).Methods("GET") router.HandleFunc("/_/search3", search3JSONHandler).Methods("GET") router.HandleFunc("/_/status/{test}", polyTestStatusHandler).Methods("GET") router.HandleFunc("/_/test", polyTestHandler).Methods("POST") router.HandleFunc("/_/triage", polyTriageHandler).Methods("POST") router.HandleFunc("/_/triagelog", polyTriageLogHandler).Methods("GET") router.HandleFunc("/_/triagelog/undo", triageUndoHandler).Methods("POST") router.HandleFunc("/_/failure", failureListJSONHandler).Methods("GET") router.HandleFunc("/_/failure/clear", failureClearJSONHandler).Methods("POST") router.HandleFunc("/_/trybot", listTrybotsJSONHandler).Methods("GET") router.HandleFunc("/byblame", byBlameHandler).Methods("GET") router.HandleFunc("/cluster", templateHandler("cluster.html")).Methods("GET") router.HandleFunc("/search2", search2Handler).Methods("GET") router.HandleFunc("/cmp/{test}", templateHandler("compare.html")).Methods("GET") router.HandleFunc("/detail", templateHandler("single.html")).Methods("GET") router.HandleFunc("/diff", templateHandler("diff.html")).Methods("GET") router.HandleFunc("/help", templateHandler("help.html")).Methods("GET") router.HandleFunc("/ignores", templateHandler("ignores.html")).Methods("GET") router.HandleFunc("/loginstatus/", login.StatusHandler) router.HandleFunc("/logout/", login.LogoutHandler) router.HandleFunc("/search", templateHandler("search.html")).Methods("GET") router.HandleFunc("/triagelog", templateHandler("triagelog.html")).Methods("GET") router.HandleFunc("/trybot", templateHandler("trybot.html")).Methods("GET") router.HandleFunc("/failures", templateHandler("failures.html")).Methods("GET") // Add the necessary middleware and have the router handle all requests. // By structuring the middleware this way we only log requests that are // authenticated. rootHandler := util.LoggingGzipRequestResponse(router) if *forceLogin { rootHandler = login.ForceAuth(rootHandler, OAUTH2_CALLBACK_PATH) } // The polyStatusHandler is being polled, so we exclude it from logging. http.HandleFunc("/_/trstatus", polyStatusHandler) http.Handle("/", rootHandler) // Start the server glog.Infoln("Serving on http://127.0.0.1" + *port) glog.Fatal(http.ListenAndServe(*port, nil)) }