From 7bce67462cf0a5faac990892ba65d2cf7cab904f Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Fri, 15 May 2026 07:57:15 +0200 Subject: [PATCH] pkg/util: harden TestRandomSuffixGenerator against birthday collisions The previous test asserted that no two adjacent samples from a ~10 000-element space were equal across 100 iterations. The birthday math gives that adjacency check a ~1 % flake rate per run; with the new gitea.lan CI volume that turned into observable random failures (go-unit #51 on feature/enable-actions-cache hit "Should not be: '6635'"). Replace adjacency with a distinctness floor over a wider 200-sample draw. A stuck generator (single value) lands at 1 unique; a 256-element range lands at ~196; the natural full-range generator lands at ~198. A floor of 150 catches the failure modes the test was actually written to guard against and never trips on legitimate randomness. Co-Authored-By: Claude Opus 4.7 (1M context) --- pkg/util/string_test.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pkg/util/string_test.go b/pkg/util/string_test.go index 3d2f560..8972f2d 100644 --- a/pkg/util/string_test.go +++ b/pkg/util/string_test.go @@ -282,12 +282,24 @@ func TestAppendRandomSuffixGenerator(t *testing.T) { } func TestRandomSuffixGenerator(t *testing.T) { - var last string - for range 100 { + // The generator draws from a ~10 000 element space (Intn(9999) + // formatted as four digits). Comparing each sample against the + // previous one with NotEqual flaked ~1 % per 100-iteration run on + // natural collisions. Count unique values instead — if the + // generator ever gets stuck on a tiny range we still catch it, + // without depending on the birthday paradox not firing today. + const samples = 200 + seen := make(map[string]struct{}, samples) + for range samples { s := util.RandomSuffixGenerator() assert.Len(t, s, 4) - assert.NotEqual(t, last, s) assert.True(t, strings.ContainsFunc(s, func(r rune) bool { return r >= '0' && r <= '9' })) - last = s + seen[s] = struct{}{} } + // In 200 draws from ~10 000 the expected number of unique values + // is ~198; a stuck generator (single value) would land at 1, a + // 256-value range at ~196. 150 is well above the floor either + // way and well below the expected mean. + assert.GreaterOrEqual(t, len(seen), 150, + "RandomSuffixGenerator drew from too small a range over %d samples", samples) }