]> Cypherpunks.ru repositories - gostls13.git/blob - src/context/context_test.go
74738fd3160b2c11a084380e2978b318f42461dc
[gostls13.git] / src / context / context_test.go
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package context
6
7 // Tests in package context cannot depend directly on package testing due to an import cycle.
8 // If your test does requires access to unexported members of the context package,
9 // add your test below as `func XTestFoo(t testingT)` and add a `TestFoo` to x_test.go
10 // that calls it. Otherwise, write a regular test in a test.go file in package context_test.
11
12 import (
13         "time"
14 )
15
16 type testingT interface {
17         Deadline() (time.Time, bool)
18         Error(args ...any)
19         Errorf(format string, args ...any)
20         Fail()
21         FailNow()
22         Failed() bool
23         Fatal(args ...any)
24         Fatalf(format string, args ...any)
25         Helper()
26         Log(args ...any)
27         Logf(format string, args ...any)
28         Name() string
29         Parallel()
30         Skip(args ...any)
31         SkipNow()
32         Skipf(format string, args ...any)
33         Skipped() bool
34 }
35
36 const veryLongDuration = 1000 * time.Hour // an arbitrary upper bound on the test's running time
37
38 func contains(m map[canceler]struct{}, key canceler) bool {
39         _, ret := m[key]
40         return ret
41 }
42
43 func XTestParentFinishesChild(t testingT) {
44         // Context tree:
45         // parent -> cancelChild
46         // parent -> valueChild -> timerChild
47         parent, cancel := WithCancel(Background())
48         cancelChild, stop := WithCancel(parent)
49         defer stop()
50         valueChild := WithValue(parent, "key", "value")
51         timerChild, stop := WithTimeout(valueChild, veryLongDuration)
52         defer stop()
53
54         select {
55         case x := <-parent.Done():
56                 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
57         case x := <-cancelChild.Done():
58                 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
59         case x := <-timerChild.Done():
60                 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
61         case x := <-valueChild.Done():
62                 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
63         default:
64         }
65
66         // The parent's children should contain the two cancelable children.
67         pc := parent.(*cancelCtx)
68         cc := cancelChild.(*cancelCtx)
69         tc := timerChild.(*timerCtx)
70         pc.mu.Lock()
71         if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) {
72                 t.Errorf("bad linkage: pc.children = %v, want %v and %v",
73                         pc.children, cc, tc)
74         }
75         pc.mu.Unlock()
76
77         if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
78                 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
79         }
80         if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
81                 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
82         }
83
84         cancel()
85
86         pc.mu.Lock()
87         if len(pc.children) != 0 {
88                 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
89         }
90         pc.mu.Unlock()
91
92         // parent and children should all be finished.
93         check := func(ctx Context, name string) {
94                 select {
95                 case <-ctx.Done():
96                 default:
97                         t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
98                 }
99                 if e := ctx.Err(); e != Canceled {
100                         t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
101                 }
102         }
103         check(parent, "parent")
104         check(cancelChild, "cancelChild")
105         check(valueChild, "valueChild")
106         check(timerChild, "timerChild")
107
108         // WithCancel should return a canceled context on a canceled parent.
109         precanceledChild := WithValue(parent, "key", "value")
110         select {
111         case <-precanceledChild.Done():
112         default:
113                 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
114         }
115         if e := precanceledChild.Err(); e != Canceled {
116                 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
117         }
118 }
119
120 func XTestChildFinishesFirst(t testingT) {
121         cancelable, stop := WithCancel(Background())
122         defer stop()
123         for _, parent := range []Context{Background(), cancelable} {
124                 child, cancel := WithCancel(parent)
125
126                 select {
127                 case x := <-parent.Done():
128                         t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
129                 case x := <-child.Done():
130                         t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
131                 default:
132                 }
133
134                 cc := child.(*cancelCtx)
135                 pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
136                 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
137                         t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
138                 }
139
140                 if pcok {
141                         pc.mu.Lock()
142                         if len(pc.children) != 1 || !contains(pc.children, cc) {
143                                 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
144                         }
145                         pc.mu.Unlock()
146                 }
147
148                 cancel()
149
150                 if pcok {
151                         pc.mu.Lock()
152                         if len(pc.children) != 0 {
153                                 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
154                         }
155                         pc.mu.Unlock()
156                 }
157
158                 // child should be finished.
159                 select {
160                 case <-child.Done():
161                 default:
162                         t.Errorf("<-child.Done() blocked, but shouldn't have")
163                 }
164                 if e := child.Err(); e != Canceled {
165                         t.Errorf("child.Err() == %v want %v", e, Canceled)
166                 }
167
168                 // parent should not be finished.
169                 select {
170                 case x := <-parent.Done():
171                         t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
172                 default:
173                 }
174                 if e := parent.Err(); e != nil {
175                         t.Errorf("parent.Err() == %v want nil", e)
176                 }
177         }
178 }
179
180 func XTestCancelRemoves(t testingT) {
181         checkChildren := func(when string, ctx Context, want int) {
182                 if got := len(ctx.(*cancelCtx).children); got != want {
183                         t.Errorf("%s: context has %d children, want %d", when, got, want)
184                 }
185         }
186
187         ctx, _ := WithCancel(Background())
188         checkChildren("after creation", ctx, 0)
189         _, cancel := WithCancel(ctx)
190         checkChildren("with WithCancel child ", ctx, 1)
191         cancel()
192         checkChildren("after canceling WithCancel child", ctx, 0)
193
194         ctx, _ = WithCancel(Background())
195         checkChildren("after creation", ctx, 0)
196         _, cancel = WithTimeout(ctx, 60*time.Minute)
197         checkChildren("with WithTimeout child ", ctx, 1)
198         cancel()
199         checkChildren("after canceling WithTimeout child", ctx, 0)
200 }
201
202 type myCtx struct {
203         Context
204 }
205
206 type myDoneCtx struct {
207         Context
208 }
209
210 func (d *myDoneCtx) Done() <-chan struct{} {
211         c := make(chan struct{})
212         return c
213 }
214 func XTestCustomContextGoroutines(t testingT) {
215         g := goroutines.Load()
216         checkNoGoroutine := func() {
217                 t.Helper()
218                 now := goroutines.Load()
219                 if now != g {
220                         t.Fatalf("%d goroutines created", now-g)
221                 }
222         }
223         checkCreatedGoroutine := func() {
224                 t.Helper()
225                 now := goroutines.Load()
226                 if now != g+1 {
227                         t.Fatalf("%d goroutines created, want 1", now-g)
228                 }
229                 g = now
230         }
231
232         _, cancel0 := WithCancel(&myDoneCtx{Background()})
233         cancel0()
234         checkCreatedGoroutine()
235
236         _, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration)
237         cancel0()
238         checkCreatedGoroutine()
239
240         checkNoGoroutine()
241         defer checkNoGoroutine()
242
243         ctx1, cancel1 := WithCancel(Background())
244         defer cancel1()
245         checkNoGoroutine()
246
247         ctx2 := &myCtx{ctx1}
248         ctx3, cancel3 := WithCancel(ctx2)
249         defer cancel3()
250         checkNoGoroutine()
251
252         _, cancel3b := WithCancel(&myDoneCtx{ctx2})
253         defer cancel3b()
254         checkCreatedGoroutine() // ctx1 is not providing Done, must not be used
255
256         ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration)
257         defer cancel4()
258         checkNoGoroutine()
259
260         ctx5, cancel5 := WithCancel(ctx4)
261         defer cancel5()
262         checkNoGoroutine()
263
264         cancel5()
265         checkNoGoroutine()
266
267         _, cancel6 := WithTimeout(ctx5, veryLongDuration)
268         defer cancel6()
269         checkNoGoroutine()
270
271         // Check applied to canceled context.
272         cancel6()
273         cancel1()
274         _, cancel7 := WithCancel(ctx5)
275         defer cancel7()
276         checkNoGoroutine()
277 }