From c77c046c8c535758d8656447de1af99f8e034da2 Mon Sep 17 00:00:00 2001 From: Adam Luzsi Date: Mon, 22 Jul 2024 21:17:33 +0200 Subject: [PATCH] make random.Unique more forgiving --- random/Unique.go | 7 +++++-- random/Unique_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/random/Unique.go b/random/Unique.go index edd9f41..6623afd 100644 --- a/random/Unique.go +++ b/random/Unique.go @@ -20,8 +20,11 @@ func Unique[T any](blk func() T, excludeList ...T) T { if len(excludeList) == 0 { return blk() } - deadline := clock.Now().Add(5 * time.Second) - for clock.Now().Before(deadline) { + var ( + retries int + deadline = clock.Now().Add(5 * time.Second) + ) + for ; clock.Now().Before(deadline) || retries < 5; retries++ { var ( v T = blk() ok bool = true diff --git a/random/Unique_test.go b/random/Unique_test.go index b094ea3..8fa4a2a 100644 --- a/random/Unique_test.go +++ b/random/Unique_test.go @@ -2,6 +2,7 @@ package random_test import ( "testing" + "time" "go.llib.dev/testcase/assert" "go.llib.dev/testcase/clock/timecop" @@ -62,4 +63,32 @@ func TestUnique(t *testing.T) { assert.False(t, out.OK) assert.NotEmpty(t, out.PanicValue) }) + t.Run("creating an item takes a lot of time then instead of time based retry, we make at least 5 attempts", func(t *testing.T) { + now := time.Now() + timecop.Travel(t, now, timecop.Freeze) + out := sandbox.Run(func() { + var i int + random.Unique(func() int { + timecop.Travel(t, 10*time.Second) + i++ + if 5 <= i { + return i + } + return 0 + }, 0) + }) + assert.True(t, out.OK) + }) + t.Run("if the unique's make function is fast enough, then more than 5 tries will be made, as long it can fit within the deadline", func(t *testing.T) { + timecop.SetSpeed(t, 1000 /* times */) + var n int + out := sandbox.Run(func() { + random.Unique(func() int { + n++ + return 0 + }, 0) + }) + assert.False(t, out.OK) + assert.True(t, 6 < n) // probably it runs at least 20000 times, so it should be definetly bigger than 6 + }) }