Skip to content

Commit

Permalink
running tests with vgt and
Browse files Browse the repository at this point in the history
  • Loading branch information
roblaszczak committed Oct 15, 2024
1 parent 312c877 commit d5a65b6
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 35 deletions.
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ More information can be found in the [TODO] blog post.

## Installation

```
```bash
go install -u github.com/roblaszczak/vgt
```

Expand All @@ -22,29 +22,38 @@ You can also run without installing by running `go run github.com/roblaszczak/vg

For visualising test results, run `go test` with the `-json` flag and pipe the output to `vgt`.

```
```bash
go test -json ./... | vgt
```

or with `go run`:

```
```bash
go test -json ./... | go run github.com/roblaszczak/vgt@latest
```

> [!WARNING]
> When you are piping go tests output to `vgt`, `vgt` will exit with 1 when tests failed.
or just `vgt` with a custom flags after `--` to run tests and visualise them:

```bash
$ vgt -- ./... -count=1 -short
10:26PM INF Running go test command="[go test -json ./... -count=1 -short]"
```

After tests were executed, a browser window will open with the visualisation.

If you want to preserve the output, you can pipe test logs to file and later pass it to `vgt`:

```
```bash
go test -json ./... > test.json
cat test.json | vgt
```


### Additional flags

```
```bash
Usage of vgt:
-debug
enable debug mode
Expand Down Expand Up @@ -75,6 +84,6 @@ it looks good.

If you made a change and want to update golden files, you can run:

```
```bash
go test . -update-golden
```
120 changes: 93 additions & 27 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package main

import (
"bufio"
"bytes"
"context"
_ "embed"
"errors"
"flag"
"fmt"
"io"
"log/slog"
"os"
"os/exec"
"os/signal"
"syscall"
"time"
Expand Down Expand Up @@ -47,7 +50,7 @@ func main() {
)
flag.Parse()

logLevel := slog.LevelWarn
logLevel := slog.LevelInfo
if debug {
logLevel = slog.LevelDebug
}
Expand All @@ -65,33 +68,11 @@ func main() {
}),
))

var r io.Reader

if fromFile == "" {
sr, err := cancelreader.NewReader(os.Stdin)
if err != nil {
slog.Error("Error creating cancel reader", "err", err)
return
}

go func() {
<-ctx.Done()
sr.Cancel()
}()

r = sr
} else {
f, err := os.Open(fromFile)
if err != nil {
slog.Error("Error opening file", "err", err)
return
}
defer func() {
_ = f.Close()
}()

r = f
r, cleanup, exitCode, done := newReader(ctx)
if !done {
return
}
defer cleanup()

scanner := bufio.NewScanner(r)

Expand All @@ -112,6 +93,91 @@ func main() {
} else {
serveHTML(ctx, result)
}

if exitCode != 0 {
os.Exit(exitCode)
}
if result.Failed {
os.Exit(1)
}
}

func newReader(ctx context.Context) (io.Reader, func(), int, bool) {
fi, err := os.Stdin.Stat()
if err != nil {
slog.Error("Error getting stdin stat", "err", err)
return nil, nil, 0, false
}

isPipe := (fi.Mode() & os.ModeCharDevice) == 0
readFromFile := fromFile != ""

if isPipe && readFromFile {
slog.Error("Can't read from file and stdin at the same time")
return nil, nil, 0, false
}

if readFromFile {
f, err := os.Open(fromFile)
if err != nil {
slog.Error("Error opening file", "err", err)
return nil, nil, 0, false
}

return f, func() {
_ = f.Close()
}, 0, true
}

if isPipe {
sr, err := cancelreader.NewReader(os.Stdin)
if err != nil {
slog.Error("Error creating cancel reader", "err", err)
return nil, nil, 0, false
}

go func() {
<-ctx.Done()
sr.Cancel()
}()

return sr, func() {}, 0, true
}

r := bytes.NewBuffer([]byte{})

command := append([]string{"go", "test", "-json"}, flag.Args()...)

slog.Info("Running go test", "command", command)

cmd := exec.Command(command[0], command[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = io.MultiWriter(r, os.Stdout)
cmd.Stderr = os.Stderr

var exitCode int

err = cmd.Run()
var exitErr *exec.ExitError
if err != nil {
if errors.As(err, &exitErr) {
// this is expected - tests failed
slog.Info("Error running go test", "err", err)
exitCode = exitErr.ExitCode()
} else {
slog.Error("Error running go test", "err", err)
return nil, nil, 0, false
}
}

go func() {
<-ctx.Done()
_ = cmd.Process.Kill()
}()

return r, func() {
_, _ = cmd.Process.Wait()
}, exitCode, true
}

func checkClosing(ctx context.Context) bool {
Expand Down
9 changes: 9 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ type ParseResult struct {
End time.Time

MaxDuration time.Duration

Failed bool
}

func (p ParseResult) TestNamesOrderedByStart() []TestName {
Expand Down Expand Up @@ -133,6 +135,8 @@ func Parse(scanner *bufio.Scanner) ParseResult {

maxDuration := time.Duration(0)

failed := false

i := 0

for scanner.Scan() {
Expand All @@ -157,6 +161,10 @@ func Parse(scanner *bufio.Scanner) ParseResult {
continue
}

if out.Action == actionFail {
failed = true
}

if !out.Time.IsZero() {
if start.IsZero() || out.Time.Before(start) {
start = out.Time
Expand Down Expand Up @@ -268,5 +276,6 @@ func Parse(scanner *bufio.Scanner) ParseResult {
Start: start,
End: end,
MaxDuration: maxDuration,
Failed: failed,
}
}
3 changes: 2 additions & 1 deletion testdata/golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -4046,5 +4046,6 @@
},
"Start": "2024-09-18T21:02:11.282888+02:00",
"End": "2024-09-18T21:12:13.0365+02:00",
"MaxDuration": 262054805000
"MaxDuration": 262054805000,
"Failed": true
}

0 comments on commit d5a65b6

Please sign in to comment.