Skip to content

Commit

Permalink
watch: set breakpoint on test function when debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
dnephin committed Nov 22, 2020
1 parent f3e8321 commit 7b1a76c
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 52 deletions.
3 changes: 1 addition & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ issues:
- linters: [stylecheck]
text: 'ST1000: at least one file in a package should have a package comment'
- linters: [errcheck]
path: log/
text: 'Error return value of `out.WriteString` is not checked'
text: 'Error return value of `.*\.WriteString` is not checked'
- linters: [unparam]
text: 'result .* is always'
- linters: [unparam]
Expand Down
26 changes: 0 additions & 26 deletions cmd/delve.go

This file was deleted.

24 changes: 0 additions & 24 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/fatih/color"
"github.com/pkg/errors"
"github.com/spf13/pflag"
"gotest.tools/gotestsum/internal/filewatcher"
"gotest.tools/gotestsum/log"
"gotest.tools/gotestsum/testjson"
)
Expand Down Expand Up @@ -41,29 +40,6 @@ func Run(name string, args []string) error {
return run(opts)
}

func runWatcher(opts *options) error {
fn := func(runOpts filewatcher.RunOptions) error {
if runOpts.Debug {
o := delveOpts{
pkgPath: runOpts.PkgPath,
args: opts.args,
}
if err := runDelve(o); !isExitCoder(err) {
return err
}
return nil
}

opts := *opts
opts.packages = []string{runOpts.PkgPath}
if err := run(&opts); !isExitCoder(err) {
return err
}
return nil
}
return filewatcher.Watch(opts.packages, fn)
}

func setupFlags(name string) (*pflag.FlagSet, *options) {
opts := &options{
hideSummary: newHideSummaryValue(),
Expand Down
1 change: 1 addition & 0 deletions cmd/rerunfails_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func TestGoTestRunFlagFromTestCases(t *testing.T) {
expected: "-test.run=^TestOne$/^SubtestA$",
},
}

for name := range testCases {
t.Run(name, func(t *testing.T) {
fn(t, testCases[name])
Expand Down
128 changes: 128 additions & 0 deletions cmd/watch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package cmd

import (
"bufio"
"context"
"fmt"
"io/ioutil"
"os"
"os/exec"

"gotest.tools/gotestsum/internal/filewatcher"
"gotest.tools/gotestsum/testjson"
)

func runWatcher(opts *options) error {
w := &watchRuns{opts: *opts}
return filewatcher.Watch(opts.packages, w.run)
}

type watchRuns struct {
opts options
prevExec *testjson.Execution
}

func (w *watchRuns) run(runOpts filewatcher.RunOptions) error {
if runOpts.Debug {
path, cleanup, err := delveInitFile(w.prevExec)
if err != nil {
return err
}
defer cleanup()
o := delveOpts{
pkgPath: runOpts.PkgPath,
args: w.opts.args,
initFilePath: path,
}
if err := runDelve(o); !isExitCoder(err) {
return err
}
return nil
}

opts := w.opts
opts.packages = []string{runOpts.PkgPath}
var err error
if w.prevExec, err = runSingle(&opts); !isExitCoder(err) {
return err
}
return nil
}

// runSingle is similar to run. It doesn't support rerun-fails. It may be
// possible to share runSingle with run, but the defer close on the handler
// would require at least 3 return values, so for now it is a copy.
func runSingle(opts *options) (*testjson.Execution, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if err := opts.Validate(); err != nil {
return nil, err
}

goTestProc, err := startGoTestFn(ctx, goTestCmdArgs(opts, rerunOpts{}))
if err != nil {
return nil, err
}

handler, err := newEventHandler(opts)
if err != nil {
return nil, err
}
defer handler.Close() // nolint: errcheck
cfg := testjson.ScanConfig{
Stdout: goTestProc.stdout,
Stderr: goTestProc.stderr,
Handler: handler,
Stop: cancel,
}
exec, err := testjson.ScanTestOutput(cfg)
if err != nil {
return exec, finishRun(opts, exec, err)
}
err = goTestProc.cmd.Wait()
return exec, finishRun(opts, exec, err)
}

func delveInitFile(exec *testjson.Execution) (string, func(), error) {
fh, err := ioutil.TempFile("", "gotestsum-delve-init")
if err != nil {
return "", nil, err
}
remove := func() {
os.Remove(fh.Name()) // nolint: errcheck
}

buf := bufio.NewWriter(fh)
for _, tc := range exec.Failed() {
fmt.Fprintf(buf, "break %s\n", tc.Test.Name())
}
buf.WriteString("continue\n")
if err := buf.Flush(); err != nil {
remove()
return "", nil, err
}
return fh.Name(), remove, nil
}

type delveOpts struct {
pkgPath string
args []string
initFilePath string
}

func runDelve(opts delveOpts) error {
pkg := opts.pkgPath
args := []string{"dlv", "test", "--wd", pkg}
args = append(args, "--output", "gotestsum-watch-debug.test")
args = append(args, "--init", opts.initFilePath)
args = append(args, pkg, "--")
args = append(args, opts.args...)

cmd := exec.Command(args[0], args[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

return cmd.Run()
}

0 comments on commit 7b1a76c

Please sign in to comment.