mirror of
https://github.com/samber/lo.git
synced 2025-12-24 12:48:02 +08:00
fix(tests): fix flaky time-based tests (#699)
* fix(tests): fix flaky time-based tests * test: replace time package with a mock Using a dedicated dependency would have been awesome, but i try to keep this repo with minimal dependencies
This commit is contained in:
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -8,6 +8,8 @@ jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -10,6 +10,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go:
|
||||
- "1.18"
|
||||
@@ -19,6 +20,7 @@ jobs:
|
||||
- "1.22"
|
||||
- "1.23"
|
||||
- "1.24"
|
||||
- "1.25"
|
||||
- "1.x"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
4
Makefile
4
Makefile
@@ -3,9 +3,9 @@ build:
|
||||
go build -v ./...
|
||||
|
||||
test:
|
||||
go test -race -v ./...
|
||||
go test -race ./...
|
||||
watch-test:
|
||||
reflex -t 50ms -s -- sh -c 'gotest -race -v ./...'
|
||||
reflex -t 50ms -s -- sh -c 'gotest -race ./...'
|
||||
|
||||
bench:
|
||||
go test -benchmem -count 3 -bench ./...
|
||||
|
||||
@@ -98,7 +98,7 @@ func TestChannelDispatcher(t *testing.T) {
|
||||
|
||||
func TestDispatchingStrategyRoundRobin(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
children := createChannels[int](3, 2)
|
||||
@@ -113,7 +113,7 @@ func TestDispatchingStrategyRoundRobin(t *testing.T) {
|
||||
|
||||
func TestDispatchingStrategyRandom(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
children := createChannels[int](2, 2)
|
||||
@@ -129,7 +129,7 @@ func TestDispatchingStrategyRandom(t *testing.T) {
|
||||
|
||||
func TestDispatchingStrategyWeightedRandom(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
children := createChannels[int](2, 2)
|
||||
@@ -147,7 +147,7 @@ func TestDispatchingStrategyWeightedRandom(t *testing.T) {
|
||||
|
||||
func TestDispatchingStrategyFirst(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
children := createChannels[int](2, 2)
|
||||
@@ -163,7 +163,7 @@ func TestDispatchingStrategyFirst(t *testing.T) {
|
||||
|
||||
func TestDispatchingStrategyLeast(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
children := createChannels[int](2, 2)
|
||||
@@ -183,7 +183,7 @@ func TestDispatchingStrategyLeast(t *testing.T) {
|
||||
|
||||
func TestDispatchingStrategyMost(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
children := createChannels[int](2, 2)
|
||||
@@ -203,7 +203,7 @@ func TestDispatchingStrategyMost(t *testing.T) {
|
||||
|
||||
func TestSliceToChannel(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
ch := SliceToChannel(2, []int{1, 2, 3})
|
||||
@@ -224,7 +224,7 @@ func TestSliceToChannel(t *testing.T) {
|
||||
|
||||
func TestChannelToSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
ch := SliceToChannel(2, []int{1, 2, 3})
|
||||
@@ -235,7 +235,7 @@ func TestChannelToSlice(t *testing.T) {
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
generator := func(yield func(int)) {
|
||||
@@ -257,7 +257,7 @@ func TestGenerate(t *testing.T) {
|
||||
|
||||
func TestBuffer(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 10*time.Millisecond)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
ch := SliceToChannel(2, []int{1, 2, 3})
|
||||
@@ -277,8 +277,8 @@ func TestBuffer(t *testing.T) {
|
||||
is.False(ok3)
|
||||
}
|
||||
|
||||
func TestBufferWithContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestBufferWithContext(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
@@ -313,47 +313,60 @@ func TestBufferWithContext(t *testing.T) {
|
||||
is.True(ok2)
|
||||
}
|
||||
|
||||
func TestBufferWithTimeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
func TestBufferWithTimeout(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 2000*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
generator := func(yield func(int)) {
|
||||
for i := 0; i < 5; i++ {
|
||||
yield(i)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
generator := func(n ...int) func(yield func(int)) {
|
||||
return func(yield func(int)) {
|
||||
for i := 0; i < len(n); i++ {
|
||||
yield(n[i])
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
ch := Generator(0, generator)
|
||||
|
||||
items1, length1, _, ok1 := BufferWithTimeout(ch, 20, 15*time.Millisecond)
|
||||
ch := Generator(0, generator(0, 1, 2, 3, 4))
|
||||
items1, length1, duration1, ok1 := BufferWithTimeout(ch, 20, 150*time.Millisecond)
|
||||
is.Equal([]int{0, 1}, items1)
|
||||
is.Equal(2, length1)
|
||||
is.InDelta(150*time.Millisecond, duration1, float64(20*time.Millisecond))
|
||||
is.True(ok1)
|
||||
|
||||
items2, length2, _, ok2 := BufferWithTimeout(ch, 20, 2*time.Millisecond)
|
||||
items2, length2, duration2, ok2 := BufferWithTimeout(ch, 20, 10*time.Millisecond)
|
||||
is.Empty(items2)
|
||||
is.Zero(length2)
|
||||
is.InDelta(10*time.Millisecond, duration2, float64(10*time.Millisecond))
|
||||
is.True(ok2)
|
||||
|
||||
items3, length3, _, ok3 := BufferWithTimeout(ch, 1, 30*time.Millisecond)
|
||||
items3, length3, duration3, ok3 := BufferWithTimeout(ch, 1, 300*time.Millisecond)
|
||||
is.Equal([]int{2}, items3)
|
||||
is.Equal(1, length3)
|
||||
is.InDelta(50*time.Millisecond, duration3, float64(20*time.Millisecond))
|
||||
is.True(ok3)
|
||||
|
||||
items4, length4, _, ok4 := BufferWithTimeout(ch, 2, 25*time.Millisecond)
|
||||
items4, length4, duration4, ok4 := BufferWithTimeout(ch, 2, 250*time.Millisecond)
|
||||
is.Equal([]int{3, 4}, items4)
|
||||
is.Equal(2, length4)
|
||||
is.InDelta(200*time.Millisecond, duration4, float64(50*time.Millisecond))
|
||||
is.True(ok4)
|
||||
|
||||
items5, length5, _, ok5 := BufferWithTimeout(ch, 3, 25*time.Millisecond)
|
||||
items5, length5, duration5, ok5 := BufferWithTimeout(ch, 3, 250*time.Millisecond)
|
||||
is.Empty(items5)
|
||||
is.Zero(length5)
|
||||
is.InDelta(100*time.Millisecond, duration5, float64(50*time.Millisecond))
|
||||
is.False(ok5)
|
||||
|
||||
items6, length6, duration6, ok6 := BufferWithTimeout(ch, 3, 250*time.Millisecond)
|
||||
is.Empty(items6)
|
||||
is.Zero(length6)
|
||||
is.InDelta(1*time.Millisecond, duration6, float64(10*time.Millisecond))
|
||||
is.False(ok6)
|
||||
}
|
||||
|
||||
func TestFanIn(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestFanIn(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
@@ -392,8 +405,8 @@ func TestFanIn(t *testing.T) {
|
||||
is.Zero(msg0)
|
||||
}
|
||||
|
||||
func TestFanOut(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestFanOut(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSynchronize(t *testing.T) {
|
||||
t.Parallel()
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
func TestSynchronize(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 1000*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
// check that callbacks are not executed concurrently
|
||||
@@ -25,7 +25,7 @@ func TestSynchronize(t *testing.T) {
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
go s.Do(func() {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
@@ -33,9 +33,7 @@ func TestSynchronize(t *testing.T) {
|
||||
wg.Wait()
|
||||
|
||||
duration := time.Since(start)
|
||||
|
||||
is.Greater(duration, 50*time.Millisecond)
|
||||
is.Less(duration, 60*time.Millisecond)
|
||||
is.InDelta(500*time.Millisecond, duration, float64(40*time.Millisecond))
|
||||
}
|
||||
|
||||
// check locker is locked
|
||||
@@ -62,8 +60,8 @@ func TestSynchronize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsync(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestAsync(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
@@ -84,8 +82,8 @@ func TestAsync(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsyncX(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestAsyncX(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
@@ -214,33 +212,29 @@ func TestAsyncX(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitFor(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestWaitFor(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testTimeout := 100 * time.Millisecond
|
||||
longTimeout := 2 * testTimeout
|
||||
shortTimeout := 4 * time.Millisecond
|
||||
t.Run("exist condition works", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
t.Run("exist condition works", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 300*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
laterTrue := func(i int) bool {
|
||||
return i >= 5
|
||||
}
|
||||
|
||||
iter, duration, ok := WaitFor(laterTrue, longTimeout, time.Millisecond)
|
||||
iter, duration, ok := WaitFor(laterTrue, 200*time.Millisecond, 10*time.Millisecond)
|
||||
is.Equal(6, iter, "unexpected iteration count")
|
||||
is.InEpsilon(6*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.InDelta(60*time.Millisecond, duration, float64(5*time.Millisecond))
|
||||
is.True(ok)
|
||||
})
|
||||
|
||||
t.Run("counter is incremented", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("counter is incremented", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
counter := 0
|
||||
@@ -250,80 +244,63 @@ func TestWaitFor(t *testing.T) {
|
||||
return false
|
||||
}
|
||||
|
||||
iter, duration, ok := WaitFor(alwaysFalse, shortTimeout, 1050*time.Microsecond)
|
||||
iter, duration, ok := WaitFor(alwaysFalse, 40*time.Millisecond, 10*time.Millisecond)
|
||||
is.Equal(counter, iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.InDelta(40*time.Millisecond, duration, float64(5*time.Millisecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
alwaysTrue := func(_ int) bool { return true }
|
||||
alwaysFalse := func(_ int) bool { return false }
|
||||
|
||||
t.Run("short timeout works", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("timeout works", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
iter, duration, ok := WaitFor(alwaysFalse, shortTimeout, 10*time.Millisecond)
|
||||
iter, duration, ok := WaitFor(alwaysFalse, 50*time.Millisecond, 100*time.Millisecond)
|
||||
is.Zero(iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.InDelta(50*time.Millisecond, duration, float64(10*time.Millisecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
t.Run("timeout works", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("exist on first condition", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
shortTimeout := 4 * time.Millisecond
|
||||
iter, duration, ok := WaitFor(alwaysFalse, shortTimeout, 10*time.Millisecond)
|
||||
is.Zero(iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
t.Run("exist on first condition", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
is := assert.New(t)
|
||||
|
||||
iter, duration, ok := WaitFor(alwaysTrue, 10*time.Millisecond, time.Millisecond)
|
||||
iter, duration, ok := WaitFor(alwaysTrue, 100*time.Millisecond, 30*time.Millisecond)
|
||||
is.Equal(1, iter, "unexpected iteration count")
|
||||
is.InEpsilon(time.Millisecond, duration, float64(5*time.Microsecond))
|
||||
is.InDelta(30*time.Millisecond, duration, float64(10*time.Millisecond))
|
||||
is.True(ok)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWaitForWithContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestWaitForWithContext(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testTimeout := 100 * time.Millisecond
|
||||
longTimeout := 2 * testTimeout
|
||||
shortTimeout := 4 * time.Millisecond
|
||||
t.Run("exist condition works", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
t.Run("exist condition works", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
laterTrue := func(_ context.Context, i int) bool {
|
||||
return i >= 5
|
||||
}
|
||||
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), laterTrue, longTimeout, time.Millisecond)
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), laterTrue, 200*time.Millisecond, 10*time.Millisecond)
|
||||
is.Equal(6, iter, "unexpected iteration count")
|
||||
is.InEpsilon(6*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.InDelta(60*time.Millisecond, duration, float64(5*time.Millisecond))
|
||||
is.True(ok)
|
||||
})
|
||||
|
||||
t.Run("counter is incremented", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("counter is incremented", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
counter := 0
|
||||
@@ -333,81 +310,68 @@ func TestWaitForWithContext(t *testing.T) {
|
||||
return false
|
||||
}
|
||||
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysFalse, shortTimeout, 1050*time.Microsecond)
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysFalse, 40*time.Millisecond, 10*time.Millisecond)
|
||||
is.Equal(counter, iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.InDelta(40*time.Millisecond, duration, float64(5*time.Millisecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
alwaysTrue := func(_ context.Context, _ int) bool { return true }
|
||||
alwaysFalse := func(_ context.Context, _ int) bool { return false }
|
||||
|
||||
t.Run("short timeout works", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("timeout works", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysFalse, shortTimeout, 10*time.Millisecond)
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysFalse, 50*time.Millisecond, 100*time.Millisecond)
|
||||
is.Zero(iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.InDelta(50*time.Millisecond, duration, float64(10*time.Millisecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
t.Run("timeout works", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("exist on first condition", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
shortTimeout := 4 * time.Millisecond
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysFalse, shortTimeout, 10*time.Millisecond)
|
||||
is.Zero(iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
t.Run("exist on first condition", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
is := assert.New(t)
|
||||
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysTrue, 10*time.Millisecond, time.Millisecond)
|
||||
iter, duration, ok := WaitForWithContext(context.Background(), alwaysTrue, 100*time.Millisecond, 10*time.Millisecond)
|
||||
is.Equal(1, iter, "unexpected iteration count")
|
||||
is.InEpsilon(time.Millisecond, duration, float64(5*time.Microsecond))
|
||||
is.InDelta(10*time.Millisecond, duration, float64(5*time.Millisecond))
|
||||
is.True(ok)
|
||||
})
|
||||
|
||||
t.Run("context cancellation stops everything", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("context cancellation stops everything", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 100*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
expiringCtx, clean := context.WithTimeout(context.Background(), 8*time.Millisecond)
|
||||
expiringCtx, clean := context.WithTimeout(context.Background(), 45*time.Millisecond)
|
||||
t.Cleanup(func() {
|
||||
clean()
|
||||
})
|
||||
|
||||
iter, duration, ok := WaitForWithContext(expiringCtx, alwaysFalse, 100*time.Millisecond, 3*time.Millisecond)
|
||||
is.Equal(2, iter, "unexpected iteration count")
|
||||
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
|
||||
iter, duration, ok := WaitForWithContext(expiringCtx, alwaysFalse, 100*time.Millisecond, 30*time.Millisecond)
|
||||
is.Equal(1, iter, "unexpected iteration count")
|
||||
is.InDelta(45*time.Millisecond, duration, float64(10*time.Millisecond))
|
||||
is.False(ok)
|
||||
})
|
||||
|
||||
t.Run("canceled context stops everything", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("canceled context stops everything", func(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
testWithTimeout(t, testTimeout)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
is := assert.New(t)
|
||||
|
||||
canceledCtx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
iter, duration, ok := WaitForWithContext(canceledCtx, alwaysFalse, 100*time.Millisecond, 1050*time.Microsecond)
|
||||
iter, duration, ok := WaitForWithContext(canceledCtx, alwaysFalse, 100*time.Millisecond, 30*time.Millisecond)
|
||||
is.Zero(iter, "unexpected iteration count")
|
||||
is.InEpsilon(1*time.Millisecond, duration, float64(5*time.Microsecond))
|
||||
is.InDelta(1*time.Millisecond, duration, float64(1*time.Millisecond))
|
||||
is.False(ok)
|
||||
})
|
||||
}
|
||||
|
||||
6
internal/xtime/README.md
Normal file
6
internal/xtime/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
# xtime
|
||||
|
||||
Lightweight mock for time package.
|
||||
|
||||
A dedicated package such as [jonboulle/clockwork](https://github.com/jonboulle/clockwork/) would be better, but I would rather limit dependencies for this package. `clockwork` does not support Go 1.18 anymore.
|
||||
40
internal/xtime/fake.go
Normal file
40
internal/xtime/fake.go
Normal file
@@ -0,0 +1,40 @@
|
||||
//nolint:revive
|
||||
package xtime
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewFakeClock() *FakeClock {
|
||||
return NewFakeClockAt(time.Now())
|
||||
}
|
||||
|
||||
func NewFakeClockAt(t time.Time) *FakeClock {
|
||||
return &FakeClock{
|
||||
time: t,
|
||||
}
|
||||
}
|
||||
|
||||
type FakeClock struct {
|
||||
_ noCopy
|
||||
|
||||
// Not protected by a mutex. If a warning is thrown in your tests,
|
||||
// just disable parallel tests.
|
||||
time time.Time
|
||||
}
|
||||
|
||||
func (c *FakeClock) Now() time.Time {
|
||||
return c.time
|
||||
}
|
||||
|
||||
func (c *FakeClock) Since(t time.Time) time.Duration {
|
||||
return c.time.Sub(t)
|
||||
}
|
||||
|
||||
func (c *FakeClock) Until(t time.Time) time.Duration {
|
||||
return t.Sub(c.time)
|
||||
}
|
||||
|
||||
func (c *FakeClock) Sleep(d time.Duration) {
|
||||
c.time = c.time.Add(d)
|
||||
}
|
||||
14
internal/xtime/noCopy.go
Normal file
14
internal/xtime/noCopy.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package xtime
|
||||
|
||||
// noCopy may be added to structs which must not be copied
|
||||
// after the first use.
|
||||
//
|
||||
// See https://golang.org/issues/8005#issuecomment-190753527
|
||||
// for details.
|
||||
//
|
||||
// Note that it must not be embedded, due to the Lock and Unlock methods.
|
||||
type noCopy struct{}
|
||||
|
||||
// Lock is a no-op used by -copylocks checker from `go vet`.
|
||||
func (*noCopy) Lock() {}
|
||||
func (*noCopy) Unlock() {}
|
||||
30
internal/xtime/real.go
Normal file
30
internal/xtime/real.go
Normal file
@@ -0,0 +1,30 @@
|
||||
//nolint:revive
|
||||
package xtime
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewRealClock() *RealClock {
|
||||
return &RealClock{}
|
||||
}
|
||||
|
||||
type RealClock struct {
|
||||
_ noCopy
|
||||
}
|
||||
|
||||
func (c *RealClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
func (c *RealClock) Since(t time.Time) time.Duration {
|
||||
return time.Since(t)
|
||||
}
|
||||
|
||||
func (c *RealClock) Until(t time.Time) time.Duration {
|
||||
return time.Until(t)
|
||||
}
|
||||
|
||||
func (c *RealClock) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
33
internal/xtime/time.go
Normal file
33
internal/xtime/time.go
Normal file
@@ -0,0 +1,33 @@
|
||||
//nolint:revive
|
||||
package xtime
|
||||
|
||||
import "time"
|
||||
|
||||
var clock Clock = &RealClock{}
|
||||
|
||||
func SetClock(c Clock) {
|
||||
clock = c
|
||||
}
|
||||
|
||||
func Now() time.Time {
|
||||
return clock.Now()
|
||||
}
|
||||
|
||||
func Since(t time.Time) time.Duration {
|
||||
return clock.Since(t)
|
||||
}
|
||||
|
||||
func Until(t time.Time) time.Duration {
|
||||
return clock.Until(t)
|
||||
}
|
||||
|
||||
func Sleep(d time.Duration) {
|
||||
clock.Sleep(d)
|
||||
}
|
||||
|
||||
type Clock interface {
|
||||
Now() time.Time
|
||||
Since(t time.Time) time.Duration
|
||||
Until(t time.Time) time.Duration
|
||||
Sleep(d time.Duration)
|
||||
}
|
||||
@@ -3,9 +3,11 @@ package lo
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo/internal/xtime"
|
||||
"go.uber.org/goleak"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
xtime.SetClock(xtime.NewFakeClock())
|
||||
goleak.VerifyTestMain(m)
|
||||
}
|
||||
|
||||
24
retry.go
24
retry.go
@@ -3,6 +3,8 @@ package lo
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo/internal/xtime"
|
||||
)
|
||||
|
||||
type debounce struct {
|
||||
@@ -172,20 +174,20 @@ func Attempt(maxIteration int, f func(index int) error) (int, error) {
|
||||
func AttemptWithDelay(maxIteration int, delay time.Duration, f func(index int, duration time.Duration) error) (int, time.Duration, error) {
|
||||
var err error
|
||||
|
||||
start := time.Now()
|
||||
start := xtime.Now()
|
||||
|
||||
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
|
||||
err = f(i, time.Since(start))
|
||||
err = f(i, xtime.Since(start))
|
||||
if err == nil {
|
||||
return i + 1, time.Since(start), nil
|
||||
return i + 1, xtime.Since(start), nil
|
||||
}
|
||||
|
||||
if maxIteration <= 0 || i+1 < maxIteration {
|
||||
time.Sleep(delay)
|
||||
xtime.Sleep(delay)
|
||||
}
|
||||
}
|
||||
|
||||
return maxIteration, time.Since(start), err
|
||||
return maxIteration, xtime.Since(start), err
|
||||
}
|
||||
|
||||
// AttemptWhile invokes a function N times until it returns valid output.
|
||||
@@ -224,23 +226,23 @@ func AttemptWhileWithDelay(maxIteration int, delay time.Duration, f func(int, ti
|
||||
var err error
|
||||
var shouldContinueInvoke bool
|
||||
|
||||
start := time.Now()
|
||||
start := xtime.Now()
|
||||
|
||||
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
|
||||
err, shouldContinueInvoke = f(i, time.Since(start))
|
||||
err, shouldContinueInvoke = f(i, xtime.Since(start))
|
||||
if !shouldContinueInvoke { // if shouldContinueInvoke is false, then return immediately
|
||||
return i + 1, time.Since(start), err
|
||||
return i + 1, xtime.Since(start), err
|
||||
}
|
||||
if err == nil {
|
||||
return i + 1, time.Since(start), nil
|
||||
return i + 1, xtime.Since(start), nil
|
||||
}
|
||||
|
||||
if maxIteration <= 0 || i+1 < maxIteration {
|
||||
time.Sleep(delay)
|
||||
xtime.Sleep(delay)
|
||||
}
|
||||
}
|
||||
|
||||
return maxIteration, time.Since(start), err
|
||||
return maxIteration, xtime.Since(start), err
|
||||
}
|
||||
|
||||
type transactionStep[T any] struct {
|
||||
|
||||
132
retry_test.go
132
retry_test.go
@@ -50,8 +50,8 @@ func TestAttempt(t *testing.T) {
|
||||
is.NoError(err4)
|
||||
}
|
||||
|
||||
func TestAttemptWithDelay(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestAttemptWithDelay(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
err := errors.New("failed")
|
||||
@@ -60,14 +60,14 @@ func TestAttemptWithDelay(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
iter2, dur2, err2 := AttemptWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) error {
|
||||
if i == 5 {
|
||||
if i == 3 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
iter3, dur3, err3 := AttemptWithDelay(2, 10*time.Millisecond, func(i int, d time.Duration) error {
|
||||
if i == 5 {
|
||||
if i == 3 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -82,20 +82,19 @@ func TestAttemptWithDelay(t *testing.T) {
|
||||
})
|
||||
|
||||
is.Equal(1, iter1)
|
||||
is.GreaterOrEqual(dur1, 0*time.Millisecond)
|
||||
is.Less(dur1, 1*time.Millisecond)
|
||||
is.InDelta(1*time.Microsecond, dur1, float64(1*time.Millisecond))
|
||||
is.NoError(err1)
|
||||
is.Equal(6, iter2)
|
||||
is.Greater(dur2, 50*time.Millisecond)
|
||||
is.Less(dur2, 60*time.Millisecond)
|
||||
|
||||
is.Equal(4, iter2)
|
||||
is.InDelta(30*time.Millisecond, dur2, float64(5*time.Millisecond))
|
||||
is.NoError(err2)
|
||||
|
||||
is.Equal(2, iter3)
|
||||
is.Greater(dur3, 10*time.Millisecond)
|
||||
is.Less(dur3, 20*time.Millisecond)
|
||||
is.InDelta(10*time.Millisecond, dur3, float64(5*time.Millisecond))
|
||||
is.ErrorIs(err3, err)
|
||||
|
||||
is.Equal(11, iter4)
|
||||
is.Greater(dur4, 100*time.Millisecond)
|
||||
is.Less(dur4, 115*time.Millisecond)
|
||||
is.InDelta(100*time.Millisecond, dur4, float64(5*time.Millisecond))
|
||||
is.NoError(err4)
|
||||
}
|
||||
|
||||
@@ -178,8 +177,8 @@ func TestAttemptWhile(t *testing.T) {
|
||||
is.NoError(err7)
|
||||
}
|
||||
|
||||
func TestAttemptWhileWithDelay(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestAttemptWhileWithDelay(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
err := errors.New("failed")
|
||||
@@ -189,21 +188,19 @@ func TestAttemptWhileWithDelay(t *testing.T) {
|
||||
})
|
||||
|
||||
is.Equal(1, iter1)
|
||||
is.GreaterOrEqual(dur1, 0*time.Millisecond)
|
||||
is.Less(dur1, 1*time.Millisecond)
|
||||
is.InDelta(1*time.Microsecond, dur1, float64(3*time.Millisecond))
|
||||
is.NoError(err1)
|
||||
|
||||
iter2, dur2, err2 := AttemptWhileWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
|
||||
if i == 5 {
|
||||
if i == 3 {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
return err, true
|
||||
})
|
||||
|
||||
is.Equal(6, iter2)
|
||||
is.Greater(dur2, 50*time.Millisecond)
|
||||
is.Less(dur2, 60*time.Millisecond)
|
||||
is.Equal(4, iter2)
|
||||
is.InDelta(30*time.Millisecond, dur2, float64(5*time.Millisecond))
|
||||
is.NoError(err2)
|
||||
|
||||
iter3, dur3, err3 := AttemptWhileWithDelay(2, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
|
||||
@@ -215,8 +212,7 @@ func TestAttemptWhileWithDelay(t *testing.T) {
|
||||
})
|
||||
|
||||
is.Equal(2, iter3)
|
||||
is.Greater(dur3, 10*time.Millisecond)
|
||||
is.Less(dur3, 20*time.Millisecond)
|
||||
is.InDelta(10*time.Millisecond, dur3, float64(5*time.Millisecond))
|
||||
is.ErrorIs(err3, err)
|
||||
|
||||
iter4, dur4, err4 := AttemptWhileWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
|
||||
@@ -228,21 +224,19 @@ func TestAttemptWhileWithDelay(t *testing.T) {
|
||||
})
|
||||
|
||||
is.Equal(11, iter4)
|
||||
is.Greater(dur4, 100*time.Millisecond)
|
||||
is.Less(dur4, 115*time.Millisecond)
|
||||
is.InDelta(100*time.Millisecond, dur4, float64(5*time.Millisecond))
|
||||
is.NoError(err4)
|
||||
|
||||
iter5, dur5, err5 := AttemptWhileWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
|
||||
if i == 5 {
|
||||
if i == 3 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return err, true
|
||||
})
|
||||
|
||||
is.Equal(6, iter5)
|
||||
is.Greater(dur5, 10*time.Millisecond)
|
||||
is.Less(dur5, 115*time.Millisecond)
|
||||
is.Equal(4, iter5)
|
||||
is.InDelta(30*time.Millisecond, dur5, float64(5*time.Millisecond))
|
||||
is.NoError(err5)
|
||||
|
||||
iter6, dur6, err6 := AttemptWhileWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
|
||||
@@ -250,8 +244,7 @@ func TestAttemptWhileWithDelay(t *testing.T) {
|
||||
})
|
||||
|
||||
is.Equal(1, iter6)
|
||||
is.Less(dur6, 10*time.Millisecond)
|
||||
is.Less(dur6, 115*time.Millisecond)
|
||||
is.InDelta(1*time.Microsecond, dur6, float64(5*time.Millisecond))
|
||||
is.NoError(err6)
|
||||
|
||||
iter7, dur7, err7 := AttemptWhileWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
|
||||
@@ -266,12 +259,12 @@ func TestAttemptWhileWithDelay(t *testing.T) {
|
||||
})
|
||||
|
||||
is.Equal(42, iter7)
|
||||
is.Less(dur7, 500*time.Millisecond)
|
||||
is.InDelta(410*time.Millisecond, dur7, float64(5*time.Millisecond))
|
||||
is.NoError(err7)
|
||||
}
|
||||
|
||||
func TestDebounce(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestDebounce(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
|
||||
f1 := func() {
|
||||
println("1. Called once after 10ms when func stopped invoking!")
|
||||
@@ -283,43 +276,43 @@ func TestDebounce(t *testing.T) {
|
||||
println("3. Called once after 10ms when func stopped invoking!")
|
||||
}
|
||||
|
||||
d1, _ := NewDebounce(10*time.Millisecond, f1)
|
||||
d1, _ := NewDebounce(100*time.Millisecond, f1)
|
||||
|
||||
// execute 3 times
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
d1()
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
|
||||
d2, _ := NewDebounce(10*time.Millisecond, f2)
|
||||
d2, _ := NewDebounce(100*time.Millisecond, f2)
|
||||
|
||||
// execute once because it is always invoked and only last invoke is worked after 100ms
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
d2()
|
||||
}
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// execute once because it is canceled after 200ms.
|
||||
d3, cancel := NewDebounce(10*time.Millisecond, f3)
|
||||
d3, cancel := NewDebounce(100*time.Millisecond, f3)
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
d3()
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
if i == 0 {
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebounceBy(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestDebounceBy(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
mu := sync.Mutex{}
|
||||
@@ -344,7 +337,7 @@ func TestDebounceBy(t *testing.T) {
|
||||
// fmt.Printf("[key=%d] 3. Called once after 10ms when func stopped invoking!\n", key)
|
||||
}
|
||||
|
||||
d1, _ := NewDebounceBy(10*time.Millisecond, f1)
|
||||
d1, _ := NewDebounceBy(100*time.Millisecond, f1)
|
||||
|
||||
// execute 3 times
|
||||
for i := 0; i < 3; i++ {
|
||||
@@ -353,16 +346,19 @@ func TestDebounceBy(t *testing.T) {
|
||||
d1(k)
|
||||
}
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Wait for debounced calls to complete
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
mu.Lock()
|
||||
is.Equal(30, output[0])
|
||||
is.Equal(30, output[1])
|
||||
is.Equal(30, output[2])
|
||||
mu.Unlock()
|
||||
|
||||
d2, _ := NewDebounceBy(10*time.Millisecond, f2)
|
||||
d2, _ := NewDebounceBy(100*time.Millisecond, f2)
|
||||
|
||||
// execute once because it is always invoked and only last invoke is worked after 100ms
|
||||
for i := 0; i < 3; i++ {
|
||||
@@ -371,10 +367,11 @@ func TestDebounceBy(t *testing.T) {
|
||||
d2(k)
|
||||
}
|
||||
}
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Wait for debounced calls to complete
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
mu.Lock()
|
||||
is.Equal(45, output[0])
|
||||
@@ -383,7 +380,7 @@ func TestDebounceBy(t *testing.T) {
|
||||
mu.Unlock()
|
||||
|
||||
// execute once because it is canceled after 200ms.
|
||||
d3, cancel := NewDebounceBy(10*time.Millisecond, f3)
|
||||
d3, cancel := NewDebounceBy(100*time.Millisecond, f3)
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
for k := 0; k < 3; k++ {
|
||||
@@ -391,7 +388,7 @@ func TestDebounceBy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
if i == 0 {
|
||||
for k := 0; k < 3; k++ {
|
||||
cancel(k)
|
||||
@@ -399,6 +396,9 @@ func TestDebounceBy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for debounced calls to complete
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
mu.Lock()
|
||||
is.Equal(75, output[0])
|
||||
is.Equal(75, output[1])
|
||||
@@ -502,14 +502,14 @@ func TestTransaction(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewThrottle(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestNewThrottle(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
callCount := 0
|
||||
f1 := func() {
|
||||
callCount++
|
||||
}
|
||||
th, reset := NewThrottle(10*time.Millisecond, f1)
|
||||
th, reset := NewThrottle(100*time.Millisecond, f1)
|
||||
|
||||
is.Zero(callCount)
|
||||
for j := 0; j < 100; j++ {
|
||||
@@ -517,7 +517,7 @@ func TestNewThrottle(t *testing.T) {
|
||||
}
|
||||
is.Equal(1, callCount)
|
||||
|
||||
time.Sleep(15 * time.Millisecond)
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
for j := 0; j < 100; j++ {
|
||||
th()
|
||||
@@ -531,14 +531,14 @@ func TestNewThrottle(t *testing.T) {
|
||||
is.Equal(3, callCount)
|
||||
}
|
||||
|
||||
func TestNewThrottleWithCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestNewThrottleWithCount(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
callCount := 0
|
||||
f1 := func() {
|
||||
callCount++
|
||||
}
|
||||
th, reset := NewThrottleWithCount(10*time.Millisecond, 3, f1)
|
||||
th, reset := NewThrottleWithCount(100*time.Millisecond, 3, f1)
|
||||
|
||||
// the function does not throttle for initial count number
|
||||
for i := 0; i < 20; i++ {
|
||||
@@ -546,7 +546,7 @@ func TestNewThrottleWithCount(t *testing.T) {
|
||||
}
|
||||
is.Equal(3, callCount)
|
||||
|
||||
time.Sleep(15 * time.Millisecond)
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
th()
|
||||
@@ -562,8 +562,8 @@ func TestNewThrottleWithCount(t *testing.T) {
|
||||
is.Equal(9, callCount)
|
||||
}
|
||||
|
||||
func TestNewThrottleBy(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestNewThrottleBy(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
callCountA := 0
|
||||
callCountB := 0
|
||||
@@ -574,7 +574,7 @@ func TestNewThrottleBy(t *testing.T) {
|
||||
callCountB++
|
||||
}
|
||||
}
|
||||
th, reset := NewThrottleBy(10*time.Millisecond, f1)
|
||||
th, reset := NewThrottleBy(100*time.Millisecond, f1)
|
||||
|
||||
is.Zero(callCountA)
|
||||
is.Zero(callCountB)
|
||||
@@ -585,7 +585,7 @@ func TestNewThrottleBy(t *testing.T) {
|
||||
is.Equal(1, callCountA)
|
||||
is.Equal(1, callCountB)
|
||||
|
||||
time.Sleep(15 * time.Millisecond)
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
for j := 0; j < 100; j++ {
|
||||
th("a")
|
||||
@@ -602,8 +602,8 @@ func TestNewThrottleBy(t *testing.T) {
|
||||
is.Equal(2, callCountB)
|
||||
}
|
||||
|
||||
func TestNewThrottleByWithCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestNewThrottleByWithCount(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
callCountA := 0
|
||||
@@ -615,7 +615,7 @@ func TestNewThrottleByWithCount(t *testing.T) {
|
||||
callCountB++
|
||||
}
|
||||
}
|
||||
th, reset := NewThrottleByWithCount(10*time.Millisecond, 3, f1)
|
||||
th, reset := NewThrottleByWithCount(100*time.Millisecond, 3, f1)
|
||||
|
||||
// the function does not throttle for initial count number
|
||||
for i := 0; i < 20; i++ {
|
||||
@@ -625,7 +625,7 @@ func TestNewThrottleByWithCount(t *testing.T) {
|
||||
is.Equal(3, callCountA)
|
||||
is.Equal(3, callCountB)
|
||||
|
||||
time.Sleep(15 * time.Millisecond)
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
th("a")
|
||||
|
||||
4
time.go
4
time.go
@@ -1,6 +1,8 @@
|
||||
package lo
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration returns the time taken to execute a function.
|
||||
// Play: https://go.dev/play/p/HQfbBbAXaFP
|
||||
|
||||
61
time_test.go
61
time_test.go
@@ -7,47 +7,52 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDuration(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestDuration(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
testWithTimeout(t, 200*time.Millisecond)
|
||||
|
||||
result := Duration(func() { time.Sleep(10 * time.Millisecond) })
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
result := Duration(func() { time.Sleep(100 * time.Millisecond) })
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
}
|
||||
|
||||
func TestDurationX(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestDurationX(t *testing.T) { //nolint:paralleltest
|
||||
// t.Parallel()
|
||||
is := assert.New(t)
|
||||
testWithTimeout(t, 1500*time.Millisecond)
|
||||
|
||||
{
|
||||
result := Duration0(func() { time.Sleep(10 * time.Millisecond) })
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
result := Duration0(func() { time.Sleep(100 * time.Millisecond) })
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
}
|
||||
|
||||
{
|
||||
a, result := Duration1(func() string { time.Sleep(10 * time.Millisecond); return "a" })
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
a, result := Duration1(func() string { time.Sleep(100 * time.Millisecond); return "a" })
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
}
|
||||
|
||||
{
|
||||
a, b, result := Duration2(func() (string, string) { time.Sleep(10 * time.Millisecond); return "a", "b" })
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
a, b, result := Duration2(func() (string, string) { time.Sleep(100 * time.Millisecond); return "a", "b" })
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
}
|
||||
|
||||
{
|
||||
a, b, c, result := Duration3(func() (string, string, string) { time.Sleep(10 * time.Millisecond); return "a", "b", "c" })
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
a, b, c, result := Duration3(func() (string, string, string) { time.Sleep(100 * time.Millisecond); return "a", "b", "c" })
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
}
|
||||
|
||||
{
|
||||
a, b, c, d, result := Duration4(func() (string, string, string, string) { time.Sleep(10 * time.Millisecond); return "a", "b", "c", "d" })
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
a, b, c, d, result := Duration4(func() (string, string, string, string) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d"
|
||||
})
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
@@ -56,10 +61,10 @@ func TestDurationX(t *testing.T) {
|
||||
|
||||
{
|
||||
a, b, c, d, e, result := Duration5(func() (string, string, string, string, string) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d", "e"
|
||||
})
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
@@ -69,10 +74,10 @@ func TestDurationX(t *testing.T) {
|
||||
|
||||
{
|
||||
a, b, c, d, e, f, result := Duration6(func() (string, string, string, string, string, string) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d", "e", "f"
|
||||
})
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
@@ -83,10 +88,10 @@ func TestDurationX(t *testing.T) {
|
||||
|
||||
{
|
||||
a, b, c, d, e, f, g, result := Duration7(func() (string, string, string, string, string, string, string) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d", "e", "f", "g"
|
||||
})
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
@@ -98,10 +103,10 @@ func TestDurationX(t *testing.T) {
|
||||
|
||||
{
|
||||
a, b, c, d, e, f, g, h, result := Duration8(func() (string, string, string, string, string, string, string, string) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d", "e", "f", "g", "h"
|
||||
})
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
@@ -114,10 +119,10 @@ func TestDurationX(t *testing.T) {
|
||||
|
||||
{
|
||||
a, b, c, d, e, f, g, h, i, result := Duration9(func() (string, string, string, string, string, string, string, string, string) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d", "e", "f", "g", "h", "i"
|
||||
})
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
@@ -131,10 +136,10 @@ func TestDurationX(t *testing.T) {
|
||||
|
||||
{
|
||||
a, b, c, d, e, f, g, h, i, j, result := Duration10(func() (string, string, string, string, string, string, string, string, string, string) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return "a", "b", "c", "d", "e", "f", "g", "h", "i", "j"
|
||||
})
|
||||
is.InEpsilon(10*time.Millisecond, result, float64(2*time.Millisecond))
|
||||
is.InDelta(100*time.Millisecond, result, float64(20*time.Millisecond))
|
||||
is.Equal("a", a)
|
||||
is.Equal("b", b)
|
||||
is.Equal("c", c)
|
||||
|
||||
Reference in New Issue
Block a user