diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2023-05-24 23:11:09 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2023-05-26 18:22:03 +1000 |
commit | 2f555ddb747690fd7cf7b3dfcb381385e01f44cb (patch) | |
tree | 2254dfe2f7e50e1de7a44d6984855fe761b6653d | |
parent | 8e6967c70273f838e4e200a61bdb631015d46bdc (diff) |
Utilise file instead of stderr for integration testswriting-integration-test-result-to-file
Windows for some reason is not properly making use of stderr so instead
we're going to write our result to a file explicitly
-rw-r--r-- | pkg/gui/test_mode.go | 28 | ||||
-rw-r--r-- | pkg/integration/clients/go_test.go | 21 | ||||
-rw-r--r-- | pkg/integration/result/result.go | 102 | ||||
-rw-r--r-- | pkg/integration/tests/commit/commit.go | 2 |
4 files changed, 148 insertions, 5 deletions
diff --git a/pkg/gui/test_mode.go b/pkg/gui/test_mode.go index be46041db..5b61f3ccc 100644 --- a/pkg/gui/test_mode.go +++ b/pkg/gui/test_mode.go @@ -1,12 +1,15 @@ package gui import ( + "fmt" "log" "os" + "runtime" "time" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/jesseduffield/lazygit/pkg/integration/result" integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -24,7 +27,15 @@ func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) { go func() { time.Sleep(time.Millisecond * 100) - test.Run(&GuiDriver{gui: gui}) + defer handlePanic() + + guiDriver := &GuiDriver{gui: gui} + test.Run(guiDriver) + + // if we're here then the test must have passed: it panics upon failure + if err := result.LogSuccess(); err != nil { + panic(err) + } gui.g.Update(func(*gocui.Gui) error { return gocui.ErrQuit @@ -42,6 +53,21 @@ func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) { } } +func handlePanic() { + if r := recover(); r != nil { + buf := make([]byte, 4096*4) // arbitrarily large buffer size + stackSize := runtime.Stack(buf, false) + stackTrace := string(buf[:stackSize]) + + if err := result.LogFailure(fmt.Sprintf("%v\n%s", r, stackTrace)); err != nil { + panic(err) + } + + // Re-panic + panic(r) + } +} + func Headless() bool { return os.Getenv("HEADLESS") != "" } diff --git a/pkg/integration/clients/go_test.go b/pkg/integration/clients/go_test.go index 29d914708..d359d6c76 100644 --- a/pkg/integration/clients/go_test.go +++ b/pkg/integration/clients/go_test.go @@ -9,6 +9,7 @@ package clients import ( "bytes" "errors" + "fmt" "io" "io/ioutil" "os" @@ -17,6 +18,7 @@ import ( "github.com/creack/pty" "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/jesseduffield/lazygit/pkg/integration/result" "github.com/jesseduffield/lazygit/pkg/integration/tests" "github.com/stretchr/testify/assert" ) @@ -63,6 +65,9 @@ func runCmdHeadless(cmd *exec.Cmd) error { "TERM=xterm", ) + resultPath := result.GetResultPath() + result.SetResultPathEnvVar(cmd, resultPath) + // not writing stderr to the pty because we want to capture a panic if // there is one. But some commands will not be in tty mode if stderr is // not a terminal. We'll need to keep an eye out for that. @@ -79,10 +84,20 @@ func runCmdHeadless(cmd *exec.Cmd) error { _, _ = io.Copy(ioutil.Discard, f) - if cmd.Wait() != nil { - // return an error with the stderr output - return errors.New(stderr.String()) + _ = cmd.Wait() + + result, err := result.ReadResult(resultPath) + if err != nil { + return fmt.Errorf("Error reading integration test result: %w", err) } + if !result.Success { + return errors.New(result.Message) + } + + // if cmd.Wait() != nil { + // // return an error with the stderr output + // return errors.New(stderr.String()) + // } return f.Close() } diff --git a/pkg/integration/result/result.go b/pkg/integration/result/result.go new file mode 100644 index 000000000..7f0bbe1d1 --- /dev/null +++ b/pkg/integration/result/result.go @@ -0,0 +1,102 @@ +package result + +import ( + "crypto/rand" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" +) + +// On windows the pty package is failing to obtain stderr text when a test fails, +// so this is our workaround: when a test fails, it writes the result to a file, +// and then the test runner reads the file and checks the result + +const PathEnvVar = "LAZYGIT_INTEGRATION_TEST_RESULT_PATH" + +type IntegrationTestResult struct { + Success bool + Message string +} + +func LogFailure(message string) error { + return writeResult(failure(message)) +} + +func LogSuccess() error { + return writeResult(success()) +} + +func failure(message string) IntegrationTestResult { + return IntegrationTestResult{Success: false, Message: message} +} + +func success() IntegrationTestResult { + return IntegrationTestResult{Success: true} +} + +func writeResult(result IntegrationTestResult) error { + resultPath := os.Getenv(PathEnvVar) + if resultPath == "" { + return fmt.Errorf("Environment variable %s not set", PathEnvVar) + } + + file, err := os.Create(resultPath) + if err != nil { + return fmt.Errorf("Error creating file: %w", err) + } + defer file.Close() + + encoder := json.NewEncoder(file) + err = encoder.Encode(result) + if err != nil { + return fmt.Errorf("Error encoding JSON: %w", err) + } + + return nil +} + +// Reads the result file stored by the lazygit test, and deletes the file +func ReadResult(resultPath string) (IntegrationTestResult, error) { + file, err := os.Open(resultPath) + if err != nil { + return IntegrationTestResult{}, fmt.Errorf("Error creating file: %w", err) + } + + decoder := json.NewDecoder(file) + var result IntegrationTestResult + err = decoder.Decode(&result) + if err != nil { + file.Close() + return IntegrationTestResult{}, fmt.Errorf("Error decoding JSON: %w", err) + } + + file.Close() + _ = os.Remove(resultPath) + + return result, nil +} + +func SetResultPathEnvVar(cmd *exec.Cmd, resultPath string) { + cmd.Env = append( + cmd.Env, + fmt.Sprintf("%s=%s", PathEnvVar, resultPath), + ) +} + +func GetResultPath() string { + return filepath.Join(os.TempDir(), fmt.Sprintf("lazygit_result_%s.json", generateRandomString(10))) +} + +func generateRandomString(length int) string { + buffer := make([]byte, length) + _, err := rand.Read(buffer) + if err != nil { + panic(fmt.Sprintf("Could not generate random string: %s", err)) + } + + randomString := base64.URLEncoding.EncodeToString(buffer) + return randomString[:length] +} diff --git a/pkg/integration/tests/commit/commit.go b/pkg/integration/tests/commit/commit.go index 3737f2e1c..0a62e0ccb 100644 --- a/pkg/integration/tests/commit/commit.go +++ b/pkg/integration/tests/commit/commit.go @@ -27,7 +27,7 @@ var Commit = NewIntegrationTest(NewIntegrationTestArgs{ PressPrimaryAction(). // stage file Lines( Contains("A myfile").IsSelected(), - Contains("?? myfile2"), + Contains("?? myfile23"), ). SelectNextItem(). PressPrimaryAction(). // stage other file |