-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathsemgroup_test.go
171 lines (135 loc) · 3.41 KB
/
semgroup_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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package semgroup
import (
"context"
"errors"
"os"
"strings"
"sync"
"testing"
)
func TestGroup_single_task(t *testing.T) {
ctx := context.Background()
g := NewGroup(ctx, 1)
g.Go(func() error { return nil })
err := g.Wait()
if err != nil {
t.Errorf("g.Wait() should not return an error")
}
}
func TestGroup_multiple_tasks(t *testing.T) {
ctx := context.Background()
g := NewGroup(ctx, 1)
count := 0
var mu sync.Mutex
inc := func() error {
mu.Lock()
count++
mu.Unlock()
return nil
}
g.Go(func() error { return inc() })
g.Go(func() error { return inc() })
g.Go(func() error { return inc() })
g.Go(func() error { return inc() })
err := g.Wait()
if err != nil {
t.Errorf("g.Wait() should not return an error")
}
if count != 4 {
t.Errorf("count should be %d, got: %d", 4, count)
}
}
func TestGroup_multiple_tasks_errors(t *testing.T) {
ctx := context.Background()
g := NewGroup(ctx, 1)
g.Go(func() error { return errors.New("foo") })
g.Go(func() error { return nil })
g.Go(func() error { return errors.New("bar") })
g.Go(func() error { return nil })
err := g.Wait()
if err == nil {
t.Fatalf("g.Wait() should return an error")
}
if !errors.As(err, &MultiError{}) {
t.Fatalf("the error should be of type MultiError")
}
wantErr := `2 error(s) occurred:
* foo
* bar`
if wantErr != err.Error() {
t.Errorf("error should be:\n%s\ngot:\n%s\n", wantErr, err.Error())
}
}
func TestGroup_deadlock(t *testing.T) {
canceledCtx, cancel := context.WithCancel(context.Background())
cancel()
g := NewGroup(canceledCtx, 1)
g.Go(func() error { return nil })
g.Go(func() error { return nil })
err := g.Wait()
if err == nil {
t.Fatalf("g.Wait() should return an error")
}
wantErr := `couldn't acquire semaphore: context canceled`
if !strings.Contains(err.Error(), wantErr) {
t.Errorf("error should contain:\n%s\ngot:\n%s\n", wantErr, err.Error())
}
}
func TestGroup_multiple_tasks_errors_Is(t *testing.T) {
ctx := context.Background()
g := NewGroup(ctx, 1)
var (
fooErr = errors.New("foo")
barErr = errors.New("bar")
bazErr = errors.New("baz")
)
g.Go(func() error { return fooErr })
g.Go(func() error { return nil })
g.Go(func() error { return barErr })
g.Go(func() error { return nil })
err := g.Wait()
if err == nil {
t.Fatalf("g.Wait() should return an error")
}
if !errors.Is(err, fooErr) {
t.Errorf("error should be contained %v\n", fooErr)
}
if !errors.Is(err, barErr) {
t.Errorf("error should be contained %v\n", barErr)
}
if errors.Is(err, bazErr) {
t.Errorf("error should not be contained %v\n", bazErr)
}
var gotMultiErr MultiError
if !errors.As(err, &gotMultiErr) {
t.Fatalf("error should be matched MultiError")
}
expectedErr := (MultiError{fooErr, barErr}).Error()
if gotMultiErr.Error() != expectedErr {
t.Errorf("error should be %q, got %q", expectedErr, gotMultiErr.Error())
}
}
type foobarErr struct{ str string }
func (e foobarErr) Error() string {
return "foobar"
}
func TestGroup_multiple_tasks_errors_As(t *testing.T) {
ctx := context.Background()
g := NewGroup(ctx, 1)
g.Go(func() error { return foobarErr{"baz"} })
g.Go(func() error { return nil })
err := g.Wait()
if err == nil {
t.Fatalf("g.Wait() should return an error")
}
var (
fbe foobarErr
pe *os.PathError
)
if !errors.As(err, &fbe) {
t.Error("error should be matched foobarErr")
}
if errors.As(err, &pe) {
t.Error("error should not be matched os.PathError")
}
}