fake_exec.go 5.8 KB

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