Skip to content

Commit cc7ff9b

Browse files
author
Vaughn Dice
committed
feat(git_push_test.go): add git push interrupt test
[skip ci] Depends on (currently pending) fix in deis/builder#369
1 parent 692b000 commit cc7ff9b

4 files changed

Lines changed: 117 additions & 2 deletions

File tree

tests/cmd/git/commands.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,29 @@ package git
33
import (
44
"fmt"
55
"net/http"
6+
"os"
67
"strconv"
8+
"time"
79

810
"github.com/deis/workflow-e2e/tests/cmd"
911
"github.com/deis/workflow-e2e/tests/model"
1012
"github.com/deis/workflow-e2e/tests/settings"
1113

1214
. "github.com/onsi/gomega"
15+
. "github.com/onsi/gomega/gbytes"
1316
. "github.com/onsi/gomega/gexec"
1417
)
1518

1619
// The functions in this file implement SUCCESS CASES for commonly used `git` commands.
1720
// This allows each of these to be re-used easily in multiple contexts.
1821

22+
const (
23+
pushCommandLineString = "GIT_SSH=%s GIT_KEY=%s git push deis master"
24+
)
25+
1926
// Push executes a `git push deis master` from the current directory using the provided key.
2027
func Push(user model.User, keyPath string, app model.App, banner string) {
21-
sess, err := cmd.Start("GIT_SSH=%s GIT_KEY=%s git push deis master", &user, settings.GitSSH, keyPath)
22-
Expect(err).NotTo(HaveOccurred())
28+
sess := doGitPush(user, keyPath)
2329
// sess.Wait(settings.MaxEventuallyTimeout)
2430
// output := string(sess.Out.Contents())
2531
// Expect(output).To(MatchRegexp(`Done, %s:v\d deployed to Deis`, app.Name))
@@ -33,3 +39,36 @@ func Push(user model.User, keyPath string, app model.App, banner string) {
3339
curlCmd = model.Cmd{CommandLineString: fmt.Sprintf(`curl -sL "%s"`, app.URL)}
3440
Eventually(cmd.Retry(curlCmd, banner, cmdRetryTimeout)).Should(BeTrue())
3541
}
42+
43+
// PushWithInterrupt executes a `git push deis master` from the current
44+
// directory using the provided key, but then halts the progress via SIGINT.
45+
func PushWithInterrupt(user model.User, keyPath string) {
46+
sess := doGitPush(user, keyPath)
47+
Eventually(sess.Err).Should(Say("Starting build... but first, coffee!"))
48+
49+
sess = sess.Interrupt()
50+
51+
newSess := doGitPush(user, keyPath)
52+
Eventually(newSess.Err).ShouldNot(Say("exec request failed on channel 0"))
53+
Eventually(newSess.Err).Should(Say("fatal: remote error: Another git push is ongoing"))
54+
Eventually(newSess, settings.MaxEventuallyTimeout).Should(Exit(128))
55+
}
56+
57+
// PushUntilResult executes a `git push deis master` from the current
58+
// directory using the provided key, until the command result satisfies
59+
// expectedCmdResult of type model.CmdResult, failing if
60+
// settings.DefaultEventuallyTimeout is reached first.
61+
func PushUntilResult(user model.User, keyPath string, expectedCmdResult model.CmdResult) {
62+
envVars := append(os.Environ(), fmt.Sprintf("DEIS_PROFILE=%s", user.Username))
63+
pushCmd := model.Cmd{Env: envVars, CommandLineString: fmt.Sprintf(
64+
pushCommandLineString, settings.GitSSH, keyPath)}
65+
66+
Eventually(cmd.RetryUntilResult(pushCmd, expectedCmdResult, 5*time.Second,
67+
settings.DefaultEventuallyTimeout)).Should(BeTrue())
68+
}
69+
70+
func doGitPush(user model.User, keyPath string) *Session {
71+
sess, err := cmd.Start(pushCommandLineString, &user, settings.GitSSH, keyPath)
72+
Expect(err).NotTo(HaveOccurred())
73+
return sess
74+
}

tests/cmd/helper.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ func StartCmd(command model.Cmd) (*gexec.Session, error) {
6666
// supplied <timeout> until the <cmd> result contains the <expectedResult>
6767
// An example use of this utility would be curl-ing a url and waiting
6868
// until the response code matches the expected response.
69+
// TODO: https://github.com/deis/workflow-e2e/issues/240
6970
func Retry(command model.Cmd, expectedResult string, timeout int) bool {
7071
var result string
7172
fmt.Fprintf(ginkgo.GinkgoWriter, "Waiting up to %d seconds for `%s` to return %s...\n", timeout, command.CommandLineString, expectedResult)
@@ -81,3 +82,38 @@ func Retry(command model.Cmd, expectedResult string, timeout int) bool {
8182
fmt.Fprintf(ginkgo.GinkgoWriter, "FAIL: '%s' does not match expected result of '%s'\n", result, expectedResult)
8283
return false
8384
}
85+
86+
// RetryUntilResult runs the provided cmd repeatedly, once every period,
87+
// up to the supplied timeout until the cmd result matches the supplied
88+
// expectedCmdResult
89+
func RetryUntilResult(command model.Cmd, expectedCmdResult model.CmdResult, period, timeout time.Duration) bool {
90+
var actualCmdResult model.CmdResult
91+
92+
fmt.Fprintf(ginkgo.GinkgoWriter,
93+
"Waiting up to %d seconds for `%s` to return expected cmdResult %s...\n",
94+
int(timeout.Seconds()), command.CommandLineString, expectedCmdResult.String())
95+
96+
tck := time.NewTicker(period)
97+
tmr := time.NewTimer(timeout)
98+
defer tck.Stop()
99+
defer tmr.Stop()
100+
for {
101+
select {
102+
case <-tck.C:
103+
sess, err := StartCmd(command)
104+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
105+
sessWait := sess.Wait()
106+
actualCmdResult = model.CmdResult{
107+
Out: sessWait.Out.Contents(),
108+
Err: sessWait.Err.Contents(),
109+
ExitCode: sessWait.ExitCode(),
110+
}
111+
if actualCmdResult.Satisfies(expectedCmdResult) {
112+
return true
113+
}
114+
case <-tmr.C:
115+
fmt.Fprintf(ginkgo.GinkgoWriter, "FAIL: Actual cmdResult '%v' does not match expected cmdResult '%v'\n", actualCmdResult, expectedCmdResult)
116+
return false
117+
}
118+
}
119+
}

tests/git_push_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ var _ = Describe("git push deis master", func() {
5959
git.Push(user, keyPath, app, "Powered by Deis")
6060
})
6161

62+
Specify("that user can interrupt the deploy of the app and recover", func() {
63+
git.PushWithInterrupt(user, keyPath)
64+
65+
git.PushUntilResult(user, keyPath,
66+
model.CmdResult{
67+
Out: nil,
68+
Err: []byte("Everything up-to-date"),
69+
ExitCode: 0,
70+
})
71+
})
72+
6273
})
6374

6475
})

