blob: 33d319ca38f7f96dd6c2cac6848a9db69e8d2618 [file] [log] [blame]
package redisutil
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"github.com/skia-dev/glog"
assert "github.com/stretchr/testify/require"
"go.skia.org/infra/go/testutils"
"go.skia.org/infra/go/util"
)
const (
// TEST_DATA_DIR is the directory with data used for benchmarks.
TEST_DATA_DIR = "./benchdata"
// TEST_DATA_STORAGE_PATH is the folder in the test data bucket.
// See go/testutils for details.
TEST_DATA_STORAGE_PATH = "common-testdata/redislru-benchdata.tar.gz"
)
type TestStruct struct {
NumDiffPixels int
PixelDiffPercent float32
PixelDiffFilePath string
// Contains the maximum difference between the images for each R/G/B channel.
MaxRGBADiffs []int
// True if the dimensions of the compared images are different.
DimDiffer bool
}
func TestRedisLRUCache(t *testing.T) {
testutils.SkipIfShort(t)
cache := NewRedisLRUCache("localhost:6379", 1, "test-di", TestStructCodec(0))
testLRUCache(t, cache)
}
func BenchmarkBigDataset(b *testing.B) {
// Download the testdata and remove the testdata directory at the end.
err := testutils.DownloadTestDataArchive(b, TEST_DATA_STORAGE_PATH, TEST_DATA_DIR)
assert.Nil(b, err, "Unable to download testdata.")
defer func() {
util.LogErr(os.RemoveAll(TEST_DATA_DIR))
}()
// Load the data
fileInfos, err := ioutil.ReadDir(TEST_DATA_DIR)
assert.Nil(b, err)
results := make(chan interface{}, len(fileInfos))
var codec TestStructCodec
counter := 0
for _, fi := range fileInfos {
if strings.HasSuffix(fi.Name(), ".json") {
go func(fName string) {
f, err := os.Open(fName)
if err != nil {
glog.Fatalf("Unable to open file %s", fName)
}
content, err := ioutil.ReadAll(f)
if err != nil {
glog.Fatalf("Unable to read file %s", fName)
}
v, err := codec.Decode(content)
if err != nil {
glog.Fatalf("Unable to decode file %s", fName)
}
if _, ok := v.(*TestStruct); !ok {
glog.Fatalln("Expected to get instance of TestStruct")
}
// Store the filepath in this field to use as cache key.
ts := v.(*TestStruct)
ts.PixelDiffFilePath = fName
results <- ts
}(filepath.Join("./benchdata", fi.Name()))
counter++
}
}
groundTruth := make(map[string]interface{}, counter)
cache := NewRedisLRUCache("localhost:6379", 1, "di", TestStructCodec(0))
rlruCache := cache.(*RedisLRUCache)
rlruCache.Purge()
for i := 0; i < counter; i++ {
ret := <-results
ts := ret.(*TestStruct)
groundTruth[ts.PixelDiffFilePath] = ret
}
glog.Infof("Done importing %d files. Starting bench.", len(groundTruth))
b.ResetTimer()
for k, v := range groundTruth {
cache.Add(k, v)
}
assert.Equal(b, len(groundTruth), cache.Len())
counter = 0
for k, v := range groundTruth {
found, ok := cache.Get(k)
assert.True(b, ok)
assert.Equal(b, v, found)
counter++
// if (counter % 1000) == 0 {
// glog.Infof("Checked %d records.", counter)
// }
}
b.StopTimer()
// Cleanup code that should not be timed but deserves to be tested.
rlruCache.Purge()
assert.Equal(b, 0, cache.Len())
}
type TestStructCodec int
func (t TestStructCodec) Encode(v interface{}) ([]byte, error) {
return json.Marshal(v)
}
func (t TestStructCodec) Decode(data []byte) (interface{}, error) {
var v TestStruct
err := json.Unmarshal(data, &v)
return &v, err
}
func testLRUCache(t *testing.T, cache util.LRUCache) {
rlruCache := cache.(*RedisLRUCache)
rlruCache.Purge()
N := 256
for i := 0; i < N; i++ {
cache.Add(strconv.Itoa(i), i)
}
// Make sure out keys are correct
assert.Equal(t, N, cache.Len())
assert.Equal(t, N, len(rlruCache.Keys()))
for _, k := range rlruCache.Keys() {
assert.IsType(t, "", k)
v, ok := cache.Get(k)
assert.True(t, ok)
assert.IsType(t, 0, v)
assert.Equal(t, k, strconv.Itoa(v.(int)))
}
for i := 0; i < N; i++ {
found, ok := cache.Get(strconv.Itoa(i))
assert.True(t, ok)
assert.IsType(t, 0, found)
assert.Equal(t, found.(int), i)
}
for i := 0; i < N; i++ {
_, ok := cache.Get(strconv.Itoa(i))
assert.True(t, ok)
oldLen := cache.Len()
cache.Remove(strconv.Itoa(i))
assert.Equal(t, oldLen-1, cache.Len())
}
assert.Equal(t, 0, cache.Len())
// Add some TestStructs to make sure the codec works.
for i := 0; i < N; i++ {
strKey := "structkey-" + strconv.Itoa(i)
ts := &TestStruct{
PixelDiffFilePath: "somesting-" + strconv.Itoa(i),
MaxRGBADiffs: []int{i * 4, i*4 + 1, i*4 + 2, i*4 + 3},
}
cache.Add(strKey, ts)
assert.Equal(t, i+1, cache.Len())
foundTS, ok := cache.Get(strKey)
assert.True(t, ok)
assert.IsType(t, &TestStruct{}, foundTS)
assert.Equal(t, ts, foundTS)
}
}