blob: 8086162b9f66573585f1c0b344e7a2d215c96dff [file] [log] [blame]
package indexer
import (
"flag"
"math/rand"
"sync"
"testing"
"time"
assert "github.com/stretchr/testify/require"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/go/database/testutil"
"go.skia.org/infra/go/eventbus"
"go.skia.org/infra/go/gcs"
"go.skia.org/infra/go/git/gitinfo"
"go.skia.org/infra/go/testutils"
"go.skia.org/infra/go/tiling"
tracedb "go.skia.org/infra/go/trace/db"
"go.skia.org/infra/golden/go/db"
"go.skia.org/infra/golden/go/expstorage"
"go.skia.org/infra/golden/go/ignore"
"go.skia.org/infra/golden/go/mocks"
"go.skia.org/infra/golden/go/storage"
"go.skia.org/infra/golden/go/types"
)
const (
// Directory with testdata.
TEST_DATA_DIR = "./testdata"
// Local file location of the test data.
TEST_DATA_PATH = TEST_DATA_DIR + "/goldentile.json.zip"
// Folder in the testdata bucket. See go/testutils for details.
TEST_DATA_STORAGE_PATH = "gold-testdata/goldentile.json.gz"
// REPO_URL is the url of the repo to check out.
REPO_URL = "https://skia.googlesource.com/skia"
// REPO_DIR contains the location of where to check out Skia for benchmarks.
REPO_DIR = "./skia"
// N_COMMITS is the number of commits used in benchmarks.
N_COMMITS = 50
// Database user used by benchmarks.
DB_USER = "readwrite"
// TEST_BUCKET_NAME is the bucket where the test file will be written.
TEST_BUCKET_NAME = "skia-infra-testdata"
// TEST_HASH_FILE_PATH is the path to the test hash file.
TEST_HASH_FILE_PATH = "hash_files/testing-known-hashes.txt"
)
// Flags used by benchmarks. Everything else uses reasonable assumptions based
// on a local setup of tracdb and skiaingestion.
var (
traceService = flag.String("trace_service", "localhost:9001", "The address of the traceservice endpoint.")
dbName = flag.String("db_name", "gold_skiacorrectness", "The name of the databased to use. User 'readwrite' and local test settings are assumed.")
)
func TestIndexer(t *testing.T) {
testutils.LargeTest(t)
err := gcs.DownloadTestDataFile(t, gcs.TEST_DATA_BUCKET, TEST_DATA_STORAGE_PATH, TEST_DATA_PATH)
assert.NoError(t, err, "Unable to download testdata.")
defer testutils.RemoveAll(t, TEST_DATA_DIR)
tileBuilder := mocks.NewMockTileBuilderFromJson(t, TEST_DATA_PATH)
eventBus := eventbus.New()
expStore := expstorage.NewMemExpectationsStore(eventBus)
gsClient, err := storage.NewGStorageClient(mocks.GetHTTPClient(t), TEST_BUCKET_NAME, TEST_HASH_FILE_PATH)
assert.NoError(t, err)
storages := &storage.Storage{
ExpectationsStore: expStore,
MasterTileBuilder: tileBuilder,
DigestStore: &mocks.MockDigestStore{
FirstSeen: time.Now().Unix(),
OkValue: true,
},
DiffStore: mocks.NewMockDiffStore(),
EventBus: eventBus,
GStorageClient: gsClient,
}
ixr, err := New(storages, time.Minute)
assert.NoError(t, err)
idxOne := ixr.GetIndex()
// Change the classifications.
changes := getChanges(t, idxOne.tilePair.Tile)
assert.NoError(t, storages.ExpectationsStore.AddChange(changes, ""))
// Wait for the re-indexing.
time.Sleep(time.Second)
idxTwo := ixr.GetIndex()
assert.NotEqual(t, idxOne, idxTwo)
}
func getChanges(t *testing.T, tile *tiling.Tile) map[string]types.TestClassification {
ret := map[string]types.TestClassification{}
labelVals := []types.Label{types.POSITIVE, types.NEGATIVE}
for _, trace := range tile.Traces {
if rand.Float32() > 0.5 {
gTrace := trace.(*types.GoldenTrace)
for _, digest := range gTrace.Values {
if digest != types.MISSING_DIGEST {
testName := gTrace.Params_[types.PRIMARY_KEY_FIELD]
if found, ok := ret[testName]; ok {
found[digest] = labelVals[rand.Int()%2]
} else {
ret[testName] = types.TestClassification{digest: labelVals[rand.Int()%2]}
}
}
}
}
}
assert.True(t, len(ret) > 0)
return ret
}
func BenchmarkIndexer(b *testing.B) {
storages, expStore := setupStorages(b)
defer testutils.RemoveAll(b, REPO_DIR)
// Build the initial index.
b.ResetTimer()
_, err := New(storages, time.Minute*15)
assert.NoError(b, err)
// Update the expectations.
changes, err := expStore.Get()
assert.NoError(b, err)
sklog.Infof("Got %d tests", len(changes.Tests))
// Wait for the indexTests to complete when we change the expectations.
var wg sync.WaitGroup
wg.Add(1)
storages.EventBus.SubscribeAsync(EV_INDEX_UPDATED, func(state interface{}) {
wg.Done()
})
assert.NoError(b, storages.ExpectationsStore.AddChange(changes.Tests, ""))
wg.Wait()
}
func setupStorages(t assert.TestingT) (*storage.Storage, expstorage.ExpectationsStore) {
flag.Parse()
// Set up the database configuration.
dbConf := testutil.LocalTestDatabaseConfig(db.MigrationSteps())
dbConf.User = DB_USER
dbConf.Name = *dbName
// Set up the diff store, the event bus and the DB connection.
diffStore := mocks.NewMockDiffStore()
evt := eventbus.New()
vdb, err := dbConf.NewVersionedDB()
assert.NoError(t, err)
expStore := expstorage.NewCachingExpectationStore(expstorage.NewSQLExpectationStore(vdb), evt)
git, err := gitinfo.CloneOrUpdate(REPO_URL, REPO_DIR, false)
assert.NoError(t, err)
traceDB, err := tracedb.NewTraceServiceDBFromAddress(*traceService, types.GoldenTraceBuilder)
assert.NoError(t, err)
masterTileBuilder, err := tracedb.NewMasterTileBuilder(traceDB, git, N_COMMITS, evt, "")
assert.NoError(t, err)
ret := &storage.Storage{
DiffStore: diffStore,
ExpectationsStore: expstorage.NewMemExpectationsStore(evt),
MasterTileBuilder: masterTileBuilder,
BranchTileBuilder: nil,
DigestStore: &mocks.MockDigestStore{IssueIDs: []int{}, OkValue: true},
NCommits: N_COMMITS,
EventBus: evt,
TrybotResults: nil,
RietveldAPI: nil,
}
ret.IgnoreStore = ignore.NewSQLIgnoreStore(vdb, ret.ExpectationsStore, ret.GetTileStreamNow(time.Minute))
_, err = ret.GetLastTileTrimmed()
assert.NoError(t, err)
return ret, expStore
}