-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgroup_test.go
142 lines (119 loc) · 3.47 KB
/
group_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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package gogroup_test
import (
"context"
"errors"
"sync/atomic"
"testing"
"time"
"github.com/google/uuid"
"github.com/newmo-oss/testid"
"go.uber.org/goleak"
"github.com/newmo-oss/gogroup"
"github.com/newmo-oss/gogroup/gogrouptest"
)
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}
func TestGroup(t *testing.T) {
t.Parallel()
var (
funcOK = func(ctx context.Context) error { return nil }
funcErr = func(ctx context.Context) error { return errors.New("error") }
funcPanic = func(ctx context.Context) error { panic("panic") }
funcCancel = func(ctx context.Context) error { doCancel(ctx); return nil }
)
type funcs []func(ctx context.Context) error
cases := map[string]struct {
funcs funcs
wantCanceledFunc int
wantErr bool
}{
// name funcs canceled error
"all-ok": {funcs{funcOK, funcOK, funcOK}, -1, false},
"first-error": {funcs{funcErr, funcOK, funcOK}, 0, true},
"second-error": {funcs{funcOK, funcErr, funcOK}, 1, true},
"first-panic": {funcs{funcPanic, funcOK, funcOK}, 0, true},
"second-panic": {funcs{funcOK, funcPanic, funcOK}, 1, true},
"first-cancel": {funcs{funcCancel, funcOK, funcOK}, 0, false},
"second-cancel": {funcs{funcOK, funcCancel, funcOK}, 1, false},
}
for name, tt := range cases {
t.Run(name, func(t *testing.T) {
t.Parallel()
var canceled atomic.Bool
var g gogroup.Group
for i, f := range tt.funcs {
g.Add(func(ctx context.Context) error {
if tt.wantCanceledFunc >= 0 && tt.wantCanceledFunc < i {
select {
case <-time.After(1 * time.Second):
case <-ctx.Done():
canceled.Store(true)
}
}
return f(ctx)
})
}
tid := t.Name() + "/" + uuid.NewString()
ctx := withCancel(testid.WithValue(context.Background(), tid))
gogrouptest.WithoutParallel(t, ctx)
err := g.Run(ctx)
switch {
case tt.wantErr && err == nil:
t.Error("expected error did not occur")
case !tt.wantErr && err != nil:
t.Error("unexpected error:", err)
}
switch {
case tt.wantCanceledFunc >= 0 && !canceled.Load():
t.Error("expected cancel did not occur")
case tt.wantCanceledFunc < 0 && canceled.Load():
t.Error("unexpected cancel")
}
})
}
}
func TestStart(t *testing.T) {
t.Parallel()
var (
funcOK = func(ctx context.Context) error { return nil }
funcErr = func(ctx context.Context) error { return errors.New("error") }
funcPanic = func(ctx context.Context) error { panic("panic") }
funcCancel = func(ctx context.Context) error { doCancel(ctx); return nil }
)
cases := map[string]struct {
fun func(context.Context) error
wantErr bool
}{
// name func error
"ok": {funcOK, false},
"error": {funcErr, true},
"cancel": {funcCancel, false},
"panic": {funcPanic, true},
}
for name, tt := range cases {
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := withCancel(context.Background())
wait := gogroup.Start(ctx, tt.fun)
err := wait()
switch {
case tt.wantErr && err == nil:
t.Error("expected error did not occur")
case !tt.wantErr && err != nil:
t.Error("unexpected error:", err)
}
})
}
}
type cancelCtxKey struct{}
func withCancel(ctx context.Context) context.Context {
ctx, cancel := context.WithCancel(ctx)
return context.WithValue(ctx, cancelCtxKey{}, cancel)
}
func doCancel(ctx context.Context) {
cancel, _ := ctx.Value(cancelCtxKey{}).(context.CancelFunc)
if cancel != nil {
cancel()
}
}