Repository: gotestyourself/gotestsum
Pull request #156 (2020-10-22 05:07:20)

Fix panic caused by missing Action=run event
I'm not sure if there is an issue open for this on the Go issue tracker. Not only is the `Action=run` event missing, so is a lot of the Action=output for some subtests.


Patch:
diff --git a/go.mod b/go.mod
index 9e01474..87377d5 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ replace github.com/spf13/pflag => github.com/dnephin/pflag v0.0.0-20200521001137
 require (
 	github.com/fatih/color v1.9.0
 	github.com/fsnotify/fsnotify v1.4.9
-	github.com/google/go-cmp v0.4.0
+	github.com/google/go-cmp v0.5.2
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
 	github.com/jonboulle/clockwork v0.1.0
 	github.com/mattn/go-colorable v0.1.6 // indirect
diff --git a/go.sum b/go.sum
index 8c7759d..cfa3fb3 100644
--- a/go.sum
+++ b/go.sum
@@ -6,6 +6,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=


Test patch:
diff --git a/cmd/rerunfails_test.go b/cmd/rerunfails_test.go
index ff21af9..d103a25 100644
--- a/cmd/rerunfails_test.go
+++ b/cmd/rerunfails_test.go
@@ -36,6 +36,28 @@ func TestWriteRerunFailsReport(t *testing.T) {
 	golden.Assert(t, string(raw), t.Name()+"-expected")
 }
 
+func TestWriteRerunFailsReport_HandlesMissingActionRunEvents(t *testing.T) {
+	reportFile := fs.NewFile(t, t.Name())
+	defer reportFile.Remove()
+
+	opts := &options{
+		rerunFailsReportFile:  reportFile.Path(),
+		rerunFailsMaxAttempts: 4,
+	}
+
+	exec, err := testjson.ScanTestOutput(testjson.ScanConfig{
+		Stdout: bytes.NewReader(golden.Get(t, "go-test-missing-run-events.out")),
+	})
+	assert.NilError(t, err)
+
+	err = writeRerunFailsReport(opts, exec)
+	assert.NilError(t, err)
+
+	raw, err := ioutil.ReadFile(reportFile.Path())
+	assert.NilError(t, err)
+	golden.Assert(t, string(raw), t.Name()+"-expected")
+}
+
 func TestGoTestRunFlagFromTestCases(t *testing.T) {
 	type testCase struct {
 		input    string
diff --git a/cmd/testdata/TestWriteRerunFailsReport_HandlesMissingActionRunEvents-expected b/cmd/testdata/TestWriteRerunFailsReport_HandlesMissingActionRunEvents-expected
new file mode 100644
index 0000000..3ef688f
--- /dev/null
+++ b/cmd/testdata/TestWriteRerunFailsReport_HandlesMissingActionRunEvents-expected
@@ -0,0 +1,3 @@
+github.com/hashicorp/consul/test/integration/connect/envoy.TestEnvoy: 5 runs, 5 failures
+github.com/hashicorp/consul/test/integration/connect/envoy.TestEnvoy/case-ent-cross-namespaces: 3 runs, 3 failures
+github.com/hashicorp/consul/test/integration/connect/envoy.TestEnvoy/case-ent-intra-namespace: 3 runs, 3 failures
diff --git a/cmd/testdata/go-test-missing-run-events.out b/cmd/testdata/go-test-missing-run-events.out
new file mode 100644
index 0000000..da91d4b
--- /dev/null
+++ b/cmd/testdata/go-test-missing-run-events.out
@@ -0,0 +1,108 @@
+{"Time":"2020-10-22T00:18:23.836961241Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy"}
+{"Time":"2020-10-22T00:19:07.176212704Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-basic"}
+{"Time":"2020-10-22T00:19:30.595333272Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-centralconf"}
+{"Time":"2020-10-22T00:20:00.782717543Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-dc-failover-gateways-none"}
+{"Time":"2020-10-22T00:21:02.358098165Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-dc-failover-gateways-remote"}
+{"Time":"2020-10-22T00:22:04.420054524Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-defaultsubset"}
+{"Time":"2020-10-22T00:22:38.212414238Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-features"}
+{"Time":"2020-10-22T00:23:09.301536045Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-subset-onlypassing"}
+{"Time":"2020-10-22T00:23:41.435709605Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-subset-redirect"}
+{"Time":"2020-10-22T00:24:16.86716551Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-svc-failover"}
+{"Time":"2020-10-22T00:25:01.571200729Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-svc-redirect-http"}
+{"Time":"2020-10-22T00:25:32.020127536Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-svc-redirect-tcp"}
+{"Time":"2020-10-22T00:26:00.566029647Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-router-features"}
+{"Time":"2020-10-22T00:26:34.976920948Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-splitter-features"}
+{"Time":"2020-10-22T00:27:09.988011217Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-consul-exec"}
+{"Time":"2020-10-22T00:27:36.461488754Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-dogstatsd-udp"}
+{"Time":"2020-10-22T00:28:03.709314906Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-cross-namespaces"}
+{"Time":"2020-10-22T00:28:54.659486846Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-gateways-local"}
+{"Time":"2020-10-22T00:29:46.702588149Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-gateways-remote"}
+{"Time":"2020-10-22T00:30:31.2432353Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-intra-namespace"}
+{"Time":"2020-10-22T00:31:23.487327584Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-namespace-discovery-chain"}
+{"Time":"2020-10-22T00:32:21.2756168Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-gateway-without-services"}
+{"Time":"2020-10-22T00:32:47.742941478Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-gateways-local"}
+{"Time":"2020-10-22T00:33:42.557718152Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-gateways-remote"}
+{"Time":"2020-10-22T00:34:23.708756405Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-grpc"}
+{"Time":"2020-10-22T00:34:51.466793964Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-http"}
+{"Time":"2020-10-22T00:35:17.958659061Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-http-badauthz"}
+{"Time":"2020-10-22T00:35:45.024612888Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-grpc"}
+{"Time":"2020-10-22T00:36:16.626166436Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-http"}
+{"Time":"2020-10-22T00:36:49.578681889Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-multiple-services"}
+{"Time":"2020-10-22T00:37:20.475516355Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-simple"}
+{"Time":"2020-10-22T00:37:52.651634624Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-tls"}
+{"Time":"2020-10-22T00:38:23.194366198Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-mesh-gateways-resolver"}
+{"Time":"2020-10-22T00:39:16.834144235Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-l7-intentions"}
+{"Time":"2020-10-22T00:39:43.921073741Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-multidc-rsa-ca"}
+{"Time":"2020-10-22T00:40:23.323700733Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-prometheus"}
+{"Time":"2020-10-22T00:40:47.546267846Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-stats-proxy"}
+{"Time":"2020-10-22T00:41:11.955878675Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-statsd-udp"}
+{"Time":"2020-10-22T00:41:40.749502998Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-hostnames"}
+{"Time":"2020-10-22T00:42:05.839131501Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-simple"}
+{"Time":"2020-10-22T00:42:33.162515422Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-subsets"}
+{"Time":"2020-10-22T00:43:01.841085827Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-without-services"}
+{"Time":"2020-10-22T00:43:24.22276926Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-upstream-config"}
+{"Time":"2020-10-22T00:43:49.179125398Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-wanfed-gw"}
+{"Time":"2020-10-22T00:44:46.641753773Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-zipkin"}
+{"Time":"2020-10-22T00:45:20.108579041Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-badauthz","Elapsed":38.97}
+{"Time":"2020-10-22T00:45:20.108606Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-basic","Elapsed":23.42}
+{"Time":"2020-10-22T00:45:20.108618156Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-centralconf","Elapsed":30.19}
+{"Time":"2020-10-22T00:45:20.108629906Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-dc-failover-gateways-none","Elapsed":61.58}
+{"Time":"2020-10-22T00:45:20.108640546Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-dc-failover-gateways-remote","Elapsed":62.06}
+{"Time":"2020-10-22T00:45:20.108652253Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-defaultsubset","Elapsed":33.79}
+{"Time":"2020-10-22T00:45:20.108662762Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-features","Elapsed":31.09}
+{"Time":"2020-10-22T00:45:20.108672795Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-subset-onlypassing","Elapsed":32.13}
+{"Time":"2020-10-22T00:45:20.108683532Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-subset-redirect","Elapsed":35.43}
+{"Time":"2020-10-22T00:45:20.108693772Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-svc-failover","Elapsed":44.7}
+{"Time":"2020-10-22T00:45:20.108706751Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-svc-redirect-http","Elapsed":30.45}
+{"Time":"2020-10-22T00:45:20.10871706Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-resolver-svc-redirect-tcp","Elapsed":28.55}
+{"Time":"2020-10-22T00:45:20.10872787Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-router-features","Elapsed":34.41}
+{"Time":"2020-10-22T00:45:20.108737871Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-cfg-splitter-features","Elapsed":35.01}
+{"Time":"2020-10-22T00:45:20.108748902Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-consul-exec","Elapsed":26.47}
+{"Time":"2020-10-22T00:45:20.108759692Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-dogstatsd-udp","Elapsed":27.25}
+{"Time":"2020-10-22T00:45:20.108770081Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-cross-namespaces","Elapsed":50.95}
+{"Time":"2020-10-22T00:45:20.108780941Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-gateways-local","Elapsed":52.04}
+{"Time":"2020-10-22T00:45:20.108791687Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-gateways-remote","Elapsed":44.54}
+{"Time":"2020-10-22T00:45:20.108802026Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-intra-namespace","Elapsed":52.24}
+{"Time":"2020-10-22T00:45:20.108812518Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-namespace-discovery-chain","Elapsed":57.79}
+{"Time":"2020-10-22T00:45:20.108823218Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-gateway-without-services","Elapsed":26.47}
+{"Time":"2020-10-22T00:45:20.108834724Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-gateways-local","Elapsed":54.81}
+{"Time":"2020-10-22T00:45:20.108845012Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-gateways-remote","Elapsed":41.15}
+{"Time":"2020-10-22T00:45:20.108856989Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-grpc","Elapsed":27.76}
+{"Time":"2020-10-22T00:45:20.108867426Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-http","Elapsed":26.49}
+{"Time":"2020-10-22T00:45:20.108878346Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-http-badauthz","Elapsed":27.07}
+{"Time":"2020-10-22T00:45:20.108888697Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-grpc","Elapsed":31.6}
+{"Time":"2020-10-22T00:45:20.108898988Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-http","Elapsed":32.95}
+{"Time":"2020-10-22T00:45:20.108910108Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-multiple-services","Elapsed":30.9}
+{"Time":"2020-10-22T00:45:20.108920326Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-simple","Elapsed":32.18}
+{"Time":"2020-10-22T00:45:20.10893017Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-gateway-tls","Elapsed":30.54}
+{"Time":"2020-10-22T00:45:20.108940126Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ingress-mesh-gateways-resolver","Elapsed":53.64}
+{"Time":"2020-10-22T00:45:20.108949868Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-l7-intentions","Elapsed":27.09}
+{"Time":"2020-10-22T00:45:20.108959852Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-multidc-rsa-ca","Elapsed":39.4}
+{"Time":"2020-10-22T00:45:20.108969973Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-prometheus","Elapsed":24.22}
+{"Time":"2020-10-22T00:45:20.108979797Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-stats-proxy","Elapsed":24.41}
+{"Time":"2020-10-22T00:45:20.108991334Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-statsd-udp","Elapsed":28.79}
+{"Time":"2020-10-22T00:45:20.109001312Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-hostnames","Elapsed":25.09}
+{"Time":"2020-10-22T00:45:20.109011226Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-simple","Elapsed":27.32}
+{"Time":"2020-10-22T00:45:20.109021026Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-subsets","Elapsed":28.68}
+{"Time":"2020-10-22T00:45:20.109031199Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-terminating-gateway-without-services","Elapsed":22.38}
+{"Time":"2020-10-22T00:45:20.109041152Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-upstream-config","Elapsed":24.96}
+{"Time":"2020-10-22T00:45:20.109050975Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-wanfed-gw","Elapsed":57.46}
+{"Time":"2020-10-22T00:45:20.109060353Z","Action":"pass","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-zipkin","Elapsed":31.09}
+{"Time":"2020-10-22T00:45:20.109064921Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy","Elapsed":1616.27}
+{"Time":"2020-10-22T00:45:20.109148885Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Elapsed":1616.276}
+{"Time":"2020-10-22T00:45:20.673179245Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy"}
+{"Time":"2020-10-22T00:46:10.218981797Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-cross-namespaces","Elapsed":44.32}
+{"Time":"2020-10-22T00:46:10.218989964Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy","Elapsed":49.55}
+{"Time":"2020-10-22T00:46:10.219542662Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Elapsed":49.549}
+{"Time":"2020-10-22T00:46:10.784497983Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy"}
+{"Time":"2020-10-22T00:47:14.789854054Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-intra-namespace","Elapsed":58.85}
+{"Time":"2020-10-22T00:47:14.789862576Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy","Elapsed":64.01}
+{"Time":"2020-10-22T00:47:14.790364204Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Elapsed":64.009}
+{"Time":"2020-10-22T00:47:15.354865459Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy"}
+{"Time":"2020-10-22T00:48:04.07040834Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-cross-namespaces","Elapsed":43.64}
+{"Time":"2020-10-22T00:48:04.070414141Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy","Elapsed":48.72}
+{"Time":"2020-10-22T00:48:04.071038715Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Elapsed":48.719}
+{"Time":"2020-10-22T00:48:04.708139615Z","Action":"run","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy"}
+{"Time":"2020-10-22T00:48:58.010967512Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy/case-ent-intra-namespace","Elapsed":48.1}
+{"Time":"2020-10-22T00:48:58.010973222Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Test":"TestEnvoy","Elapsed":53.3}
+{"Time":"2020-10-22T00:48:58.011515541Z","Action":"fail","Package":"github.com/hashicorp/consul/test/integration/connect/envoy","Elapsed":53.306}
diff --git a/testjson/execution.go b/testjson/execution.go
index f7ba22e..d006e3d 100644
--- a/testjson/execution.go
+++ b/testjson/execution.go
@@ -8,6 +8,7 @@ import (
 	"io"
 	"sort"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/jonboulle/clockwork"
@@ -261,11 +262,12 @@ func newPackage() *Package {
 
 // Execution of one or more test packages
 type Execution struct {
-	started   time.Time
-	packages  map[string]*Package
-	errors    []string
-	done      bool
-	lastRunID int
+	started    time.Time
+	packages   map[string]*Package
+	errorsLock sync.RWMutex
+	errors     []string
+	done       bool
+	lastRunID  int
 }
 
 func (e *Execution) add(event TestEvent) {
@@ -296,27 +298,40 @@ func (e *Execution) addPackageEvent(pkg *Package, event TestEvent) {
 	}
 }
 
-func (p *Package) addTestEvent(event TestEvent) {
-	root, _ := TestName(event.Test).Split()
+func (p *Package) newTestCaseFromEvent(event TestEvent) TestCase {
+	// Incremental total before using it as the ID, because ID 0 is used for
+	// the package output
+	p.Total++
+	return TestCase{
+		Package: event.Package,
+		Test:    TestName(event.Test),
+		ID:      p.Total,
+		RunID:   event.RunID,
+	}
+}
 
-	switch event.Action {
-	case ActionRun:
-		// Incremental total before using it as the ID, because ID 0 is used for
-		// the package output
-		p.Total++
-		tc := TestCase{
-			Package: event.Package,
-			Test:    TestName(event.Test),
-			ID:      p.Total,
-			RunID:   event.RunID,
-		}
+func (p *Package) addTestEvent(event TestEvent) {
+	if event.Action == ActionRun {
+		tc := p.newTestCaseFromEvent(event)
 		p.running[event.Test] = tc
 
 		if tc.Test.IsSubTest() {
+			root, _ := TestName(event.Test).Split()
 			rootID := p.running[root].ID
 			p.subTests[rootID] = append(p.subTests[rootID], tc.ID)
 		}
 		return
+	}
+
+	tc := p.running[event.Test]
+	// This appears to be a bug in 'go test' or test2json. This test is missing
+	// an Action=run event. Create one on the first event received from the test.
+	if tc.ID == 0 {
+		tc = p.newTestCaseFromEvent(event)
+		p.running[event.Test] = tc
+	}
+
+	switch event.Action {
 	case ActionOutput, ActionBench:
 		tc := p.running[event.Test]
 		p.addOutput(tc.ID, event.Output)
@@ -326,7 +341,6 @@ func (p *Package) addTestEvent(event TestEvent) {
 	}
 
 	// the event.Action must be one of the three test end events
-	tc := p.running[event.Test]
 	delete(p.running, event.Test)
 	tc.Elapsed = elapsedDuration(event.Elapsed)
 
@@ -336,6 +350,7 @@ func (p *Package) addTestEvent(event TestEvent) {
 
 		// If this is a subtest, mark the root test as having a failed subtest
 		if tc.Test.IsSubTest() {
+			root, _ := TestName(event.Test).Split()
 			rootTestCase := p.running[root]
 			rootTestCase.hasSubTestFailed = true
 			p.running[root] = rootTestCase
@@ -462,11 +477,15 @@ func (e *Execution) addError(err string) {
 	if strings.HasPrefix(err, "# ") {
 		return
 	}
+	e.errorsLock.Lock()
 	e.errors = append(e.errors, err)
+	e.errorsLock.Unlock()
 }
 
 // Errors returns a list of all the errors.
 func (e *Execution) Errors() []string {
+	e.errorsLock.RLock()
+	defer e.errorsLock.RUnlock()
 	return e.errors
 }
 
diff --git a/testjson/format_test.go b/testjson/format_test.go
index 4392ca7..c0fcab1 100644
--- a/testjson/format_test.go
+++ b/testjson/format_test.go
@@ -118,6 +118,7 @@ var expectedExecution = &Execution{
 var cmpExecutionShallow = gocmp.Options{
 	gocmp.AllowUnexported(Execution{}, Package{}),
 	gocmp.FilterPath(stringPath("started"), opt.TimeWithThreshold(10*time.Second)),
+	cmpopts.IgnoreFields(Execution{}, "errorsLock"),
 	cmpopts.EquateEmpty(),
 	cmpPackageShallow,
 }
diff --git a/testjson/summary.go b/testjson/summary.go
index 9a1ce89..0bbbee0 100644
--- a/testjson/summary.go
+++ b/testjson/summary.go
@@ -150,7 +150,7 @@ type executionSummary interface {
 }
 
 type noOutputSummary struct {
-	Execution
+	*Execution
 }
 
 func (s *noOutputSummary) OutputLines(_ TestCase) []string {
@@ -161,7 +161,7 @@ func newExecSummary(execution *Execution, opts Summary) executionSummary {
 	if opts.Includes(SummarizeOutput) {
 		return execution
 	}
-	return &noOutputSummary{Execution: *execution}
+	return &noOutputSummary{Execution: execution}
 }
 
 func writeTestCaseSummary(out io.Writer, execution executionSummary, conf testCaseFormatConfig) {