tests/model/model.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package model
22

33
import (
4+
"bytes"
45
"fmt"
56
"math/rand"
67
"path"
@@ -72,3 +73,31 @@ func getDir() string {
7273
_, filename, _, _ := runtime.Caller(1)
7374
return path.Dir(filename)
7475
}
76+
77+
// CmdResult represents a generic command result, with expected Out, Err and
78+
// ExitCode
79+
type CmdResult struct {
80+
Out []byte
81+
Err []byte
82+
ExitCode int
83+
}
84+
85+
// Satisfies returns whether or not the original CmdResult, ocd, meets all of
86+
// the expectations contained in the expeced CmdResult, ecd
87+
func (ocd CmdResult) Satisfies(ecd CmdResult) bool {
88+
if !bytes.Contains(ocd.Out, ecd.Out) {
89+
return false
90+
}
91+
if !bytes.Contains(ocd.Err, ecd.Err) {
92+
return false
93+
}
94+
if ocd.ExitCode != ecd.ExitCode {
95+
return false
96+
}
97+
return true
98+
}
99+
100+
// String returns the CmdResult in printable form
101+
func (ocd CmdResult) String() string {
102+
return fmt.Sprintf("[Out: '%s', Err: '%s', ExitCode: '%d']", ocd.Out, ocd.Err, ocd.ExitCode)
103+
}

0 commit comments

Comments
 (0)