1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-21 12:16:54 +02:00

support running integration tests in parallel

This commit is contained in:
CI 2020-10-06 08:01:25 +11:00 committed by Jesse Duffield
parent 2724f3888a
commit 2657060aa2
8 changed files with 89 additions and 42 deletions

View File

@ -32,27 +32,31 @@ import (
// TODO: support passing an env var for playback speed, given it's currently pretty fast // TODO: support passing an env var for playback speed, given it's currently pretty fast
type integrationTest struct { type integrationTest struct {
name string name string
fixture string fixture string
startSpeed int
} }
func tests() []integrationTest { func tests() []integrationTest {
return []integrationTest{ return []integrationTest{
{ {
name: "commit", name: "commit",
fixture: "newFile", fixture: "newFile",
startSpeed: 10,
}, },
{ {
name: "squash", name: "squash",
fixture: "manyCommits", fixture: "manyCommits",
}, },
{ {
name: "patchBuilding", name: "patchBuilding",
fixture: "updatedFile", fixture: "updatedFile",
startSpeed: 3,
}, },
{ {
name: "patchBuilding2", name: "patchBuilding2",
fixture: "updatedFile", fixture: "updatedFile",
startSpeed: 3,
}, },
{ {
name: "mergeConflicts", name: "mergeConflicts",
@ -69,9 +73,11 @@ func tests() []integrationTest {
} }
} }
func generateSnapshot(t *testing.T) string { func generateSnapshot(t *testing.T, actualDir string) string {
osCommand := oscommands.NewDummyOSCommand() osCommand := oscommands.NewDummyOSCommand()
cmd := `bash -c "git status; cat ./*; git log --pretty=%B -p"` cmd := fmt.Sprintf(`bash -c "cd %s && git status; cat ./*; git log --pretty=%%B -p"`, actualDir)
// need to copy from current directory to
snapshot, err := osCommand.RunCommandWithOutput(cmd) snapshot, err := osCommand.RunCommandWithOutput(cmd)
assert.NoError(t, err) assert.NoError(t, err)
@ -96,12 +102,7 @@ func findOrCreateDir(path string) {
func Test(t *testing.T) { func Test(t *testing.T) {
tests := tests() tests := tests()
gotoRootDirectory() rootDir := getRootDirectory()
rootDir, err := os.Getwd()
if err != nil {
panic(err)
}
record := os.Getenv("RECORD_EVENTS") != "" record := os.Getenv("RECORD_EVENTS") != ""
updateSnapshots := record || os.Getenv("UPDATE_SNAPSHOTS") != "" updateSnapshots := record || os.Getenv("UPDATE_SNAPSHOTS") != ""
@ -110,7 +111,15 @@ func Test(t *testing.T) {
test := test test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
speeds := []int{10, 5, 1} if usePty() {
t.Parallel()
}
startSpeed := 10
if test.startSpeed != 0 {
startSpeed = test.startSpeed
}
speeds := []int{startSpeed, 5, 1}
if updateSnapshots { if updateSnapshots {
// have to go at original speed if updating snapshots in case we go to fast and create a junk snapshot // have to go at original speed if updating snapshots in case we go to fast and create a junk snapshot
speeds = []int{1} speeds = []int{1}
@ -120,21 +129,19 @@ func Test(t *testing.T) {
t.Logf("%s: attempting test at speed %d\n", test.name, speed) t.Logf("%s: attempting test at speed %d\n", test.name, speed)
testPath := filepath.Join(rootDir, "test", "integration", test.name) testPath := filepath.Join(rootDir, "test", "integration", test.name)
actualDir := filepath.Join(testPath, "actual")
findOrCreateDir(testPath) findOrCreateDir(testPath)
snapshotPath := filepath.Join(testPath, "snapshot.txt") snapshotPath := filepath.Join(testPath, "snapshot.txt")
err := os.Chdir(rootDir) prepareIntegrationTestDir(testPath)
assert.NoError(t, err)
prepareIntegrationTestDir() err := createFixture(rootDir, test.fixture, actualDir)
err = createFixture(rootDir, test.fixture)
assert.NoError(t, err) assert.NoError(t, err)
runLazygit(t, testPath, rootDir, record, speed) runLazygit(t, testPath, rootDir, record, speed)
actual := generateSnapshot(t) actual := generateSnapshot(t, actualDir)
if updateSnapshots { if updateSnapshots {
err := ioutil.WriteFile(snapshotPath, []byte(actual), 0600) err := ioutil.WriteFile(snapshotPath, []byte(actual), 0600)
@ -146,6 +153,7 @@ func Test(t *testing.T) {
expected := string(expectedBytes) expected := string(expectedBytes)
if expected == actual { if expected == actual {
t.Logf("%s: success at speed %d\n", test.name, speed)
break break
} }
@ -158,9 +166,9 @@ func Test(t *testing.T) {
} }
} }
func createFixture(rootDir string, name string) error { func createFixture(rootDir string, name string, actualDir string) error {
osCommand := oscommands.NewDummyOSCommand() osCommand := oscommands.NewDummyOSCommand()
cmd := exec.Command("bash", filepath.Join(rootDir, "test", "fixtures", fmt.Sprintf("%s.sh", name))) cmd := exec.Command("bash", filepath.Join(rootDir, "test", "fixtures", fmt.Sprintf("%s.sh", name)), actualDir)
if err := osCommand.RunExecutable(cmd); err != nil { if err := osCommand.RunExecutable(cmd); err != nil {
return err return err
@ -169,20 +177,27 @@ func createFixture(rootDir string, name string) error {
return nil return nil
} }
func gotoRootDirectory() { func getRootDirectory() string {
path, err := os.Getwd()
if err != nil {
panic(err)
}
for { for {
_, err := os.Stat(".git") _, err := os.Stat(filepath.Join(path, ".git"))
if err == nil { if err == nil {
return return path
} }
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
panic(err) panic(err)
} }
if err = os.Chdir(".."); err != nil { path = filepath.Dir(path)
panic(err)
if path == "/" {
panic("must run in lazygit folder or child folder")
} }
} }
} }
@ -193,6 +208,7 @@ func runLazygit(t *testing.T, testPath string, rootDir string, record bool, spee
replayPath := filepath.Join(testPath, "recording.json") replayPath := filepath.Join(testPath, "recording.json")
cmdStr := fmt.Sprintf("go run %s", filepath.Join(rootDir, "main.go")) cmdStr := fmt.Sprintf("go run %s", filepath.Join(rootDir, "main.go"))
templateConfigDir := filepath.Join(rootDir, "test", "default_test_config") templateConfigDir := filepath.Join(rootDir, "test", "default_test_config")
actualDir := filepath.Join(testPath, "actual")
exists, err := osCommand.FileExists(filepath.Join(testPath, "config")) exists, err := osCommand.FileExists(filepath.Join(testPath, "config"))
assert.NoError(t, err) assert.NoError(t, err)
@ -201,14 +217,14 @@ func runLazygit(t *testing.T, testPath string, rootDir string, record bool, spee
templateConfigDir = filepath.Join(testPath, "config") templateConfigDir = filepath.Join(testPath, "config")
} }
configDir := filepath.Join(rootDir, "test", "integration_test_config") configDir := filepath.Join(testPath, "used_config")
err = os.RemoveAll(configDir) err = os.RemoveAll(configDir)
assert.NoError(t, err) assert.NoError(t, err)
err = oscommands.CopyDir(templateConfigDir, configDir) err = oscommands.CopyDir(templateConfigDir, configDir)
assert.NoError(t, err) assert.NoError(t, err)
cmdStr = fmt.Sprintf("%s --use-config-dir=%s", cmdStr, configDir) cmdStr = fmt.Sprintf("%s --use-config-dir=%s --path=%s", cmdStr, configDir, actualDir)
cmd := osCommand.ExecutableFromString(cmdStr) cmd := osCommand.ExecutableFromString(cmdStr)
cmd.Env = append(cmd.Env, fmt.Sprintf("REPLAY_SPEED=%d", speed)) cmd.Env = append(cmd.Env, fmt.Sprintf("REPLAY_SPEED=%d", speed))
@ -226,7 +242,7 @@ func runLazygit(t *testing.T, testPath string, rootDir string, record bool, spee
} }
// if we're on CI we'll need to use a PTY. We can work that out by seeing if the 'TERM' env is defined. // if we're on CI we'll need to use a PTY. We can work that out by seeing if the 'TERM' env is defined.
if os.Getenv("TERM") == "" { if usePty() {
cmd.Env = append(cmd.Env, "TERM=xterm") cmd.Env = append(cmd.Env, "TERM=xterm")
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 100, Cols: 100}) f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 100, Cols: 100})
@ -243,8 +259,13 @@ func runLazygit(t *testing.T, testPath string, rootDir string, record bool, spee
} }
} }
func prepareIntegrationTestDir() { func usePty() bool {
path := filepath.Join("test", "integration_test") return true
return os.Getenv("TERM") == ""
}
func prepareIntegrationTestDir(testPath string) {
path := filepath.Join(testPath, "actual")
// remove contents of integration test directory // remove contents of integration test directory
dir, err := ioutil.ReadDir(path) dir, err := ioutil.ReadDir(path)
@ -261,8 +282,4 @@ func prepareIntegrationTestDir() {
for _, d := range dir { for _, d := range dir {
os.RemoveAll(filepath.Join(path, d.Name())) os.RemoveAll(filepath.Join(path, d.Name()))
} }
if err := os.Chdir(path); err != nil {
panic(err)
}
} }

View File

@ -28,6 +28,11 @@ func (gui *Gui) replayRecordedEvents() {
return return
} }
go func() {
time.Sleep(time.Second * 20)
log.Fatal("20 seconds is up, lazygit recording took too long to complete")
}()
events, err := gui.loadRecordedEvents() events, err := gui.loadRecordedEvents()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -49,13 +54,26 @@ func (gui *Gui) replayRecordedEvents() {
} }
} }
for _, event := range events { // The playback could be paused at any time because integration tests run concurrently.
// Therefore we can't just check for a given event whether we've passed its timestamp,
// or else we'll have an explosion of keypresses after the test is resumed.
// We need to check if we've waited long enough since the last event was replayed.
for i, event := range events {
var prevEventTimestamp int64 = 0
if i > 0 {
prevEventTimestamp = events[i-1].Timestamp
}
timeToWait := (event.Timestamp - prevEventTimestamp) / int64(speed)
if i == 0 {
timeToWait += leeway
}
var timeWaited int64 = 0
middle: middle:
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
now := gui.timeSinceStart()*int64(speed) - leeway timeWaited += 1
if gui.g != nil && now >= event.Timestamp { if gui.g != nil && timeWaited >= timeToWait {
gui.g.ReplayedEvents <- *event.Event gui.g.ReplayedEvents <- *event.Event
break middle break middle
} }

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
cd $1
git init git init
git config user.email "CI@example.com" git config user.email "CI@example.com"

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
cd $1
git init git init
git config user.email "CI@example.com" git config user.email "CI@example.com"
git config user.name "CI" git config user.name "CI"

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
cd $1
git init git init
git config user.email "CI@example.com" git config user.email "CI@example.com"

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
cd $1
git init git init
git config user.email "CI@example.com" git config user.email "CI@example.com"

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
cd $1
git init git init
git config user.email "CI@example.com" git config user.email "CI@example.com"

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
cd $1
git init git init
git config user.email "CI@example.com" git config user.email "CI@example.com"