@@ -27,6 +27,7 @@ import (
27
27
"os/exec"
28
28
"reflect"
29
29
"runtime"
30
+ "runtime/debug"
30
31
"sort"
31
32
"strconv"
32
33
"strings"
@@ -3038,19 +3039,47 @@ func TestTransportAndServerSharedBodyRace_h1(t *testing.T) {
3038
3039
testTransportAndServerSharedBodyRace (t , h1Mode )
3039
3040
}
3040
3041
func TestTransportAndServerSharedBodyRace_h2 (t * testing.T ) {
3041
- t .Skip ("failing in http2 mode; golang.org/issue/13556" )
3042
3042
testTransportAndServerSharedBodyRace (t , h2Mode )
3043
3043
}
3044
3044
func testTransportAndServerSharedBodyRace (t * testing.T , h2 bool ) {
3045
3045
defer afterTest (t )
3046
3046
3047
3047
const bodySize = 1 << 20
3048
3048
3049
+ // errorf is like t.Errorf, but also writes to println. When
3050
+ // this test fails, it hangs. This helps debugging and I've
3051
+ // added this enough times "temporarily". It now gets added
3052
+ // full time.
3053
+ errorf := func (format string , args ... interface {}) {
3054
+ v := fmt .Sprintf (format , args ... )
3055
+ println (v )
3056
+ t .Error (v )
3057
+ }
3058
+
3049
3059
unblockBackend := make (chan bool )
3050
3060
backend := newClientServerTest (t , h2 , HandlerFunc (func (rw ResponseWriter , req * Request ) {
3051
- io .CopyN (rw , req .Body , bodySize )
3061
+ gone := rw .(CloseNotifier ).CloseNotify ()
3062
+ didCopy := make (chan interface {})
3063
+ go func () {
3064
+ n , err := io .CopyN (rw , req .Body , bodySize )
3065
+ didCopy <- []interface {}{n , err }
3066
+ }()
3067
+ isGone := false
3068
+ Loop:
3069
+ for {
3070
+ select {
3071
+ case <- didCopy :
3072
+ break Loop
3073
+ case <- gone :
3074
+ isGone = true
3075
+ case <- time .After (time .Second ):
3076
+ println ("1 second passes in backend, proxygone=" , isGone )
3077
+ }
3078
+ }
3052
3079
<- unblockBackend
3053
3080
}))
3081
+ var quitTimer * time.Timer
3082
+ defer func () { quitTimer .Stop () }()
3054
3083
defer backend .close ()
3055
3084
3056
3085
backendRespc := make (chan * Response , 1 )
@@ -3063,17 +3092,17 @@ func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
3063
3092
3064
3093
bresp , err := proxy .c .Do (req2 )
3065
3094
if err != nil {
3066
- t . Errorf ("Proxy outbound request: %v" , err )
3095
+ errorf ("Proxy outbound request: %v" , err )
3067
3096
return
3068
3097
}
3069
3098
_ , err = io .CopyN (ioutil .Discard , bresp .Body , bodySize / 2 )
3070
3099
if err != nil {
3071
- t . Errorf ("Proxy copy error: %v" , err )
3100
+ errorf ("Proxy copy error: %v" , err )
3072
3101
return
3073
3102
}
3074
3103
backendRespc <- bresp // to close later
3075
3104
3076
- // Try to cause a race: Both the DefaultTransport and the proxy handler's Server
3105
+ // Try to cause a race: Both the Transport and the proxy handler's Server
3077
3106
// will try to read/close req.Body (aka req2.Body)
3078
3107
if h2 {
3079
3108
close (cancel )
@@ -3083,6 +3112,20 @@ func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
3083
3112
rw .Write ([]byte ("OK" ))
3084
3113
}))
3085
3114
defer proxy .close ()
3115
+ defer func () {
3116
+ // Before we shut down our two httptest.Servers, start a timer.
3117
+ // We choose 7 seconds because httptest.Server starts logging
3118
+ // warnings to stderr at 5 seconds. If we don't disarm this bomb
3119
+ // in 7 seconds (after the two httptest.Server.Close calls above),
3120
+ // then we explode with stacks.
3121
+ quitTimer = time .AfterFunc (7 * time .Second , func () {
3122
+ debug .SetTraceback ("ALL" )
3123
+ stacks := make ([]byte , 1 << 20 )
3124
+ stacks = stacks [:runtime .Stack (stacks , true )]
3125
+ fmt .Fprintf (os .Stderr , "%s" , stacks )
3126
+ log .Fatalf ("Timeout." )
3127
+ })
3128
+ }()
3086
3129
3087
3130
defer close (unblockBackend )
3088
3131
req , _ := NewRequest ("POST" , proxy .ts .URL , io .LimitReader (neverEnding ('a' ), bodySize ))
0 commit comments