builder/docker: StepPull test, driver abstraction for tests

This commit is contained in:
Mitchell Hashimoto 2013-11-09 12:12:23 -08:00
parent 2da9233655
commit 62b81dc432
7 changed files with 99 additions and 3 deletions

View File

@ -56,6 +56,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
state.Put("hook", hook)
state.Put("ui", ui)
// Setup the driver that will talk to Docker
state.Put("driver", &DockerDriver{
Ui: ui,
})
// Run!
if b.config.PackerDebug {
b.runner = &multistep.DebugRunner{

9
builder/docker/driver.go Normal file
View File

@ -0,0 +1,9 @@
package docker
// Driver is the interface that has to be implemented to communicate with
// Docker. The Driver interface also allows the steps to be tested since
// a mock driver can be shimmed in.
type Driver interface {
// Pull should pull down the given image.
Pull(image string) error
}

View File

@ -0,0 +1,15 @@
package docker
import (
"github.com/mitchellh/packer/packer"
"os/exec"
)
type DockerDriver struct {
Ui packer.Ui
}
func (d *DockerDriver) Pull(image string) error {
cmd := exec.Command("docker", "pull", image)
return runAndStream(cmd, d.Ui)
}

View File

@ -0,0 +1,15 @@
package docker
// MockDriver is a driver implementation that can be used for tests.
type MockDriver struct {
PullError error
PullCalled bool
PullImage string
}
func (d *MockDriver) Pull(image string) error {
d.PullCalled = true
d.PullImage = image
return d.PullError
}

View File

@ -4,18 +4,17 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"os/exec"
)
type StepPull struct{}
func (s *StepPull) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
ui.Say(fmt.Sprintf("Pulling Docker image: %s", config.Image))
cmd := exec.Command("docker", "pull", config.Image)
if err := runAndStream(cmd, ui); err != nil {
if err := driver.Pull(config.Image); err != nil {
err := fmt.Errorf("Error pulling Docker image: %s", err)
state.Put("error", err)
ui.Error(err.Error())

View File

@ -0,0 +1,52 @@
package docker
import (
"errors"
"github.com/mitchellh/multistep"
"testing"
)
func TestStepPull_impl(t *testing.T) {
var _ multistep.Step = new(StepPull)
}
func TestStepPull(t *testing.T) {
state := testState(t)
step := new(StepPull)
defer step.Cleanup(state)
config := state.Get("config").(*Config)
driver := state.Get("driver").(*MockDriver)
// run the step
if action := step.Run(state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
// verify we did the right thing
if !driver.PullCalled {
t.Fatal("should've pulled")
}
if driver.PullImage != config.Image {
t.Fatalf("bad: %#v", driver.PullImage)
}
}
func TestStepPull_error(t *testing.T) {
state := testState(t)
step := new(StepPull)
defer step.Cleanup(state)
driver := state.Get("driver").(*MockDriver)
driver.PullError = errors.New("foo")
// run the step
if action := step.Run(state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v", action)
}
// verify we have an error
if _, ok := state.GetOk("error"); !ok {
t.Fatal("should have error")
}
}

View File

@ -10,6 +10,7 @@ import (
func testState(t *testing.T) multistep.StateBag {
state := new(multistep.BasicStateBag)
state.Put("config", testConfigStruct(t))
state.Put("driver", &MockDriver{})
state.Put("hook", &packer.MockHook{})
state.Put("ui", &packer.BasicUi{
Reader: new(bytes.Buffer),