From a1d519b9ef9134bea639621fcce86c0f941833ce Mon Sep 17 00:00:00 2001 From: kcross Date: Thu, 14 Aug 2025 12:06:45 +0100 Subject: [PATCH] fix: Removed the datarace condition when using variables after `assert.Eventually` timeout --- .gitignore | 2 ++ assert/assertions.go | 8 ++++++-- require/requirements_test.go | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6e1bb22a2..50eec10e3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,8 @@ _testmain.go .DS_Store +.idea + # Output of "go test -c" /assert/assert.test /require/require.test diff --git a/assert/assertions.go b/assert/assertions.go index de8de0cb6..364b8febd 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -13,6 +13,7 @@ import ( "runtime" "runtime/debug" "strings" + "sync" "time" "unicode" "unicode/utf8" @@ -1989,9 +1990,9 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t if h, ok := t.(tHelper); ok { h.Helper() } - ch := make(chan bool, 1) - checkCond := func() { ch <- condition() } + wg := &sync.WaitGroup{} + checkCond := func() { defer wg.Done(); ch <- condition() } timer := time.NewTimer(waitFor) defer timer.Stop() @@ -2002,14 +2003,17 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t var tickC <-chan time.Time // Check the condition once first on the initial call. + wg.Add(1) go checkCond() for { select { case <-timer.C: + wg.Wait() return Fail(t, "Condition never satisfied", msgAndArgs...) case <-tickC: tickC = nil + wg.Add(1) go checkCond() case v := <-ch: if v { diff --git a/require/requirements_test.go b/require/requirements_test.go index 7cb63a554..02bccad53 100644 --- a/require/requirements_test.go +++ b/require/requirements_test.go @@ -788,3 +788,22 @@ func TestEventuallyWithTTrue(t *testing.T) { False(t, mockT.Failed, "Check should pass") Equal(t, 2, counter, "Condition is expected to be called 2 times") } + +func TestEventuallyTimeout(t *testing.T) { + t.Parallel() + + mockT := new(MockT) + + counter := 0 + condition := func() bool { + counter += 1 + // this is here to check for data race conditions. + time.Sleep(20 * time.Millisecond) + return false + } + //Done to check for data race + counter += 1 + Eventually(mockT, condition, 100*time.Millisecond, 20*time.Millisecond) + True(t, mockT.Failed, "check should fail") + Greater(t, counter, 2, "we should have more than one iteration") +}