diff --git a/vbm.go b/vbm.go index dd0df6f..6baaef3 100644 --- a/vbm.go +++ b/vbm.go @@ -2,7 +2,10 @@ package virtualbox import ( "bytes" + "context" "errors" + "io" + "io/ioutil" "log" "os" "os/exec" @@ -37,52 +40,48 @@ var ( ErrVBMNotFound = errors.New("VBoxManage not found") ) -func vbm(args ...string) error { - cmd := exec.Command(VBM, args...) +// executor abstracts the execution method that is being used to run the +// command. +type executor func(context.Context, io.Writer, io.Writer, ...string) error + +var defaultExecutor executor = cmdExecutor + +func cmdExecutor(ctx context.Context, so io.Writer, se io.Writer, args ...string) error { + cmd := exec.CommandContext(ctx, VBM, args...) if Verbose { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr log.Printf("executing: %v %v", VBM, strings.Join(args, " ")) } - if err := cmd.Run(); err != nil { + cmd.Stdout = so + cmd.Stderr = se + err := cmd.Run() + if err != nil { if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound { - return ErrVBMNotFound + err = ErrVBMNotFound } - return err } - return nil + return err } -func vbmOut(args ...string) (string, error) { - cmd := exec.Command(VBM, args...) +func vbm(args ...string) error { + so, se := ioutil.Discard, ioutil.Discard if Verbose { - cmd.Stderr = os.Stderr - log.Printf("executing: %v %v", VBM, strings.Join(args, " ")) + so = os.Stdout + se = os.Stderr } + return defaultExecutor(context.Background(), so, se, args...) +} - b, err := cmd.Output() - if err != nil { - if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound { - err = ErrVBMNotFound - } +func vbmOut(args ...string) (string, error) { + so, se := new(bytes.Buffer), ioutil.Discard + if Verbose { + se = os.Stderr } - return string(b), err + err := defaultExecutor(context.Background(), so, se, args...) + return so.String(), err } func vbmOutErr(args ...string) (string, string, error) { - cmd := exec.Command(VBM, args...) - if Verbose { - log.Printf("executing: %v %v", VBM, strings.Join(args, " ")) - } - var stdout bytes.Buffer - var stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound { - err = ErrVBMNotFound - } - } - return stdout.String(), stderr.String(), err + so, se := new(bytes.Buffer), new(bytes.Buffer) + err := defaultExecutor(context.Background(), so, se, args...) + return so.String(), se.String(), err } diff --git a/vbm_test.go b/vbm_test.go index 0355a11..105cc95 100644 --- a/vbm_test.go +++ b/vbm_test.go @@ -1,13 +1,12 @@ package virtualbox import ( + "context" + "io" + "os" "testing" ) -func init() { - Verbose = true -} - func TestVBMOut(t *testing.T) { b, err := vbmOut("list", "vms") if err != nil { @@ -15,3 +14,22 @@ func TestVBMOut(t *testing.T) { } t.Logf("%s", b) } + +func setup() { + Verbose = true + + defaultExecutor = mockExecutor +} + +func TestMain(m *testing.M) { + setup() + os.Exit(m.Run()) +} + +func mockExecutor(ctx context.Context, so io.Writer, se io.Writer, args ...string) error { + // TODO: By returning nil we are causing all the tests to pass because the + // current ones do not check the output of the command. Here we would + // keep the state of the machines, immitating VBoxManage - thus + // eliminating it as a dependency. + return nil +}