package metrics import ( "testing" "time" ) func TestNewMetrics(t *testing.T) { m := New() if m.CacheHits == nil { t.Error("expected CacheHits to be initialized") } if m.CacheMisses == nil { t.Error("expected CacheMisses to be initialized") } if m.layerTTLs == nil { t.Error("expected layerTTLs to be initialized") } if m.SearchDuration == nil { t.Error("expected SearchDuration to be initialized") } if m.SearchDuration.maxValues != 1000 { t.Errorf("expected maxValues 1000, got %d", m.SearchDuration.maxValues) } } func TestMetricsRecordCacheHit(t *testing.T) { m := New() m.RecordCacheHit("search") m.RecordCacheHit("search") m.mu.Lock() hits := m.CacheHits["search"] m.mu.Unlock() if hits != 2 { t.Errorf("expected 2 cache hits, got %d", hits) } } func TestMetricsRecordCacheMiss(t *testing.T) { m := New() m.RecordCacheMiss("search") m.RecordCacheMiss("search") m.mu.Lock() misses := m.CacheMisses["search"] m.mu.Unlock() if misses != 2 { t.Errorf("expected 2 cache misses, got %d", misses) } } func TestMetricsRecordAPIQuota(t *testing.T) { m := New() m.RecordAPIQuota(1000) m.mu.Lock() quota := m.APIQuotaRemaining m.mu.Unlock() if quota != 1000 { t.Errorf("expected API quota 1000, got %d", quota) } } func TestMetricsRecordCircuitBreakerTrip(t *testing.T) { m := New() m.RecordCircuitBreakerTrip() m.RecordCircuitBreakerTrip() m.mu.Lock() trips := m.CircuitBreakerTrips m.mu.Unlock() if trips != 2 { t.Errorf("expected 2 circuit breaker trips, got %d", trips) } } func TestMetricsRecordSearch(t *testing.T) { m := New() m.RecordSearch(1000000000) // 1 second in nanoseconds m.RecordSearch(2000000000) // 2 seconds in nanoseconds m.mu.Lock() count := m.SearchCount valuesLen := len(m.SearchDuration.values) m.mu.Unlock() if count != 2 { t.Errorf("expected SearchCount 2, got %d", count) } if valuesLen != 2 { t.Errorf("expected 2 duration values, got %d", valuesLen) } } func TestMetricsRecordSearchTrim(t *testing.T) { m := New() m.SearchDuration.maxValues = 2 for i := 0; i < 5; i++ { m.RecordSearch(int64(i * 1000000000)) } m.mu.Lock() valuesLen := len(m.SearchDuration.values) m.mu.Unlock() if valuesLen != 2 { t.Errorf("expected 2 duration values after trim, got %d", valuesLen) } } func TestMetricsGetCacheHitRate(t *testing.T) { m := New() m.RecordCacheHit("search") m.RecordCacheHit("search") m.RecordCacheMiss("search") rate := m.GetCacheHitRate("search") if rate != 0.6666666666666666 { // 2/3 t.Errorf("expected cache hit rate 0.6666666666666666, got %f", rate) } // Test with no data rateEmpty := m.GetCacheHitRate("empty") if rateEmpty != 0 { t.Errorf("expected cache hit rate 0 for empty layer, got %f", rateEmpty) } } func TestMetricsGetMetricsJSON(t *testing.T) { m := New() m.RecordCacheHit("search") m.RecordCacheMiss("search") m.RecordAPIQuota(500) m.RecordCircuitBreakerTrip() m.RecordSearch(1000000000) json := m.GetMetricsJSON() if json["cache_hits"] == nil { t.Error("expected cache_hits in JSON") } if json["cache_misses"] == nil { t.Error("expected cache_misses in JSON") } if json["api_quota_remaining"] != int64(500) { t.Errorf("expected api_quota_remaining 500, got %v", json["api_quota_remaining"]) } if json["circuit_breaker_trips"] != int64(1) { t.Errorf("expected circuit_breaker_trips 1, got %v", json["circuit_breaker_trips"]) } if json["search_count"] != int64(1) { t.Errorf("expected search_count 1, got %v", json["search_count"]) } } func TestMetricsSetAndGetLayerTTL(t *testing.T) { m := New() m.SetLayerTTL("search", 3600*time.Second) ttl, ok := m.GetLayerTTL("search") if !ok { t.Error("expected TTL to be found for 'search' layer") } if ttl != 3600*time.Second { t.Errorf("expected TTL 3600s, got %v", ttl) } _, ok = m.GetLayerTTL("nonexistent") if ok { t.Error("expected TTL to not be found for 'nonexistent' layer") } }