mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-08-08 22:36:49 +02:00
Support passing -race flag to integration tests (#3019)
This commit is contained in:
2
Makefile
2
Makefile
@@ -44,7 +44,7 @@ update-cheatsheet:
|
|||||||
# For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md.
|
# For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md.
|
||||||
.PHONY: integration-test-tui
|
.PHONY: integration-test-tui
|
||||||
integration-test-tui:
|
integration-test-tui:
|
||||||
go run cmd/integration_test/main.go tui
|
go run cmd/integration_test/main.go tui $(filter-out $@,$(MAKECMDGOALS))
|
||||||
|
|
||||||
.PHONY: integration-test-cli
|
.PHONY: integration-test-cli
|
||||||
integration-test-cli:
|
integration-test-cli:
|
||||||
|
@@ -26,6 +26,29 @@ Usage:
|
|||||||
> go run cmd/integration_test/main.go help
|
> go run cmd/integration_test/main.go help
|
||||||
`
|
`
|
||||||
|
|
||||||
|
type flagInfo struct {
|
||||||
|
name string // name of the flag; can be used with "-" or "--"
|
||||||
|
flag *bool // a pointer to the variable that should be set to true when this flag is passed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes the args that you want to parse (excluding the program name and any
|
||||||
|
// subcommands), and returns the remaining args with the flags removed
|
||||||
|
func parseFlags(args []string, flags []flagInfo) []string {
|
||||||
|
outer:
|
||||||
|
for len(args) > 0 {
|
||||||
|
for _, f := range flags {
|
||||||
|
if args[0] == "-"+f.name || args[0] == "--"+f.name {
|
||||||
|
*f.flag = true
|
||||||
|
args = args[1:]
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
log.Fatal(usage)
|
log.Fatal(usage)
|
||||||
@@ -35,27 +58,26 @@ func main() {
|
|||||||
case "help":
|
case "help":
|
||||||
fmt.Println(usage)
|
fmt.Println(usage)
|
||||||
case "cli":
|
case "cli":
|
||||||
testNames := os.Args[2:]
|
|
||||||
slow := false
|
slow := false
|
||||||
sandbox := false
|
sandbox := false
|
||||||
waitForDebugger := false
|
waitForDebugger := false
|
||||||
// get the next arg if it's --slow
|
raceDetector := false
|
||||||
if len(os.Args) > 2 {
|
testNames := parseFlags(os.Args[2:], []flagInfo{
|
||||||
if os.Args[2] == "--slow" || os.Args[2] == "-slow" {
|
{"slow", &slow},
|
||||||
testNames = os.Args[3:]
|
{"sandbox", &sandbox},
|
||||||
slow = true
|
{"debug", &waitForDebugger},
|
||||||
} else if os.Args[2] == "--sandbox" || os.Args[2] == "-sandbox" {
|
{"race", &raceDetector},
|
||||||
testNames = os.Args[3:]
|
})
|
||||||
sandbox = true
|
clients.RunCLI(testNames, slow, sandbox, waitForDebugger, raceDetector)
|
||||||
} else if os.Args[2] == "--debug" || os.Args[2] == "-debug" {
|
|
||||||
testNames = os.Args[3:]
|
|
||||||
waitForDebugger = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clients.RunCLI(testNames, slow, sandbox, waitForDebugger)
|
|
||||||
case "tui":
|
case "tui":
|
||||||
clients.RunTUI()
|
raceDetector := false
|
||||||
|
remainingArgs := parseFlags(os.Args[2:], []flagInfo{
|
||||||
|
{"race", &raceDetector},
|
||||||
|
})
|
||||||
|
if len(remainingArgs) > 0 {
|
||||||
|
log.Fatal("tui only supports the -race argument.")
|
||||||
|
}
|
||||||
|
clients.RunTUI(raceDetector)
|
||||||
default:
|
default:
|
||||||
log.Fatal(usage)
|
log.Fatal(usage)
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
// If invoked directly, you can specify tests to run by passing their names as positional arguments
|
// If invoked directly, you can specify tests to run by passing their names as positional arguments
|
||||||
|
|
||||||
func RunCLI(testNames []string, slow bool, sandbox bool, waitForDebugger bool) {
|
func RunCLI(testNames []string, slow bool, sandbox bool, waitForDebugger bool, raceDetector bool) {
|
||||||
inputDelay := tryConvert(os.Getenv("INPUT_DELAY"), 0)
|
inputDelay := tryConvert(os.Getenv("INPUT_DELAY"), 0)
|
||||||
if slow {
|
if slow {
|
||||||
inputDelay = SLOW_INPUT_DELAY
|
inputDelay = SLOW_INPUT_DELAY
|
||||||
@@ -36,6 +36,7 @@ func RunCLI(testNames []string, slow bool, sandbox bool, waitForDebugger bool) {
|
|||||||
runAndPrintFatalError,
|
runAndPrintFatalError,
|
||||||
sandbox,
|
sandbox,
|
||||||
waitForDebugger,
|
waitForDebugger,
|
||||||
|
raceDetector,
|
||||||
inputDelay,
|
inputDelay,
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
@@ -87,12 +88,15 @@ outer:
|
|||||||
return testsToRun
|
return testsToRun
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCmdInTerminal(cmd *exec.Cmd) error {
|
func runCmdInTerminal(cmd *exec.Cmd) (int, error) {
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
return cmd.Run()
|
if err := cmd.Start(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
return cmd.Process.Pid, cmd.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryConvert(numStr string, defaultVal int) int {
|
func tryConvert(numStr string, defaultVal int) int {
|
||||||
|
@@ -27,6 +27,7 @@ func TestIntegration(t *testing.T) {
|
|||||||
|
|
||||||
parallelTotal := tryConvert(os.Getenv("PARALLEL_TOTAL"), 1)
|
parallelTotal := tryConvert(os.Getenv("PARALLEL_TOTAL"), 1)
|
||||||
parallelIndex := tryConvert(os.Getenv("PARALLEL_INDEX"), 0)
|
parallelIndex := tryConvert(os.Getenv("PARALLEL_INDEX"), 0)
|
||||||
|
raceDetector := os.Getenv("LAZYGIT_RACE_DETECTOR") != ""
|
||||||
testNumber := 0
|
testNumber := 0
|
||||||
|
|
||||||
err := components.RunTests(
|
err := components.RunTests(
|
||||||
@@ -53,6 +54,7 @@ func TestIntegration(t *testing.T) {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
raceDetector,
|
||||||
0,
|
0,
|
||||||
// Allow two attempts at each test to get around flakiness
|
// Allow two attempts at each test to get around flakiness
|
||||||
2,
|
2,
|
||||||
@@ -61,7 +63,7 @@ func TestIntegration(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCmdHeadless(cmd *exec.Cmd) error {
|
func runCmdHeadless(cmd *exec.Cmd) (int, error) {
|
||||||
cmd.Env = append(
|
cmd.Env = append(
|
||||||
cmd.Env,
|
cmd.Env,
|
||||||
"HEADLESS=true",
|
"HEADLESS=true",
|
||||||
@@ -79,15 +81,16 @@ func runCmdHeadless(cmd *exec.Cmd) error {
|
|||||||
// running other commands in a pty.
|
// running other commands in a pty.
|
||||||
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 300, Cols: 300})
|
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 300, Cols: 300})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = io.Copy(io.Discard, f)
|
_, _ = io.Copy(io.Discard, f)
|
||||||
|
|
||||||
if cmd.Wait() != nil {
|
if cmd.Wait() != nil {
|
||||||
|
_ = f.Close()
|
||||||
// return an error with the stderr output
|
// return an error with the stderr output
|
||||||
return errors.New(stderr.String())
|
return cmd.Process.Pid, errors.New(stderr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.Close()
|
return cmd.Process.Pid, f.Close()
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
var SLOW_INPUT_DELAY = 600
|
var SLOW_INPUT_DELAY = 600
|
||||||
|
|
||||||
func RunTUI() {
|
func RunTUI(raceDetector bool) {
|
||||||
rootDir := utils.GetLazyRootDirectory()
|
rootDir := utils.GetLazyRootDirectory()
|
||||||
testDir := filepath.Join(rootDir, "test", "integration")
|
testDir := filepath.Join(rootDir, "test", "integration")
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ func RunTUI() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
suspendAndRunTest(currentTest, true, false, 0)
|
suspendAndRunTest(currentTest, true, false, raceDetector, 0)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -98,7 +98,7 @@ func RunTUI() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
suspendAndRunTest(currentTest, false, false, 0)
|
suspendAndRunTest(currentTest, false, false, raceDetector, 0)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -111,7 +111,7 @@ func RunTUI() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
suspendAndRunTest(currentTest, false, false, SLOW_INPUT_DELAY)
|
suspendAndRunTest(currentTest, false, false, raceDetector, SLOW_INPUT_DELAY)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -124,7 +124,7 @@ func RunTUI() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
suspendAndRunTest(currentTest, false, true, 0)
|
suspendAndRunTest(currentTest, false, true, raceDetector, 0)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -284,12 +284,12 @@ func (self *app) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod go
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func suspendAndRunTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, inputDelay int) {
|
func suspendAndRunTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, raceDetector bool, inputDelay int) {
|
||||||
if err := gocui.Screen.Suspend(); err != nil {
|
if err := gocui.Screen.Suspend(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
runTuiTest(test, sandbox, waitForDebugger, inputDelay)
|
runTuiTest(test, sandbox, waitForDebugger, raceDetector, inputDelay)
|
||||||
|
|
||||||
fmt.Fprintf(os.Stdout, "\n%s", style.FgGreen.Sprint("press enter to return"))
|
fmt.Fprintf(os.Stdout, "\n%s", style.FgGreen.Sprint("press enter to return"))
|
||||||
fmt.Scanln() // wait for enter press
|
fmt.Scanln() // wait for enter press
|
||||||
@@ -384,7 +384,7 @@ func quit(g *gocui.Gui, v *gocui.View) error {
|
|||||||
return gocui.ErrQuit
|
return gocui.ErrQuit
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTuiTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, inputDelay int) {
|
func runTuiTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, raceDetector bool, inputDelay int) {
|
||||||
err := components.RunTests(
|
err := components.RunTests(
|
||||||
[]*components.IntegrationTest{test},
|
[]*components.IntegrationTest{test},
|
||||||
log.Printf,
|
log.Printf,
|
||||||
@@ -392,6 +392,7 @@ func runTuiTest(test *components.IntegrationTest, sandbox bool, waitForDebugger
|
|||||||
runAndPrintError,
|
runAndPrintError,
|
||||||
sandbox,
|
sandbox,
|
||||||
waitForDebugger,
|
waitForDebugger,
|
||||||
|
raceDetector,
|
||||||
inputDelay,
|
inputDelay,
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
@@ -26,10 +26,11 @@ const (
|
|||||||
func RunTests(
|
func RunTests(
|
||||||
tests []*IntegrationTest,
|
tests []*IntegrationTest,
|
||||||
logf func(format string, formatArgs ...interface{}),
|
logf func(format string, formatArgs ...interface{}),
|
||||||
runCmd func(cmd *exec.Cmd) error,
|
runCmd func(cmd *exec.Cmd) (int, error),
|
||||||
testWrapper func(test *IntegrationTest, f func() error),
|
testWrapper func(test *IntegrationTest, f func() error),
|
||||||
sandbox bool,
|
sandbox bool,
|
||||||
waitForDebugger bool,
|
waitForDebugger bool,
|
||||||
|
raceDetector bool,
|
||||||
inputDelay int,
|
inputDelay int,
|
||||||
maxAttempts int,
|
maxAttempts int,
|
||||||
) error {
|
) error {
|
||||||
@@ -41,7 +42,7 @@ func RunTests(
|
|||||||
|
|
||||||
testDir := filepath.Join(projectRootDir, "test", "_results")
|
testDir := filepath.Join(projectRootDir, "test", "_results")
|
||||||
|
|
||||||
if err := buildLazygit(); err != nil {
|
if err := buildLazygit(raceDetector); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ func RunTests(
|
|||||||
)
|
)
|
||||||
|
|
||||||
for i := 0; i < maxAttempts; i++ {
|
for i := 0; i < maxAttempts; i++ {
|
||||||
err := runTest(test, paths, projectRootDir, logf, runCmd, sandbox, waitForDebugger, inputDelay, gitVersion)
|
err := runTest(test, paths, projectRootDir, logf, runCmd, sandbox, waitForDebugger, raceDetector, inputDelay, gitVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if i == maxAttempts-1 {
|
if i == maxAttempts-1 {
|
||||||
return err
|
return err
|
||||||
@@ -82,9 +83,10 @@ func runTest(
|
|||||||
paths Paths,
|
paths Paths,
|
||||||
projectRootDir string,
|
projectRootDir string,
|
||||||
logf func(format string, formatArgs ...interface{}),
|
logf func(format string, formatArgs ...interface{}),
|
||||||
runCmd func(cmd *exec.Cmd) error,
|
runCmd func(cmd *exec.Cmd) (int, error),
|
||||||
sandbox bool,
|
sandbox bool,
|
||||||
waitForDebugger bool,
|
waitForDebugger bool,
|
||||||
|
raceDetector bool,
|
||||||
inputDelay int,
|
inputDelay int,
|
||||||
gitVersion *git_commands.GitVersion,
|
gitVersion *git_commands.GitVersion,
|
||||||
) error {
|
) error {
|
||||||
@@ -107,12 +109,17 @@ func runTest(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = runCmd(cmd)
|
pid, err := runCmd(cmd)
|
||||||
if err != nil {
|
|
||||||
return err
|
// Print race detector log regardless of the command's exit status
|
||||||
|
if raceDetector {
|
||||||
|
logPath := fmt.Sprintf("%s.%d", raceDetectorLogsPath(), pid)
|
||||||
|
if bytes, err := os.ReadFile(logPath); err == nil {
|
||||||
|
logf("Race detector log:\n" + string(bytes))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareTestDir(
|
func prepareTestDir(
|
||||||
@@ -131,15 +138,18 @@ func prepareTestDir(
|
|||||||
return createFixture(test, paths, rootDir)
|
return createFixture(test, paths, rootDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildLazygit() error {
|
func buildLazygit(raceDetector bool) error {
|
||||||
// // TODO: remove this line!
|
// // TODO: remove this line!
|
||||||
// // skipping this because I'm not making changes to the app code atm.
|
// // skipping this because I'm not making changes to the app code atm.
|
||||||
// return nil
|
// return nil
|
||||||
|
|
||||||
|
args := []string{"go", "build"}
|
||||||
|
if raceDetector {
|
||||||
|
args = append(args, "-race")
|
||||||
|
}
|
||||||
|
args = append(args, "-o", tempLazygitPath(), filepath.FromSlash("pkg/integration/clients/injector/main.go"))
|
||||||
osCommand := oscommands.NewDummyOSCommand()
|
osCommand := oscommands.NewDummyOSCommand()
|
||||||
return osCommand.Cmd.New([]string{
|
return osCommand.Cmd.New(args).Run()
|
||||||
"go", "build", "-o", tempLazygitPath(), filepath.FromSlash("pkg/integration/clients/injector/main.go"),
|
|
||||||
}).Run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFixture(test *IntegrationTest, paths Paths, rootDir string) error {
|
func createFixture(test *IntegrationTest, paths Paths, rootDir string) error {
|
||||||
@@ -202,6 +212,9 @@ func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandb
|
|||||||
if waitForDebugger {
|
if waitForDebugger {
|
||||||
cmdObj.AddEnvVars("WAIT_FOR_DEBUGGER=true")
|
cmdObj.AddEnvVars("WAIT_FOR_DEBUGGER=true")
|
||||||
}
|
}
|
||||||
|
// Set a race detector log path only to avoid spamming the terminal with the
|
||||||
|
// logs. We are not showing this anywhere yet.
|
||||||
|
cmdObj.AddEnvVars(fmt.Sprintf("GORACE=log_path=%s", raceDetectorLogsPath()))
|
||||||
if test.ExtraEnvVars() != nil {
|
if test.ExtraEnvVars() != nil {
|
||||||
for key, value := range test.ExtraEnvVars() {
|
for key, value := range test.ExtraEnvVars() {
|
||||||
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", key, value))
|
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", key, value))
|
||||||
@@ -221,6 +234,10 @@ func tempLazygitPath() string {
|
|||||||
return filepath.Join("/tmp", "lazygit", "test_lazygit")
|
return filepath.Join("/tmp", "lazygit", "test_lazygit")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func raceDetectorLogsPath() string {
|
||||||
|
return filepath.Join("/tmp", "lazygit", "race_log")
|
||||||
|
}
|
||||||
|
|
||||||
func findOrCreateDir(path string) {
|
func findOrCreateDir(path string) {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Reference in New Issue
Block a user