summaryrefslogtreecommitdiffstats
path: root/src/cmd/test2json/main.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cmd/test2json/main.go149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/cmd/test2json/main.go b/src/cmd/test2json/main.go
new file mode 100644
index 0000000..fdf681a
--- /dev/null
+++ b/src/cmd/test2json/main.go
@@ -0,0 +1,149 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test2json converts go test output to a machine-readable JSON stream.
+//
+// Usage:
+//
+// go tool test2json [-p pkg] [-t] [./pkg.test -test.v [-test.paniconexit0]]
+//
+// Test2json runs the given test command and converts its output to JSON;
+// with no command specified, test2json expects test output on standard input.
+// It writes a corresponding stream of JSON events to standard output.
+// There is no unnecessary input or output buffering, so that
+// the JSON stream can be read for “live updates” of test status.
+//
+// The -p flag sets the package reported in each test event.
+//
+// The -t flag requests that time stamps be added to each test event.
+//
+// The test must be invoked with -test.v. Additionally passing
+// -test.paniconexit0 will cause test2json to exit with a non-zero
+// status if one of the tests being run calls os.Exit(0).
+//
+// Note that test2json is only intended for converting a single test
+// binary's output. To convert the output of a "go test" command,
+// use "go test -json" instead of invoking test2json directly.
+//
+// Output Format
+//
+// The JSON stream is a newline-separated sequence of TestEvent objects
+// corresponding to the Go struct:
+//
+// type TestEvent struct {
+// Time time.Time // encodes as an RFC3339-format string
+// Action string
+// Package string
+// Test string
+// Elapsed float64 // seconds
+// Output string
+// }
+//
+// The Time field holds the time the event happened.
+// It is conventionally omitted for cached test results.
+//
+// The Action field is one of a fixed set of action descriptions:
+//
+// run - the test has started running
+// pause - the test has been paused
+// cont - the test has continued running
+// pass - the test passed
+// bench - the benchmark printed log output but did not fail
+// fail - the test or benchmark failed
+// output - the test printed output
+// skip - the test was skipped or the package contained no tests
+//
+// The Package field, if present, specifies the package being tested.
+// When the go command runs parallel tests in -json mode, events from
+// different tests are interlaced; the Package field allows readers to
+// separate them.
+//
+// The Test field, if present, specifies the test, example, or benchmark
+// function that caused the event. Events for the overall package test
+// do not set Test.
+//
+// The Elapsed field is set for "pass" and "fail" events. It gives the time
+// elapsed for the specific test or the overall package test that passed or failed.
+//
+// The Output field is set for Action == "output" and is a portion of the test's output
+// (standard output and standard error merged together). The output is
+// unmodified except that invalid UTF-8 output from a test is coerced
+// into valid UTF-8 by use of replacement characters. With that one exception,
+// the concatenation of the Output fields of all output events is the exact
+// output of the test execution.
+//
+// When a benchmark runs, it typically produces a single line of output
+// giving timing results. That line is reported in an event with Action == "output"
+// and no Test field. If a benchmark logs output or reports a failure
+// (for example, by using b.Log or b.Error), that extra output is reported
+// as a sequence of events with Test set to the benchmark name, terminated
+// by a final event with Action == "bench" or "fail".
+// Benchmarks have no events with Action == "run", "pause", or "cont".
+//
+package main
+
+import (
+ "flag"
+ "fmt"
+ exec "internal/execabs"
+ "io"
+ "os"
+
+ "cmd/internal/test2json"
+)
+
+var (
+ flagP = flag.String("p", "", "report `pkg` as the package being tested in each event")
+ flagT = flag.Bool("t", false, "include timestamps in events")
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: go tool test2json [-p pkg] [-t] [./pkg.test -test.v]\n")
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ var mode test2json.Mode
+ if *flagT {
+ mode |= test2json.Timestamp
+ }
+ c := test2json.NewConverter(os.Stdout, *flagP, mode)
+ defer c.Close()
+
+ if flag.NArg() == 0 {
+ io.Copy(c, os.Stdin)
+ } else {
+ args := flag.Args()
+ cmd := exec.Command(args[0], args[1:]...)
+ w := &countWriter{0, c}
+ cmd.Stdout = w
+ cmd.Stderr = w
+ err := cmd.Run()
+ if err != nil {
+ if w.n > 0 {
+ // Assume command printed why it failed.
+ } else {
+ fmt.Fprintf(c, "test2json: %v\n", err)
+ }
+ }
+ c.Exited(err)
+ if err != nil {
+ c.Close()
+ os.Exit(1)
+ }
+ }
+}
+
+type countWriter struct {
+ n int64
+ w io.Writer
+}
+
+func (w *countWriter) Write(b []byte) (int, error) {
+ w.n += int64(len(b))
+ return w.w.Write(b)
+}