github.com/jaylevin/jenkins-library@v1.230.4/pkg/mock/runner.go (about) 1 //go:build !release 2 // +build !release 3 4 package mock 5 6 import ( 7 "io" 8 "io/ioutil" 9 "regexp" 10 "strings" 11 12 "github.com/SAP/jenkins-library/pkg/command" 13 ) 14 15 type ExecMockRunner struct { 16 Dir []string 17 Env []string 18 ExitCode int 19 Calls []ExecCall 20 stdin io.Reader 21 stdout io.Writer 22 stderr io.Writer 23 Stub func(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error 24 StdoutReturn map[string]string 25 ShouldFailOnCommand map[string]error 26 } 27 28 type ExecCall struct { 29 Execution *Execution 30 Async bool 31 Exec string 32 Params []string 33 } 34 35 type Execution struct { 36 Killed bool 37 } 38 39 type ShellMockRunner struct { 40 Dir string 41 Env []string 42 ExitCode int 43 Calls []string 44 Shell []string 45 stdin io.Reader 46 stdout io.Writer 47 stderr io.Writer 48 StdoutReturn map[string]string 49 ShouldFailOnCommand map[string]error 50 } 51 52 func (m *ExecMockRunner) SetDir(d string) { 53 m.Dir = append(m.Dir, d) 54 } 55 56 func (m *ExecMockRunner) SetEnv(e []string) { 57 m.Env = e 58 } 59 60 func (m *ExecMockRunner) AppendEnv(e []string) { 61 m.Env = append(m.Env, e...) 62 } 63 64 func (m *ExecMockRunner) RunExecutable(e string, p ...string) error { 65 66 exec := ExecCall{Exec: e, Params: p} 67 m.Calls = append(m.Calls, exec) 68 69 c := strings.Join(append([]string{e}, p...), " ") 70 71 return m.handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) 72 } 73 74 func (m *ExecMockRunner) GetExitCode() int { 75 return m.ExitCode 76 } 77 78 func (m *ExecMockRunner) RunExecutableInBackground(e string, p ...string) (command.Execution, error) { 79 80 execution := Execution{} 81 exec := ExecCall{Exec: e, Params: p, Async: true, Execution: &execution} 82 m.Calls = append(m.Calls, exec) 83 84 c := strings.Join(append([]string{e}, p...), " ") 85 86 err := m.handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) 87 if err != nil { 88 return nil, err 89 } 90 return &execution, nil 91 } 92 93 func (m *ExecMockRunner) Stdin(in io.Reader) { 94 m.stdin = in 95 } 96 97 func (m *ExecMockRunner) Stdout(out io.Writer) { 98 m.stdout = out 99 } 100 101 func (m *ExecMockRunner) GetStdout() io.Writer { 102 return m.stdout 103 } 104 105 func (m *ExecMockRunner) Stderr(err io.Writer) { 106 m.stderr = err 107 } 108 109 func (m *ExecMockRunner) GetStderr() io.Writer { 110 return m.stderr 111 } 112 113 func (m *ExecMockRunner) handleCall(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error { 114 if m.Stub != nil { 115 return m.Stub(call, stdoutReturn, shouldFailOnCommand, stdout) 116 } else { 117 return handleCall(call, stdoutReturn, shouldFailOnCommand, stdout) 118 } 119 } 120 121 func (m *ShellMockRunner) SetDir(d string) { 122 m.Dir = d 123 } 124 125 func (m *ShellMockRunner) SetEnv(e []string) { 126 m.Env = append(m.Env, e...) 127 } 128 129 func (m *ShellMockRunner) AppendEnv(e []string) { 130 m.Env = append(m.Env, e...) 131 } 132 133 func (m *ShellMockRunner) RunShell(s string, c string) error { 134 135 m.Shell = append(m.Shell, s) 136 m.Calls = append(m.Calls, c) 137 138 return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) 139 } 140 141 func (m *ShellMockRunner) GetExitCode() int { 142 return m.ExitCode 143 } 144 145 func (e *Execution) Kill() error { 146 e.Killed = true 147 return nil 148 } 149 150 func (e *Execution) Wait() error { 151 return nil 152 } 153 154 func handleCall(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error { 155 156 if stdoutReturn != nil { 157 for k, v := range stdoutReturn { 158 159 found := k == call 160 161 if !found { 162 163 r, e := regexp.Compile(k) 164 if e != nil { 165 return e 166 // we don't distinguish here between an error returned 167 // since it was configured or returning this error here 168 // indicating an invalid regex. Anyway: when running the 169 // test we will see it ... 170 } 171 if r.MatchString(call) { 172 found = true 173 174 } 175 } 176 177 if found { 178 stdout.Write([]byte(v)) 179 } 180 } 181 } 182 183 if shouldFailOnCommand != nil { 184 for k, v := range shouldFailOnCommand { 185 186 found := k == call 187 188 if !found { 189 r, e := regexp.Compile(k) 190 if e != nil { 191 return e 192 // we don't distinguish here between an error returned 193 // since it was configured or returning this error here 194 // indicating an invalid regex. Anyway: when running the 195 // test we will see it ... 196 } 197 if r.MatchString(call) { 198 found = true 199 200 } 201 } 202 203 if found { 204 return v 205 } 206 } 207 } 208 209 return nil 210 } 211 212 func (m *ShellMockRunner) Stdin(in io.Reader) { 213 m.stdin = in 214 } 215 216 func (m *ShellMockRunner) Stdout(out io.Writer) { 217 m.stdout = out 218 } 219 220 func (m *ShellMockRunner) GetStdout() io.Writer { 221 return m.stdout 222 } 223 224 func (m *ShellMockRunner) GetStderr() io.Writer { 225 return m.stderr 226 } 227 228 func (m *ShellMockRunner) Stderr(err io.Writer) { 229 m.stderr = err 230 } 231 232 type StepOptions struct { 233 TestParam string `json:"testParam,omitempty"` 234 } 235 236 func OpenFileMock(name string, tokens map[string]string) (io.ReadCloser, error) { 237 var r string 238 switch name { 239 case "testDefaults.yml": 240 r = "general:\n testParam: testValue" 241 case "testDefaultsInvalid.yml": 242 r = "invalid yaml" 243 default: 244 r = "" 245 } 246 return ioutil.NopCloser(strings.NewReader(r)), nil 247 }