Skip to content

Commit 8db4d2f

Browse files
committed
Added default executor modifiable for tests.
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.
1 parent 2576aa8 commit 8db4d2f

File tree

2 files changed

+55
-33
lines changed

2 files changed

+55
-33
lines changed

vbm.go

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package virtualbox
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
7+
"io"
8+
"io/ioutil"
69
"log"
710
"os"
811
"os/exec"
@@ -37,52 +40,53 @@ var (
3740
ErrVBMNotFound = errors.New("VBoxManage not found")
3841
)
3942

40-
func vbm(args ...string) error {
41-
cmd := exec.Command(VBM, args...)
43+
// executor abstracts the execution method that is being used to run the
44+
// command.
45+
type executor func(context.Context, io.Writer, io.Writer, ...string) error
46+
47+
var defaultExecutor executor = cmdExecutor
48+
49+
func cmdExecutor(ctx context.Context, so io.Writer, se io.Writer, args ...string) error {
50+
cmd := exec.CommandContext(ctx, VBM, args...)
4251
if Verbose {
43-
cmd.Stdout = os.Stdout
44-
cmd.Stderr = os.Stderr
4552
log.Printf("executing: %v %v", VBM, strings.Join(args, " "))
4653
}
47-
if err := cmd.Run(); err != nil {
54+
cmd.Stdout = so
55+
cmd.Stderr = se
56+
err := cmd.Run()
57+
if err != nil {
4858
if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound {
49-
return ErrVBMNotFound
59+
err = ErrVBMNotFound
5060
}
51-
return err
5261
}
53-
return nil
62+
return err
5463
}
5564

56-
func vbmOut(args ...string) (string, error) {
57-
cmd := exec.Command(VBM, args...)
65+
func vbm(args ...string) error {
66+
so, se := ioutil.Discard, ioutil.Discard
5867
if Verbose {
59-
cmd.Stderr = os.Stderr
68+
so = os.Stdout
69+
se = os.Stderr
6070
log.Printf("executing: %v %v", VBM, strings.Join(args, " "))
6171
}
72+
return defaultExecutor(context.Background(), so, se, args...)
73+
}
6274

63-
b, err := cmd.Output()
64-
if err != nil {
65-
if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound {
66-
err = ErrVBMNotFound
67-
}
75+
func vbmOut(args ...string) (string, error) {
76+
so, se := new(bytes.Buffer), ioutil.Discard
77+
if Verbose {
78+
se = os.Stderr
79+
log.Printf("executing: %v %v", VBM, strings.Join(args, " "))
6880
}
69-
return string(b), err
81+
err := defaultExecutor(context.Background(), so, se, args...)
82+
return so.String(), err
7083
}
7184

7285
func vbmOutErr(args ...string) (string, string, error) {
73-
cmd := exec.Command(VBM, args...)
86+
so, se := new(bytes.Buffer), new(bytes.Buffer)
7487
if Verbose {
7588
log.Printf("executing: %v %v", VBM, strings.Join(args, " "))
7689
}
77-
var stdout bytes.Buffer
78-
var stderr bytes.Buffer
79-
cmd.Stdout = &stdout
80-
cmd.Stderr = &stderr
81-
err := cmd.Run()
82-
if err != nil {
83-
if ee, ok := err.(*exec.Error); ok && ee == exec.ErrNotFound {
84-
err = ErrVBMNotFound
85-
}
86-
}
87-
return stdout.String(), stderr.String(), err
90+
err := defaultExecutor(context.Background(), so, se, args...)
91+
return so.String(), se.String(), err
8892
}

vbm_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
package virtualbox
22

33
import (
4+
"context"
5+
"io"
6+
"os"
47
"testing"
58
)
69

7-
func init() {
8-
Verbose = true
9-
}
10-
1110
func TestVBMOut(t *testing.T) {
1211
b, err := vbmOut("list", "vms")
1312
if err != nil {
1413
t.Fatal(err)
1514
}
1615
t.Logf("%s", b)
1716
}
17+
18+
func setup() {
19+
Verbose = true
20+
21+
defaultExecutor = mockExecutor
22+
}
23+
24+
func TestMain(m *testing.M) {
25+
setup()
26+
os.Exit(m.Run())
27+
}
28+
29+
func mockExecutor(ctx context.Context, so io.Writer, se io.Writer, args ...string) error {
30+
// TODO: By returning nil we are causing all the tests to pass because the
31+
// current ones do not check the output of the command. Here we would
32+
// keep the state of the machines, immitating VBoxManage - thus
33+
// eliminating it as a dependency.
34+
return nil
35+
}

0 commit comments

Comments
 (0)