amaniquery-agent / internal /cache /cache_test.go
Deployment
Automated deployment update
4b1daed
Raw
History Blame Contribute Delete
6.83 kB
package cache_test
import (
"context"
"testing"
"time"
"github.com/AmaniQuery/amaniquery/internal/cache"
)
// TestLRUCache_SetGet verifies basic set/get operations
func TestLRUCache_SetGet(t *testing.T) {
lru := cache.NewLRUCache(100)
// Test set and get
lru.Set("key1", []byte("value1"))
value, found := lru.Get("key1")
if !found {
t.Fatal("Expected to find key1")
}
if string(value) != "value1" {
t.Errorf("Expected 'value1', got '%s'", string(value))
}
// Test missing key
_, found = lru.Get("nonexistent")
if found {
t.Error("Expected not to find nonexistent key")
}
}
// TestLRUCache_Update verifies updating existing keys
func TestLRUCache_Update(t *testing.T) {
lru := cache.NewLRUCache(100)
lru.Set("key1", []byte("original"))
lru.Set("key1", []byte("updated"))
value, found := lru.Get("key1")
if !found {
t.Fatal("Expected to find key1")
}
if string(value) != "updated" {
t.Errorf("Expected 'updated', got '%s'", string(value))
}
}
// TestLRUCache_Eviction verifies LRU eviction when over capacity
func TestLRUCache_Eviction(t *testing.T) {
lru := cache.NewLRUCache(3)
// Fill cache to capacity
lru.Set("key1", []byte("value1"))
lru.Set("key2", []byte("value2"))
lru.Set("key3", []byte("value3"))
// Access key1 to make it recently used
lru.Get("key1")
// Add new key, should evict key2 (least recently used)
lru.Set("key4", []byte("value4"))
// key2 should be evicted
_, found := lru.Get("key2")
if found {
t.Error("Expected key2 to be evicted")
}
// key1 should still exist (was accessed recently)
_, found = lru.Get("key1")
if !found {
t.Error("Expected key1 to still exist")
}
// key3 and key4 should exist
_, found = lru.Get("key3")
if !found {
t.Error("Expected key3 to exist")
}
_, found = lru.Get("key4")
if !found {
t.Error("Expected key4 to exist")
}
}
// TestLRUCache_Delete verifies deletion operations
func TestLRUCache_Delete(t *testing.T) {
lru := cache.NewLRUCache(100)
lru.Set("key1", []byte("value1"))
lru.Set("key2", []byte("value2"))
lru.Delete("key1")
_, found := lru.Get("key1")
if found {
t.Error("Expected key1 to be deleted")
}
// key2 should still exist
_, found = lru.Get("key2")
if !found {
t.Error("Expected key2 to still exist")
}
}
// TestLRUCache_DeleteNonexistent verifies deleting nonexistent keys doesn't panic
func TestLRUCache_DeleteNonexistent(t *testing.T) {
lru := cache.NewLRUCache(100)
// Should not panic
lru.Delete("nonexistent")
}
// TestCacheMissError tests the error type
func TestCacheMissError(t *testing.T) {
err := cache.ErrCacheMiss
if err.Error() != "cache miss" {
t.Errorf("Expected 'cache miss', got '%s'", err.Error())
}
}
// TestMultiTierCache_LocalOnly tests cache without Redis connection
func TestMultiTierCache_LocalOnly(t *testing.T) {
// Create cache with invalid Redis URL to ensure Redis is not used
cfg := cache.Config{
RedisURL: "redis://invalid:6379", // Will fail connection
LocalSize: 100,
TTL: time.Hour,
MaxRetries: 1,
PoolSize: 1,
}
c, err := cache.New(cfg)
if err != nil {
t.Fatalf("Failed to create cache: %v", err)
}
defer c.Close()
ctx := context.Background()
// Set and get should work with local cache
err = c.Set(ctx, "key1", []byte("value1"), 0)
if err != nil {
t.Fatalf("Set failed: %v", err)
}
value, err := c.Get(ctx, "key1")
if err != nil {
t.Fatalf("Get failed: %v", err)
}
if string(value) != "value1" {
t.Errorf("Expected 'value1', got '%s'", string(value))
}
}
// TestMultiTierCache_CacheMiss tests cache miss behavior
func TestMultiTierCache_CacheMiss(t *testing.T) {
cfg := cache.Config{
RedisURL: "redis://invalid:6379",
LocalSize: 100,
TTL: time.Hour,
MaxRetries: 1,
PoolSize: 1,
}
c, err := cache.New(cfg)
if err != nil {
t.Fatalf("Failed to create cache: %v", err)
}
defer c.Close()
ctx := context.Background()
_, err = c.Get(ctx, "nonexistent")
if err == nil {
t.Error("Expected cache miss error")
}
}
// TestMultiTierCache_Delete tests deletion
func TestMultiTierCache_Delete(t *testing.T) {
cfg := cache.Config{
RedisURL: "redis://invalid:6379",
LocalSize: 100,
TTL: time.Hour,
MaxRetries: 1,
PoolSize: 1,
}
c, err := cache.New(cfg)
if err != nil {
t.Fatalf("Failed to create cache: %v", err)
}
defer c.Close()
ctx := context.Background()
// Set then delete
c.Set(ctx, "key1", []byte("value1"), 0)
err = c.Delete(ctx, "key1")
if err != nil {
t.Fatalf("Delete failed: %v", err)
}
// Should be gone
_, err = c.Get(ctx, "key1")
if err == nil {
t.Error("Expected cache miss after delete")
}
}
// TestMultiTierCache_JSON tests JSON operations
func TestMultiTierCache_JSON(t *testing.T) {
cfg := cache.Config{
RedisURL: "redis://invalid:6379",
LocalSize: 100,
TTL: time.Hour,
MaxRetries: 1,
PoolSize: 1,
}
c, err := cache.New(cfg)
if err != nil {
t.Fatalf("Failed to create cache: %v", err)
}
defer c.Close()
ctx := context.Background()
type testData struct {
Name string `json:"name"`
Value int `json:"value"`
}
original := testData{Name: "test", Value: 42}
err = c.SetJSON(ctx, "json-key", original, 0)
if err != nil {
t.Fatalf("SetJSON failed: %v", err)
}
var result testData
err = c.GetJSON(ctx, "json-key", &result)
if err != nil {
t.Fatalf("GetJSON failed: %v", err)
}
if result.Name != original.Name || result.Value != original.Value {
t.Errorf("JSON mismatch: expected %+v, got %+v", original, result)
}
}
// TestMultiTierCache_Metrics tests metrics tracking
func TestMultiTierCache_Metrics(t *testing.T) {
cfg := cache.Config{
RedisURL: "redis://invalid:6379",
LocalSize: 100,
TTL: time.Hour,
MaxRetries: 1,
PoolSize: 1,
}
c, err := cache.New(cfg)
if err != nil {
t.Fatalf("Failed to create cache: %v", err)
}
defer c.Close()
ctx := context.Background()
// Set and get to generate metrics
c.Set(ctx, "key1", []byte("value1"), 0)
c.Get(ctx, "key1") // Hit
c.Get(ctx, "key2") // Miss
metrics := c.GetMetrics()
if metrics.LocalHits != 1 {
t.Errorf("Expected 1 local hit, got %d", metrics.LocalHits)
}
if metrics.LocalMisses != 1 {
t.Errorf("Expected 1 local miss, got %d", metrics.LocalMisses)
}
}
// BenchmarkLRUCache_Set benchmarks LRU set operations
func BenchmarkLRUCache_Set(b *testing.B) {
lru := cache.NewLRUCache(10000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
lru.Set("key"+string(rune(i%1000)), []byte("value"))
}
}
// BenchmarkLRUCache_Get benchmarks LRU get operations
func BenchmarkLRUCache_Get(b *testing.B) {
lru := cache.NewLRUCache(10000)
// Pre-populate
for i := 0; i < 1000; i++ {
lru.Set("key"+string(rune(i)), []byte("value"))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
lru.Get("key" + string(rune(i%1000)))
}
}