-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathhelper.go
More file actions
119 lines (103 loc) · 4.11 KB
/
helper.go
File metadata and controls
119 lines (103 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package cmd
import (
"fmt"
"io"
"os"
"os/exec"
"strings"
"time"
"github.com/deis/workflow-e2e/tests/model"
"github.com/deis/workflow-e2e/tests/settings"
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
)
// The functions in this file implement a generic command execution and inspection framework.
// Execute executes the command generated by fmt.Sprintf(cmdLine, args...) and returns its output.
func Execute(cmdLine string, args ...interface{}) (string, error) {
var cmd *exec.Cmd
shCommand := fmt.Sprintf(cmdLine, args...)
if settings.Debug {
fmt.Println(shCommand)
}
cmd = exec.Command("/bin/sh", "-c", shCommand)
outputBytes, err := cmd.CombinedOutput()
output := string(outputBytes)
if settings.Debug {
fmt.Println(output)
}
return output, err
}
// Start executes the provided command (often a `deis` command of some sort) as the specified user
// (by selecting the corresponding profile). Optional arguments may also be supplied that will be
// substituted into the provided command using fmt.Sprintf(...).
func Start(cmdLine string, user *model.User, args ...interface{}) (*gexec.Session, error) {
if user != nil {
envVars := append(os.Environ(), fmt.Sprintf("DEIS_PROFILE=%s", user.Username))
ourCommand := model.Cmd{Env: envVars, CommandLineString: fmt.Sprintf(cmdLine, args...)}
return StartCmd(ourCommand)
}
ourCommand := model.Cmd{Env: os.Environ(), CommandLineString: fmt.Sprintf(cmdLine, args...)}
return StartCmd(ourCommand)
}
// StartCmd executes the provided model.Command. It is used primarily by the Start function
// (above), but is also used directly in scenarios where tests must execute fine-grained control
// over the environment in which the command will be executed.
func StartCmd(command model.Cmd) (*gexec.Session, error) {
execCmd := exec.Command("/bin/sh", "-c", command.CommandLineString)
execCmd.Env = command.Env
io.WriteString(ginkgo.GinkgoWriter, fmt.Sprintf("$ %s\n", command.CommandLineString))
return gexec.Start(execCmd, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
}
// Retry runs the provided <cmd> repeatedly, once a second up to the
// supplied <timeout> until the <cmd> result contains the <expectedResult>
// An example use of this utility would be curl-ing a url and waiting
// until the response code matches the expected response.
// TODO: https://github.com/deis/workflow-e2e/issues/240
func Retry(command model.Cmd, expectedResult string, timeout int) bool {
var result string
fmt.Fprintf(ginkgo.GinkgoWriter, "Waiting up to %d seconds for `%s` to return %s...\n", timeout, command.CommandLineString, expectedResult)
for i := 0; i < timeout; i++ {
sess, err := StartCmd(command)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
result = string(sess.Wait().Out.Contents())
if strings.Contains(result, expectedResult) {
return true
}
time.Sleep(1 * time.Second)
}
fmt.Fprintf(ginkgo.GinkgoWriter, "FAIL: '%s' does not match expected result of '%s'\n", result, expectedResult)
return false
}
// RetryUntilResult runs the provided cmd repeatedly, once every period,
// up to the supplied timeout until the cmd result matches the supplied
// expectedCmdResult
func RetryUntilResult(command model.Cmd, expectedCmdResult model.CmdResult, period, timeout time.Duration) bool {
var actualCmdResult model.CmdResult
fmt.Fprintf(ginkgo.GinkgoWriter,
"Waiting up to %d seconds for `%s` to return expected cmdResult %s...\n",
int(timeout.Seconds()), command.CommandLineString, expectedCmdResult.String())
tck := time.NewTicker(period)
tmr := time.NewTimer(timeout)
defer tck.Stop()
defer tmr.Stop()
for {
select {
case <-tck.C:
sess, err := StartCmd(command)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
sessWait := sess.Wait()
actualCmdResult = model.CmdResult{
Out: sessWait.Out.Contents(),
Err: sessWait.Err.Contents(),
ExitCode: sessWait.ExitCode(),
}
if actualCmdResult.Satisfies(expectedCmdResult) {
return true
}
case <-tmr.C:
fmt.Fprintf(ginkgo.GinkgoWriter, "FAIL: Actual cmdResult '%v' does not match expected cmdResult '%v'\n", actualCmdResult, expectedCmdResult)
return false
}
}
}