github.com/kubernetes/utils@v0.0.0-20190308190857-21c4ce38f2a7/exec/testing/fake_exec.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package testingexec 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 24 "k8s.io/utils/exec" 25 ) 26 27 // FakeExec is a simple scripted Interface type. 28 type FakeExec struct { 29 CommandScript []FakeCommandAction 30 CommandCalls int 31 LookPathFunc func(string) (string, error) 32 } 33 34 var _ exec.Interface = &FakeExec{} 35 36 // FakeCommandAction is the function to be executed 37 type FakeCommandAction func(cmd string, args ...string) exec.Cmd 38 39 // Command is to track the commands that are executed 40 func (fake *FakeExec) Command(cmd string, args ...string) exec.Cmd { 41 if fake.CommandCalls > len(fake.CommandScript)-1 { 42 panic(fmt.Sprintf("ran out of Command() actions. Could not handle command [%d]: %s args: %v", fake.CommandCalls, cmd, args)) 43 } 44 i := fake.CommandCalls 45 fake.CommandCalls++ 46 return fake.CommandScript[i](cmd, args...) 47 } 48 49 // CommandContext wraps arguments into exec.Cmd 50 func (fake *FakeExec) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd { 51 return fake.Command(cmd, args...) 52 } 53 54 // LookPath is for finding the path of a file 55 func (fake *FakeExec) LookPath(file string) (string, error) { 56 return fake.LookPathFunc(file) 57 } 58 59 // FakeCmd is a simple scripted Cmd type. 60 type FakeCmd struct { 61 Argv []string 62 CombinedOutputScript []FakeCombinedOutputAction 63 CombinedOutputCalls int 64 CombinedOutputLog [][]string 65 RunScript []FakeRunAction 66 RunCalls int 67 RunLog [][]string 68 Dirs []string 69 Stdin io.Reader 70 Stdout io.Writer 71 Stderr io.Writer 72 Env []string 73 StdoutPipeResponse FakeStdIOPipeResponse 74 StderrPipeResponse FakeStdIOPipeResponse 75 WaitResponse error 76 StartResponse error 77 } 78 79 var _ exec.Cmd = &FakeCmd{} 80 81 // InitFakeCmd is for creating a fake exec.Cmd 82 func InitFakeCmd(fake *FakeCmd, cmd string, args ...string) exec.Cmd { 83 fake.Argv = append([]string{cmd}, args...) 84 return fake 85 } 86 87 // FakeStdIOPipeResponse holds responses to use as fakes for the StdoutPipe and 88 // StderrPipe method calls 89 type FakeStdIOPipeResponse struct { 90 ReadCloser io.ReadCloser 91 Error error 92 } 93 94 // FakeCombinedOutputAction is a function type 95 type FakeCombinedOutputAction func() ([]byte, error) 96 97 // FakeRunAction is a function type 98 type FakeRunAction func() ([]byte, []byte, error) 99 100 // SetDir sets the directory 101 func (fake *FakeCmd) SetDir(dir string) { 102 fake.Dirs = append(fake.Dirs, dir) 103 } 104 105 // SetStdin sets the stdin 106 func (fake *FakeCmd) SetStdin(in io.Reader) { 107 fake.Stdin = in 108 } 109 110 // SetStdout sets the stdout 111 func (fake *FakeCmd) SetStdout(out io.Writer) { 112 fake.Stdout = out 113 } 114 115 // SetStderr sets the stderr 116 func (fake *FakeCmd) SetStderr(out io.Writer) { 117 fake.Stderr = out 118 } 119 120 // SetEnv sets the environment variables 121 func (fake *FakeCmd) SetEnv(env []string) { 122 fake.Env = env 123 } 124 125 // StdoutPipe returns an injected ReadCloser & error (via StdoutPipeResponse) 126 // to be able to inject an output stream on Stdout 127 func (fake *FakeCmd) StdoutPipe() (io.ReadCloser, error) { 128 return fake.StdoutPipeResponse.ReadCloser, fake.StdoutPipeResponse.Error 129 } 130 131 // StderrPipe returns an injected ReadCloser & error (via StderrPipeResponse) 132 // to be able to inject an output stream on Stderr 133 func (fake *FakeCmd) StderrPipe() (io.ReadCloser, error) { 134 return fake.StderrPipeResponse.ReadCloser, fake.StderrPipeResponse.Error 135 } 136 137 // Start mimicks starting the process (in the background) and returns the 138 // injected StartResponse 139 func (fake *FakeCmd) Start() error { 140 return fake.StartResponse 141 } 142 143 // Wait mimicks waiting for the process to exit returns the 144 // injected WaitResponse 145 func (fake *FakeCmd) Wait() error { 146 return fake.WaitResponse 147 } 148 149 // Run sets runs the command 150 func (fake *FakeCmd) Run() error { 151 if fake.RunCalls > len(fake.RunScript)-1 { 152 panic("ran out of Run() actions") 153 } 154 if fake.RunLog == nil { 155 fake.RunLog = [][]string{} 156 } 157 i := fake.RunCalls 158 fake.RunLog = append(fake.RunLog, append([]string{}, fake.Argv...)) 159 fake.RunCalls++ 160 stdout, stderr, err := fake.RunScript[i]() 161 if stdout != nil { 162 fake.Stdout.Write(stdout) 163 } 164 if stderr != nil { 165 fake.Stderr.Write(stderr) 166 } 167 return err 168 } 169 170 // CombinedOutput returns the output from the command 171 func (fake *FakeCmd) CombinedOutput() ([]byte, error) { 172 if fake.CombinedOutputCalls > len(fake.CombinedOutputScript)-1 { 173 panic("ran out of CombinedOutput() actions") 174 } 175 if fake.CombinedOutputLog == nil { 176 fake.CombinedOutputLog = [][]string{} 177 } 178 i := fake.CombinedOutputCalls 179 fake.CombinedOutputLog = append(fake.CombinedOutputLog, append([]string{}, fake.Argv...)) 180 fake.CombinedOutputCalls++ 181 return fake.CombinedOutputScript[i]() 182 } 183 184 // Output is the response from the command 185 func (fake *FakeCmd) Output() ([]byte, error) { 186 return nil, fmt.Errorf("unimplemented") 187 } 188 189 // Stop is to stop the process 190 func (fake *FakeCmd) Stop() { 191 // no-op 192 } 193 194 // FakeExitError is a simple fake ExitError type. 195 type FakeExitError struct { 196 Status int 197 } 198 199 var _ exec.ExitError = FakeExitError{} 200 201 func (fake FakeExitError) String() string { 202 return fmt.Sprintf("exit %d", fake.Status) 203 } 204 205 func (fake FakeExitError) Error() string { 206 return fake.String() 207 } 208 209 // Exited always returns true 210 func (fake FakeExitError) Exited() bool { 211 return true 212 } 213 214 // ExitStatus returns the fake status 215 func (fake FakeExitError) ExitStatus() int { 216 return fake.Status 217 }