Make http2 interop tests always pass, and instead give a report
diff --git a/tools/http2_interop/http2interop_test.go b/tools/http2_interop/http2interop_test.go
index b35d085..2295340 100644
--- a/tools/http2_interop/http2interop_test.go
+++ b/tools/http2_interop/http2interop_test.go
@@ -3,6 +3,7 @@
 import (
 	"crypto/tls"
 	"crypto/x509"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -68,6 +69,7 @@
 }
 
 func TestClientShortSettings(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -79,6 +81,7 @@
 }
 
 func TestShortPreface(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -90,6 +93,7 @@
 }
 
 func TestUnknownFrameType(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -100,6 +104,7 @@
 }
 
 func TestClientPrefaceWithStreamId(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
@@ -109,6 +114,7 @@
 }
 
 func TestTLSApplicationProtocol(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
@@ -118,6 +124,7 @@
 }
 
 func TestTLSMaxVersion(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
@@ -129,6 +136,7 @@
 }
 
 func TestTLSBadCipherSuites(t *testing.T) {
+	defer Report(t)()
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
@@ -151,5 +159,10 @@
 
 func TestMain(m *testing.M) {
 	flag.Parse()
-	os.Exit(m.Run())
+	m.Run()
+	if err := json.NewEncoder(os.Stderr).Encode(&allCaseInfos); err != nil {
+		fmt.Println("Failed to encode", err)
+	}
+	// Always pass
+	os.Exit(0)
 }
diff --git a/tools/http2_interop/testsuite.go b/tools/http2_interop/testsuite.go
new file mode 100644
index 0000000..fcfacf5
--- /dev/null
+++ b/tools/http2_interop/testsuite.go
@@ -0,0 +1,44 @@
+package http2interop
+
+import (
+	"runtime"
+	"strings"
+	"sync"
+	"testing"
+)
+
+// When a test is skipped or fails, runtime.Goexit() is called which destroys the callstack.
+// This means the name of the test case is lost, so we need to grab a copy of pc before.
+func Report(t testing.TB) func() {
+	pc, _, _, ok := runtime.Caller(1)
+	if !ok {
+		t.Fatal("Can't get caller info")
+	}
+	return func() {
+		fn := runtime.FuncForPC(pc)
+		fullName := fn.Name()
+		name := strings.Split(fullName, ".")[1]
+		allCaseInfos.lock.Lock()
+		defer allCaseInfos.lock.Unlock()
+		allCaseInfos.Cases = append(allCaseInfos.Cases, &caseInfo{
+			Name:    name,
+			Passed:  !t.Failed(),
+			Skipped: t.Skipped(),
+		})
+	}
+}
+
+type caseInfo struct {
+	Name    string `json:"name"`
+	Passed  bool   `json:"passed"`
+	Skipped bool   `json:"skipped"`
+}
+
+type caseInfos struct {
+	lock  sync.Mutex
+	Cases []*caseInfo `json:"cases"`
+}
+
+var (
+	allCaseInfos = caseInfos{}
+)