package imgcache import ( "bytes" "testing" "time" "github.com/prometheus/client_golang/prometheus" "sneak.berlin/go/pixa/internal/imagerequest" ) // gatheredValue returns the value of the metric name on registry: a // counter's or a gauge's value. func gatheredValue(t *testing.T, registry *prometheus.Registry, name string) float64 { t.Helper() families, err := registry.Gather() if err != nil { t.Fatalf("failed to gather the metrics: %v", err) } for _, family := range families { if family.GetName() != name { continue } metric := family.GetMetric()[0] if metric.GetGauge() != nil { return metric.GetGauge().GetValue() } return metric.GetCounter().GetValue() } t.Fatalf("the metric %s is not on the registry", name) return 0 } // TestEvictToLimit_CountsEvictionsAndUsage stores four variants of 1000 // bytes in a cache limited to 3000 bytes. EvictToLimit must count the one // eviction and its bytes, and set the usage and limit gauges. func TestEvictToLimit_CountsEvictionsAndUsage(t *testing.T) { t.Parallel() const limit = 3000 registry := prometheus.NewRegistry() cache, err := NewCache(evictionTestDB(t), Config{StateDir: t.TempDir(), MaxBytes: limit}, registry) if err != nil { t.Fatalf("NewCache() error = %v", err) } keys := []imagerequest.VariantKey{ testVariantKeyOne, testVariantKeyTwo, testVariantKeyThree, testVariantKeyFour, } for i, key := range keys { storeEvictionTestVariant(t, cache, key, bytes.Repeat([]byte{0x01}, 1000)) setVariantLastAccessed(t, cache, key, time.Now().Add(-time.Duration(len(keys)-i)*time.Hour)) } err = cache.EvictToLimit(t.Context()) if err != nil { t.Fatalf("EvictToLimit() error = %v", err) } want := map[string]float64{ "pixa_cache_evictions_total": 1, "pixa_cache_evicted_bytes_total": 1000, "pixa_cache_usage_bytes": 3000, "pixa_cache_max_bytes": limit, } for name, value := range want { got := gatheredValue(t, registry, name) t.Logf("%s = %v", name, got) if got != value { t.Errorf("%s = %v, want %v", name, got, value) } } } // TestEvictNotCheckedRecently_CountsEvictions stores a source of 6 bytes and // a variant of 7 bytes last checked with upstream 31 days ago. // EvictNotCheckedRecently must count both evictions and their 13 bytes. func TestEvictNotCheckedRecently_CountsEvictions(t *testing.T) { t.Parallel() registry := prometheus.NewRegistry() cache, err := NewCache(evictionTestDB(t), Config{StateDir: t.TempDir(), MaxBytes: 1 << 30}, registry) if err != nil { t.Fatalf("NewCache() error = %v", err) } old := time.Now().Add(-31 * 24 * time.Hour) _, err = cache.PutSource(t.Context(), imagerequest.Source{Host: testHostCDN, Path: "/old.jpg"}, bytes.NewReader([]byte("source")), SourceInfo{FetchedAt: old, CheckedAt: old}) if err != nil { t.Fatalf("PutSource() error = %v", err) } err = cache.PutVariant(t.Context(), testVariantKeyOne, SourceInfo{CheckedAt: old}, bytes.NewReader([]byte("variant"))) if err != nil { t.Fatalf("PutVariant() error = %v", err) } err = cache.EvictNotCheckedRecently(t.Context()) if err != nil { t.Fatalf("EvictNotCheckedRecently() error = %v", err) } want := map[string]float64{ "pixa_cache_evictions_total": 2, "pixa_cache_evicted_bytes_total": 13, } for name, value := range want { got := gatheredValue(t, registry, name) t.Logf("%s = %v", name, got) if got != value { t.Errorf("%s = %v, want %v", name, got, value) } } }