github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/context/context_test.go (about) 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 -> afterChild 48 parent, cancel := WithCancel(Background()) 49 cancelChild, stop := WithCancel(parent) 50 defer stop() 51 valueChild := WithValue(parent, "key", "value") 52 timerChild, stop := WithTimeout(valueChild, veryLongDuration) 53 defer stop() 54 afterStop := AfterFunc(parent, func() {}) 55 defer afterStop() 56 57 select { 58 case x := <-parent.Done(): 59 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) 60 case x := <-cancelChild.Done(): 61 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x) 62 case x := <-timerChild.Done(): 63 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x) 64 case x := <-valueChild.Done(): 65 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x) 66 default: 67 } 68 69 // The parent's children should contain the three cancelable children. 70 pc := parent.(*cancelCtx) 71 cc := cancelChild.(*cancelCtx) 72 tc := timerChild.(*timerCtx) 73 pc.mu.Lock() 74 var ac *afterFuncCtx 75 for c := range pc.children { 76 if a, ok := c.(*afterFuncCtx); ok { 77 ac = a 78 break 79 } 80 } 81 if len(pc.children) != 3 || !contains(pc.children, cc) || !contains(pc.children, tc) || ac == nil { 82 t.Errorf("bad linkage: pc.children = %v, want %v, %v, and an afterFunc", 83 pc.children, cc, tc) 84 } 85 pc.mu.Unlock() 86 87 if p, ok := parentCancelCtx(cc.Context); !ok || p != pc { 88 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc) 89 } 90 if p, ok := parentCancelCtx(tc.Context); !ok || p != pc { 91 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc) 92 } 93 if p, ok := parentCancelCtx(ac.Context); !ok || p != pc { 94 t.Errorf("bad linkage: parentCancelCtx(afterChild.Context) = %v, %v want %v, true", p, ok, pc) 95 } 96 97 cancel() 98 99 pc.mu.Lock() 100 if len(pc.children) != 0 { 101 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children) 102 } 103 pc.mu.Unlock() 104 105 // parent and children should all be finished. 106 check := func(ctx Context, name string) { 107 select { 108 case <-ctx.Done(): 109 default: 110 t.Errorf("<-%s.Done() blocked, but shouldn't have", name) 111 } 112 if e := ctx.Err(); e != Canceled { 113 t.Errorf("%s.Err() == %v want %v", name, e, Canceled) 114 } 115 } 116 check(parent, "parent") 117 check(cancelChild, "cancelChild") 118 check(valueChild, "valueChild") 119 check(timerChild, "timerChild") 120 121 // WithCancel should return a canceled context on a canceled parent. 122 precanceledChild := WithValue(parent, "key", "value") 123 select { 124 case <-precanceledChild.Done(): 125 default: 126 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have") 127 } 128 if e := precanceledChild.Err(); e != Canceled { 129 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled) 130 } 131 } 132 133 func XTestChildFinishesFirst(t testingT) { 134 cancelable, stop := WithCancel(Background()) 135 defer stop() 136 for _, parent := range []Context{Background(), cancelable} { 137 child, cancel := WithCancel(parent) 138 139 select { 140 case x := <-parent.Done(): 141 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) 142 case x := <-child.Done(): 143 t.Errorf("<-child.Done() == %v want nothing (it should block)", x) 144 default: 145 } 146 147 cc := child.(*cancelCtx) 148 pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background() 149 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) { 150 t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok) 151 } 152 153 if pcok { 154 pc.mu.Lock() 155 if len(pc.children) != 1 || !contains(pc.children, cc) { 156 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc) 157 } 158 pc.mu.Unlock() 159 } 160 161 cancel() 162 163 if pcok { 164 pc.mu.Lock() 165 if len(pc.children) != 0 { 166 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children) 167 } 168 pc.mu.Unlock() 169 } 170 171 // child should be finished. 172 select { 173 case <-child.Done(): 174 default: 175 t.Errorf("<-child.Done() blocked, but shouldn't have") 176 } 177 if e := child.Err(); e != Canceled { 178 t.Errorf("child.Err() == %v want %v", e, Canceled) 179 } 180 181 // parent should not be finished. 182 select { 183 case x := <-parent.Done(): 184 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) 185 default: 186 } 187 if e := parent.Err(); e != nil { 188 t.Errorf("parent.Err() == %v want nil", e) 189 } 190 } 191 } 192 193 func XTestCancelRemoves(t testingT) { 194 checkChildren := func(when string, ctx Context, want int) { 195 if got := len(ctx.(*cancelCtx).children); got != want { 196 t.Errorf("%s: context has %d children, want %d", when, got, want) 197 } 198 } 199 200 ctx, _ := WithCancel(Background()) 201 checkChildren("after creation", ctx, 0) 202 _, cancel := WithCancel(ctx) 203 checkChildren("with WithCancel child ", ctx, 1) 204 cancel() 205 checkChildren("after canceling WithCancel child", ctx, 0) 206 207 ctx, _ = WithCancel(Background()) 208 checkChildren("after creation", ctx, 0) 209 _, cancel = WithTimeout(ctx, 60*time.Minute) 210 checkChildren("with WithTimeout child ", ctx, 1) 211 cancel() 212 checkChildren("after canceling WithTimeout child", ctx, 0) 213 214 ctx, _ = WithCancel(Background()) 215 checkChildren("after creation", ctx, 0) 216 stop := AfterFunc(ctx, func() {}) 217 checkChildren("with AfterFunc child ", ctx, 1) 218 stop() 219 checkChildren("after stopping AfterFunc child ", ctx, 0) 220 } 221 222 type myCtx struct { 223 Context 224 } 225 226 type myDoneCtx struct { 227 Context 228 } 229 230 func (d *myDoneCtx) Done() <-chan struct{} { 231 c := make(chan struct{}) 232 return c 233 } 234 func XTestCustomContextGoroutines(t testingT) { 235 g := goroutines.Load() 236 checkNoGoroutine := func() { 237 t.Helper() 238 now := goroutines.Load() 239 if now != g { 240 t.Fatalf("%d goroutines created", now-g) 241 } 242 } 243 checkCreatedGoroutine := func() { 244 t.Helper() 245 now := goroutines.Load() 246 if now != g+1 { 247 t.Fatalf("%d goroutines created, want 1", now-g) 248 } 249 g = now 250 } 251 252 _, cancel0 := WithCancel(&myDoneCtx{Background()}) 253 cancel0() 254 checkCreatedGoroutine() 255 256 _, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration) 257 cancel0() 258 checkCreatedGoroutine() 259 260 checkNoGoroutine() 261 defer checkNoGoroutine() 262 263 ctx1, cancel1 := WithCancel(Background()) 264 defer cancel1() 265 checkNoGoroutine() 266 267 ctx2 := &myCtx{ctx1} 268 ctx3, cancel3 := WithCancel(ctx2) 269 defer cancel3() 270 checkNoGoroutine() 271 272 _, cancel3b := WithCancel(&myDoneCtx{ctx2}) 273 defer cancel3b() 274 checkCreatedGoroutine() // ctx1 is not providing Done, must not be used 275 276 ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration) 277 defer cancel4() 278 checkNoGoroutine() 279 280 ctx5, cancel5 := WithCancel(ctx4) 281 defer cancel5() 282 checkNoGoroutine() 283 284 cancel5() 285 checkNoGoroutine() 286 287 _, cancel6 := WithTimeout(ctx5, veryLongDuration) 288 defer cancel6() 289 checkNoGoroutine() 290 291 // Check applied to canceled context. 292 cancel6() 293 cancel1() 294 _, cancel7 := WithCancel(ctx5) 295 defer cancel7() 296 checkNoGoroutine() 297 }