@@ -20,6 +20,7 @@ import (
2020 "context"
2121 "fmt"
2222 "io"
23+ "sync"
2324
2425 "k8s.io/utils/exec"
2526)
@@ -32,30 +33,28 @@ type FakeExec struct {
3233 // ExactOrder enforces that commands are called in the order they are scripted,
3334 // and with the exact same arguments
3435 ExactOrder bool
35- // DisableScripts removes the requirement that a slice of FakeCommandAction be
36- // populated before calling Command(). This makes the fakeexec (and subsequent
37- // calls to Run() or CombinedOutput() always return success and there is no
38- // ability to set their output.
36+ // DisableScripts removes the requirement that CommandScripts be populated
37+ // before calling Command(). This makes Command() and subsequent calls to
38+ // Run() or CombinedOutput() always return success and empty output.
3939 DisableScripts bool
40+
41+ mu sync.Mutex
4042}
4143
4244var _ exec.Interface = & FakeExec {}
4345
4446// FakeCommandAction is the function to be executed
4547type FakeCommandAction func (cmd string , args ... string ) exec.Cmd
4648
47- // Command is to track the commands that are executed
49+ // Command returns the next unexecuted command in CommandScripts.
50+ // This function is safe for concurrent access as long as the underlying
51+ // FakeExec struct is not modified during execution.
4852func (fake * FakeExec ) Command (cmd string , args ... string ) exec.Cmd {
4953 if fake .DisableScripts {
5054 fakeCmd := & FakeCmd {DisableScripts : true }
5155 return InitFakeCmd (fakeCmd , cmd , args ... )
5256 }
53- if fake .CommandCalls > len (fake .CommandScript )- 1 {
54- panic (fmt .Sprintf ("ran out of Command() actions. Could not handle command [%d]: %s args: %v" , fake .CommandCalls , cmd , args ))
55- }
56- i := fake .CommandCalls
57- fake .CommandCalls ++
58- fakeCmd := fake .CommandScript [i ](cmd , args ... )
57+ fakeCmd := fake .nextCommand (cmd , args )
5958 if fake .ExactOrder {
6059 argv := append ([]string {cmd }, args ... )
6160 fc := fakeCmd .(* FakeCmd )
@@ -74,6 +73,18 @@ func (fake *FakeExec) Command(cmd string, args ...string) exec.Cmd {
7473 return fakeCmd
7574}
7675
76+ func (fake * FakeExec ) nextCommand (cmd string , args []string ) exec.Cmd {
77+ fake .mu .Lock ()
78+ defer fake .mu .Unlock ()
79+
80+ if fake .CommandCalls > len (fake .CommandScript )- 1 {
81+ panic (fmt .Sprintf ("ran out of Command() actions. Could not handle command [%d]: %s args: %v" , fake .CommandCalls , cmd , args ))
82+ }
83+ i := fake .CommandCalls
84+ fake .CommandCalls ++
85+ return fake .CommandScript [i ](cmd , args ... )
86+ }
87+
7788// CommandContext wraps arguments into exec.Cmd
7889func (fake * FakeExec ) CommandContext (ctx context.Context , cmd string , args ... string ) exec.Cmd {
7990 return fake .Command (cmd , args ... )
0 commit comments