...

Source file src/cmd/test2json/main.go

     1	// Copyright 2017 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Test2json converts go test output to a machine-readable JSON stream.
     6	//
     7	// Usage:
     8	//
     9	//	go tool test2json [-p pkg] [-t] [./pkg.test -test.v]
    10	//
    11	// Test2json runs the given test command and converts its output to JSON;
    12	// with no command specified, test2json expects test output on standard input.
    13	// It writes a corresponding stream of JSON events to standard output.
    14	// There is no unnecessary input or output buffering, so that
    15	// the JSON stream can be read for “live updates” of test status.
    16	//
    17	// The -p flag sets the package reported in each test event.
    18	//
    19	// The -t flag requests that time stamps be added to each test event.
    20	//
    21	// Note that test2json is only intended for converting a single test
    22	// binary's output. To convert the output of a "go test" command,
    23	// use "go test -json" instead of invoking test2json directly.
    24	//
    25	// Output Format
    26	//
    27	// The JSON stream is a newline-separated sequence of TestEvent objects
    28	// corresponding to the Go struct:
    29	//
    30	//	type TestEvent struct {
    31	//		Time    time.Time // encodes as an RFC3339-format string
    32	//		Action  string
    33	//		Package string
    34	//		Test    string
    35	//		Elapsed float64 // seconds
    36	//		Output  string
    37	//	}
    38	//
    39	// The Time field holds the time the event happened.
    40	// It is conventionally omitted for cached test results.
    41	//
    42	// The Action field is one of a fixed set of action descriptions:
    43	//
    44	//	run    - the test has started running
    45	//	pause  - the test has been paused
    46	//	cont   - the test has continued running
    47	//	pass   - the test passed
    48	//	bench  - the benchmark printed log output but did not fail
    49	//	fail   - the test or benchmark failed
    50	//	output - the test printed output
    51	//	skip   - the test was skipped or the package contained no tests
    52	//
    53	// The Package field, if present, specifies the package being tested.
    54	// When the go command runs parallel tests in -json mode, events from
    55	// different tests are interlaced; the Package field allows readers to
    56	// separate them.
    57	//
    58	// The Test field, if present, specifies the test, example, or benchmark
    59	// function that caused the event. Events for the overall package test
    60	// do not set Test.
    61	//
    62	// The Elapsed field is set for "pass" and "fail" events. It gives the time
    63	// elapsed for the specific test or the overall package test that passed or failed.
    64	//
    65	// The Output field is set for Action == "output" and is a portion of the test's output
    66	// (standard output and standard error merged together). The output is
    67	// unmodified except that invalid UTF-8 output from a test is coerced
    68	// into valid UTF-8 by use of replacement characters. With that one exception,
    69	// the concatenation of the Output fields of all output events is the exact
    70	// output of the test execution.
    71	//
    72	// When a benchmark runs, it typically produces a single line of output
    73	// giving timing results. That line is reported in an event with Action == "output"
    74	// and no Test field. If a benchmark logs output or reports a failure
    75	// (for example, by using b.Log or b.Error), that extra output is reported
    76	// as a sequence of events with Test set to the benchmark name, terminated
    77	// by a final event with Action == "bench" or "fail".
    78	// Benchmarks have no events with Action == "run", "pause", or "cont".
    79	//
    80	package main
    81	
    82	import (
    83		"flag"
    84		"fmt"
    85		"io"
    86		"os"
    87		"os/exec"
    88	
    89		"cmd/internal/test2json"
    90	)
    91	
    92	var (
    93		flagP = flag.String("p", "", "report `pkg` as the package being tested in each event")
    94		flagT = flag.Bool("t", false, "include timestamps in events")
    95	)
    96	
    97	func usage() {
    98		fmt.Fprintf(os.Stderr, "usage: go tool test2json [-p pkg] [-t] [./pkg.test -test.v]\n")
    99		os.Exit(2)
   100	}
   101	
   102	func main() {
   103		flag.Usage = usage
   104		flag.Parse()
   105	
   106		var mode test2json.Mode
   107		if *flagT {
   108			mode |= test2json.Timestamp
   109		}
   110		c := test2json.NewConverter(os.Stdout, *flagP, mode)
   111		defer c.Close()
   112	
   113		if flag.NArg() == 0 {
   114			io.Copy(c, os.Stdin)
   115		} else {
   116			args := flag.Args()
   117			cmd := exec.Command(args[0], args[1:]...)
   118			w := &countWriter{0, c}
   119			cmd.Stdout = w
   120			cmd.Stderr = w
   121			if err := cmd.Run(); err != nil {
   122				if w.n > 0 {
   123					// Assume command printed why it failed.
   124				} else {
   125					fmt.Fprintf(c, "test2json: %v\n", err)
   126				}
   127				c.Close()
   128				os.Exit(1)
   129			}
   130		}
   131	}
   132	
   133	type countWriter struct {
   134		n int64
   135		w io.Writer
   136	}
   137	
   138	func (w *countWriter) Write(b []byte) (int, error) {
   139		w.n += int64(len(b))
   140		return w.w.Write(b)
   141	}
   142	

View as plain text