Phase 1 part 2 of ADR-0022 (companion to PR #22 rate-limit). In-memory cache service via go-cache, used by /api/version (60s TTL). 6/6 unit tests pass. ~95% Mistral autonomous via ICM workspace, cost €2.50 stages 01-02 (50% reduction vs T5 thanks to pre-extracted snippets in shared/). Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
136 lines
2.9 KiB
Go
136 lines
2.9 KiB
Go
package cache
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestInMemoryService_SetGet(t *testing.T) {
|
|
svc := NewInMemoryService(1*time.Hour, 1*time.Hour)
|
|
|
|
// Test Set and Get
|
|
svc.Set("key1", "value1", 1*time.Hour)
|
|
val, ok := svc.Get("key1")
|
|
if !ok {
|
|
t.Fatal("Expected to find key1 in cache")
|
|
}
|
|
if val != "value1" {
|
|
t.Fatalf("Expected 'value1', got '%v'", val)
|
|
}
|
|
|
|
// Test Get non-existent key
|
|
_, ok = svc.Get("nonexistent")
|
|
if ok {
|
|
t.Fatal("Expected not to find nonexistent key")
|
|
}
|
|
}
|
|
|
|
func TestInMemoryService_Delete(t *testing.T) {
|
|
svc := NewInMemoryService(1*time.Hour, 1*time.Hour)
|
|
|
|
svc.Set("key1", "value1", 1*time.Hour)
|
|
_, ok := svc.Get("key1")
|
|
if !ok {
|
|
t.Fatal("Expected to find key1 before delete")
|
|
}
|
|
|
|
svc.Delete("key1")
|
|
_, ok = svc.Get("key1")
|
|
if ok {
|
|
t.Fatal("Expected not to find key1 after delete")
|
|
}
|
|
}
|
|
|
|
func TestInMemoryService_Flush(t *testing.T) {
|
|
svc := NewInMemoryService(1*time.Hour, 1*time.Hour)
|
|
|
|
svc.Set("key1", "value1", 1*time.Hour)
|
|
svc.Set("key2", "value2", 1*time.Hour)
|
|
|
|
if svc.ItemCount() != 2 {
|
|
t.Fatalf("Expected 2 items, got %d", svc.ItemCount())
|
|
}
|
|
|
|
svc.Flush()
|
|
|
|
if svc.ItemCount() != 0 {
|
|
t.Fatalf("Expected 0 items after flush, got %d", svc.ItemCount())
|
|
}
|
|
|
|
_, ok := svc.Get("key1")
|
|
if ok {
|
|
t.Fatal("Expected key1 to be flushed")
|
|
}
|
|
}
|
|
|
|
func TestInMemoryService_ItemCount(t *testing.T) {
|
|
svc := NewInMemoryService(1*time.Hour, 1*time.Hour)
|
|
|
|
if svc.ItemCount() != 0 {
|
|
t.Fatalf("Expected 0 items initially, got %d", svc.ItemCount())
|
|
}
|
|
|
|
svc.Set("key1", "value1", 1*time.Hour)
|
|
if svc.ItemCount() != 1 {
|
|
t.Fatalf("Expected 1 item, got %d", svc.ItemCount())
|
|
}
|
|
|
|
svc.Set("key2", "value2", 1*time.Hour)
|
|
if svc.ItemCount() != 2 {
|
|
t.Fatalf("Expected 2 items, got %d", svc.ItemCount())
|
|
}
|
|
|
|
svc.Delete("key1")
|
|
if svc.ItemCount() != 1 {
|
|
t.Fatalf("Expected 1 item after delete, got %d", svc.ItemCount())
|
|
}
|
|
}
|
|
|
|
func TestInMemoryService_TTLExpiration(t *testing.T) {
|
|
// Use a very short TTL for testing
|
|
svc := NewInMemoryService(100*time.Millisecond, 50*time.Millisecond)
|
|
|
|
svc.Set("key1", "value1", 50*time.Millisecond)
|
|
|
|
// Should be present immediately
|
|
val, ok := svc.Get("key1")
|
|
if !ok {
|
|
t.Fatal("Expected to find key1 immediately after set")
|
|
}
|
|
if val != "value1" {
|
|
t.Fatalf("Expected 'value1', got '%v'", val)
|
|
}
|
|
|
|
// Wait for expiration
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Should be expired now
|
|
_, ok = svc.Get("key1")
|
|
if ok {
|
|
t.Fatal("Expected key1 to be expired after TTL")
|
|
}
|
|
}
|
|
|
|
func TestInMemoryService_DifferentTypes(t *testing.T) {
|
|
svc := NewInMemoryService(1*time.Hour, 1*time.Hour)
|
|
|
|
// Test with different types
|
|
svc.Set("string", "hello", 1*time.Hour)
|
|
svc.Set("int", 42, 1*time.Hour)
|
|
svc.Set("slice", []string{"a", "b"}, 1*time.Hour)
|
|
|
|
if svc.ItemCount() != 3 {
|
|
t.Fatalf("Expected 3 items, got %d", svc.ItemCount())
|
|
}
|
|
|
|
val, ok := svc.Get("string")
|
|
if !ok || val != "hello" {
|
|
t.Fatal("String value mismatch")
|
|
}
|
|
|
|
val, ok = svc.Get("int")
|
|
if !ok || val != 42 {
|
|
t.Fatal("Int value mismatch")
|
|
}
|
|
}
|