mirror of
https://github.com/jstemmer/go-junit-report.git
synced 2025-04-04 20:50:14 -05:00
parser/gotest: Create JSONEventReader in internal reader package
The JSONEventReader implements reading lines with metadata and replaces the gotest.jsonReader struct.
This commit is contained in:
parent
bd21d54501
commit
85f2715ac9
@ -3,7 +3,10 @@ package reader
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LineReader is an interface to read lines with optional Metadata.
|
||||
@ -68,3 +71,52 @@ func (r *LimitedLineReader) ReadLine() (string, *Metadata, error) {
|
||||
}
|
||||
return buf.String(), nil, nil
|
||||
}
|
||||
|
||||
// Event represents a JSON event emitted by `go test -json`.
|
||||
type Event struct {
|
||||
Time time.Time
|
||||
Action string
|
||||
Package string
|
||||
Test string
|
||||
Elapsed float64 // seconds
|
||||
Output string
|
||||
}
|
||||
|
||||
// JSONEventReader reads JSON events from an io.Reader object.
|
||||
type JSONEventReader struct {
|
||||
r *LimitedLineReader
|
||||
}
|
||||
|
||||
var _ LineReader = &JSONEventReader{}
|
||||
|
||||
// jsonLineLimit is the maximum size of a single JSON line emitted by `go test
|
||||
// -json`.
|
||||
const jsonLineLimit = 64 * 1024
|
||||
|
||||
// NewJSONEventReader returns a JSONEventReader to read the data in JSON
|
||||
// events from r.
|
||||
func NewJSONEventReader(r io.Reader) *JSONEventReader {
|
||||
return &JSONEventReader{NewLimitedLineReader(r, jsonLineLimit)}
|
||||
}
|
||||
|
||||
// ReadLine returns the next line from the underlying reader.
|
||||
func (r *JSONEventReader) ReadLine() (string, *Metadata, error) {
|
||||
for {
|
||||
line, _, err := r.r.ReadLine()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if len(line) == 0 || line[0] != '{' {
|
||||
return line, nil, nil
|
||||
}
|
||||
event := &Event{}
|
||||
if err := json.Unmarshal([]byte(line), event); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if event.Output == "" {
|
||||
// Skip events without output
|
||||
continue
|
||||
}
|
||||
return strings.TrimSuffix(event.Output, "\n"), &Metadata{Package: event.Package}, nil
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
const testingLimit = 4 * 1024 * 1024
|
||||
@ -66,3 +68,34 @@ func TestLimitedLineReader(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONEventReader(t *testing.T) {
|
||||
input := `some other output
|
||||
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK"}
|
||||
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK","Output":"=== RUN TestOK\n"}
|
||||
`
|
||||
want := []struct {
|
||||
line string
|
||||
metadata *Metadata
|
||||
}{
|
||||
{"some other output", nil},
|
||||
{"=== RUN TestOK", &Metadata{Package: "package/name/ok"}},
|
||||
}
|
||||
|
||||
r := NewJSONEventReader(strings.NewReader(input))
|
||||
for i := 0; i < len(want); i++ {
|
||||
line, metadata, err := r.ReadLine()
|
||||
if err == io.EOF {
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("ReadLine() returned error %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want[i].line, line); diff != "" {
|
||||
t.Errorf("ReadLine() returned incorrect line, diff (-want, +got):\n%s\n", diff)
|
||||
}
|
||||
if diff := cmp.Diff(want[i].metadata, metadata); diff != "" {
|
||||
t.Errorf("ReadLine() Returned incorrect metadata, diff (-want, +got):\n%s\n", diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
package gotest
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/jstemmer/go-junit-report/v2/gtr"
|
||||
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/reader"
|
||||
)
|
||||
|
||||
// NewJSONParser returns a new Go test json output parser.
|
||||
@ -22,56 +20,10 @@ type JSONParser struct {
|
||||
// Parse parses Go test json output from the given io.Reader r and returns
|
||||
// gtr.Report.
|
||||
func (p *JSONParser) Parse(r io.Reader) (gtr.Report, error) {
|
||||
return p.gp.Parse(newJSONReader(r))
|
||||
return p.gp.parse(reader.NewJSONEventReader(r))
|
||||
}
|
||||
|
||||
// Events returns the events created by the parser.
|
||||
func (p *JSONParser) Events() []Event {
|
||||
return p.gp.Events()
|
||||
}
|
||||
|
||||
type jsonEvent struct {
|
||||
Time time.Time
|
||||
Action string
|
||||
Package string
|
||||
Test string
|
||||
Elapsed float64 // seconds
|
||||
Output string
|
||||
}
|
||||
|
||||
type jsonReader struct {
|
||||
r *bufio.Reader
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func newJSONReader(reader io.Reader) *jsonReader {
|
||||
return &jsonReader{r: bufio.NewReader(reader)}
|
||||
}
|
||||
|
||||
func (j *jsonReader) Read(p []byte) (int, error) {
|
||||
var err error
|
||||
for len(j.buf) == 0 {
|
||||
j.buf, err = j.readNextLine()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
n := copy(p, j.buf)
|
||||
j.buf = j.buf[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (j jsonReader) readNextLine() ([]byte, error) {
|
||||
line, err := j.r.ReadBytes('\n')
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 || line[0] != '{' {
|
||||
return line, nil
|
||||
}
|
||||
var event jsonEvent
|
||||
if err := json.Unmarshal(line, &event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(event.Output), nil
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
package gotest
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
var input = `some other output
|
||||
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK"}
|
||||
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK","Output":"=== RUN TestOK\n"}
|
||||
`
|
||||
|
||||
func TestJSONReaderReadAll(t *testing.T) {
|
||||
r := newJSONReader(strings.NewReader(input))
|
||||
got, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
want := `some other output
|
||||
=== RUN TestOK
|
||||
`
|
||||
|
||||
if diff := cmp.Diff(want, string(got)); diff != "" {
|
||||
t.Errorf("unexpected result from jsonReader, diff (-want, +got):\n%s\n", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONReaderReadSmallBuffer(t *testing.T) {
|
||||
expected := [][]byte{
|
||||
[]byte("some"),
|
||||
[]byte(" oth"),
|
||||
[]byte("er o"),
|
||||
[]byte("utpu"),
|
||||
[]byte("t\n"),
|
||||
[]byte("=== "),
|
||||
[]byte("RUN "),
|
||||
[]byte(" Te"),
|
||||
[]byte("stOK"),
|
||||
[]byte("\n"),
|
||||
}
|
||||
|
||||
r := newJSONReader(strings.NewReader(input))
|
||||
buf := make([]byte, 4)
|
||||
for _, want := range expected {
|
||||
n, err := r.Read(buf)
|
||||
if err != nil {
|
||||
t.Fatalf("Read error: %v", err)
|
||||
}
|
||||
|
||||
got := buf[:n]
|
||||
if diff := cmp.Diff(string(want), string(got)); diff != "" {
|
||||
t.Fatalf("unexpected result from jsonReader, diff (-want, +got):\n%s\n", diff)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := r.Read(buf)
|
||||
if err != io.EOF {
|
||||
t.Fatalf("unexpected error from jsonReader: got %v, want %v", err, io.EOF)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user