github.com/yukk001/go1.10.8@v0.0.0-20190813125351-6df2d3982e20/src/testing/sub_test.go (about) 1 // Copyright 2016 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 testing 6 7 import ( 8 "bytes" 9 "fmt" 10 "regexp" 11 "runtime" 12 "strings" 13 "sync" 14 "sync/atomic" 15 "time" 16 ) 17 18 func init() { 19 // Make benchmark tests run 10* faster. 20 *benchTime = 100 * time.Millisecond 21 } 22 23 func TestTestContext(t *T) { 24 const ( 25 add1 = 0 26 done = 1 27 ) 28 // After each of the calls are applied to the context, the 29 type call struct { 30 typ int // run or done 31 // result from applying the call 32 running int 33 waiting int 34 started bool 35 } 36 testCases := []struct { 37 max int 38 run []call 39 }{{ 40 max: 1, 41 run: []call{ 42 {typ: add1, running: 1, waiting: 0, started: true}, 43 {typ: done, running: 0, waiting: 0, started: false}, 44 }, 45 }, { 46 max: 1, 47 run: []call{ 48 {typ: add1, running: 1, waiting: 0, started: true}, 49 {typ: add1, running: 1, waiting: 1, started: false}, 50 {typ: done, running: 1, waiting: 0, started: true}, 51 {typ: done, running: 0, waiting: 0, started: false}, 52 {typ: add1, running: 1, waiting: 0, started: true}, 53 }, 54 }, { 55 max: 3, 56 run: []call{ 57 {typ: add1, running: 1, waiting: 0, started: true}, 58 {typ: add1, running: 2, waiting: 0, started: true}, 59 {typ: add1, running: 3, waiting: 0, started: true}, 60 {typ: add1, running: 3, waiting: 1, started: false}, 61 {typ: add1, running: 3, waiting: 2, started: false}, 62 {typ: add1, running: 3, waiting: 3, started: false}, 63 {typ: done, running: 3, waiting: 2, started: true}, 64 {typ: add1, running: 3, waiting: 3, started: false}, 65 {typ: done, running: 3, waiting: 2, started: true}, 66 {typ: done, running: 3, waiting: 1, started: true}, 67 {typ: done, running: 3, waiting: 0, started: true}, 68 {typ: done, running: 2, waiting: 0, started: false}, 69 {typ: done, running: 1, waiting: 0, started: false}, 70 {typ: done, running: 0, waiting: 0, started: false}, 71 }, 72 }} 73 for i, tc := range testCases { 74 ctx := &testContext{ 75 startParallel: make(chan bool), 76 maxParallel: tc.max, 77 } 78 for j, call := range tc.run { 79 doCall := func(f func()) chan bool { 80 done := make(chan bool) 81 go func() { 82 f() 83 done <- true 84 }() 85 return done 86 } 87 started := false 88 switch call.typ { 89 case add1: 90 signal := doCall(ctx.waitParallel) 91 select { 92 case <-signal: 93 started = true 94 case ctx.startParallel <- true: 95 <-signal 96 } 97 case done: 98 signal := doCall(ctx.release) 99 select { 100 case <-signal: 101 case <-ctx.startParallel: 102 started = true 103 <-signal 104 } 105 } 106 if started != call.started { 107 t.Errorf("%d:%d:started: got %v; want %v", i, j, started, call.started) 108 } 109 if ctx.running != call.running { 110 t.Errorf("%d:%d:running: got %v; want %v", i, j, ctx.running, call.running) 111 } 112 if ctx.numWaiting != call.waiting { 113 t.Errorf("%d:%d:waiting: got %v; want %v", i, j, ctx.numWaiting, call.waiting) 114 } 115 } 116 } 117 } 118 119 func TestTRun(t *T) { 120 realTest := t 121 testCases := []struct { 122 desc string 123 ok bool 124 maxPar int 125 chatty bool 126 output string 127 f func(*T) 128 }{{ 129 desc: "failnow skips future sequential and parallel tests at same level", 130 ok: false, 131 maxPar: 1, 132 output: ` 133 --- FAIL: failnow skips future sequential and parallel tests at same level (N.NNs) 134 --- FAIL: failnow skips future sequential and parallel tests at same level/#00 (N.NNs) 135 `, 136 f: func(t *T) { 137 ranSeq := false 138 ranPar := false 139 t.Run("", func(t *T) { 140 t.Run("par", func(t *T) { 141 t.Parallel() 142 ranPar = true 143 }) 144 t.Run("seq", func(t *T) { 145 ranSeq = true 146 }) 147 t.FailNow() 148 t.Run("seq", func(t *T) { 149 realTest.Error("test must be skipped") 150 }) 151 t.Run("par", func(t *T) { 152 t.Parallel() 153 realTest.Error("test must be skipped.") 154 }) 155 }) 156 if !ranPar { 157 realTest.Error("parallel test was not run") 158 } 159 if !ranSeq { 160 realTest.Error("sequential test was not run") 161 } 162 }, 163 }, { 164 desc: "failure in parallel test propagates upwards", 165 ok: false, 166 maxPar: 1, 167 output: ` 168 --- FAIL: failure in parallel test propagates upwards (N.NNs) 169 --- FAIL: failure in parallel test propagates upwards/#00 (N.NNs) 170 --- FAIL: failure in parallel test propagates upwards/#00/par (N.NNs) 171 `, 172 f: func(t *T) { 173 t.Run("", func(t *T) { 174 t.Parallel() 175 t.Run("par", func(t *T) { 176 t.Parallel() 177 t.Fail() 178 }) 179 }) 180 }, 181 }, { 182 desc: "skipping without message, chatty", 183 ok: true, 184 chatty: true, 185 output: ` 186 === RUN skipping without message, chatty 187 --- SKIP: skipping without message, chatty (N.NNs)`, 188 f: func(t *T) { t.SkipNow() }, 189 }, { 190 desc: "chatty with recursion", 191 ok: true, 192 chatty: true, 193 output: ` 194 === RUN chatty with recursion 195 === RUN chatty with recursion/#00 196 === RUN chatty with recursion/#00/#00 197 --- PASS: chatty with recursion (N.NNs) 198 --- PASS: chatty with recursion/#00 (N.NNs) 199 --- PASS: chatty with recursion/#00/#00 (N.NNs)`, 200 f: func(t *T) { 201 t.Run("", func(t *T) { 202 t.Run("", func(t *T) {}) 203 }) 204 }, 205 }, { 206 desc: "skipping without message, not chatty", 207 ok: true, 208 f: func(t *T) { t.SkipNow() }, 209 }, { 210 desc: "skipping after error", 211 output: ` 212 --- FAIL: skipping after error (N.NNs) 213 sub_test.go:NNN: an error 214 sub_test.go:NNN: skipped`, 215 f: func(t *T) { 216 t.Error("an error") 217 t.Skip("skipped") 218 }, 219 }, { 220 desc: "use Run to locally synchronize parallelism", 221 ok: true, 222 maxPar: 1, 223 f: func(t *T) { 224 var count uint32 225 t.Run("waitGroup", func(t *T) { 226 for i := 0; i < 4; i++ { 227 t.Run("par", func(t *T) { 228 t.Parallel() 229 atomic.AddUint32(&count, 1) 230 }) 231 } 232 }) 233 if count != 4 { 234 t.Errorf("count was %d; want 4", count) 235 } 236 }, 237 }, { 238 desc: "alternate sequential and parallel", 239 // Sequential tests should partake in the counting of running threads. 240 // Otherwise, if one runs parallel subtests in sequential tests that are 241 // itself subtests of parallel tests, the counts can get askew. 242 ok: true, 243 maxPar: 1, 244 f: func(t *T) { 245 t.Run("a", func(t *T) { 246 t.Parallel() 247 t.Run("b", func(t *T) { 248 // Sequential: ensure running count is decremented. 249 t.Run("c", func(t *T) { 250 t.Parallel() 251 }) 252 253 }) 254 }) 255 }, 256 }, { 257 desc: "alternate sequential and parallel 2", 258 // Sequential tests should partake in the counting of running threads. 259 // Otherwise, if one runs parallel subtests in sequential tests that are 260 // itself subtests of parallel tests, the counts can get askew. 261 ok: true, 262 maxPar: 2, 263 f: func(t *T) { 264 for i := 0; i < 2; i++ { 265 t.Run("a", func(t *T) { 266 t.Parallel() 267 time.Sleep(time.Nanosecond) 268 for i := 0; i < 2; i++ { 269 t.Run("b", func(t *T) { 270 time.Sleep(time.Nanosecond) 271 for i := 0; i < 2; i++ { 272 t.Run("c", func(t *T) { 273 t.Parallel() 274 time.Sleep(time.Nanosecond) 275 }) 276 } 277 278 }) 279 } 280 }) 281 } 282 }, 283 }, { 284 desc: "stress test", 285 ok: true, 286 maxPar: 4, 287 f: func(t *T) { 288 t.Parallel() 289 for i := 0; i < 12; i++ { 290 t.Run("a", func(t *T) { 291 t.Parallel() 292 time.Sleep(time.Nanosecond) 293 for i := 0; i < 12; i++ { 294 t.Run("b", func(t *T) { 295 time.Sleep(time.Nanosecond) 296 for i := 0; i < 12; i++ { 297 t.Run("c", func(t *T) { 298 t.Parallel() 299 time.Sleep(time.Nanosecond) 300 t.Run("d1", func(t *T) {}) 301 t.Run("d2", func(t *T) {}) 302 t.Run("d3", func(t *T) {}) 303 t.Run("d4", func(t *T) {}) 304 }) 305 } 306 }) 307 } 308 }) 309 } 310 }, 311 }, { 312 desc: "skip output", 313 ok: true, 314 maxPar: 4, 315 f: func(t *T) { 316 t.Skip() 317 }, 318 }, { 319 desc: "panic on goroutine fail after test exit", 320 ok: false, 321 maxPar: 4, 322 f: func(t *T) { 323 ch := make(chan bool) 324 t.Run("", func(t *T) { 325 go func() { 326 <-ch 327 defer func() { 328 if r := recover(); r == nil { 329 realTest.Errorf("expected panic") 330 } 331 ch <- true 332 }() 333 t.Errorf("failed after success") 334 }() 335 }) 336 ch <- true 337 <-ch 338 }, 339 }} 340 for _, tc := range testCases { 341 ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", "")) 342 buf := &bytes.Buffer{} 343 root := &T{ 344 common: common{ 345 signal: make(chan bool), 346 name: "Test", 347 w: buf, 348 chatty: tc.chatty, 349 }, 350 context: ctx, 351 } 352 ok := root.Run(tc.desc, tc.f) 353 ctx.release() 354 355 if ok != tc.ok { 356 t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok) 357 } 358 if ok != !root.Failed() { 359 t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) 360 } 361 if ctx.running != 0 || ctx.numWaiting != 0 { 362 t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting) 363 } 364 got := strings.TrimSpace(buf.String()) 365 want := strings.TrimSpace(tc.output) 366 re := makeRegexp(want) 367 if ok, err := regexp.MatchString(re, got); !ok || err != nil { 368 t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) 369 } 370 } 371 } 372 373 func TestBRun(t *T) { 374 work := func(b *B) { 375 for i := 0; i < b.N; i++ { 376 time.Sleep(time.Nanosecond) 377 } 378 } 379 testCases := []struct { 380 desc string 381 failed bool 382 chatty bool 383 output string 384 f func(*B) 385 }{{ 386 desc: "simulate sequential run of subbenchmarks.", 387 f: func(b *B) { 388 b.Run("", func(b *B) { work(b) }) 389 time1 := b.result.NsPerOp() 390 b.Run("", func(b *B) { work(b) }) 391 time2 := b.result.NsPerOp() 392 if time1 >= time2 { 393 t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2) 394 } 395 }, 396 }, { 397 desc: "bytes set by all benchmarks", 398 f: func(b *B) { 399 b.Run("", func(b *B) { b.SetBytes(10); work(b) }) 400 b.Run("", func(b *B) { b.SetBytes(10); work(b) }) 401 if b.result.Bytes != 20 { 402 t.Errorf("bytes: got: %d; want 20", b.result.Bytes) 403 } 404 }, 405 }, { 406 desc: "bytes set by some benchmarks", 407 // In this case the bytes result is meaningless, so it must be 0. 408 f: func(b *B) { 409 b.Run("", func(b *B) { b.SetBytes(10); work(b) }) 410 b.Run("", func(b *B) { work(b) }) 411 b.Run("", func(b *B) { b.SetBytes(10); work(b) }) 412 if b.result.Bytes != 0 { 413 t.Errorf("bytes: got: %d; want 0", b.result.Bytes) 414 } 415 }, 416 }, { 417 desc: "failure carried over to root", 418 failed: true, 419 output: "--- FAIL: root", 420 f: func(b *B) { b.Fail() }, 421 }, { 422 desc: "skipping without message, chatty", 423 chatty: true, 424 output: "--- SKIP: root", 425 f: func(b *B) { b.SkipNow() }, 426 }, { 427 desc: "skipping with message, chatty", 428 chatty: true, 429 output: ` 430 --- SKIP: root 431 sub_test.go:NNN: skipping`, 432 f: func(b *B) { b.Skip("skipping") }, 433 }, { 434 desc: "chatty with recursion", 435 chatty: true, 436 f: func(b *B) { 437 b.Run("", func(b *B) { 438 b.Run("", func(b *B) {}) 439 }) 440 }, 441 }, { 442 desc: "skipping without message, not chatty", 443 f: func(b *B) { b.SkipNow() }, 444 }, { 445 desc: "skipping after error", 446 failed: true, 447 output: ` 448 --- FAIL: root 449 sub_test.go:NNN: an error 450 sub_test.go:NNN: skipped`, 451 f: func(b *B) { 452 b.Error("an error") 453 b.Skip("skipped") 454 }, 455 }, { 456 desc: "memory allocation", 457 f: func(b *B) { 458 const bufSize = 256 459 alloc := func(b *B) { 460 var buf [bufSize]byte 461 for i := 0; i < b.N; i++ { 462 _ = append([]byte(nil), buf[:]...) 463 } 464 } 465 b.Run("", func(b *B) { 466 alloc(b) 467 b.ReportAllocs() 468 }) 469 b.Run("", func(b *B) { 470 alloc(b) 471 b.ReportAllocs() 472 }) 473 // runtime.MemStats sometimes reports more allocations than the 474 // benchmark is responsible for. Luckily the point of this test is 475 // to ensure that the results are not underreported, so we can 476 // simply verify the lower bound. 477 if got := b.result.MemAllocs; got < 2 { 478 t.Errorf("MemAllocs was %v; want 2", got) 479 } 480 if got := b.result.MemBytes; got < 2*bufSize { 481 t.Errorf("MemBytes was %v; want %v", got, 2*bufSize) 482 } 483 }, 484 }} 485 for _, tc := range testCases { 486 var ok bool 487 buf := &bytes.Buffer{} 488 // This is almost like the Benchmark function, except that we override 489 // the benchtime and catch the failure result of the subbenchmark. 490 root := &B{ 491 common: common{ 492 signal: make(chan bool), 493 name: "root", 494 w: buf, 495 chatty: tc.chatty, 496 }, 497 benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure. 498 benchTime: time.Microsecond, 499 } 500 root.runN(1) 501 if ok != !tc.failed { 502 t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed) 503 } 504 if !ok != root.Failed() { 505 t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) 506 } 507 // All tests are run as subtests 508 if root.result.N != 1 { 509 t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N) 510 } 511 got := strings.TrimSpace(buf.String()) 512 want := strings.TrimSpace(tc.output) 513 re := makeRegexp(want) 514 if ok, err := regexp.MatchString(re, got); !ok || err != nil { 515 t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) 516 } 517 } 518 } 519 520 func makeRegexp(s string) string { 521 s = strings.Replace(s, ":NNN:", `:\d\d\d:`, -1) 522 s = strings.Replace(s, "(N.NNs)", `\(\d*\.\d*s\)`, -1) 523 return s 524 } 525 526 func TestBenchmarkOutput(t *T) { 527 // Ensure Benchmark initialized common.w by invoking it with an error and 528 // normal case. 529 Benchmark(func(b *B) { b.Error("do not print this output") }) 530 Benchmark(func(b *B) {}) 531 } 532 533 func TestBenchmarkStartsFrom1(t *T) { 534 var first = true 535 Benchmark(func(b *B) { 536 if first && b.N != 1 { 537 panic(fmt.Sprintf("Benchmark() first N=%v; want 1", b.N)) 538 } 539 first = false 540 }) 541 } 542 543 func TestBenchmarkReadMemStatsBeforeFirstRun(t *T) { 544 var first = true 545 Benchmark(func(b *B) { 546 if first && (b.startAllocs == 0 || b.startBytes == 0) { 547 panic(fmt.Sprintf("ReadMemStats not called before first run")) 548 } 549 first = false 550 }) 551 } 552 553 func TestParallelSub(t *T) { 554 c := make(chan int) 555 block := make(chan int) 556 for i := 0; i < 10; i++ { 557 go func(i int) { 558 <-block 559 t.Run(fmt.Sprint(i), func(t *T) {}) 560 c <- 1 561 }(i) 562 } 563 close(block) 564 for i := 0; i < 10; i++ { 565 <-c 566 } 567 } 568 569 type funcWriter func([]byte) (int, error) 570 571 func (fw funcWriter) Write(b []byte) (int, error) { return fw(b) } 572 573 func TestRacyOutput(t *T) { 574 var runs int32 // The number of running Writes 575 var races int32 // Incremented for each race detected 576 raceDetector := func(b []byte) (int, error) { 577 // Check if some other goroutine is concurrently calling Write. 578 if atomic.LoadInt32(&runs) > 0 { 579 atomic.AddInt32(&races, 1) // Race detected! 580 } 581 atomic.AddInt32(&runs, 1) 582 defer atomic.AddInt32(&runs, -1) 583 runtime.Gosched() // Increase probability of a race 584 return len(b), nil 585 } 586 587 var wg sync.WaitGroup 588 root := &T{ 589 common: common{w: funcWriter(raceDetector), chatty: true}, 590 context: newTestContext(1, newMatcher(regexp.MatchString, "", "")), 591 } 592 root.Run("", func(t *T) { 593 for i := 0; i < 100; i++ { 594 wg.Add(1) 595 go func(i int) { 596 defer wg.Done() 597 t.Run(fmt.Sprint(i), func(t *T) { 598 t.Logf("testing run %d", i) 599 }) 600 }(i) 601 } 602 }) 603 wg.Wait() 604 605 if races > 0 { 606 t.Errorf("detected %d racy Writes", races) 607 } 608 } 609 610 func TestBenchmark(t *T) { 611 res := Benchmark(func(b *B) { 612 for i := 0; i < 5; i++ { 613 b.Run("", func(b *B) { 614 for i := 0; i < b.N; i++ { 615 time.Sleep(time.Millisecond) 616 } 617 }) 618 } 619 }) 620 if res.NsPerOp() < 4000000 { 621 t.Errorf("want >5ms; got %v", time.Duration(res.NsPerOp())) 622 } 623 }