Example #1
0
func Init() {
	rand.Seed(time.Now().UnixNano())
	if *resourcesDir == "" {
		_, filename, _, _ := runtime.Caller(0)
		*resourcesDir = filepath.Join(filepath.Dir(filename), "../..")
	}

	loadTemplates()

	var err error
	git, err = gitinfo.CloneOrUpdate(*gitRepoURL, *gitRepoDir, false)
	if err != nil {
		glog.Fatal(err)
	}
	evt := eventbus.New(nil)
	tileStats = tilestats.New(evt)

	// Connect to traceDB and create the builders.
	db, err := tracedb.NewTraceServiceDBFromAddress(*traceservice, types.PerfTraceBuilder)
	if err != nil {
		glog.Fatalf("Failed to connect to tracedb: %s", err)
	}

	masterTileBuilder, err = tracedb.NewMasterTileBuilder(db, git, *tileSize, evt)
	if err != nil {
		glog.Fatalf("Failed to build trace/db.DB: %s", err)
	}
	branchTileBuilder = tracedb.NewBranchTileBuilder(db, git, rietveld.RIETVELD_SKIA_URL, evt)
}
Example #2
0
func main() {
	defer common.LogPanic()
	common.Init()

	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		os.Exit(1)
	}

	bucket, prefix := args[0], args[1]
	v, err := skiaversion.GetVersion()
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Version %s, built at %s", v.Commit, v.Date)

	if *nsqdAddress == "" {
		glog.Fatal("Missing address of nsqd server.")
	}

	globalEventBus, err := geventbus.NewNSQEventBus(*nsqdAddress)
	if err != nil {
		glog.Fatalf("Unable to connect to NSQ server: %s", err)
	}

	eventBus := eventbus.New(globalEventBus)
	eventBus.SubscribeAsync(event.StorageEvent(bucket, prefix), func(evData interface{}) {
		data := evData.(*event.GoogleStorageEventData)
		glog.Infof("Google Storage notification from bucket\n %s:  %s : %s", data.Updated, data.Bucket, data.Name)
	})
	select {}
}
Example #3
0
func main() {
	common.Init()

	v, err := skiaversion.GetVersion()
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Version %s, built at %s", v.Commit, v.Date)

	if *nsqdAddress == "" {
		glog.Fatal("Missing address of nsqd server.")
	}

	globalEventBus, err := geventbus.NewNSQEventBus(*nsqdAddress)
	if err != nil {
		glog.Fatalf("Unable to connect to NSQ server: %s", err)
	}

	eventBus := eventbus.New(globalEventBus)
	eventBus.SubscribeAsync(event.GLOBAL_GOOGLE_STORAGE, func(evData interface{}) {
		data := evData.(*event.GoogleStorageEventData)
		glog.Infof("Google Storage notification from bucket\n %s:  %s : %s", data.Updated, data.Bucket, data.Name)
	})
	select {}
}
Example #4
0
func main() {
	common.Init()

	v, err := skiaversion.GetVersion()
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Version %s, built at %s", v.Commit, v.Date)

	if *nsqdAddress == "" {
		glog.Fatal("Missing address of nsqd server.")
	}

	globalEventBus, err := geventbus.NewNSQEventBus(*nsqdAddress)
	if err != nil {
		glog.Fatalf("Unable to connect to NSQ server: %s", err)
	}

	eventBus := eventbus.New(globalEventBus)

	// Send events every so often.
	for _ = range time.Tick(2 * time.Second) {
		evData := &event.GoogleStorageEventData{
			Bucket:  "test-bucket",
			Name:    "test-name",
			Updated: time.Now().String(),
		}
		eventBus.Publish(event.GLOBAL_GOOGLE_STORAGE, evData)
		glog.Infof("Sent Event: %#v ", evData)
	}
}
Example #5
0
func main() {
	defer common.LogPanic()
	common.InitWithMetrics("grandcentral", graphiteServer)
	v, err := skiaversion.GetVersion()
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Version %s, built at %s", v.Commit, v.Date)

	if *nsqdAddress == "" {
		glog.Fatal("Missing address of nsqd server.")
	}
	globalEventBus, err := geventbus.NewNSQEventBus(*nsqdAddress)
	if err != nil {
		glog.Fatalf("Unable to connect to NSQ server: %s", err)
	}
	eventBus = eventbus.New(globalEventBus)

	if *testing {
		*useMetadata = false
	}
	serverURL := "https://" + *host
	if *testing {
		serverURL = "http://" + *host + *port
	}
	runServer(serverURL)
}
Example #6
0
func main() {
	defer common.LogPanic()
	common.InitWithMetrics("grandcentral", graphiteServer)
	v, err := skiaversion.GetVersion()
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Version %s, built at %s", v.Commit, v.Date)

	if *nsqdAddress == "" {
		glog.Fatal("Missing address of nsqd server.")
	}
	globalEventBus, err := geventbus.NewNSQEventBus(*nsqdAddress)
	if err != nil {
		glog.Fatalf("Unable to connect to NSQ server: %s", err)
	}
	eventBus = eventbus.New(globalEventBus)

	// Add a subscription for the each event type. This prevents the messages
	// to queue up if there are no other clients connected.
	eventBus.SubscribeAsync(event.GLOBAL_GOOGLE_STORAGE, func(evData interface{}) {})
	eventBus.SubscribeAsync(event.GLOBAL_BUILDBOT, func(evData interface{}) {})

	if *testing {
		*useMetadata = false
	}
	serverURL := "https://" + *host
	if *testing {
		serverURL = "http://" + *host + *port
	}
	runServer(serverURL)
}
func BenchmarkHistory(b *testing.B) {
	assert.Nil(b, os.MkdirAll(TEST_DATA_DIR, 0755))
	defer testutils.RemoveAll(b, TEST_DATA_DIR)

	digestStore, err := digeststore.New(TEST_DATA_DIR)
	assert.Nil(b, err)

	tileBuilder := mocks.GetTileBuilderFromEnv(b)
	storages := &storage.Storage{
		MasterTileBuilder: tileBuilder,
		DigestStore:       digestStore,
		EventBus:          eventbus.New(nil),
	}

	tile := tileBuilder.GetTile()
	assert.Nil(b, Init(storages, 0))

	// Gather the runtimes of the testname/digest lookup.
	runtimes := make([]int64, 0, 1000000)
	timeIt := func(testName, digest string) (bool, error) {
		startTime := time.Now().UnixNano()
		_, found, err := digestStore.Get(testName, digest)
		runtimes = append(runtimes, (time.Now().UnixNano()-startTime)/1000)
		return found, err
	}

	b.ResetTimer()
	tileLen := tile.LastCommitIndex() + 1
	for _, trace := range tile.Traces {
		testName := trace.Params()[types.PRIMARY_KEY_FIELD]
		gTrace := trace.(*types.GoldenTrace)
		for _, digest := range gTrace.Values[:tileLen] {
			if digest != types.MISSING_DIGEST {
				found, err := timeIt(testName, digest)
				assert.Nil(b, err)
				assert.True(b, found)
			}
		}
	}

	var avg int64 = 0
	for _, val := range runtimes {
		avg += val
	}
	glog.Infof("Average lookup time: %.3fus", float64(avg)/float64(len(runtimes)))
	glog.Infof("Number of lookups  : %d", len(runtimes))
}
func TestMySQLExpectationsStore(t *testing.T) {
	// Set up the test database.
	testDb := testutil.SetupMySQLTestDatabase(t, db.MigrationSteps())
	defer testDb.Close(t)

	conf := testutil.LocalTestDatabaseConfig(db.MigrationSteps())
	vdb, err := conf.NewVersionedDB()
	assert.Nil(t, err)

	// Test the MySQL backed store
	sqlStore := NewSQLExpectationStore(vdb)
	testExpectationStore(t, sqlStore, nil)

	// Test the caching version of the MySQL store.
	eventBus := eventbus.New(nil)
	cachingStore := NewCachingExpectationStore(sqlStore, eventBus)
	testExpectationStore(t, cachingStore, eventBus)
}
Example #9
0
// GetTileBuilderFromEnv looks at the TEST_TRACEDB_ADDRESS environement variable for the
// name of directory that contains tiles. If it's defined it will return a
// TileStore instance. If the not the calling test will fail.
func GetTileBuilderFromEnv(t assert.TestingT) tracedb.MasterTileBuilder {
	traceDBAddress := os.Getenv("TEST_TRACEDB_ADDRESS")
	assert.NotEqual(t, "", traceDBAddress, "Please define the TEST_TRACEDB_ADDRESS environment variable to point to the traceDB.")

	gitURL := os.Getenv("TEST_GIT_URL")
	assert.NotEqual(t, "", traceDBAddress, "Please define the TEST_TRACEDB_ADDRESS environment variable to point to the Git URL.")

	gitRepoDir, err := ioutil.TempDir("", "gitrepo")
	assert.Nil(t, err)

	git, err := gitinfo.CloneOrUpdate(gitURL, gitRepoDir, false)
	if err != nil {
		glog.Fatal(err)
	}

	eventBus := eventbus.New(nil)
	db, err := tracedb.NewTraceServiceDBFromAddress(traceDBAddress, types.GoldenTraceBuilder)
	assert.Nil(t, err)

	tileBuilder, err := tracedb.NewMasterTileBuilder(db, git, 50, eventBus)
	assert.Nil(t, err)
	return tileBuilder
}
func TestNewTraceDBBuilder(t *testing.T) {
	defer cleanup()

	// First spin up a traceservice server that we wil talk to.
	server, err := traceservice.NewTraceServiceServer(FILENAME)
	if err != nil {
		t.Fatalf("Failed to initialize the tracestore server: %s", err)
	}

	// Start the server on an open port.
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to listen: %v", err)
	}
	port := lis.Addr().String()
	s := grpc.NewServer()
	traceservice.RegisterTraceServiceServer(s, server)
	go func() {
		t.Fatalf("Failed while serving: %s", s.Serve(lis))
	}()

	// Get a Git repo.
	tr := util.NewTempRepo()
	defer tr.Cleanup()

	// Set up a connection to the server.
	conn, err := grpc.Dial(port, grpc.WithInsecure())
	if err != nil {
		t.Fatalf("did not connect: %v", err)
	}
	ts, err := db.NewTraceServiceDB(conn, types.PerfTraceBuilder)
	if err != nil {
		t.Fatalf("Failed to create tracedb.DB: %s", err)
	}
	defer util.Close(ts)

	git, err := gitinfo.NewGitInfo(filepath.Join(tr.Dir, "testrepo"), false, false)
	if err != nil {
		t.Fatal(err)
	}
	hashes := git.LastN(50)
	assert.Equal(t, 50, len(hashes))

	// Populate the tracedb with some data.
	commitID := &db.CommitID{
		Timestamp: git.Timestamp(hashes[1]).Unix(),
		ID:        hashes[1],
		Source:    "master",
	}

	entries := map[string]*db.Entry{
		"key:8888:android": &db.Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.01),
		},
		"key:gpu:win8": &db.Entry{
			Params: map[string]string{
				"config":   "gpu",
				"platform": "win8",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(1.234),
		},
	}

	err = ts.Add(commitID, entries)
	if err != nil {
		t.Fatalf("Failed to add data to traceservice: %s", err)
	}

	evt := eventbus.New(nil)
	traceDB, err := db.NewTraceServiceDBFromAddress(port, types.PerfTraceBuilder)
	assert.Nil(t, err)

	builder, err := db.NewMasterTileBuilder(traceDB, git, 50, evt)
	if err != nil {
		t.Fatalf("Failed to construct TraceStore: %s", err)
	}
	tile := builder.GetTile()
	assert.Equal(t, 50, len(tile.Commits))
	assert.Equal(t, 2, len(tile.Traces))
	assert.Equal(t, commitID.ID, tile.Commits[1].Hash)
	assert.Equal(t, "Joe Gregorio ([email protected])", tile.Commits[1].Author)

	ptrace := tile.Traces["key:8888:android"].(*types.PerfTrace)
	assert.Equal(t, 0.01, ptrace.Values[1])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])

	ptrace = tile.Traces["key:gpu:win8"].(*types.PerfTrace)
	assert.Equal(t, 1.234, ptrace.Values[1])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])

	// Now add more data to the tracestore, trigger LoadTile() and check the results.
	commitID = &db.CommitID{
		Timestamp: git.Timestamp(hashes[2]).Unix(),
		ID:        hashes[2],
		Source:    "master",
	}

	entries = map[string]*db.Entry{
		"key:8888:android": &db.Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.02),
		},
		"key:565:ubuntu": &db.Entry{
			Params: map[string]string{
				"config":   "565",
				"platform": "ubuntu",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(2.345),
		},
	}

	err = ts.Add(commitID, entries)
	if err != nil {
		t.Fatalf("Failed to add data to traceservice: %s", err)
	}

	// Access the LoadTile method without exposing it in the MasterBuilder interface.
	type hasLoadTile interface {
		LoadTile() error
	}
	masterBuilder := builder.(hasLoadTile)
	if err := masterBuilder.LoadTile(); err != nil {
		t.Fatalf("Failed to force load Tile: %s", err)
	}

	tile = builder.GetTile()
	assert.Equal(t, 50, len(tile.Commits))
	assert.Equal(t, 3, len(tile.Traces))
	assert.Equal(t, commitID.ID, tile.Commits[2].Hash)

	ptrace = tile.Traces["key:8888:android"].(*types.PerfTrace)
	assert.Equal(t, 0.01, ptrace.Values[1])
	assert.Equal(t, 0.02, ptrace.Values[2])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[3])

	ptrace = tile.Traces["key:gpu:win8"].(*types.PerfTrace)
	assert.Equal(t, 1.234, ptrace.Values[1])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])

	ptrace = tile.Traces["key:565:ubuntu"].(*types.PerfTrace)
	assert.Equal(t, 2.345, ptrace.Values[2])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[3])
}
Example #11
0
/**
  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))
}
Example #12
0
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))
}
Example #13
0
func testStatusWatcher(t assert.TestingT, tileBuilder tracedb.MasterTileBuilder) {
	eventBus := eventbus.New(nil)
	storages := &storage.Storage{
		ExpectationsStore: expstorage.NewMemExpectationsStore(eventBus),
		MasterTileBuilder: tileBuilder,
		DigestStore:       &MockDigestStore{},
		EventBus:          eventBus,
	}

	watcher, err := New(storages)
	assert.Nil(t, err)

	// Go through all corpora and change all the Items to positive.
	status := watcher.GetStatus()
	assert.NotNil(t, status)

	for idx, corpStatus := range status.CorpStatus {
		// Make sure no digests has any issues attached.
		storages.DigestStore.(*MockDigestStore).issueIDs = nil

		assert.False(t, corpStatus.OK)
		tile, err := storages.GetLastTileTrimmed(true)
		assert.Nil(t, err)

		changes := map[string]types.TestClassification{}
		posOrNeg := []types.Label{types.POSITIVE, types.NEGATIVE}
		for _, trace := range tile.Traces {
			if trace.Params()[types.CORPUS_FIELD] == corpStatus.Name {
				gTrace := trace.(*types.GoldenTrace)
				testName := gTrace.Params()[types.PRIMARY_KEY_FIELD]
				for _, digest := range gTrace.Values {
					if _, ok := changes[testName]; !ok {
						changes[testName] = map[string]types.Label{}
					}
					changes[testName][digest] = posOrNeg[rand.Int()%2]
				}
			}
		}

		// Update the expecations and wait for the status to change.
		assert.Nil(t, storages.ExpectationsStore.AddChange(changes, ""))
		time.Sleep(1 * time.Second)
		newStatus := watcher.GetStatus()
		assert.False(t, newStatus.CorpStatus[idx].OK)
		assert.False(t, newStatus.OK)

		// Make sure all tests have an issue attached to each DigestInfo and
		// trigger another expectations update.
		storages.DigestStore.(*MockDigestStore).issueIDs = []int{1}
		assert.Nil(t, storages.ExpectationsStore.AddChange(changes, ""))
		time.Sleep(1 * time.Second)

		// Make sure the current corpus is now ok.
		newStatus = watcher.GetStatus()
		assert.True(t, newStatus.CorpStatus[idx].OK)
	}

	// All corpora are ok therefore the overall status should be ok.
	newStatus := watcher.GetStatus()
	assert.True(t, newStatus.OK)
}
Example #14
0
func TestBlamerWithSyntheticData(t *testing.T) {
	start := time.Now().Unix()
	commits := []*tiling.Commit{
		&tiling.Commit{CommitTime: start + 10, Hash: "h1", Author: "John Doe 1"},
		&tiling.Commit{CommitTime: start + 20, Hash: "h2", Author: "John Doe 2"},
		&tiling.Commit{CommitTime: start + 30, Hash: "h3", Author: "John Doe 3"},
		&tiling.Commit{CommitTime: start + 40, Hash: "h4", Author: "John Doe 4"},
		&tiling.Commit{CommitTime: start + 50, Hash: "h5", Author: "John Doe 5"},
	}

	params := []map[string]string{
		map[string]string{"name": "foo", "config": "8888", "source_type": "gm"},
		map[string]string{"name": "foo", "config": "565", "source_type": "gm"},
		map[string]string{"name": "foo", "config": "gpu", "source_type": "gm"},
		map[string]string{"name": "bar", "config": "8888", "source_type": "gm"},
		map[string]string{"name": "bar", "config": "565", "source_type": "gm"},
		map[string]string{"name": "bar", "config": "gpu", "source_type": "gm"},
		map[string]string{"name": "baz", "config": "565", "source_type": "gm"},
		map[string]string{"name": "baz", "config": "gpu", "source_type": "gm"},
	}

	DI_1, DI_2, DI_3 := "digest1", "digest2", "digest3"
	DI_4, DI_5, DI_6 := "digest4", "digest5", "digest6"
	DI_7, DI_8, DI_9 := "digest7", "digest8", "digest9"
	MISS := types.MISSING_DIGEST

	digests := [][]string{
		[]string{MISS, MISS, DI_1, MISS, MISS},
		[]string{MISS, DI_1, DI_1, DI_2, MISS},
		[]string{DI_3, MISS, MISS, MISS, MISS},
		[]string{DI_5, DI_4, DI_5, DI_5, DI_5},
		[]string{DI_6, MISS, DI_4, MISS, MISS},
		[]string{MISS, MISS, MISS, MISS, MISS},
		[]string{DI_7, DI_7, MISS, DI_8, MISS},
		[]string{DI_7, MISS, DI_7, DI_8, MISS},
	}

	// Make sure the data are consistent and create a mock TileStore.
	assert.Equal(t, len(commits), len(digests[0]))
	assert.Equal(t, len(digests), len(params))

	eventBus := eventbus.New(nil)
	storages := &storage.Storage{
		ExpectationsStore: expstorage.NewMemExpectationsStore(eventBus),
		MasterTileBuilder: mocks.NewMockTileBuilder(t, digests, params, commits),
		DigestStore:       &mocks.MockDigestStore{FirstSeen: start + 1000, OkValue: true},
		EventBus:          eventBus,
	}
	blamer, err := New(storages)
	assert.Nil(t, err)

	// Check when completely untriaged
	blameLists, _ := blamer.GetAllBlameLists()
	assert.NotNil(t, blameLists)

	assert.Equal(t, 3, len(blameLists))
	assert.Equal(t, 3, len(blameLists["foo"]))
	assert.Equal(t, []int{1, 0, 0, 0}, blameLists["foo"][DI_1].Freq)
	assert.Equal(t, []int{1, 0}, blameLists["foo"][DI_2].Freq)
	assert.Equal(t, []int{1, 0, 0, 0, 0}, blameLists["foo"][DI_3].Freq)

	assert.Equal(t, 3, len(blameLists["bar"]))
	assert.Equal(t, []int{2, 0, 0, 0}, blameLists["bar"][DI_4].Freq)
	assert.Equal(t, []int{1, 0, 0, 0, 0}, blameLists["bar"][DI_5].Freq)
	assert.Equal(t, []int{1, 0, 0, 0, 0}, blameLists["bar"][DI_6].Freq)

	assert.Equal(t, &BlameDistribution{Freq: []int{1}}, blamer.GetBlame("foo", DI_1, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{3}}, blamer.GetBlame("foo", DI_2, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{0}}, blamer.GetBlame("foo", DI_3, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{1}}, blamer.GetBlame("bar", DI_4, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{0}}, blamer.GetBlame("bar", DI_5, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{0}}, blamer.GetBlame("bar", DI_6, commits))

	// Classify some digests and re-calculate.
	changes := map[string]types.TestClassification{
		"foo": map[string]types.Label{DI_1: types.POSITIVE, DI_2: types.NEGATIVE},
		"bar": map[string]types.Label{DI_4: types.POSITIVE, DI_6: types.NEGATIVE},
	}
	assert.Nil(t, storages.ExpectationsStore.AddChange(changes, ""))

	// Wait for the change to propagate.
	waitForChange(blamer, blameLists)
	blameLists, _ = blamer.GetAllBlameLists()

	assert.Equal(t, 3, len(blameLists))
	assert.Equal(t, 1, len(blameLists["foo"]))
	assert.Equal(t, []int{1, 0, 0, 0, 0}, blameLists["foo"][DI_3].Freq)

	assert.Equal(t, 1, len(blameLists["bar"]))
	assert.Equal(t, []int{1, 0, 0, 0, 0}, blameLists["bar"][DI_5].Freq)
	assert.Equal(t, []int{1, 2, 0}, blameLists["baz"][DI_8].Freq)

	assert.Equal(t, &BlameDistribution{Freq: []int{0}}, blamer.GetBlame("foo", DI_3, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{0}}, blamer.GetBlame("bar", DI_5, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{3}}, blamer.GetBlame("baz", DI_8, commits))

	// Change the underlying tile and trigger with another change.
	tile := storages.MasterTileBuilder.GetTile()

	// Get the trace for the last parameters and set a value.
	gTrace := tile.Traces[mocks.TraceKey(params[5])].(*types.GoldenTrace)
	gTrace.Values[2] = DI_9

	assert.Nil(t, storages.ExpectationsStore.AddChange(changes, ""))

	// Wait for the change to propagate.
	waitForChange(blamer, blameLists)
	blameLists, _ = blamer.GetAllBlameLists()

	assert.Equal(t, 3, len(blameLists))
	assert.Equal(t, 1, len(blameLists["foo"]))
	assert.Equal(t, 2, len(blameLists["bar"]))
	assert.Equal(t, []int{1, 0, 0}, blameLists["bar"][DI_9].Freq)

	assert.Equal(t, &BlameDistribution{Freq: []int{2}}, blamer.GetBlame("bar", DI_9, commits))

	// Simulate the case where the digest is not found in digest store.
	storages.DigestStore.(*mocks.MockDigestStore).OkValue = false
	assert.Nil(t, storages.ExpectationsStore.AddChange(changes, ""))
	time.Sleep(10 * time.Millisecond)
	blameLists, _ = blamer.GetAllBlameLists()
	assert.Equal(t, 3, len(blameLists))
	assert.Equal(t, 1, len(blameLists["foo"]))
	assert.Equal(t, 2, len(blameLists["bar"]))
	assert.Equal(t, []int{1, 0, 0}, blameLists["bar"][DI_9].Freq)

	assert.Equal(t, &BlameDistribution{Freq: []int{2}}, blamer.GetBlame("bar", DI_9, commits))
	assert.Equal(t, &BlameDistribution{Freq: []int{1}}, blamer.GetBlame("bar", DI_9, commits[1:4]))
	assert.Equal(t, &BlameDistribution{Freq: []int{}}, blamer.GetBlame("bar", DI_9, commits[0:2]))
}
Example #15
0
func testBlamerWithLiveData(t assert.TestingT, tileBuilder tracedb.MasterTileBuilder) {
	eventBus := eventbus.New(nil)
	storage := &storage.Storage{
		ExpectationsStore: expstorage.NewMemExpectationsStore(eventBus),
		MasterTileBuilder: tileBuilder,
		DigestStore: &mocks.MockDigestStore{
			FirstSeen: time.Now().Unix(),
			OkValue:   true,
		},
		EventBus: eventBus,
	}

	blamer, err := New(storage)
	assert.Nil(t, err)

	// Wait until we have a blamelist.
	var blameLists map[string]map[string]*BlameDistribution
	for {
		blameLists, _ = blamer.GetAllBlameLists()
		if blameLists != nil {
			break
		}
	}

	tile := storage.MasterTileBuilder.GetTile()

	// Since we set the 'First' timestamp of all digest info entries
	// to Now. We should get a non-empty blamelist of all digests.
	oneTestName := ""
	oneDigest := ""
	forEachTestDigestDo(tile, func(testName, digest string) {
		assert.NotNil(t, blameLists[testName][digest])
		assert.True(t, len(blameLists[testName][digest].Freq) > 0)

		// Remember the last one for later.
		oneTestName, oneDigest = testName, digest
	})

	// Change the classification of one test and trigger the recalculation.
	changes := map[string]types.TestClassification{
		oneTestName: map[string]types.Label{oneDigest: types.POSITIVE},
	}
	assert.Nil(t, storage.ExpectationsStore.AddChange(changes, ""))

	// Wait for change to propagate.
	waitForChange(blamer, blameLists)
	blameLists, _ = blamer.GetAllBlameLists()

	// Assert the correctness of the blamelists.
	forEachTestDigestDo(tile, func(testName, digest string) {
		if (testName == oneTestName) && (digest == oneDigest) {
			assert.Nil(t, blameLists[testName][digest])
		} else {
			assert.NotNil(t, blameLists[testName][digest])
			assert.True(t, len(blameLists[testName][digest].Freq) > 0)
		}
	})

	// Set 'First' for all digests in the past and trigger another
	// calculation.
	storage.DigestStore.(*mocks.MockDigestStore).FirstSeen = 0
	assert.Nil(t, storage.ExpectationsStore.AddChange(changes, ""))
	waitForChange(blamer, blameLists)
	blameLists, _ = blamer.GetAllBlameLists()

	// Randomly assign labels to the different digests and make sure
	// that the blamelists are correct.
	storage.DigestStore.(*mocks.MockDigestStore).FirstSeen = time.Now().Unix()

	changes = map[string]types.TestClassification{}
	choices := []types.Label{types.POSITIVE, types.NEGATIVE, types.UNTRIAGED}
	forEachTestDigestDo(tile, func(testName, digest string) {
		targetTest := changes[testName]
		if targetTest == nil {
			targetTest = map[string]types.Label{}
		}
		// Randomly skip some digests.
		label := choices[rand.Int()%len(choices)]
		if label != types.UNTRIAGED {
			targetTest[digest] = label
		}
	})

	// Add the labels and wait for the recalculation.
	assert.Nil(t, storage.ExpectationsStore.AddChange(changes, ""))
	waitForChange(blamer, blameLists)
	blameLists, commits := blamer.GetAllBlameLists()

	expecations, err := storage.ExpectationsStore.Get()
	assert.Nil(t, err)

	// Verify that the results are plausible.
	forEachTestTraceDo(tile, func(testName string, values []string) {
		for idx, digest := range values {
			if digest != types.MISSING_DIGEST {
				label := expecations.Classification(testName, digest)
				if label == types.UNTRIAGED {
					bl := blameLists[testName][digest]
					assert.NotNil(t, bl)
					freq := bl.Freq
					assert.True(t, len(freq) > 0)
					startIdx := len(commits) - len(freq)
					assert.True(t, (startIdx >= 0) && (startIdx <= idx), fmt.Sprintf("Expected (%s): Smaller than %d but got %d.", digest, startIdx, idx))
				}
			}
		}
	})
}