main_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2013 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. package http_test
  5. import (
  6. "fmt"
  7. "io"
  8. "log"
  9. "net/http"
  10. "os"
  11. "runtime"
  12. "sort"
  13. "strings"
  14. "testing"
  15. "time"
  16. )
  17. var quietLog = log.New(io.Discard, "", 0)
  18. func TestMain(m *testing.M) {
  19. v := m.Run()
  20. if v == 0 && goroutineLeaked() {
  21. os.Exit(1)
  22. }
  23. os.Exit(v)
  24. }
  25. func interestingGoroutines() (gs []string) {
  26. buf := make([]byte, 2<<20)
  27. buf = buf[:runtime.Stack(buf, true)]
  28. for _, g := range strings.Split(string(buf), "\n\n") {
  29. _, stack, _ := strings.Cut(g, "\n")
  30. stack = strings.TrimSpace(stack)
  31. if stack == "" ||
  32. strings.Contains(stack, "testing.(*M).before.func1") ||
  33. strings.Contains(stack, "os/signal.signal_recv") ||
  34. strings.Contains(stack, "created by net.startServer") ||
  35. strings.Contains(stack, "created by testing.RunTests") ||
  36. strings.Contains(stack, "closeWriteAndWait") ||
  37. strings.Contains(stack, "testing.Main(") ||
  38. // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28)
  39. strings.Contains(stack, "runtime.goexit") ||
  40. strings.Contains(stack, "created by runtime.gc") ||
  41. strings.Contains(stack, "interestingGoroutines") ||
  42. strings.Contains(stack, "runtime.MHeap_Scavenger") {
  43. continue
  44. }
  45. gs = append(gs, stack)
  46. }
  47. sort.Strings(gs)
  48. return
  49. }
  50. // Verify the other tests didn't leave any goroutines running.
  51. func goroutineLeaked() bool {
  52. if testing.Short() || runningBenchmarks() {
  53. // Don't worry about goroutine leaks in -short mode or in
  54. // benchmark mode. Too distracting when there are false positives.
  55. return false
  56. }
  57. var stackCount map[string]int
  58. for i := 0; i < 5; i++ {
  59. n := 0
  60. stackCount = make(map[string]int)
  61. gs := interestingGoroutines()
  62. for _, g := range gs {
  63. stackCount[g]++
  64. n++
  65. }
  66. if n == 0 {
  67. return false
  68. }
  69. // Wait for goroutines to schedule and die off:
  70. time.Sleep(100 * time.Millisecond)
  71. }
  72. fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
  73. for stack, count := range stackCount {
  74. fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
  75. }
  76. return true
  77. }
  78. // setParallel marks t as a parallel test if we're in short mode
  79. // (all.bash), but as a serial test otherwise. Using t.Parallel isn't
  80. // compatible with the afterTest func in non-short mode.
  81. func setParallel(t *testing.T) {
  82. if strings.Contains(t.Name(), "HTTP2") {
  83. http.CondSkipHTTP2(t)
  84. }
  85. if testing.Short() {
  86. t.Parallel()
  87. }
  88. }
  89. func runningBenchmarks() bool {
  90. for i, arg := range os.Args {
  91. if strings.HasPrefix(arg, "-test.bench=") && !strings.HasSuffix(arg, "=") {
  92. return true
  93. }
  94. if arg == "-test.bench" && i < len(os.Args)-1 && os.Args[i+1] != "" {
  95. return true
  96. }
  97. }
  98. return false
  99. }
  100. func afterTest(t testing.TB) {
  101. http.DefaultTransport.(*http.Transport).CloseIdleConnections()
  102. if testing.Short() {
  103. return
  104. }
  105. var bad string
  106. badSubstring := map[string]string{
  107. ").readLoop(": "a Transport",
  108. ").writeLoop(": "a Transport",
  109. "created by net/http/httptest.(*Server).Start": "an httptest.Server",
  110. "timeoutHandler": "a TimeoutHandler",
  111. "net.(*netFD).connect(": "a timing out dial",
  112. ").noteClientGone(": "a closenotifier sender",
  113. }
  114. var stacks string
  115. for i := 0; i < 10; i++ {
  116. bad = ""
  117. stacks = strings.Join(interestingGoroutines(), "\n\n")
  118. for substr, what := range badSubstring {
  119. if strings.Contains(stacks, substr) {
  120. bad = what
  121. }
  122. }
  123. if bad == "" {
  124. return
  125. }
  126. // Bad stuff found, but goroutines might just still be
  127. // shutting down, so give it some time.
  128. time.Sleep(250 * time.Millisecond)
  129. }
  130. t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
  131. }
  132. // waitCondition reports whether fn eventually returned true,
  133. // checking immediately and then every checkEvery amount,
  134. // until waitFor has elapsed, at which point it returns false.
  135. func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
  136. deadline := time.Now().Add(waitFor)
  137. for time.Now().Before(deadline) {
  138. if fn() {
  139. return true
  140. }
  141. time.Sleep(checkEvery)
  142. }
  143. return false
  144. }
  145. // waitErrCondition is like waitCondition but with errors instead of bools.
  146. func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
  147. deadline := time.Now().Add(waitFor)
  148. var err error
  149. for time.Now().Before(deadline) {
  150. if err = fn(); err == nil {
  151. return nil
  152. }
  153. time.Sleep(checkEvery)
  154. }
  155. return err
  156. }