package analytics import "testing" func TestTopKExactBelowCapAndBoundedAbove(t *testing.T) { k := NewTopK() for i := 0; i < 100; i++ { k.Add("/p"+itoa(i), int64(i+1)) } f := k.Fold() if len(f) != 100 || f["/p99"] != 100 || k.Approximate() { t.Fatalf("below cap must be exact: len=%d p99=%d approx=%v", len(f), f["/p99"], k.Approximate()) } for i := 0; i < 2000; i++ { k.Add("/q"+itoa(i), 1) } f = k.Fold() if len(f) > TopKSize+1 || !k.Approximate() || f[OtherKey] == 0 { t.Fatalf("above cap: len=%d approx=%v other=%d", len(f), k.Approximate(), f[OtherKey]) } // Total mass is conserved between counters and _other. var total int64 for _, v := range f { total += v } if total != 100*101/2+2000 { t.Fatalf("mass %d", total) } // A heavy hitter survives. if f["/p99"] < 100-2000/TopKSize { t.Fatalf("heavy hitter undercounted: %d", f["/p99"]) } } func TestTopKMergeRefolds(t *testing.T) { a, b := NewTopK(), NewTopK() for i := 0; i < 400; i++ { a.Add("/a"+itoa(i), 2) b.Add("/b"+itoa(i), 3) } a.Merge(b) f := a.Fold() if len(f) > TopKSize+1 || f[OtherKey] == 0 { t.Fatalf("merged 800 keys must fold to ≤501: %d", len(f)) } r := TopKFrom(f) if r.other != f[OtherKey] || len(r.counts) != len(f)-1 { t.Fatal("TopKFrom must invert Fold") } long := NewTopK() long.Add(string(make([]byte, 300)), 1) for key := range long.Fold() { if len(key) > MaxKeyLen { t.Fatal("keys must be capped at 256 bytes") } } }