blob: d76c5bfc98836dcbd49ffb4dafe016c465f9c32a [file] [log] [blame]
package traceservice
import (
"context"
"encoding/binary"
"fmt"
"math"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"go.skia.org/infra/go/testutils/unittest"
"go.skia.org/infra/go/trace/db/perftypes"
"go.skia.org/infra/go/util"
)
const (
FILENAME = "/tmp/tracestore_test.db"
)
func cleanup() {
if err := os.Remove(FILENAME); err != nil {
fmt.Printf("Failed to clean up %s: %s", FILENAME, err)
}
}
func TestCommitID(t *testing.T) {
unittest.SmallTest(t)
// Test that CommitIDs round trip through byte slices.
now := time.Unix(time.Now().Unix(), 0)
c := &CommitID{
Timestamp: now.Unix(),
Id: "abc1234",
Source: "master",
}
b, err := CommitIDToBytes(c)
if err != nil {
t.Fatalf("Failed to convert CommitID to []byte: %s", err)
}
cp, err := CommitIDFromBytes(b)
assert.NoError(t, err)
assert.Equal(t, c, cp)
// Handle error conditions such as empty byte slices.
_, err = CommitIDFromBytes([]byte{})
assert.Error(t, err)
b, err = CommitIDToBytes(c)
if err != nil {
t.Fatalf("Failed to convert CommitID to []byte: %s", err)
}
short1 := b[:8]
_, err = CommitIDFromBytes(short1)
assert.Error(t, err, "Input []byte has malformed time.")
_, err = CommitIDFromBytes([]byte("fred!barney"))
assert.Error(t, err, "Input []byte value too few seperators.")
bad_cid := &CommitID{
Timestamp: now.Unix(),
Id: "abc!1234",
Source: "master",
}
_, err = CommitIDToBytes(bad_cid)
assert.NotNil(t, err)
}
func TestImpl(t *testing.T) {
unittest.MediumTest(t)
ts, err := NewTraceServiceServer(FILENAME)
assert.NoError(t, err)
defer util.Close(ts)
defer cleanup()
now := time.Unix(100, 0)
first := now.Unix()
second := now.Add(time.Minute).Unix()
commitIDs := []*CommitID{
{
Timestamp: first,
Id: "abc123",
Source: "master",
},
{
Timestamp: second,
Id: "xyz789",
Source: "master",
},
}
params := &AddParamsRequest{
Params: []*ParamsPair{
{
Key: "key:8888:android",
Params: map[string]string{
"config": "8888",
"platform": "android",
"type": "skp",
},
},
{
Key: "key:gpu:win8",
Params: map[string]string{
"config": "gpu",
"platform": "win8",
"type": "skp",
},
},
},
}
ctx := context.Background()
// First confirm that Ping() works.
_, err = ts.Ping(ctx, &Empty{})
assert.NoError(t, err)
// Confirm that these traceids don't have Params stored in the db yet.
missingRequest := &MissingParamsRequest{
Traceids: []string{"key:8888:android", "key:gpu:win8"},
}
missingResp, err := ts.MissingParams(ctx, missingRequest)
assert.NoError(t, err)
assert.Equal(t, missingResp.Traceids, missingRequest.Traceids)
// Now add the Params for them.
_, err = ts.AddParams(ctx, params)
assert.NoError(t, err)
// Confirm the missing list is now empty.
nowMissing, err := ts.MissingParams(ctx, missingRequest)
assert.Equal(t, []string{}, nowMissing.Traceids)
addReq := &AddRequest{
Commitid: commitIDs[0],
Values: []*ValuePair{
{
Key: "key:gpu:win8",
Value: perftypes.BytesFromFloat64(1.234),
},
{
Key: "key:8888:android",
Value: perftypes.BytesFromFloat64(0.01),
},
},
}
// Add a commit.
_, err = ts.Add(ctx, addReq)
assert.NoError(t, err)
// List, GetValues, and GetParams for the added commit.
listReq := &ListRequest{
Begin: first,
End: second,
}
listResp, err := ts.List(ctx, listReq)
assert.NoError(t, err)
assert.Equal(t, 1, len(listResp.Commitids))
assert.Equal(t, "abc123", listResp.Commitids[0].Id)
valuesReq := &GetValuesRequest{
Commitid: commitIDs[0],
}
valuesResp, err := ts.GetValues(ctx, valuesReq)
assert.NoError(t, err)
assert.Equal(t, 2, len(valuesResp.Values))
expected := map[string]float64{
"key:gpu:win8": 1.234,
"key:8888:android": 0.01,
}
for _, v := range valuesResp.Values {
assert.Equal(t, expected[v.Key], math.Float64frombits(binary.LittleEndian.Uint64(v.Value)))
}
assert.NotEqual(t, "", valuesResp.Md5)
paramsReq := &GetParamsRequest{
Traceids: []string{"key:8888:android", "key:gpu:win8"},
}
paramsResp, err := ts.GetParams(ctx, paramsReq)
assert.NoError(t, err)
assert.Equal(t, "8888", paramsResp.Params[0].Params["config"])
assert.Equal(t, "win8", paramsResp.Params[1].Params["platform"])
// Request the raw data for the commit.
rawRequest := &GetValuesRequest{
Commitid: commitIDs[0],
}
rawResp, err := ts.GetValuesRaw(ctx, rawRequest)
assert.NoError(t, err)
assert.Equal(t, 34, len(rawResp.Value))
assert.Equal(t, valuesResp.Md5, rawResp.Md5, "Should get the same md5 regardless of how you request the data.")
// Confirm that we can decode the info on the client side.
ci, err := NewCommitInfo(rawResp.Value)
assert.NoError(t, err)
// The keys are trace64ids, so test that we can convert them to traceids,
// i.e. from uint64's to strings.
keys64 := []uint64{}
for k := range ci.Values {
keys64 = append(keys64, k)
}
assert.Equal(t, 2, len(keys64))
traceidsRequest := &GetTraceIDsRequest{
Id: keys64,
}
traceids, err := ts.GetTraceIDs(ctx, traceidsRequest)
assert.NoError(t, err)
assert.Equal(t, 2, len(traceids.Ids))
assert.True(t, util.In(traceids.Ids[0].Id, paramsReq.Traceids))
assert.True(t, util.In(traceids.Ids[1].Id, paramsReq.Traceids))
}
func TestAtomize(t *testing.T) {
unittest.MediumTest(t)
ts, err := NewTraceServiceServer(FILENAME)
assert.NoError(t, err)
defer util.Close(ts)
defer cleanup()
ids, err := ts.atomize([]string{"foo"})
assert.NoError(t, err)
assert.Equal(t, uint64(1), ids["foo"])
ids, err = ts.atomize([]string{"foo"})
assert.NoError(t, err)
assert.Equal(t, uint64(1), ids["foo"])
ids, err = ts.atomize([]string{"bar"})
assert.NoError(t, err)
assert.Equal(t, uint64(2), ids["bar"])
ids, err = ts.atomize([]string{"foo"})
assert.NoError(t, err)
assert.Equal(t, uint64(1), ids["foo"])
}
func TestCommitInfo(t *testing.T) {
unittest.SmallTest(t)
// Test roundtripping through []byte.
c := &CommitInfo{
Values: map[uint64][]byte{
uint64(1): []byte("foo"),
uint64(3): []byte(""),
uint64(0xffffffff): []byte("last"),
},
}
cp, err := NewCommitInfo(c.ToBytes())
if err != nil {
t.Fatalf("Failed NewCommitInfo: %s", err)
}
assert.Equal(t, 3, len(cp.Values))
assert.Equal(t, "foo", string(cp.Values[uint64(1)]))
assert.Equal(t, c, cp)
// Test error handling.
cnil, err := NewCommitInfo(nil)
if err != nil {
t.Fatalf("Failed NewCommitInfo: %s", err)
}
assert.Equal(t, 0, len(cnil.Values))
b := c.ToBytes()
// Test inputs that should fail.
_, err = NewCommitInfo(b[1:])
assert.Error(t, err)
_, err = NewCommitInfo(b[:len(b)-1])
assert.Error(t, err)
}