blob: f9bfcace1cd2e4d10ab9bb429888f2c738b566b0 [file] [log] [blame]
// Package parser has funcs for parsing ingestion files.
package parser
import (
"fmt"
"io/ioutil"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/paramtools"
"go.skia.org/infra/go/testutils"
"go.skia.org/infra/go/testutils/unittest"
"go.skia.org/infra/perf/go/config"
"go.skia.org/infra/perf/go/file"
"go.skia.org/infra/perf/go/ingest/format"
"go.skia.org/infra/perf/go/types"
)
const goodBranchName = "some-branch-name"
var (
expectedGoodParams = paramtools.Params{
"arch": "x86",
"branch": "some-branch-name",
"config": "meta",
"gpu": "GTX660",
"model": "ShuttleA",
"os": "Ubuntu12",
"sub_result": "max_rss_mb",
"system": "UNIX",
"test": "memory_usage_0_0",
}
)
func TestGetParamsAndValuesFromLegacyFormat_Success(t *testing.T) {
unittest.SmallTest(t)
// Load the sample data file as BenchData.
r := testutils.GetReader(t, filepath.Join("legacy", "success.json"))
benchData, err := format.ParseLegacyFormat(r)
require.NoError(t, err)
params, values := getParamsAndValuesFromLegacyFormat(benchData)
assert.Len(t, values, 4)
assert.Len(t, params, 4)
assert.Contains(t, values, float32(858))
assert.Contains(t, params, expectedGoodParams)
}
func TestGetParamsAndValuesFromFormat_Success(t *testing.T) {
unittest.SmallTest(t)
// Load the sample data file as BenchData.
r := testutils.GetReader(t, filepath.Join("version_1", "success.json"))
f, err := format.Parse(r)
require.NoError(t, err)
params, values := getParamsAndValuesFromVersion1Format(f)
assert.Len(t, values, 4)
assert.Len(t, params, 4)
assert.Contains(t, values, float32(858))
assert.Contains(t, params, expectedGoodParams)
}
func TestParser(t *testing.T) {
unittest.SmallTest(t)
// Loop over all the ingestion formats we support. Parallel test files with
// the same names are held in subdirectories of 'testdata'.
for _, ingestionFormat := range []string{"legacy", "version_1"} {
for name, subTest := range SubTests {
subTestName := fmt.Sprintf("%s_%s", name, ingestionFormat)
t.Run(subTestName, func(t *testing.T) {
p, f := parserForTest(t, ingestionFormat, subTest.filename)
subTest.SubTestFunction(t, p, f)
})
}
}
}
func parserForTest(t *testing.T, subdir, filename string) (*Parser, file.File) {
unittest.SmallTest(t)
instanceConfig := &config.InstanceConfig{
IngestionConfig: config.IngestionConfig{
Branches: []string{goodBranchName},
},
}
ret := New(instanceConfig)
ret.parseCounter.Reset()
ret.parseFailCounter.Reset()
// Load the sample data file as BenchData.
r := testutils.GetReader(t, filepath.Join(subdir, filename))
return ret, file.File{
Name: filename,
Contents: r,
}
}
// SubTestFunction is a func we will call to test one aspect of Parser.Parse.
type SubTestFunction func(t *testing.T, p *Parser, f file.File)
// SubTests are all the subtests we have for Parser.Parse
var SubTests = map[string]struct {
SubTestFunction SubTestFunction
filename string
}{
"parse_Success": {parse_Success, "success.json"},
"parse_NoBranchSpecified_Success": {parse_NoBranchSpecified_Success, "success.json"},
"parse_MalformedJSONError": {parse_MalformedJSONError, "invalid.json"},
"parse_SkipIfNotListedInBranches": {parse_SkipIfNotListedInBranches, "unknown_branch.json"},
"parse_SkipIfListedInBranchesButHasNoData": {parse_SkipIfListedInBranchesButHasNoData, "no_results.json"},
"parse_OnlyOneMeasurementInfile": {parse_OnlyOneMeasurementInfile, "one_measurement.json"},
"parse_OnlyOneMeasurementWithValueZeroInfile": {parse_OnlyOneMeasurementWithValueZeroInfile, "zero_measurement.json"},
"parse_ReadErr": {parse_ReadErr, "success.json"},
"parseTryBot_Success": {parseTryBot_Success, "success.json"},
"parseTryBot_MalformedJSONError": {parseTryBot_MalformedJSONError, "invalid.json"},
"parseTryBot_ReadErr": {parseTryBot_ReadErr, "success.json"},
}
func parse_Success(t *testing.T, p *Parser, f file.File) {
params, values, gitHash, err := p.Parse(f)
require.NoError(t, err)
assert.Equal(t, "fe4a4029a080bc955e9588d05a6cd9eb490845d4", gitHash)
assert.Len(t, values, 4)
assert.Len(t, params, 4)
assert.Contains(t, values, float32(858))
assert.Contains(t, params, expectedGoodParams)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(0), p.parseFailCounter.Get())
}
func parseTryBot_Success(t *testing.T, p *Parser, f file.File) {
cl, patch, err := p.ParseTryBot(f)
require.NoError(t, err)
assert.Equal(t, types.CL("327697"), cl)
assert.Equal(t, "1", patch)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(0), p.parseFailCounter.Get())
}
func parse_NoBranchSpecified_Success(t *testing.T, p *Parser, f file.File) {
p.branchNames = nil
params, values, gitHash, err := p.Parse(f)
require.NoError(t, err)
assert.Equal(t, "fe4a4029a080bc955e9588d05a6cd9eb490845d4", gitHash)
assert.Len(t, values, 4)
assert.Len(t, params, 4)
assert.Contains(t, values, float32(858))
assert.Contains(t, params, expectedGoodParams)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(0), p.parseFailCounter.Get())
}
func parse_MalformedJSONError(t *testing.T, p *Parser, f file.File) {
_, _, _, err := p.Parse(f)
require.Error(t, err)
assert.NotEqual(t, ErrFileShouldBeSkipped, err)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(1), p.parseFailCounter.Get())
}
func parseTryBot_MalformedJSONError(t *testing.T, p *Parser, f file.File) {
_, _, err := p.ParseTryBot(f)
require.Error(t, err)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(1), p.parseFailCounter.Get())
}
func parse_SkipIfNotListedInBranches(t *testing.T, p *Parser, f file.File) {
_, _, _, err := p.Parse(f)
assert.Equal(t, ErrFileShouldBeSkipped, err)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(0), p.parseFailCounter.Get())
}
func parse_SkipIfListedInBranchesButHasNoData(t *testing.T, p *Parser, f file.File) {
_, _, _, err := p.Parse(f)
assert.Equal(t, ErrFileShouldBeSkipped, err)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(0), p.parseFailCounter.Get())
}
func parse_OnlyOneMeasurementInfile(t *testing.T, p *Parser, f file.File) {
params, values, gitHash, err := p.Parse(f)
require.NoError(t, err)
assert.Len(t, params, 1)
assert.Equal(t, "fe4a4029a080bc955e9588d05a6cd9eb490845d4", gitHash)
assert.Equal(t, values, []float32{12.3})
}
func parse_OnlyOneMeasurementWithValueZeroInfile(t *testing.T, p *Parser, f file.File) {
params, values, gitHash, err := p.Parse(f)
require.NoError(t, err)
assert.Len(t, params, 1)
assert.Equal(t, "fe4a4029a080bc955e9588d05a6cd9eb490845d4", gitHash)
assert.Equal(t, values, []float32{0.0})
}
type alwaysErrReader struct{}
func (a alwaysErrReader) Read(p []byte) (n int, err error) {
return 0, fmt.Errorf("Error reading.")
}
func parseTryBot_ReadErr(t *testing.T, p *Parser, f file.File) {
f.Contents = ioutil.NopCloser(alwaysErrReader{})
_, _, err := p.ParseTryBot(f)
require.Error(t, err)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(1), p.parseFailCounter.Get())
}
func parse_ReadErr(t *testing.T, p *Parser, f file.File) {
f.Contents = ioutil.NopCloser(alwaysErrReader{})
_, _, _, err := p.Parse(f)
require.Error(t, err)
assert.Equal(t, int64(1), p.parseCounter.Get())
assert.Equal(t, int64(1), p.parseFailCounter.Get())
}
func TestGetSamplesFromLegacyFormat_GoodData_Success(t *testing.T) {
unittest.SmallTest(t)
// Load the sample data file as BenchData.
r := testutils.GetReader(t, filepath.Join("legacy", "samples_success.json"))
b, err := format.ParseLegacyFormat(r)
require.NoError(t, err)
res := GetSamplesFromLegacyFormat(b)
require.Equal(t, 2, len(res))
expected := SamplesSet{
",bench_type=micro,config=8888,name=writepix_pm_bgra_srgb,source_type=bench,sub_result=min_ms,test=writepix_pm_bgra_srgb_640_480,": {
Params: paramtools.Params{
"bench_type": "micro",
"config": "8888",
"name": "writepix_pm_bgra_srgb",
"source_type": "bench",
"sub_result": "min_ms",
"test": "writepix_pm_bgra_srgb_640_480",
},
Values: []float64{
0.1828799247741699, 0.1826989650726318, 0.1827061176300049, 0.1827809810638428, 0.1825799942016602, 0.1826908588409424, 0.1829240322113037, 0.182894229888916, 0.1915080547332764, 0.1832039356231689, 0.1829140186309814, 0.1829030513763428, 0.1829860210418701, 0.182703971862793, 0.1829319000244141, 0.1827821731567383, 0.1828160285949707, 0.1827318668365479, 0.1829230785369873, 0.1828629970550537},
},
",bench_type=micro,config=8888,name=writepix_um_bgra_srgb,source_type=bench,sub_result=min_ms,test=writepix_um_bgra_srgb_640_480,": {
Params: paramtools.Params{
"bench_type": "micro",
"config": "8888",
"name": "writepix_um_bgra_srgb",
"source_type": "bench",
"sub_result": "min_ms",
"test": "writepix_um_bgra_srgb_640_480",
},
Values: []float64{
0.2057559490203857, 0.1993551254272461, 0.198721170425415, 0.1989059448242188, 0.1990170478820801, 0.1992101669311523, 0.1991400718688965, 0.1987521648406982, 0.1994550228118896, 0.199286937713623, 0.1990699768066406, 0.1992120742797852, 0.198800802230835, 0.1989920139312744, 0.199099063873291, 0.2042169570922852, 0.1992931365966797, 0.1988308429718018, 0.1994678974151611, 0.1989710330963135,
},
}}
assert.Equal(t, expected, res)
}
func TestGetSamplesFromLegacyFormat_EmptyData_Success(t *testing.T) {
unittest.SmallTest(t)
// Load the sample data file as BenchData.
r := testutils.GetReader(t, filepath.Join("legacy", "samples_no_results.json"))
b, err := format.ParseLegacyFormat(r)
require.NoError(t, err)
res := GetSamplesFromLegacyFormat(b)
assert.Empty(t, res)
}
func TestSamplesSetAdd_EmptySamples_Success(t *testing.T) {
unittest.SmallTest(t)
a := SamplesSet{}
b := SamplesSet{}
a.Add(b)
require.Empty(t, a)
}
func TestSamplesSetAdd_NonEmptySamples_Success(t *testing.T) {
unittest.SmallTest(t)
a := SamplesSet{
",config=8888,": Samples{
Params: paramtools.Params{"config": "8888"},
Values: []float64{1.0, 2.0},
},
",config=565,": {
Params: paramtools.Params{"config": "565"},
Values: []float64{},
},
}
b := SamplesSet{
",config=8888,": {
Params: paramtools.Params{"config": "8888"},
Values: []float64{2.0, 3.0},
},
",config=gles,": {
Params: paramtools.Params{"config": "gles"},
Values: []float64{4.0},
},
}
a.Add(b)
expected := SamplesSet{
",config=8888,": {
Params: paramtools.Params{"config": "8888"},
Values: []float64{1.0, 2.0, 2.0, 3.0},
},
",config=565,": {
Params: paramtools.Params{"config": "565"},
Values: []float64{},
},
",config=gles,": {
Params: paramtools.Params{"config": "gles"},
Values: []float64{4.0},
},
}
require.Equal(t, expected, a)
}