-
Notifications
You must be signed in to change notification settings - Fork 10
/
repeat_test.go
116 lines (98 loc) · 2.6 KB
/
repeat_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package ydb
import (
"context"
"fmt"
"path/filepath"
"reflect"
"runtime"
"strconv"
"testing"
"time"
"github.com/yandex-cloud/ydb-go-sdk/v2/timeutil"
"github.com/yandex-cloud/ydb-go-sdk/v2/timeutil/timetest"
)
func TestRepeater(t *testing.T) {
timerC := make(chan time.Time, 1)
timer := timetest.Timer{
Ch: timerC,
}
cleanup := timeutil.StubTestHookNewTimer(func(time.Duration) timeutil.Timer {
return timer
})
defer cleanup()
exec := make(chan struct{}, 1)
r := NewRepeater(42*time.Second, 0,
func(_ context.Context) {
exec <- struct{}{}
})
timerC <- time.Now()
assertRecv(t, 500*time.Millisecond, exec)
assertNoRecv(t, 50*time.Millisecond, exec)
r.Stop()
timerC <- time.Now()
assertNoRecv(t, 50*time.Millisecond, exec)
}
func TestRepeaterCancelation(t *testing.T) {
var (
timerC = make(chan time.Time)
enter = make(chan struct{}, 2)
exit = make(chan struct{}, 2)
)
timer := timetest.Timer{
Ch: timerC,
}
cleanup := timeutil.StubTestHookNewTimer(func(time.Duration) timeutil.Timer {
return timer
})
defer cleanup()
r := NewRepeater(42*time.Second, 0,
func(ctx context.Context) {
enter <- struct{}{}
<-ctx.Done()
exit <- struct{}{}
})
// Run callback in a separate goroutine to avoid deadlock.
// That is, StubTimer run its function in the same goroutine as Emit
// called.
go func() { timerC <- time.Now() }()
const timeout = 100 * time.Millisecond
assertRecv(t, timeout, enter)
assertNoRecv(t, timeout, enter)
assertNoRecv(t, timeout, exit)
r.Stop()
assertRecv(t, timeout, exit)
}
func recv(ch interface{}, timeout time.Duration) error {
i, _, _ := reflect.Select([]reflect.SelectCase{
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)},
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(time.After(timeout))},
})
if i == 0 {
return nil
}
return fmt.Errorf("timed out: %s", timeout)
}
func noRecv(ch interface{}, timeout time.Duration) error {
i, _, _ := reflect.Select([]reflect.SelectCase{
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)},
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(time.After(timeout))},
})
if i == 1 {
return nil
}
return fmt.Errorf("unexepcted filling")
}
func assertRecv(t *testing.T, timeout time.Duration, ch interface{}) {
if err := recv(ch, timeout); err != nil {
t.Fatalf("%s: %v", fileLine(2), err)
}
}
func assertNoRecv(t *testing.T, timeout time.Duration, ch interface{}) {
if err := noRecv(ch, timeout); err != nil {
t.Fatalf("%s: %v", fileLine(2), err)
}
}
func fileLine(skip int) string {
_, file, line, _ := runtime.Caller(skip)
return filepath.Base(file) + ":" + strconv.Itoa(line)
}