190 lines
3.7 KiB
Go
190 lines
3.7 KiB
Go
package vaultik
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
func TestBlobDiskCache_BasicGetPut(t *testing.T) {
|
|
cache, err := newBlobDiskCache(1 << 20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = cache.Close() }()
|
|
|
|
data := []byte("hello world")
|
|
if err := cache.Put("key1", data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, ok := cache.Get("key1")
|
|
if !ok {
|
|
t.Fatal("expected cache hit")
|
|
}
|
|
if !bytes.Equal(got, data) {
|
|
t.Fatalf("got %q, want %q", got, data)
|
|
}
|
|
|
|
_, ok = cache.Get("nonexistent")
|
|
if ok {
|
|
t.Fatal("expected cache miss")
|
|
}
|
|
}
|
|
|
|
func TestBlobDiskCache_EvictionUnderPressure(t *testing.T) {
|
|
maxBytes := int64(1000)
|
|
cache, err := newBlobDiskCache(maxBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = cache.Close() }()
|
|
|
|
for i := 0; i < 5; i++ {
|
|
data := make([]byte, 300)
|
|
if err := cache.Put(fmt.Sprintf("key%d", i), data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if cache.Size() > maxBytes {
|
|
t.Fatalf("cache size %d exceeds max %d", cache.Size(), maxBytes)
|
|
}
|
|
|
|
if !cache.Has("key4") {
|
|
t.Fatal("expected key4 to be cached")
|
|
}
|
|
if cache.Has("key0") {
|
|
t.Fatal("expected key0 to be evicted")
|
|
}
|
|
}
|
|
|
|
func TestBlobDiskCache_OversizedEntryRejected(t *testing.T) {
|
|
cache, err := newBlobDiskCache(100)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = cache.Close() }()
|
|
|
|
data := make([]byte, 200)
|
|
if err := cache.Put("big", data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if cache.Has("big") {
|
|
t.Fatal("oversized entry should not be cached")
|
|
}
|
|
}
|
|
|
|
func TestBlobDiskCache_UpdateInPlace(t *testing.T) {
|
|
cache, err := newBlobDiskCache(1 << 20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = cache.Close() }()
|
|
|
|
if err := cache.Put("key1", []byte("v1")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := cache.Put("key1", []byte("version2")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, ok := cache.Get("key1")
|
|
if !ok {
|
|
t.Fatal("expected hit")
|
|
}
|
|
if string(got) != "version2" {
|
|
t.Fatalf("got %q, want %q", got, "version2")
|
|
}
|
|
if cache.Len() != 1 {
|
|
t.Fatalf("expected 1 entry, got %d", cache.Len())
|
|
}
|
|
if cache.Size() != int64(len("version2")) {
|
|
t.Fatalf("expected size %d, got %d", len("version2"), cache.Size())
|
|
}
|
|
}
|
|
|
|
func TestBlobDiskCache_ReadAt(t *testing.T) {
|
|
cache, err := newBlobDiskCache(1 << 20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = cache.Close() }()
|
|
|
|
data := make([]byte, 1024)
|
|
if _, err := rand.Read(data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := cache.Put("blob1", data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
chunk, err := cache.ReadAt("blob1", 100, 200)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Equal(chunk, data[100:300]) {
|
|
t.Fatal("ReadAt returned wrong data")
|
|
}
|
|
|
|
_, err = cache.ReadAt("blob1", 900, 200)
|
|
if err == nil {
|
|
t.Fatal("expected error for out-of-bounds read")
|
|
}
|
|
|
|
_, err = cache.ReadAt("missing", 0, 10)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing key")
|
|
}
|
|
}
|
|
|
|
func TestBlobDiskCache_Close(t *testing.T) {
|
|
cache, err := newBlobDiskCache(1 << 20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := cache.Put("key1", []byte("data")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := cache.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestBlobDiskCache_LRUOrder(t *testing.T) {
|
|
cache, err := newBlobDiskCache(200)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = cache.Close() }()
|
|
|
|
d := make([]byte, 100)
|
|
if err := cache.Put("a", d); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := cache.Put("b", d); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Access "a" to make it most recently used
|
|
cache.Get("a")
|
|
|
|
// Adding "c" should evict "b" (LRU), not "a"
|
|
if err := cache.Put("c", d); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !cache.Has("a") {
|
|
t.Fatal("expected 'a' to survive")
|
|
}
|
|
if !cache.Has("c") {
|
|
t.Fatal("expected 'c' to be present")
|
|
}
|
|
if cache.Has("b") {
|
|
t.Fatal("expected 'b' to be evicted")
|
|
}
|
|
}
|