cmd/gogio: make e2e test output consistent

Fix a long-standing TODO: instead of each sub-test handling its own
output separately, just make each expose its output via an io.Reader.
Then, the shared driverBase code can tell if any of the lines contain
the magic "gio frame ready" string.

Reduces the amount of code a bit, but most importantly, it keeps the "is
a frame ready?" logic in a single place.

In the future, this also enables us to do more with all the e2e test app
output consistently. For example, we might want to add a -debug flag to
always log output lines as they happen.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
This commit is contained in:
Daniel Martí
2020-05-10 17:31:14 +01:00
committed by Elias Naur
parent 9ad412ea0b
commit 023e022255
7 changed files with 54 additions and 83 deletions
+29 -5
View File
@@ -3,11 +3,13 @@
package main_test
import (
"bufio"
"errors"
"flag"
"fmt"
"image"
"image/color"
"io"
"io/ioutil"
"os"
"os/exec"
@@ -50,17 +52,13 @@ type driverBase struct {
width, height int
// TODO(mvdan): Make this lower-level, so that each driver can simply
// send us each line of output from the app. That will let us
// deduplicate some code, and also show app output as test logs in a
// consistent way.
output io.Reader
frameNotifs chan bool
}
func (d *driverBase) initBase(t *testing.T, width, height int) {
d.T = t
d.width, d.height = width, height
d.frameNotifs = make(chan bool, 1)
}
func TestEndToEnd(t *testing.T) {
@@ -251,6 +249,32 @@ func checkImageCorners(img image.Image, topLeft, topRight, botLeft, botRight col
func (d *driverBase) waitForFrame() {
d.Helper()
if d.frameNotifs == nil {
// Start the goroutine that reads output lines and notifies of
// new frames via frameNotifs. The test doesn't wait for this
// goroutine to finish; it will naturally end when the output
// reader reaches an error like EOF.
d.frameNotifs = make(chan bool, 1)
if d.output == nil {
d.Fatal("need an output reader to be notified of frames")
}
go func() {
scanner := bufio.NewScanner(d.output)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "gio frame ready") {
d.frameNotifs <- true
}
}
// Since we're only interested in the output while the
// app runs, and we don't know when it finishes here,
// ignore "already closed" pipe errors.
if err := scanner.Err(); err != nil && !errors.Is(err, os.ErrClosed) {
d.Errorf("reading app output: %v", err)
}
}()
}
// Unfortunately, there isn't a way to select on a test failing, since
// testing.T doesn't have anything like a context or a "done" channel.
//