blob: 1ef96925c28d67e9709f0d5eff2f726bc137c738 [file] [log] [blame]
package summary_test
import (
"net/url"
"testing"
"time"
assert "github.com/stretchr/testify/require"
"go.skia.org/infra/go/testutils/unittest"
"go.skia.org/infra/go/tiling"
"go.skia.org/infra/golden/go/blame"
"go.skia.org/infra/golden/go/digest_counter"
"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/summary"
"go.skia.org/infra/golden/go/types"
)
/**
Conditions to test.
Traces
------
id | config | test name | corpus(source_type) | digests
a 8888 test_first gm aaa+, bbb-
b 565 test_first gm ccc?, ddd?
c gpu test_first gm eee+
d 8888 test_second gm fff-, ggg?
e 8888 test_third image jjj?
Expectations
------------
test_first aaa pos
test_first bbb neg
test_first ccc unt
test_first ddd unt
test_first eee pos
test_second fff neg
Ignores
-------
config=565
Note no entry for test_third or ggg, meaning untriaged.
Test the following conditions and make sure you get
the expected test summaries.
source_type=gm
test_first - pos(aaa, eee):2 neg(bbb):1
test_second - neg(fff):1 unt(ggg):1
source_type=gm includeIgnores=true
test_first - pos(aaa, eee):2 neg(bbb):1 unt(ccc, ddd):2
test_second - neg(fff):1 unt(ggg):1
source_type=gm includeIgnores=true testName=test_first
test_first - pos(aaa, eee):2 neg(bbb):1 unt(ccc, ddd):2
testname = test_first
test_first - pos(aaa, eee):2 neg(bbb):1
testname = test_third
test_third - unt(jjj):1
config=565&config=8888
test_first - pos(aaa):1 neg(bbb):1
test_second - neg(fff):1 unt(ggg):1
test_third - unt(jjj):1
config=565&config=8888 head=true
test_first - neg(bbb):1
test_second - unt(ggg):1
test_third - unt(jjj):1
config=gpu
test_first - pos(eee):1
config=unknown
<empty>
*/
func TestCalcSummaries(t *testing.T) {
unittest.SmallTest(t)
tile := &tiling.Tile{
Traces: map[tiling.TraceId]tiling.Trace{
// These trace ids have been shortened for test terseness.
// A real trace id would be like ",config=8888,source_type=gm,name=foo,"
"a": &types.GoldenTrace{
Digests: types.DigestSlice{"aaa", "bbb"},
Keys: map[string]string{
"config": "8888",
types.CORPUS_FIELD: "gm",
types.PRIMARY_KEY_FIELD: string(FirstTest),
},
},
"b": &types.GoldenTrace{
Digests: types.DigestSlice{"ccc", "ddd"},
Keys: map[string]string{
"config": "565",
types.CORPUS_FIELD: "gm",
types.PRIMARY_KEY_FIELD: string(FirstTest),
},
},
"c": &types.GoldenTrace{
Digests: types.DigestSlice{"eee", types.MISSING_DIGEST},
Keys: map[string]string{
"config": "gpu",
types.CORPUS_FIELD: "gm",
types.PRIMARY_KEY_FIELD: string(FirstTest),
},
},
"d": &types.GoldenTrace{
Digests: types.DigestSlice{"fff", "ggg"},
Keys: map[string]string{
"config": "8888",
types.CORPUS_FIELD: "gm",
types.PRIMARY_KEY_FIELD: string(SecondTest),
},
},
"e": &types.GoldenTrace{
Digests: types.DigestSlice{"jjj", types.MISSING_DIGEST},
Keys: map[string]string{
"config": "8888",
types.CORPUS_FIELD: "image",
types.PRIMARY_KEY_FIELD: string(ThirdTest),
},
},
},
Commits: []*tiling.Commit{
{
CommitTime: 42,
Hash: "ffffffffffffffffffffffffffffffffffffffff",
Author: "test@test.cz",
},
{
CommitTime: 45,
Hash: "gggggggggggggggggggggggggggggggggggggggg",
Author: "test@test.cz",
},
},
Scale: 0,
TileIndex: 0,
}
// TODO(kjlubick): This test should use mockery-based mocks.
mes := &mocks.ExpectationsStore{}
defer mes.AssertExpectations(t)
mes.On("Get").Return(types.Expectations{
FirstTest: map[types.Digest]types.Label{
"aaa": types.POSITIVE,
"bbb": types.NEGATIVE,
"ccc": types.UNTRIAGED,
"ddd": types.UNTRIAGED,
"eee": types.POSITIVE,
},
SecondTest: map[types.Digest]types.Label{
"fff": types.NEGATIVE,
},
}, nil)
storages := &storage.Storage{
ExpectationsStore: mes,
IgnoreStore: ignore.NewMemIgnoreStore(),
MasterTileBuilder: mocks.NewMockTileBuilderFromTile(t, tile),
NCommits: 50,
}
dc := digest_counter.New(tile)
assert.NoError(t, storages.IgnoreStore.Create(&ignore.IgnoreRule{
ID: 1,
Name: "user@example.com",
Expires: time.Now().Add(time.Hour),
Query: "config=565",
}))
tileWithIgnoreApplied, _, err := storage.FilterIgnored(tile, storages.IgnoreStore)
assert.NoError(t, err)
exp, err := storages.ExpectationsStore.Get()
assert.NoError(t, err)
blamer, err := blame.New(tile, exp)
assert.NoError(t, err)
// Query all gms with ignores
if sum, err := summary.NewSummaryMap(storages, tileWithIgnoreApplied, dc, blamer, nil, url.Values{types.CORPUS_FIELD: {"gm"}}, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 2, len(sum))
triageCountsCorrect(t, sum, FirstTest, 2, 1, 0)
triageCountsCorrect(t, sum, SecondTest, 0, 1, 1)
assert.Nil(t, sum[ThirdTest]) // no gms for ThirdTest
// The only 2 untriaged digests for this test ignored because they were 565
assert.Empty(t, sum[FirstTest].UntHashes)
assert.Equal(t, types.DigestSlice{"ggg"}, sum[SecondTest].UntHashes)
}
// Query all gms with full tile.
if sum, err := summary.NewSummaryMap(storages, tile, dc, blamer, nil, url.Values{types.CORPUS_FIELD: {"gm"}}, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 2, len(sum))
triageCountsCorrect(t, sum, FirstTest, 2, 1, 2)
triageCountsCorrect(t, sum, SecondTest, 0, 1, 1)
assert.Nil(t, sum[ThirdTest]) // no gms for ThirdTest
assert.Equal(t, types.DigestSlice{"ccc", "ddd"}, sum[FirstTest].UntHashes)
assert.Equal(t, types.DigestSlice{"ggg"}, sum[SecondTest].UntHashes)
}
// Query gms belonging to test FirstTest from full tile
if sum, err := summary.NewSummaryMap(storages, tile, dc, blamer, types.TestNameSet{FirstTest: true}, url.Values{types.CORPUS_FIELD: {"gm"}}, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 1, len(sum))
triageCountsCorrect(t, sum, FirstTest, 2, 1, 2)
assert.Equal(t, types.DigestSlice{"ccc", "ddd"}, sum[FirstTest].UntHashes)
assert.Nil(t, sum[SecondTest])
assert.Nil(t, sum[ThirdTest])
}
// Query all digests belonging to test FirstTest from tile with ignores applied
if sum, err := summary.NewSummaryMap(storages, tileWithIgnoreApplied, dc, blamer, types.TestNameSet{FirstTest: true}, nil, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 1, len(sum))
triageCountsCorrect(t, sum, FirstTest, 2, 1, 0)
// Again, the only untriaged hashes are removed from the ignore
assert.Empty(t, sum[FirstTest].UntHashes)
assert.Nil(t, sum[SecondTest])
assert.Nil(t, sum[ThirdTest])
}
// query any digest in 8888 OR 565 from tile with ignores applied
if sum, err := summary.NewSummaryMap(storages, tileWithIgnoreApplied, dc, blamer, nil, url.Values{"config": {"8888", "565"}}, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 3, len(sum))
triageCountsCorrect(t, sum, FirstTest, 1, 1, 0)
triageCountsCorrect(t, sum, SecondTest, 0, 1, 1)
triageCountsCorrect(t, sum, ThirdTest, 0, 0, 1)
// Even though we queried for the 565, the untriaged ones won't show up because of ignores.
assert.Empty(t, sum[FirstTest].UntHashes)
assert.Equal(t, types.DigestSlice{"ggg"}, sum[SecondTest].UntHashes)
assert.Equal(t, types.DigestSlice{"jjj"}, sum[ThirdTest].UntHashes)
}
// query any digest in 8888 OR 565 from tile with ignores applied at Head
if sum, err := summary.NewSummaryMap(storages, tileWithIgnoreApplied, dc, blamer, nil, url.Values{"config": {"8888", "565"}}, true); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 3, len(sum))
// These numbers are are a bit lower because we are only looking at head.
// Those with missing digests should "pull forward" their last result (see ThirdTest)
triageCountsCorrect(t, sum, FirstTest, 0, 1, 0)
triageCountsCorrect(t, sum, SecondTest, 0, 0, 1)
triageCountsCorrect(t, sum, ThirdTest, 0, 0, 1)
assert.Empty(t, sum[FirstTest].UntHashes)
assert.Equal(t, types.DigestSlice{"ggg"}, sum[SecondTest].UntHashes)
assert.Equal(t, types.DigestSlice{"jjj"}, sum[ThirdTest].UntHashes)
}
// Query any digest with the gpu config
if sum, err := summary.NewSummaryMap(storages, tileWithIgnoreApplied, dc, blamer, nil, url.Values{"config": {"gpu"}}, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 1, len(sum))
// Only one digest should be found, and it is not triaged.
triageCountsCorrect(t, sum, FirstTest, 1, 0, 0)
assert.Empty(t, sum[FirstTest].UntHashes)
}
// Nothing should show up from an unknown query
if sum, err := summary.NewSummaryMap(storages, tileWithIgnoreApplied, dc, blamer, nil, url.Values{"config": {"unknown"}}, false); err != nil {
t.Fatalf("Failed to calc: %s", err)
} else {
assert.Equal(t, 0, len(sum))
}
}
func TestCombine(t *testing.T) {
unittest.SmallTest(t)
first := summary.SummaryMap{
FirstTest: {
Name: FirstTest,
Diameter: 4,
Pos: 2,
Neg: 3,
Untriaged: 1,
UntHashes: types.DigestSlice{AlphaDigest},
Num: 6,
Corpus: "gm",
Blame: []*blame.WeightedBlame{
{
Author: "test@example.com",
Prob: 1.00,
},
},
},
SecondTest: {
Name: SecondTest,
Diameter: 14,
Pos: 12,
Neg: 13,
Untriaged: 1,
UntHashes: types.DigestSlice{BetaDigest},
Num: 26,
Corpus: "gm",
Blame: []*blame.WeightedBlame{
{
Author: "other@example.com",
Prob: 0.5,
},
{
Author: "test@example.com",
Prob: 0.5,
},
},
},
}
second := summary.SummaryMap{
FirstTest: {
Name: FirstTest,
Diameter: 24,
Pos: 22,
Neg: 23,
Untriaged: 0,
UntHashes: types.DigestSlice{},
Num: 45,
Corpus: "gm",
Blame: []*blame.WeightedBlame{},
},
ThirdTest: {
Name: ThirdTest,
Diameter: 34,
Pos: 32,
Neg: 33,
Untriaged: 1,
UntHashes: types.DigestSlice{GammaDigest},
Num: 66,
Corpus: "gm",
Blame: []*blame.WeightedBlame{
{
Author: "nobody@example.com",
Prob: 1.0,
},
},
},
}
result := first.Combine(second)
// Originals first and second should be unchanged
assert.Len(t, first, 2)
assert.Len(t, second, 2)
assert.Len(t, result, 3)
assert.Len(t, first[FirstTest].Blame, 1)
assert.Len(t, second[FirstTest].Blame, 0)
assert.Len(t, result[FirstTest].Blame, 0)
assert.Contains(t, result, FirstTest)
assert.Contains(t, result, SecondTest)
assert.Contains(t, result, ThirdTest)
}
func triageCountsCorrect(t *testing.T, sum summary.SummaryMap, name types.TestName, pos, neg, unt int) {
s, ok := sum[name]
assert.True(t, ok, "Could not find %s in %#v", name, sum)
assert.Equal(t, pos, s.Pos, "Postive count wrong")
assert.Equal(t, neg, s.Neg, "Negative count wrong")
assert.Equal(t, unt, s.Untriaged, "Untriaged count wrong")
}
const (
FirstTest = types.TestName("test_first")
SecondTest = types.TestName("test_second")
ThirdTest = types.TestName("test_third")
AlphaDigest = types.Digest("aaaec803b2ce49e4a541068d495ab570")
BetaDigest = types.Digest("bbb9ee4a034fdeddd1b65be92debe731")
GammaDigest = types.Digest("ccc8f073f388469e0193300623691a36")
)