http2: fix flaky TestTransportHandlerBodyClose

Don't assume goroutines are gone immediately.

Copy the waitCondition & waitErrCondition helpers from net/http's
tests, so we can assume both exist in both repos, even though we only
use one of them as of this CL.

Fixes golang/go#22889

Change-Id: Ife251c9552bc68646e174a7ac082b363e32132a1
Reviewed-on: https://go-review.googlesource.com/114012
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/http2/http2_test.go b/http2/http2_test.go
index 5248776..667db48 100644
--- a/http2/http2_test.go
+++ b/http2/http2_test.go
@@ -14,6 +14,7 @@
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"golang.org/x/net/http2/hpack"
 )
@@ -197,3 +198,30 @@
 		t.Logf("Keys allocs = %v; want <1", allocs)
 	}
 }
+
+// waitCondition reports whether fn eventually returned true,
+// checking immediately and then every checkEvery amount,
+// until waitFor has elapsed, at which point it returns false.
+func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
+	deadline := time.Now().Add(waitFor)
+	for time.Now().Before(deadline) {
+		if fn() {
+			return true
+		}
+		time.Sleep(checkEvery)
+	}
+	return false
+}
+
+// waitErrCondition is like waitCondition but with errors instead of bools.
+func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
+	deadline := time.Now().Add(waitFor)
+	var err error
+	for time.Now().Before(deadline) {
+		if err = fn(); err == nil {
+			return nil
+		}
+		time.Sleep(checkEvery)
+	}
+	return err
+}
diff --git a/http2/transport_test.go b/http2/transport_test.go
index ed58ce8..636f155 100644
--- a/http2/transport_test.go
+++ b/http2/transport_test.go
@@ -2395,11 +2395,12 @@
 	}
 	tr.CloseIdleConnections()
 
-	gd := runtime.NumGoroutine() - g0
-	if gd > numReq/2 {
+	if !waitCondition(5*time.Second, 100*time.Millisecond, func() bool {
+		gd := runtime.NumGoroutine() - g0
+		return gd < numReq/2
+	}) {
 		t.Errorf("appeared to leak goroutines")
 	}
-
 }
 
 // https://golang.org/issue/15930