Skip to content

Commit

Permalink
Added default executor modifiable for tests.
Browse files Browse the repository at this point in the history
The executor abstraction allows us to introduce a mock executor, which removes
the need for VBoxManage installed on the box, as well as introducting various
failure scenarios which could then be tested and improve the reliability of the
project.

With the current implementation, the mock executor always returns nil, and
allows all tests to pass. This behaviour should be changed in the future,
perhaps adapted even more with closures to allow the list of items that should
be returned as output.
  • Loading branch information
VoyTechnology committed Nov 13, 2019
1 parent 2576aa8 commit f8abf83
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 37 deletions.
65 changes: 32 additions & 33 deletions vbm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package virtualbox

import (
"bytes"
"context"
"errors"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
Expand Down Expand Up @@ -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
}
26 changes: 22 additions & 4 deletions vbm_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
package virtualbox

import (
"context"
"io"
"os"
"testing"
)

func init() {
Verbose = true
}

func TestVBMOut(t *testing.T) {
b, err := vbmOut("list", "vms")
if err != nil {
t.Fatal(err)
}
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
}

0 comments on commit f8abf83

Please sign in to comment.