...
1 package helper
2
3 import (
4 "fmt"
5 "os"
6 "os/exec"
7 "path/filepath"
8 "runtime"
9 "time"
10
11 . "github.com/onsi/ginkgo/v2"
12 . "github.com/onsi/gomega"
13 "github.com/onsi/gomega/gexec"
14 )
15
16 type CmdWrapper struct {
17 Cmd *exec.Cmd
18 program string
19 args []string
20 writer *gexec.PrefixedWriter
21 session *gexec.Session
22 timeout time.Duration
23 intervalSeconds time.Duration
24 stopChan chan bool
25 err error
26 maxRetry int
27 pass bool
28 }
29
30 func Cmd(program string, args ...string) *CmdWrapper {
31 prefix := fmt.Sprintf("[%s] ", filepath.Base(program))
32 prefixWriter := gexec.NewPrefixedWriter(prefix, GinkgoWriter)
33 command := exec.Command(program, args...)
34 setSysProcAttr(command)
35 return &CmdWrapper{
36 Cmd: command,
37 program: program,
38 args: args,
39 writer: prefixWriter,
40 }
41 }
42
43 func (cw *CmdWrapper) Runner() *CmdWrapper {
44 fmt.Fprintln(GinkgoWriter, runningCmd(cw.Cmd))
45 cw.session, cw.err = gexec.Start(cw.Cmd, cw.writer, cw.writer)
46 timeout := time.After(cw.timeout)
47 if cw.timeout > 0 {
48 select {
49 case <-cw.stopChan:
50 if cw.session != nil {
51 if runtime.GOOS == "windows" {
52 cw.session.Kill()
53 } else {
54 cw.session.Terminate()
55 }
56 }
57 case <-timeout:
58 if cw.session != nil {
59 if runtime.GOOS == "windows" {
60 cw.session.Kill()
61 } else {
62 cw.session.Terminate()
63 }
64 }
65 }
66 } else if cw.maxRetry > 0 {
67 cw.session.Wait()
68
69 if !cw.pass {
70
71
72 if cw.session.ExitCode() == 0 {
73 time.Sleep(cw.intervalSeconds * time.Second)
74 cw.maxRetry = cw.maxRetry - 1
75 cw.Runner()
76 }
77 return cw
78 } else {
79
80 if cw.session.ExitCode() != 0 {
81 time.Sleep(cw.intervalSeconds * time.Second)
82 cw.maxRetry = cw.maxRetry - 1
83 cw.Runner()
84 }
85 return cw
86 }
87 }
88 return cw
89 }
90
91 func (cw *CmdWrapper) WithRetry(maxRetry int, intervalSeconds time.Duration) *CmdWrapper {
92 cw.maxRetry = maxRetry
93 cw.intervalSeconds = intervalSeconds
94 return cw
95 }
96
97 func (cw *CmdWrapper) ShouldPass() *CmdWrapper {
98 cw.pass = true
99 cw.Runner()
100 Expect(cw.err).NotTo(HaveOccurred())
101 Eventually(cw.session).Should(gexec.Exit(0), runningCmd(cw.session.Command))
102 return cw
103 }
104
105 func (cw *CmdWrapper) ShouldFail() *CmdWrapper {
106 cw.pass = false
107 cw.Runner()
108 Consistently(cw.session).ShouldNot(gexec.Exit(0), runningCmd(cw.session.Command))
109 return cw
110 }
111
112 func (cw *CmdWrapper) ShouldRun() *CmdWrapper {
113 cw.Runner()
114 return cw
115 }
116
117 func (cw *CmdWrapper) Should(f func(session *gexec.Session)) {
118 cw.Runner()
119 f(cw.session)
120 cw.session.Wait()
121 }
122
123 func (cw *CmdWrapper) WithTerminate(timeoutAfter time.Duration, stop chan bool) *CmdWrapper {
124 cw.timeout = timeoutAfter * time.Second
125 cw.stopChan = stop
126 return cw
127 }
128
129 func (cw *CmdWrapper) WithTimeout(timeoutAfter time.Duration) *CmdWrapper {
130 cw.timeout = timeoutAfter * time.Second
131 return cw
132 }
133
134 func (cw *CmdWrapper) WithWorkingDir(dir string) *CmdWrapper {
135 cw.Cmd.Dir = dir
136 return cw
137 }
138
139 func (cw *CmdWrapper) WithEnv(args ...string) *CmdWrapper {
140 cw.Cmd.Env = args
141 return cw
142 }
143
144 func (cw *CmdWrapper) AddEnv(args ...string) *CmdWrapper {
145 if cw.Cmd.Env == nil {
146 cw.Cmd.Env = append(cw.Cmd.Env, os.Environ()...)
147 }
148 cw.Cmd.Env = append(cw.Cmd.Env, args...)
149 return cw
150 }
151
152 func (cw *CmdWrapper) OutAndErr() (string, string) {
153 return string(cw.session.Wait().Out.Contents()), string(cw.session.Wait().Err.Contents())
154 }
155
156 func (cw *CmdWrapper) Out() string {
157 return string(cw.session.Wait().Out.Contents())
158 }
159
160 func (cw *CmdWrapper) Err() string {
161 return string(cw.session.Wait().Err.Contents())
162 }
163
View as plain text