From d6bf22343d4fa240c9f09e8347eab521df60eab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Stemmer?= Date: Thu, 11 Aug 2022 23:07:30 +0100 Subject: [PATCH] parser/gotest: Move event processing into reportBuilder --- parser/gotest/gotest.go | 29 +--- parser/gotest/gotest_test.go | 219 -------------------------- parser/gotest/report_builder.go | 34 ++++ parser/gotest/report_builder_test.go | 227 +++++++++++++++++++++++++++ 4 files changed, 262 insertions(+), 247 deletions(-) diff --git a/parser/gotest/gotest.go b/parser/gotest/gotest.go index 3623dca..b79daeb 100644 --- a/parser/gotest/gotest.go +++ b/parser/gotest/gotest.go @@ -169,34 +169,7 @@ func (p *Parser) report(events []Event) gtr.Report { rb.timestampFunc = p.timestampFunc } for _, ev := range events { - switch ev.Type { - case "run_test": - rb.CreateTest(ev.Name) - case "pause_test": - rb.PauseTest(ev.Name) - case "cont_test": - rb.ContinueTest(ev.Name) - case "end_test": - rb.EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent) - case "run_benchmark": - rb.CreateBenchmark(ev.Name) - case "benchmark": - rb.BenchmarkResult(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp) - case "end_benchmark": - rb.EndBenchmark(ev.Name, ev.Result) - case "status": - rb.End() - case "summary": - rb.CreatePackage(ev.Name, ev.Result, ev.Duration, ev.Data) - case "coverage": - rb.Coverage(ev.CovPct, ev.CovPackages) - case "build_output": - rb.CreateBuildError(ev.Name) - case "output": - rb.AppendOutput(ev.Data) - default: - fmt.Printf("unhandled event type: %v\n", ev.Type) - } + rb.ProcessEvent(ev) } return rb.Build() } diff --git a/parser/gotest/gotest_test.go b/parser/gotest/gotest_test.go index 2aa3975..7e66f1a 100644 --- a/parser/gotest/gotest_test.go +++ b/parser/gotest/gotest_test.go @@ -6,8 +6,6 @@ import ( "testing" "time" - "github.com/jstemmer/go-junit-report/v2/gtr" - "github.com/google/go-cmp/cmp" ) @@ -215,220 +213,3 @@ func TestParseLine(t *testing.T) { }) } } - -func TestReport(t *testing.T) { - events := []Event{ - {Type: "run_test", Name: "TestOne"}, - {Type: "output", Data: "\tHello"}, - {Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 1 * time.Millisecond}, - {Type: "status", Result: "PASS"}, - {Type: "run_test", Name: "TestSkip"}, - {Type: "end_test", Name: "TestSkip", Result: "SKIP", Duration: 1 * time.Millisecond}, - {Type: "summary", Result: "ok", Name: "package/name", Duration: 1 * time.Millisecond}, - {Type: "run_test", Name: "TestOne"}, - {Type: "output", Data: "\tfile_test.go:10: error"}, - {Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 1 * time.Millisecond}, - {Type: "status", Result: "FAIL"}, - {Type: "summary", Result: "FAIL", Name: "package/name2", Duration: 1 * time.Millisecond}, - {Type: "output", Data: "goarch: amd64"}, - {Type: "run_benchmark", Name: "BenchmarkOne"}, - {Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 100}, - {Type: "end_benchmark", Name: "BenchmarkOne", Result: "BENCH"}, - {Type: "run_benchmark", Name: "BenchmarkTwo"}, - {Type: "benchmark", Name: "BenchmarkTwo"}, - {Type: "end_benchmark", Name: "BenchmarkTwo", Result: "FAIL"}, - {Type: "status", Result: "PASS"}, - {Type: "summary", Result: "ok", Name: "package/name3", Duration: 1234 * time.Millisecond}, - {Type: "build_output", Name: "package/failing1"}, - {Type: "output", Data: "error message"}, - {Type: "summary", Result: "FAIL", Name: "package/failing1", Data: "[build failed]"}, - } - want := gtr.Report{ - Packages: []gtr.Package{ - { - Name: "package/name", - Duration: 1 * time.Millisecond, - Timestamp: testTimestamp, - Tests: []gtr.Test{ - { - ID: 1, - Name: "TestOne", - Duration: 1 * time.Millisecond, - Result: gtr.Pass, - Output: []string{ - "\tHello", // TODO: strip tabs? - }, - Data: map[string]interface{}{}, - }, - { - ID: 2, - Name: "TestSkip", - Duration: 1 * time.Millisecond, - Result: gtr.Skip, - Data: map[string]interface{}{}, - }, - }, - }, - { - Name: "package/name2", - Duration: 1 * time.Millisecond, - Timestamp: testTimestamp, - Tests: []gtr.Test{ - { - ID: 3, - Name: "TestOne", - Duration: 1 * time.Millisecond, - Result: gtr.Fail, - Output: []string{ - "\tfile_test.go:10: error", - }, - Data: map[string]interface{}{}, - }, - }, - }, - { - Name: "package/name3", - Duration: 1234 * time.Millisecond, - Timestamp: testTimestamp, - Tests: []gtr.Test{ - { - ID: 4, - Name: "BenchmarkOne", - Result: gtr.Pass, - Data: map[string]interface{}{key: Benchmark{NsPerOp: 100}}, - }, - { - ID: 5, - Name: "BenchmarkTwo", - Result: gtr.Fail, - Data: map[string]interface{}{}, - }, - }, - Output: []string{"goarch: amd64"}, - }, - { - Name: "package/failing1", - Timestamp: testTimestamp, - BuildError: gtr.Error{ - ID: 6, - Name: "package/failing1", - Cause: "[build failed]", - Output: []string{"error message"}, - }, - }, - }, - } - - parser := NewParser(TimestampFunc(testTimestampFunc)) - got := parser.report(events) - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("FromEvents report incorrect, diff (-want, +got):\n%v", diff) - } -} - -func TestSubtestModes(t *testing.T) { - events := []Event{ - {Type: "run_test", Name: "TestParent"}, - {Type: "output", Data: "TestParent before"}, - {Type: "run_test", Name: "TestParent/Subtest#1"}, - {Type: "output", Data: "Subtest#1 output"}, - {Type: "run_test", Name: "TestParent/Subtest#2"}, - {Type: "output", Data: "Subtest#2 output"}, - {Type: "cont_test", Name: "TestParent"}, - {Type: "output", Data: "TestParent after"}, - {Type: "end_test", Name: "TestParent", Result: "PASS", Duration: 1 * time.Millisecond}, - {Type: "end_test", Name: "TestParent/Subtest#1", Result: "FAIL", Duration: 2 * time.Millisecond}, - {Type: "end_test", Name: "TestParent/Subtest#2", Result: "PASS", Duration: 3 * time.Millisecond}, - {Type: "output", Data: "output"}, - {Type: "summary", Result: "FAIL", Name: "package/name", Duration: 1 * time.Millisecond}, - } - - tests := []struct { - name string - mode SubtestMode - want gtr.Report - }{ - { - name: "ignore subtest parent results", - mode: IgnoreParentResults, - want: gtr.Report{ - Packages: []gtr.Package{ - { - Name: "package/name", - Duration: 1 * time.Millisecond, - Timestamp: testTimestamp, - Tests: []gtr.Test{ - { - ID: 1, - Name: "TestParent", - Duration: 1 * time.Millisecond, - Result: gtr.Pass, - Output: []string{"TestParent before", "TestParent after"}, - Data: map[string]interface{}{}, - }, - { - ID: 2, - Name: "TestParent/Subtest#1", - Duration: 2 * time.Millisecond, - Result: gtr.Fail, - Output: []string{"Subtest#1 output"}, - Data: map[string]interface{}{}, - }, - { - ID: 3, - Name: "TestParent/Subtest#2", - Duration: 3 * time.Millisecond, - Result: gtr.Pass, - Output: []string{"Subtest#2 output"}, - Data: map[string]interface{}{}, - }, - }, - Output: []string{"output"}, - }, - }, - }, - }, - { - name: "exclude subtest parents", - mode: ExcludeParents, - want: gtr.Report{ - Packages: []gtr.Package{ - { - Name: "package/name", - Duration: 1 * time.Millisecond, - Timestamp: testTimestamp, - Tests: []gtr.Test{ - { - ID: 2, - Name: "TestParent/Subtest#1", - Duration: 2 * time.Millisecond, - Result: gtr.Fail, - Output: []string{"Subtest#1 output"}, - Data: map[string]interface{}{}, - }, - { - ID: 3, - Name: "TestParent/Subtest#2", - Duration: 3 * time.Millisecond, - Result: gtr.Pass, - Output: []string{"Subtest#2 output"}, - Data: map[string]interface{}{}, - }, - }, - Output: []string{"TestParent before", "TestParent after", "output"}, - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - parser := NewParser(TimestampFunc(testTimestampFunc), SetSubtestMode(test.mode)) - got := parser.report(events) - if diff := cmp.Diff(test.want, got); diff != "" { - t.Errorf("Invalid report created from events, diff (-want, +got):\n%v", diff) - } - }) - } -} diff --git a/parser/gotest/report_builder.go b/parser/gotest/report_builder.go index 2c0d612..e005579 100644 --- a/parser/gotest/report_builder.go +++ b/parser/gotest/report_builder.go @@ -1,6 +1,7 @@ package gotest import ( + "fmt" "strings" "time" @@ -49,6 +50,39 @@ func newReportBuilder() *reportBuilder { } } +// ProcessEvent gives an event to this reportBuilder to be processed for this +// report. +func (b *reportBuilder) ProcessEvent(ev Event) { + switch ev.Type { + case "run_test": + b.CreateTest(ev.Name) + case "pause_test": + b.PauseTest(ev.Name) + case "cont_test": + b.ContinueTest(ev.Name) + case "end_test": + b.EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent) + case "run_benchmark": + b.CreateBenchmark(ev.Name) + case "benchmark": + b.BenchmarkResult(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp) + case "end_benchmark": + b.EndBenchmark(ev.Name, ev.Result) + case "status": + b.End() + case "summary": + b.CreatePackage(ev.Name, ev.Result, ev.Duration, ev.Data) + case "coverage": + b.Coverage(ev.CovPct, ev.CovPackages) + case "build_output": + b.CreateBuildError(ev.Name) + case "output": + b.AppendOutput(ev.Data) + default: + fmt.Printf("reportBuilder: unhandled event type: %v\n", ev.Type) + } +} + // newID returns a new unique id and sets the active context this id. func (b *reportBuilder) newID() int { id := b.nextID diff --git a/parser/gotest/report_builder_test.go b/parser/gotest/report_builder_test.go index e986fb0..4d88b2f 100644 --- a/parser/gotest/report_builder_test.go +++ b/parser/gotest/report_builder_test.go @@ -2,12 +2,239 @@ package gotest import ( "testing" + "time" "github.com/jstemmer/go-junit-report/v2/gtr" "github.com/google/go-cmp/cmp" ) +func TestReport(t *testing.T) { + events := []Event{ + {Type: "run_test", Name: "TestOne"}, + {Type: "output", Data: "\tHello"}, + {Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 1 * time.Millisecond}, + {Type: "status", Result: "PASS"}, + {Type: "run_test", Name: "TestSkip"}, + {Type: "end_test", Name: "TestSkip", Result: "SKIP", Duration: 1 * time.Millisecond}, + {Type: "summary", Result: "ok", Name: "package/name", Duration: 1 * time.Millisecond}, + {Type: "run_test", Name: "TestOne"}, + {Type: "output", Data: "\tfile_test.go:10: error"}, + {Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 1 * time.Millisecond}, + {Type: "status", Result: "FAIL"}, + {Type: "summary", Result: "FAIL", Name: "package/name2", Duration: 1 * time.Millisecond}, + {Type: "output", Data: "goarch: amd64"}, + {Type: "run_benchmark", Name: "BenchmarkOne"}, + {Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 100}, + {Type: "end_benchmark", Name: "BenchmarkOne", Result: "BENCH"}, + {Type: "run_benchmark", Name: "BenchmarkTwo"}, + {Type: "benchmark", Name: "BenchmarkTwo"}, + {Type: "end_benchmark", Name: "BenchmarkTwo", Result: "FAIL"}, + {Type: "status", Result: "PASS"}, + {Type: "summary", Result: "ok", Name: "package/name3", Duration: 1234 * time.Millisecond}, + {Type: "build_output", Name: "package/failing1"}, + {Type: "output", Data: "error message"}, + {Type: "summary", Result: "FAIL", Name: "package/failing1", Data: "[build failed]"}, + } + want := gtr.Report{ + Packages: []gtr.Package{ + { + Name: "package/name", + Duration: 1 * time.Millisecond, + Timestamp: testTimestamp, + Tests: []gtr.Test{ + { + ID: 1, + Name: "TestOne", + Duration: 1 * time.Millisecond, + Result: gtr.Pass, + Output: []string{ + "\tHello", // TODO: strip tabs? + }, + Data: map[string]interface{}{}, + }, + { + ID: 2, + Name: "TestSkip", + Duration: 1 * time.Millisecond, + Result: gtr.Skip, + Data: map[string]interface{}{}, + }, + }, + }, + { + Name: "package/name2", + Duration: 1 * time.Millisecond, + Timestamp: testTimestamp, + Tests: []gtr.Test{ + { + ID: 3, + Name: "TestOne", + Duration: 1 * time.Millisecond, + Result: gtr.Fail, + Output: []string{ + "\tfile_test.go:10: error", + }, + Data: map[string]interface{}{}, + }, + }, + }, + { + Name: "package/name3", + Duration: 1234 * time.Millisecond, + Timestamp: testTimestamp, + Tests: []gtr.Test{ + { + ID: 4, + Name: "BenchmarkOne", + Result: gtr.Pass, + Data: map[string]interface{}{key: Benchmark{NsPerOp: 100}}, + }, + { + ID: 5, + Name: "BenchmarkTwo", + Result: gtr.Fail, + Data: map[string]interface{}{}, + }, + }, + Output: []string{"goarch: amd64"}, + }, + { + Name: "package/failing1", + Timestamp: testTimestamp, + BuildError: gtr.Error{ + ID: 6, + Name: "package/failing1", + Cause: "[build failed]", + Output: []string{"error message"}, + }, + }, + }, + } + + rb := newReportBuilder() + rb.timestampFunc = testTimestampFunc + for _, ev := range events { + rb.ProcessEvent(ev) + } + got := rb.Build() + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("FromEvents report incorrect, diff (-want, +got):\n%v", diff) + } +} + +func TestSubtestModes(t *testing.T) { + events := []Event{ + {Type: "run_test", Name: "TestParent"}, + {Type: "output", Data: "TestParent before"}, + {Type: "run_test", Name: "TestParent/Subtest#1"}, + {Type: "output", Data: "Subtest#1 output"}, + {Type: "run_test", Name: "TestParent/Subtest#2"}, + {Type: "output", Data: "Subtest#2 output"}, + {Type: "cont_test", Name: "TestParent"}, + {Type: "output", Data: "TestParent after"}, + {Type: "end_test", Name: "TestParent", Result: "PASS", Duration: 1 * time.Millisecond}, + {Type: "end_test", Name: "TestParent/Subtest#1", Result: "FAIL", Duration: 2 * time.Millisecond}, + {Type: "end_test", Name: "TestParent/Subtest#2", Result: "PASS", Duration: 3 * time.Millisecond}, + {Type: "output", Data: "output"}, + {Type: "summary", Result: "FAIL", Name: "package/name", Duration: 1 * time.Millisecond}, + } + + tests := []struct { + name string + mode SubtestMode + want gtr.Report + }{ + { + name: "ignore subtest parent results", + mode: IgnoreParentResults, + want: gtr.Report{ + Packages: []gtr.Package{ + { + Name: "package/name", + Duration: 1 * time.Millisecond, + Timestamp: testTimestamp, + Tests: []gtr.Test{ + { + ID: 1, + Name: "TestParent", + Duration: 1 * time.Millisecond, + Result: gtr.Pass, + Output: []string{"TestParent before", "TestParent after"}, + Data: map[string]interface{}{}, + }, + { + ID: 2, + Name: "TestParent/Subtest#1", + Duration: 2 * time.Millisecond, + Result: gtr.Fail, + Output: []string{"Subtest#1 output"}, + Data: map[string]interface{}{}, + }, + { + ID: 3, + Name: "TestParent/Subtest#2", + Duration: 3 * time.Millisecond, + Result: gtr.Pass, + Output: []string{"Subtest#2 output"}, + Data: map[string]interface{}{}, + }, + }, + Output: []string{"output"}, + }, + }, + }, + }, + { + name: "exclude subtest parents", + mode: ExcludeParents, + want: gtr.Report{ + Packages: []gtr.Package{ + { + Name: "package/name", + Duration: 1 * time.Millisecond, + Timestamp: testTimestamp, + Tests: []gtr.Test{ + { + ID: 2, + Name: "TestParent/Subtest#1", + Duration: 2 * time.Millisecond, + Result: gtr.Fail, + Output: []string{"Subtest#1 output"}, + Data: map[string]interface{}{}, + }, + { + ID: 3, + Name: "TestParent/Subtest#2", + Duration: 3 * time.Millisecond, + Result: gtr.Pass, + Output: []string{"Subtest#2 output"}, + Data: map[string]interface{}{}, + }, + }, + Output: []string{"TestParent before", "TestParent after", "output"}, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + rb := newReportBuilder() + rb.timestampFunc = testTimestampFunc + rb.subtestMode = test.mode + for _, ev := range events { + rb.ProcessEvent(ev) + } + got := rb.Build() + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("Invalid report created from events, diff (-want, +got):\n%v", diff) + } + }) + } +} + func TestGroupBenchmarksByName(t *testing.T) { tests := []struct { name string