From b8e996074b489defd3b613961063a0a0bf979056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Fri, 1 Nov 2019 23:16:49 +0000 Subject: [PATCH] cmd/gogio: rip out cgo deps for x11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead rely on more tiny standalone tools. In this case, scrot lets us take png screenshots, and works well. On the plus side, we remove some large X Go deps, and we don't need nearly as much code. While at it, skip if any of the tools are missing, and actually defer the cleanup funcs so that they run when we fail the test early. Signed-off-by: Daniel Martí --- cmd/go.mod | 4 ---- cmd/go.sum | 6 ----- cmd/gogio/e2e_test.go | 10 ++++---- cmd/gogio/x11_test.go | 56 +++++++++++++++++-------------------------- 4 files changed, 27 insertions(+), 49 deletions(-) diff --git a/cmd/go.mod b/cmd/go.mod index 50b29af6..77a12e58 100644 --- a/cmd/go.mod +++ b/cmd/go.mod @@ -4,10 +4,6 @@ go 1.13 require ( gioui.org v0.0.0-20191030194120-b53c2a7c9d56 - github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect - github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect - github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 - github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 github.com/chromedp/cdproto v0.0.0-20191009033829-c22f49c9ff0a github.com/chromedp/chromedp v0.5.1 golang.org/x/image v0.0.0-20190802002840-cff245a6509b diff --git a/cmd/go.sum b/cmd/go.sum index 234e109c..2aeaf7f6 100644 --- a/cmd/go.sum +++ b/cmd/go.sum @@ -1,14 +1,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20191030194120-b53c2a7c9d56 h1:ZC5qDUrd0+64qlceTlMC1DM3bjEqAMohfP+3aE3U5OE= gioui.org v0.0.0-20191030194120-b53c2a7c9d56/go.mod h1:KqFFi2Dq5gYA3FJ0sDOt8OBXoMsuxMtE8v2f0JExXAY= -github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA= -github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= -github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= -github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 h1:O/r2Sj+8QcMF7V5IcmiE2sMFV2q3J47BEirxbXJAdzA= -github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k= github.com/chromedp/cdproto v0.0.0-20191009033829-c22f49c9ff0a h1:AuIGvB6IuWpMEdfKQ+t77D6dzLpNftzxAsktehYyWn8= github.com/chromedp/cdproto v0.0.0-20191009033829-c22f49c9ff0a/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g= github.com/chromedp/chromedp v0.5.1 h1:PAqhoCWCHzRphYnmmxLSiYk7EEwDplCm4woTCCaV2cQ= diff --git a/cmd/gogio/e2e_test.go b/cmd/gogio/e2e_test.go index bda20078..eb542cf4 100644 --- a/cmd/gogio/e2e_test.go +++ b/cmd/gogio/e2e_test.go @@ -39,11 +39,15 @@ type TestDriver interface { func runEndToEndTest(t *testing.T, driver TestDriver) { width, height := 800, 600 cleanups := driver.Start(t, "testdata/red.go", width, height) + for _, cleanup := range cleanups { + defer cleanup() + } // The colors are split in four rectangular sections. Check the corners // of each of the sections. We check the corners left to right, top to // bottom, like when reading left-to-right text. wantColors := func(topLeft, topRight, botLeft, botRight color.RGBA) { + t.Helper() img := driver.Screenshot() size := img.Bounds().Size() // We expect to receive a width*height screenshot. @@ -98,14 +102,10 @@ func runEndToEndTest(t *testing.T, driver TestDriver) { driver.Click(1*(width/4), 1*(height/4)) driver.Click(3*(width/4), 3*(height/4)) wantColors(red, white, black, red) - - // Run the cleanup funcs from last to first, as if they were defers. - for i := len(cleanups) - 1; i >= 0; i-- { - cleanups[i]() - } } func wantColor(t *testing.T, img image.Image, x, y int, want color.Color) { + t.Helper() r, g, b, _ := want.RGBA() got := img.At(x, y) r_, g_, b_, _ := got.RGBA() diff --git a/cmd/gogio/x11_test.go b/cmd/gogio/x11_test.go index 34de3eca..72113b0b 100644 --- a/cmd/gogio/x11_test.go +++ b/cmd/gogio/x11_test.go @@ -11,6 +11,7 @@ import ( "context" "fmt" "image" + "image/png" "io" "io/ioutil" "math/rand" @@ -20,20 +21,12 @@ import ( "sync" "testing" "time" - - "github.com/BurntSushi/xgb" - "github.com/BurntSushi/xgb/xproto" - "github.com/BurntSushi/xgbutil" - "github.com/BurntSushi/xgbutil/xgraphics" ) type X11TestDriver struct { t *testing.T display string - - // conn holds the connection to X. - conn *xgbutil.XUtil } func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cleanups []func()) { @@ -57,8 +50,15 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl xflags = append(xflags, "-screen", fmt.Sprintf("%dx%d", width, height)) } xflags = append(xflags, d.display) - if _, err := exec.LookPath(xprog); err != nil { - d.t.Skipf("%s needed to run with -headless=%t", xprog, *headless) + + for _, prog := range []string{ + xprog, // to run the X server + "scrot", // to take screenshots + "xdotool", // to send input + } { + if _, err := exec.LookPath(prog); err != nil { + d.t.Skipf("%s needed to run", prog) + } } // First, build the app. @@ -99,9 +99,8 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl // Wait for up to 1s (100 * 10ms) for the X server to be ready. for i := 0; ; i++ { time.Sleep(10 * time.Millisecond) - // This socket path isn't terribly portable, but the xgb - // library we use does the same, and we only really care - // about Linux here. + // This socket path isn't terribly portable, but it's + // okay for now. socket := fmt.Sprintf("/tmp/.X11-unix/X%s", d.display[1:]) if _, err := os.Stat(socket); err == nil { break @@ -127,7 +126,7 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl ctx, cancel := context.WithCancel(context.Background()) cmd := exec.CommandContext(ctx, bin) out := &bytes.Buffer{} - cmd.Env = append(os.Environ(), "DISPLAY="+d.display) + cmd.Env = []string{"DISPLAY=" + d.display} cmd.Stdout = out cmd.Stderr = out if err := cmd.Start(); err != nil { @@ -145,24 +144,6 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl }() } - // Finally, connect to the X server. - xgb.Logger.SetOutput(testLogWriter{d.t}) - xgbutil.Logger.SetOutput(testLogWriter{d.t}) - conn, err := xgbutil.NewConnDisplay(d.display) - if err != nil { - d.t.Fatal(err) - } - d.conn = conn - cleanups = append(cleanups, func() { - conn.Conn().Close() - // TODO(mvdan): Figure out a way to remove this sleep - // without introducing a panic. The xgb code will - // encounter a panic if the Xorg server exits before xgb - // has shut down fully. - // See: https://github.com/BurntSushi/xgb/pull/44 - time.Sleep(10 * time.Millisecond) - }) - // Wait for the gio app to render. // TODO(mvdan): synchronize with the app instead time.Sleep(400 * time.Millisecond) @@ -171,7 +152,14 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl } func (d *X11TestDriver) Screenshot() image.Image { - img, err := xgraphics.NewDrawable(d.conn, xproto.Drawable(d.conn.RootWin())) + cmd := exec.Command("scrot", "--silent", "--overwrite", "/dev/stdout") + cmd.Env = []string{"DISPLAY=" + d.display} + out, err := cmd.CombinedOutput() + if err != nil { + d.t.Errorf("%s", out) + d.t.Fatal(err) + } + img, err := png.Decode(bytes.NewReader(out)) if err != nil { d.t.Fatal(err) } @@ -184,7 +172,7 @@ func (d *X11TestDriver) xdotool(args ...interface{}) { strs[i] = fmt.Sprint(arg) } cmd := exec.Command("xdotool", strs...) - cmd.Env = append(os.Environ(), "DISPLAY="+d.display) + cmd.Env = []string{"DISPLAY=" + d.display} if out, err := cmd.CombinedOutput(); err != nil { d.t.Errorf("%s", out) d.t.Fatal(err)