Skip to content

Commit 1af1851

Browse files
committed
support reading stdout/stderr from streams
It can be useful to let the user run the test command(s) itself, for example when complex shell scripts are involved which need to invoke `go test` multiple times. With -stdin, the `go test` stdout is expected on stdin of gotestsum, so it can be used in a pipe. To detect abnormal termination of the test commands, bash with "set -o pipefail" should be used. Beware that such failures are not detected by gotestsum. To also capture stderr with gotestsum, stderr must get redirected like this: mkfifo /tmp/pipe go test ... 2>/tmp/pipe | gotestsum -stdin -stderr 3 3</tmp/pipe
1 parent 8253d0e commit 1af1851

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

cmd/main.go

+39-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"fmt"
@@ -70,6 +71,10 @@ func setupFlags(name string) (*pflag.FlagSet, *options) {
7071
"use different icons, see help for options")
7172
flags.BoolVar(&opts.rawCommand, "raw-command", false,
7273
"don't prepend 'go test -json' to the 'go test' command")
74+
flags.BoolVar(&opts.readStdin, "stdin", false,
75+
"don't run any command, instead read go test stdout from stdin")
76+
flags.IntVar(&opts.readStderrFD, "stderr", 0,
77+
"read go test stderr from a certain `file descriptor` (only valid in combination with -stdin)")
7378
flags.BoolVar(&opts.ignoreNonJSONOutputLines, "ignore-non-json-output-lines", false,
7479
"write non-JSON 'go test' output lines to stderr instead of failing")
7580
flags.Lookup("ignore-non-json-output-lines").Hidden = true
@@ -176,6 +181,8 @@ type options struct {
176181
formatOptions testjson.FormatOptions
177182
debug bool
178183
rawCommand bool
184+
readStdin bool
185+
readStderrFD int
179186
ignoreNonJSONOutputLines bool
180187
jsonFile string
181188
jsonFileTimingEvents string
@@ -212,6 +219,15 @@ func (o options) Validate() error {
212219
return fmt.Errorf("-failfast can not be used with --rerun-fails " +
213220
"because not all test cases will run")
214221
}
222+
if o.rawCommand && o.readStdin {
223+
return errors.New("-stdin and -rawCommand are mutually exclusive")
224+
}
225+
if o.readStdin && len(o.args) > 0 {
226+
return fmt.Errorf("-stdin does not support additional arguments (%q)", o.args)
227+
}
228+
if o.readStderrFD > 0 && !o.readStdin {
229+
return errors.New("-stderr depends on -stdin")
230+
}
215231
return nil
216232
}
217233

@@ -264,29 +280,45 @@ func run(opts *options) error {
264280
return err
265281
}
266282

267-
goTestProc, err := startGoTestFn(ctx, "", goTestCmdArgs(opts, rerunOpts{}))
268-
if err != nil {
269-
return err
270-
}
271-
272283
handler, err := newEventHandler(opts)
273284
if err != nil {
274285
return err
275286
}
276287
defer handler.Close() // nolint: errcheck
277288
cfg := testjson.ScanConfig{
278-
Stdout: goTestProc.stdout,
279-
Stderr: goTestProc.stderr,
280289
Handler: handler,
281290
Stop: cancel,
282291
IgnoreNonJSONOutputLines: opts.ignoreNonJSONOutputLines,
283292
}
293+
294+
var goTestProc *proc
295+
if opts.readStdin {
296+
cfg.Stdout = os.Stdin
297+
if opts.readStderrFD > 0 {
298+
cfg.Stderr = os.NewFile(uintptr(opts.readStderrFD), fmt.Sprintf("go test stderr on fd %d", opts.stderr))
299+
} else {
300+
cfg.Stderr = bytes.NewReader(nil)
301+
}
302+
} else {
303+
p, err := startGoTestFn(ctx, "", goTestCmdArgs(opts, rerunOpts{}))
304+
if err != nil {
305+
return err
306+
}
307+
goTestProc = p
308+
cfg.Stdout = p.stdout
309+
cfg.Stderr = p.stderr
310+
}
311+
284312
exec, err := testjson.ScanTestOutput(cfg)
285313
handler.Flush()
286314
if err != nil {
287315
return finishRun(opts, exec, err)
288316
}
289317

318+
if opts.readStdin {
319+
return finishRun(opts, exec, nil)
320+
}
321+
290322
exitErr := goTestProc.cmd.Wait()
291323
if signum := atomic.LoadInt32(&goTestProc.signal); signum != 0 {
292324
return finishRun(opts, exec, exitError{num: signalExitCode + int(signum)})

cmd/testdata/gotestsum-help-text

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Flags:
2626
--rerun-fails-max-failures int do not rerun any tests if the initial run has more than this number of failures (default 10)
2727
--rerun-fails-report string write a report to the file, of the tests that were rerun
2828
--rerun-fails-run-root-test rerun the entire root testcase when any of its subtests fail, instead of only the failed subtest
29+
--stderr file descriptor read go test stderr from a certain file descriptor (only valid in combination with -stdin)
30+
--stdin don't run any command, instead read go test stdout from stdin
2931
--version show version and exit
3032
--watch watch go files, and run tests when a file is modified
3133
--watch-chdir in watch mode change the working directory to the directory with the modified file before running tests

0 commit comments

Comments
 (0)