Files
lo/retry_test.go
2023-03-20 15:12:54 +01:00

501 lines
9.4 KiB
Go

package lo
import (
"fmt"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestAttempt(t *testing.T) {
t.Parallel()
is := assert.New(t)
err := fmt.Errorf("failed")
iter1, err1 := Attempt(42, func(i int) error {
return nil
})
iter2, err2 := Attempt(42, func(i int) error {
if i == 5 {
return nil
}
return err
})
iter3, err3 := Attempt(2, func(i int) error {
if i == 5 {
return nil
}
return err
})
iter4, err4 := Attempt(0, func(i int) error {
if i < 42 {
return err
}
return nil
})
is.Equal(iter1, 1)
is.Equal(err1, nil)
is.Equal(iter2, 6)
is.Equal(err2, nil)
is.Equal(iter3, 2)
is.Equal(err3, err)
is.Equal(iter4, 43)
is.Equal(err4, nil)
}
func TestAttemptWithDelay(t *testing.T) {
t.Parallel()
is := assert.New(t)
err := fmt.Errorf("failed")
iter1, dur1, err1 := AttemptWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) error {
return nil
})
iter2, dur2, err2 := AttemptWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) error {
if i == 5 {
return nil
}
return err
})
iter3, dur3, err3 := AttemptWithDelay(2, 10*time.Millisecond, func(i int, d time.Duration) error {
if i == 5 {
return nil
}
return err
})
iter4, dur4, err4 := AttemptWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) error {
if i < 10 {
return err
}
return nil
})
is.Equal(iter1, 1)
is.Greater(dur1, 0*time.Millisecond)
is.Less(dur1, 1*time.Millisecond)
is.Equal(err1, nil)
is.Equal(iter2, 6)
is.Greater(dur2, 50*time.Millisecond)
is.Less(dur2, 60*time.Millisecond)
is.Equal(err2, nil)
is.Equal(iter3, 2)
is.Greater(dur3, 10*time.Millisecond)
is.Less(dur3, 20*time.Millisecond)
is.Equal(err3, err)
is.Equal(iter4, 11)
is.Greater(dur4, 100*time.Millisecond)
is.Less(dur4, 115*time.Millisecond)
is.Equal(err4, nil)
}
func TestAttemptWhile(t *testing.T) {
is := assert.New(t)
err := fmt.Errorf("failed")
iter1, err1 := AttemptWhile(42, func(i int) (error, bool) {
return nil, true
})
is.Equal(iter1, 1)
is.Nil(err1)
iter2, err2 := AttemptWhile(42, func(i int) (error, bool) {
if i == 5 {
return nil, true
}
return err, true
})
is.Equal(iter2, 6)
is.Nil(err2)
iter3, err3 := AttemptWhile(2, func(i int) (error, bool) {
if i == 5 {
return nil, true
}
return err, true
})
is.Equal(iter3, 2)
is.Equal(err3, err)
iter4, err4 := AttemptWhile(0, func(i int) (error, bool) {
if i < 42 {
return err, true
}
return nil, true
})
is.Equal(iter4, 43)
is.Nil(err4)
iter5, err5 := AttemptWhile(0, func(i int) (error, bool) {
if i == 5 {
return nil, false
}
return err, true
})
is.Equal(iter5, 6)
is.Nil(err5)
iter6, err6 := AttemptWhile(0, func(i int) (error, bool) {
return nil, false
})
is.Equal(iter6, 1)
is.Nil(err6)
iter7, err7 := AttemptWhile(42, func(i int) (error, bool) {
if i == 42 {
return nil, false
}
if i < 41 {
return err, true
}
return nil, true
})
is.Equal(iter7, 42)
is.Nil(err7)
}
func TestAttemptWhileWithDelay(t *testing.T) {
is := assert.New(t)
err := fmt.Errorf("failed")
iter1, dur1, err1 := AttemptWhileWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
return nil, true
})
is.Equal(iter1, 1)
is.Greater(dur1, 0*time.Millisecond)
is.Less(dur1, 1*time.Millisecond)
is.Nil(err1)
iter2, dur2, err2 := AttemptWhileWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
if i == 5 {
return nil, true
}
return err, true
})
is.Equal(iter2, 6)
is.Greater(dur2, 50*time.Millisecond)
is.Less(dur2, 60*time.Millisecond)
is.Nil(err2)
iter3, dur3, err3 := AttemptWhileWithDelay(2, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
if i == 5 {
return nil, true
}
return err, true
})
is.Equal(iter3, 2)
is.Greater(dur3, 10*time.Millisecond)
is.Less(dur3, 20*time.Millisecond)
is.Equal(err3, err)
iter4, dur4, err4 := AttemptWhileWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
if i < 10 {
return err, true
}
return nil, true
})
is.Equal(iter4, 11)
is.Greater(dur4, 100*time.Millisecond)
is.Less(dur4, 115*time.Millisecond)
is.Nil(err4)
iter5, dur5, err5 := AttemptWhileWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
if i == 5 {
return nil, false
}
return err, true
})
is.Equal(iter5, 6)
is.Greater(dur5, 10*time.Millisecond)
is.Less(dur5, 115*time.Millisecond)
is.Nil(err5)
iter6, dur6, err6 := AttemptWhileWithDelay(0, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
return nil, false
})
is.Equal(iter6, 1)
is.Less(dur6, 10*time.Millisecond)
is.Less(dur6, 115*time.Millisecond)
is.Nil(err6)
iter7, dur7, err7 := AttemptWhileWithDelay(42, 10*time.Millisecond, func(i int, d time.Duration) (error, bool) {
if i == 42 {
return nil, false
}
if i < 41 {
return err, true
}
return nil, true
})
is.Equal(iter7, 42)
is.Less(dur7, 500*time.Millisecond)
is.Nil(err7)
}
func TestDebounce(t *testing.T) {
t.Parallel()
f1 := func() {
println("1. Called once after 10ms when func stopped invoking!")
}
f2 := func() {
println("2. Called once after 10ms when func stopped invoking!")
}
f3 := func() {
println("3. Called once after 10ms when func stopped invoking!")
}
d1, _ := NewDebounce(10*time.Millisecond, f1)
// execute 3 times
for i := 0; i < 3; i++ {
for j := 0; j < 10; j++ {
d1()
}
time.Sleep(20 * time.Millisecond)
}
d2, _ := NewDebounce(10*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(10 * time.Millisecond)
// execute once because it is canceled after 200ms.
d3, cancel := NewDebounce(10*time.Millisecond, f3)
for i := 0; i < 3; i++ {
for j := 0; j < 10; j++ {
d3()
}
time.Sleep(20 * time.Millisecond)
if i == 0 {
cancel()
}
}
}
func TestDebounceBy(t *testing.T) {
t.Parallel()
is := assert.New(t)
mu := sync.Mutex{}
output := map[int]int{0: 0, 1: 0, 2: 0}
f1 := func(key int, count int) {
mu.Lock()
output[key] += count
mu.Unlock()
// fmt.Printf("[key=%d] 1. Called once after 10ms when func stopped invoking!\n", key)
}
f2 := func(key int, count int) {
mu.Lock()
output[key] += count
mu.Unlock()
// fmt.Printf("[key=%d] 2. Called once after 10ms when func stopped invoking!\n", key)
}
f3 := func(key int, count int) {
mu.Lock()
output[key] += count
mu.Unlock()
// fmt.Printf("[key=%d] 3. Called once after 10ms when func stopped invoking!\n", key)
}
d1, _ := NewDebounceBy(10*time.Millisecond, f1)
// execute 3 times
for i := 0; i < 3; i++ {
for j := 0; j < 10; j++ {
for k := 0; k < 3; k++ {
d1(k)
}
}
time.Sleep(20 * time.Millisecond)
}
mu.Lock()
is.EqualValues(output[0], 30)
is.EqualValues(output[1], 30)
is.EqualValues(output[2], 30)
mu.Unlock()
d2, _ := NewDebounceBy(10*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++ {
for k := 0; k < 3; k++ {
d2(k)
}
}
time.Sleep(5 * time.Millisecond)
}
time.Sleep(10 * time.Millisecond)
mu.Lock()
is.EqualValues(output[0], 45)
is.EqualValues(output[1], 45)
is.EqualValues(output[2], 45)
mu.Unlock()
// execute once because it is canceled after 200ms.
d3, cancel := NewDebounceBy(10*time.Millisecond, f3)
for i := 0; i < 3; i++ {
for j := 0; j < 10; j++ {
for k := 0; k < 3; k++ {
d3(k)
}
}
time.Sleep(20 * time.Millisecond)
if i == 0 {
for k := 0; k < 3; k++ {
cancel(k)
}
}
}
mu.Lock()
is.EqualValues(output[0], 75)
is.EqualValues(output[1], 75)
is.EqualValues(output[2], 75)
mu.Unlock()
}
func TestTransation(t *testing.T) {
is := assert.New(t)
// no error
{
transaction := NewTransaction[int]().
Then(
func(state int) (int, error) {
return state + 100, nil
},
func(state int) int {
return state - 100
},
).
Then(
func(state int) (int, error) {
return state + 21, nil
},
func(state int) int {
return state - 21
},
)
state, err := transaction.Process(21)
is.Equal(142, state)
is.Equal(nil, err)
}
// with error
{
transaction := NewTransaction[int]().
Then(
func(state int) (int, error) {
return state + 100, nil
},
func(state int) int {
return state - 100
},
).
Then(
func(state int) (int, error) {
return state, assert.AnError
},
func(state int) int {
return state - 21
},
).
Then(
func(state int) (int, error) {
return state + 42, nil
},
func(state int) int {
return state - 42
},
)
state, err := transaction.Process(21)
is.Equal(21, state)
is.Equal(assert.AnError, err)
}
// with error + update value
{
transaction := NewTransaction[int]().
Then(
func(state int) (int, error) {
return state + 100, nil
},
func(state int) int {
return state - 100
},
).
Then(
func(state int) (int, error) {
return state + 21, assert.AnError
},
func(state int) int {
return state - 21
},
).
Then(
func(state int) (int, error) {
return state + 42, nil
},
func(state int) int {
return state - 42
},
)
state, err := transaction.Process(21)
is.Equal(42, state)
is.Equal(assert.AnError, err)
}
}