github.com/gofunct/common@v0.0.0-20190131174352-fd058c7fbf22/pkg/exec/testing/fake_exec.go (about)

     1  package testingexec
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/gofunct/common/pkg/exec"
     9  )
    10  
    11  // FakeExec is a simple scripted Interface type.
    12  type FakeExec struct {
    13  	CommandScript []FakeCommandAction
    14  	CommandCalls  int
    15  	LookPathFunc  func(string) (string, error)
    16  }
    17  
    18  var _ exec.Interface = &FakeExec{}
    19  
    20  // FakeCommandAction is the function to be executed
    21  type FakeCommandAction func(cmd string, args ...string) exec.Cmd
    22  
    23  // Command is to track the commands that are executed
    24  func (fake *FakeExec) Command(cmd string, args ...string) exec.Cmd {
    25  	if fake.CommandCalls > len(fake.CommandScript)-1 {
    26  		panic(fmt.Sprintf("ran out of Command() actions. Could not handle command [%d]: %s args: %v", fake.CommandCalls, cmd, args))
    27  	}
    28  	i := fake.CommandCalls
    29  	fake.CommandCalls++
    30  	return fake.CommandScript[i](cmd, args...)
    31  }
    32  
    33  // CommandContext wraps arguments into exec.Cmd
    34  func (fake *FakeExec) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd {
    35  	return fake.Command(cmd, args...)
    36  }
    37  
    38  // LookPath is for finding the path of a file
    39  func (fake *FakeExec) LookPath(file string) (string, error) {
    40  	return fake.LookPathFunc(file)
    41  }
    42  
    43  // FakeCmd is a simple scripted Cmd type.
    44  type FakeCmd struct {
    45  	Argv                 []string
    46  	CombinedOutputScript []FakeCombinedOutputAction
    47  	CombinedOutputCalls  int
    48  	CombinedOutputLog    [][]string
    49  	RunScript            []FakeRunAction
    50  	RunCalls             int
    51  	RunLog               [][]string
    52  	Dirs                 []string
    53  	Stdin                io.Reader
    54  	Stdout               io.Writer
    55  	Stderr               io.Writer
    56  	Env                  []string
    57  	StdoutPipeResponse   FakeStdIOPipeResponse
    58  	StderrPipeResponse   FakeStdIOPipeResponse
    59  	WaitResponse         error
    60  	StartResponse        error
    61  }
    62  
    63  var _ exec.Cmd = &FakeCmd{}
    64  
    65  // InitFakeCmd is for creating a fake exec.Cmd
    66  func InitFakeCmd(fake *FakeCmd, cmd string, args ...string) exec.Cmd {
    67  	fake.Argv = append([]string{cmd}, args...)
    68  	return fake
    69  }
    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  
    78  // FakeCombinedOutputAction is a function type
    79  type FakeCombinedOutputAction func() ([]byte, error)
    80  
    81  // FakeRunAction is a function type
    82  type FakeRunAction func() ([]byte, []byte, error)
    83  
    84  // SetDir sets the directory
    85  func (fake *FakeCmd) SetDir(dir string) {
    86  	fake.Dirs = append(fake.Dirs, dir)
    87  }
    88  
    89  // SetStdin sets the stdin
    90  func (fake *FakeCmd) SetStdin(in io.Reader) {
    91  	fake.Stdin = in
    92  }
    93  
    94  // SetStdout sets the stdout
    95  func (fake *FakeCmd) SetStdout(out io.Writer) {
    96  	fake.Stdout = out
    97  }
    98  
    99  // SetStderr sets the stderr
   100  func (fake *FakeCmd) SetStderr(out io.Writer) {
   101  	fake.Stderr = out
   102  }
   103  
   104  // SetEnv sets the environment variables
   105  func (fake *FakeCmd) SetEnv(env []string) {
   106  	fake.Env = env
   107  }
   108  
   109  // StdoutPipe returns an injected ReadCloser & error (via StdoutPipeResponse)
   110  // to be able to inject an output stream on Stdout
   111  func (fake *FakeCmd) StdoutPipe() (io.ReadCloser, error) {
   112  	return fake.StdoutPipeResponse.ReadCloser, fake.StdoutPipeResponse.Error
   113  }
   114  
   115  // StderrPipe returns an injected ReadCloser & error (via StderrPipeResponse)
   116  // to be able to inject an output stream on Stderr
   117  func (fake *FakeCmd) StderrPipe() (io.ReadCloser, error) {
   118  	return fake.StderrPipeResponse.ReadCloser, fake.StderrPipeResponse.Error
   119  }
   120  
   121  // Start mimicks starting the process (in the background) and returns the
   122  // injected StartResponse
   123  func (fake *FakeCmd) Start() error {
   124  	return fake.StartResponse
   125  }
   126  
   127  // Wait mimicks waiting for the process to exit returns the
   128  // injected WaitResponse
   129  func (fake *FakeCmd) Wait() error {
   130  	return fake.WaitResponse
   131  }
   132  
   133  // Run sets runs the command
   134  func (fake *FakeCmd) Run() error {
   135  	if fake.RunCalls > len(fake.RunScript)-1 {
   136  		panic("ran out of Run() actions")
   137  	}
   138  	if fake.RunLog == nil {
   139  		fake.RunLog = [][]string{}
   140  	}
   141  	i := fake.RunCalls
   142  	fake.RunLog = append(fake.RunLog, append([]string{}, fake.Argv...))
   143  	fake.RunCalls++
   144  	stdout, stderr, err := fake.RunScript[i]()
   145  	if stdout != nil {
   146  		fake.Stdout.Write(stdout)
   147  	}
   148  	if stderr != nil {
   149  		fake.Stderr.Write(stderr)
   150  	}
   151  	return err
   152  }
   153  
   154  // CombinedOutput returns the output from the command
   155  func (fake *FakeCmd) CombinedOutput() ([]byte, error) {
   156  	if fake.CombinedOutputCalls > len(fake.CombinedOutputScript)-1 {
   157  		panic("ran out of CombinedOutput() actions")
   158  	}
   159  	if fake.CombinedOutputLog == nil {
   160  		fake.CombinedOutputLog = [][]string{}
   161  	}
   162  	i := fake.CombinedOutputCalls
   163  	fake.CombinedOutputLog = append(fake.CombinedOutputLog, append([]string{}, fake.Argv...))
   164  	fake.CombinedOutputCalls++
   165  	return fake.CombinedOutputScript[i]()
   166  }
   167  
   168  // Output is the response from the command
   169  func (fake *FakeCmd) Output() ([]byte, error) {
   170  	return nil, fmt.Errorf("unimplemented")
   171  }
   172  
   173  // Stop is to stop the process
   174  func (fake *FakeCmd) Stop() {
   175  	// no-op
   176  }
   177  
   178  // FakeExitError is a simple fake ExitError type.
   179  type FakeExitError struct {
   180  	Status int
   181  }
   182  
   183  var _ exec.ExitError = FakeExitError{}
   184  
   185  func (fake FakeExitError) String() string {
   186  	return fmt.Sprintf("exit %d", fake.Status)
   187  }
   188  
   189  func (fake FakeExitError) Error() string {
   190  	return fake.String()
   191  }
   192  
   193  // Exited always returns true
   194  func (fake FakeExitError) Exited() bool {
   195  	return true
   196  }
   197  
   198  // ExitStatus returns the fake status
   199  func (fake FakeExitError) ExitStatus() int {
   200  	return fake.Status
   201  }