From b3cf187c011edbb91a10753d3a7849833e5115f3 Mon Sep 17 00:00:00 2001 From: nikitar020 Date: Thu, 14 Mar 2019 20:05:05 +0700 Subject: [PATCH] Solve intermittent build errors --- gui/gui.go | 34 +++++++++-------- main.go | 15 +++++++- main_test.go | 104 +++++++++++++++++++++++++++++++++------------------ 3 files changed, 99 insertions(+), 54 deletions(-) diff --git a/gui/gui.go b/gui/gui.go index be228f5..00a32fc 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -67,6 +67,7 @@ type GUI struct { selectionRegionMode buffer.SelectionRegionMode mainThreadFunc chan func() + wakerEnded chan bool } func Min(x, y int) int { @@ -412,16 +413,6 @@ func (gui *GUI) Render() error { gl.Disable(gl.DEPTH_TEST) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - go func() { - for { - <-ticker.C - gui.logger.Sync() - } - }() - gui.terminal.SetProgram(program) latestVersion := "" @@ -502,9 +493,13 @@ Buffer Size: %d lines } } - close(stop) // Tell waker to end. + gui.logger.Debug("Stopping render...") + + close(stop) // Tell waker to end... + <-gui.wakerEnded // ...and wait it to end + + gui.logger.Debug("Render stopped") - gui.logger.Debugf("Stopping render...") return nil } @@ -514,9 +509,11 @@ Buffer Size: %d lines // redrawn. Limiting is applied on wakeups to avoid excessive CPU // usage when the terminal is being updated rapidly. func (gui *GUI) waker(stop <-chan struct{}) { + gui.wakerEnded = make(chan bool) dirty := gui.terminal.Dirty() var nextWake <-chan time.Time var last time.Time +forLoop: for { select { case <-dirty: @@ -540,9 +537,10 @@ func (gui *GUI) waker(stop <-chan struct{}) { glfw.PostEmptyEvent() nextWake = nil case <-stop: - return + break forLoop } } + gui.wakerEnded <- true } func (gui *GUI) renderTerminalData(shouldLock bool) { @@ -819,9 +817,15 @@ func (gui *GUI) Screenshot(path string) { if err != nil { panic(err) } - file, _ := os.Create(path) + file, err := os.Create(path) + if err != nil { + panic(err) + } defer file.Close() - png.Encode(file, img) + err = png.Encode(file, img) + if err != nil { + panic(err) + } } func (gui *GUI) windowPosChangeCallback(w *glfw.Window, xpos int, ypos int) { diff --git a/main.go b/main.go index 1b4114c..ce71553 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "github.com/liamg/aminal/platform" "github.com/liamg/aminal/terminal" "github.com/riywo/loginshell" + "time" ) type callback func(terminal *terminal.Terminal, g *gui.GUI) @@ -32,7 +33,17 @@ func initialize(unitTestfunc callback, configOverride *config.Config) { fmt.Printf("Failed to create logger: %s\n", err) os.Exit(1) } - defer logger.Sync() + ticker := time.NewTicker(time.Second) + go func() { + for { + <-ticker.C + logger.Sync() + } + }() + defer func() { + ticker.Stop() + logger.Sync() + }() if conf.CPUProfile != "" { logger.Infof("Starting CPU profiling...") @@ -61,7 +72,7 @@ func initialize(unitTestfunc callback, configOverride *config.Config) { guestProcess, err := pty.CreateGuestProcess(shellStr) if err != nil { pty.Close() - logger.Fatalf("Failed to start your shell: %s", err) + logger.Fatalf("Failed to start your shell \"%s\": %s", shellStr, err) } defer guestProcess.Close() diff --git a/main_test.go b/main_test.go index ab91005..8edbae9 100644 --- a/main_test.go +++ b/main_test.go @@ -5,17 +5,15 @@ package main import ( "flag" "fmt" + "github.com/carlogit/phash" + "github.com/liamg/aminal/config" + "github.com/liamg/aminal/gui" + "github.com/liamg/aminal/terminal" "os" "runtime" "strings" "testing" "time" - - "github.com/liamg/aminal/config" - "github.com/liamg/aminal/gui" - "github.com/liamg/aminal/terminal" - - "github.com/carlogit/phash" ) var termRef *terminal.Terminal @@ -47,10 +45,14 @@ func hash(path string) string { return imageHash } +func imagesAreEqual(expected string, actual string) int { + expectedHash := hash(expected) + actualHash := hash(actual) + return phash.GetDistance(expectedHash, actualHash) +} + func compareImages(expected string, actual string) { - template := hash(expected) - screen := hash(actual) - distance := phash.GetDistance(template, screen) + distance := imagesAreEqual(expected, actual) if distance != 0 { os.Exit(terminate(fmt.Sprintf("Screenshot \"%s\" doesn't match expected image \"%s\". Distance of hashes difference: %d\n", actual, expected, distance))) @@ -58,19 +60,48 @@ func compareImages(expected string, actual string) { } func send(terminal *terminal.Terminal, cmd string) { - terminal.Write([]byte(cmd)) + err := terminal.Write([]byte(cmd)) + if err != nil { + panic(err) + } } func enter(terminal *terminal.Terminal) { - terminal.Write([]byte("\n")) + err := terminal.Write([]byte("\n")) + if err != nil { + panic(err) + } } -func validateScreen(img string) { +func validateScreen(img string, waitForChange bool) { + fmt.Printf("taking screenshot: %s and comparing...", img) + guiRef.Screenshot(img) compareImages(strings.Join([]string{"vttest/", img}, ""), img) + fmt.Printf("compare OK\n") + enter(termRef) - sleep() + + if waitForChange { + fmt.Print("Waiting for screen change...") + attempts := 10 + for { + sleep() + actualScren := "temp.png" + guiRef.Screenshot(actualScren) + distance := imagesAreEqual(actualScren, img) + if distance != 0 { + break + } + fmt.Printf(" %d", attempts) + attempts-- + if attempts <= 0 { + break + } + } + fmt.Print("done\n") + } } func TestMain(m *testing.M) { @@ -115,12 +146,12 @@ func TestCursorMovement(t *testing.T) { os.Exit(terminate(fmt.Sprintf("ActiveBuffer doesn't match vttest template vttest/test-cursor-movement-1"))) } - validateScreen("test-cursor-movement-1.png") - validateScreen("test-cursor-movement-2.png") - validateScreen("test-cursor-movement-3.png") - validateScreen("test-cursor-movement-4.png") - validateScreen("test-cursor-movement-5.png") - validateScreen("test-cursor-movement-6.png") + validateScreen("test-cursor-movement-1.png", true) + validateScreen("test-cursor-movement-2.png", true) + validateScreen("test-cursor-movement-3.png", true) + validateScreen("test-cursor-movement-4.png", true) + validateScreen("test-cursor-movement-5.png", true) + validateScreen("test-cursor-movement-6.png", false) g.Close() } @@ -142,21 +173,21 @@ func TestScreenFeatures(t *testing.T) { send(term, "2\n") sleep() - validateScreen("test-screen-features-1.png") - validateScreen("test-screen-features-2.png") - validateScreen("test-screen-features-3.png") - validateScreen("test-screen-features-4.png") - validateScreen("test-screen-features-5.png") - validateScreen("test-screen-features-6.png") - validateScreen("test-screen-features-7.png") - validateScreen("test-screen-features-8.png") - validateScreen("test-screen-features-9.png") - validateScreen("test-screen-features-10.png") - validateScreen("test-screen-features-11.png") - validateScreen("test-screen-features-12.png") - validateScreen("test-screen-features-13.png") - validateScreen("test-screen-features-14.png") - validateScreen("test-screen-features-15.png") + validateScreen("test-screen-features-1.png", true) + validateScreen("test-screen-features-2.png", true) + validateScreen("test-screen-features-3.png", true) + validateScreen("test-screen-features-4.png", true) + validateScreen("test-screen-features-5.png", true) + validateScreen("test-screen-features-6.png", true) + validateScreen("test-screen-features-7.png", true) + validateScreen("test-screen-features-8.png", true) + validateScreen("test-screen-features-9.png", true) + validateScreen("test-screen-features-10.png", true) + validateScreen("test-screen-features-11.png", true) + validateScreen("test-screen-features-12.png", true) + validateScreen("test-screen-features-13.png", true) + validateScreen("test-screen-features-14.png", true) + validateScreen("test-screen-features-15.png", false) g.Close() } @@ -178,10 +209,9 @@ func TestSixel(t *testing.T) { send(term, "clear\n") sleep() send(term, "cat example.sixel\n") - sleep(4) + sleep(10) // Displaying SIXEL graphics *sometimes* takes long time. Excessive synchronization??? - guiRef.Screenshot("test-sixel.png") - validateScreen("test-sixel.png") + validateScreen("test-sixel.png", false) g.Close() }