packer-cn/packer/provisioner_test.go

346 lines
7.5 KiB
Go

package packer
import (
"context"
"errors"
"fmt"
"testing"
"time"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
func TestProvisionHook_Impl(t *testing.T) {
var raw interface{}
raw = &ProvisionHook{}
if _, ok := raw.(packersdk.Hook); !ok {
t.Fatalf("must be a Hook")
}
}
func TestProvisionHook(t *testing.T) {
pA := &packersdk.MockProvisioner{}
pB := &packersdk.MockProvisioner{}
ui := testUi()
var comm packersdk.Communicator = new(packersdk.MockCommunicator)
var data interface{} = nil
hook := &ProvisionHook{
Provisioners: []*HookedProvisioner{
{pA, nil, ""},
{pB, nil, ""},
},
}
hook.Run(context.Background(), "foo", ui, comm, data)
if !pA.ProvCalled {
t.Error("provision should be called on pA")
}
if !pB.ProvCalled {
t.Error("provision should be called on pB")
}
}
func TestProvisionHook_nilComm(t *testing.T) {
pA := &packersdk.MockProvisioner{}
pB := &packersdk.MockProvisioner{}
ui := testUi()
var comm packersdk.Communicator = nil
var data interface{} = nil
hook := &ProvisionHook{
Provisioners: []*HookedProvisioner{
{pA, nil, ""},
{pB, nil, ""},
},
}
err := hook.Run(context.Background(), "foo", ui, comm, data)
if err == nil {
t.Fatal("should error")
}
}
func TestProvisionHook_cancel(t *testing.T) {
topCtx, topCtxCancel := context.WithCancel(context.Background())
p := &packersdk.MockProvisioner{
ProvFunc: func(ctx context.Context) error {
topCtxCancel()
<-ctx.Done()
return ctx.Err()
},
}
hook := &ProvisionHook{
Provisioners: []*HookedProvisioner{
{p, nil, ""},
},
}
err := hook.Run(topCtx, "foo", nil, new(packersdk.MockCommunicator), nil)
if err == nil {
t.Fatal("should have err")
}
}
// TODO(mitchellh): Test that they're run in the proper order
func TestPausedProvisioner_impl(t *testing.T) {
var _ packersdk.Provisioner = new(PausedProvisioner)
}
func TestPausedProvisionerPrepare(t *testing.T) {
mock := new(packersdk.MockProvisioner)
prov := &PausedProvisioner{
Provisioner: mock,
}
prov.Prepare(42)
if !mock.PrepCalled {
t.Fatal("prepare should be called")
}
if mock.PrepConfigs[0] != 42 {
t.Fatal("should have proper configs")
}
}
func TestPausedProvisionerProvision(t *testing.T) {
mock := new(packersdk.MockProvisioner)
prov := &PausedProvisioner{
Provisioner: mock,
}
ui := testUi()
comm := new(packersdk.MockCommunicator)
prov.Provision(context.Background(), ui, comm, make(map[string]interface{}))
if !mock.ProvCalled {
t.Fatal("prov should be called")
}
if mock.ProvUi != ui {
t.Fatal("should have proper ui")
}
if mock.ProvCommunicator != comm {
t.Fatal("should have proper comm")
}
}
func TestPausedProvisionerProvision_waits(t *testing.T) {
startTime := time.Now()
waitTime := 50 * time.Millisecond
prov := &PausedProvisioner{
PauseBefore: waitTime,
Provisioner: &packersdk.MockProvisioner{
ProvFunc: func(context.Context) error {
timeSinceStartTime := time.Since(startTime)
if timeSinceStartTime < waitTime {
return fmt.Errorf("Spent not enough time waiting: %s", timeSinceStartTime)
}
return nil
},
},
}
err := prov.Provision(context.Background(), testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
if err != nil {
t.Fatalf("prov failed: %v", err)
}
}
func TestPausedProvisionerCancel(t *testing.T) {
topCtx, cancelTopCtx := context.WithCancel(context.Background())
mock := new(packersdk.MockProvisioner)
prov := &PausedProvisioner{
Provisioner: mock,
}
mock.ProvFunc = func(ctx context.Context) error {
cancelTopCtx()
<-ctx.Done()
return ctx.Err()
}
err := prov.Provision(topCtx, testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
if err == nil {
t.Fatal("should have err")
}
}
func TestDebuggedProvisioner_impl(t *testing.T) {
var _ packersdk.Provisioner = new(DebuggedProvisioner)
}
func TestDebuggedProvisionerPrepare(t *testing.T) {
mock := new(packersdk.MockProvisioner)
prov := &DebuggedProvisioner{
Provisioner: mock,
}
prov.Prepare(42)
if !mock.PrepCalled {
t.Fatal("prepare should be called")
}
if mock.PrepConfigs[0] != 42 {
t.Fatal("should have proper configs")
}
}
func TestDebuggedProvisionerProvision(t *testing.T) {
mock := new(packersdk.MockProvisioner)
prov := &DebuggedProvisioner{
Provisioner: mock,
}
ui := testUi()
comm := new(packersdk.MockCommunicator)
writeReader(ui, "\n")
prov.Provision(context.Background(), ui, comm, make(map[string]interface{}))
if !mock.ProvCalled {
t.Fatal("prov should be called")
}
if mock.ProvUi != ui {
t.Fatal("should have proper ui")
}
if mock.ProvCommunicator != comm {
t.Fatal("should have proper comm")
}
}
func TestDebuggedProvisionerCancel(t *testing.T) {
topCtx, topCtxCancel := context.WithCancel(context.Background())
mock := new(packersdk.MockProvisioner)
prov := &DebuggedProvisioner{
Provisioner: mock,
}
mock.ProvFunc = func(ctx context.Context) error {
topCtxCancel()
<-ctx.Done()
return ctx.Err()
}
err := prov.Provision(topCtx, testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
if err == nil {
t.Fatal("should have error")
}
}
func TestRetriedProvisioner_impl(t *testing.T) {
var _ packersdk.Provisioner = new(RetriedProvisioner)
}
func TestRetriedProvisionerPrepare(t *testing.T) {
mock := new(packersdk.MockProvisioner)
prov := &RetriedProvisioner{
Provisioner: mock,
}
err := prov.Prepare(42)
if err != nil {
t.Fatal("should not have errored")
}
if !mock.PrepCalled {
t.Fatal("prepare should be called")
}
if mock.PrepConfigs[0] != 42 {
t.Fatal("should have proper configs")
}
}
func TestRetriedProvisionerProvision(t *testing.T) {
mock := &packersdk.MockProvisioner{
ProvFunc: func(ctx context.Context) error {
return errors.New("failed")
},
}
prov := &RetriedProvisioner{
MaxRetries: 2,
Provisioner: mock,
}
ui := testUi()
comm := new(packersdk.MockCommunicator)
err := prov.Provision(context.Background(), ui, comm, make(map[string]interface{}))
if err != nil {
t.Fatal("should not have errored")
}
if !mock.ProvCalled {
t.Fatal("prov should be called")
}
if !mock.ProvRetried {
t.Fatal("prov should be retried")
}
if mock.ProvUi != ui {
t.Fatal("should have proper ui")
}
if mock.ProvCommunicator != comm {
t.Fatal("should have proper comm")
}
}
func TestRetriedProvisionerCancelledProvision(t *testing.T) {
// Don't retry if context is cancelled
ctx, topCtxCancel := context.WithCancel(context.Background())
mock := &packersdk.MockProvisioner{
ProvFunc: func(ctx context.Context) error {
topCtxCancel()
<-ctx.Done()
return ctx.Err()
},
}
prov := &RetriedProvisioner{
MaxRetries: 2,
Provisioner: mock,
}
ui := testUi()
comm := new(packersdk.MockCommunicator)
err := prov.Provision(ctx, ui, comm, make(map[string]interface{}))
if err == nil {
t.Fatal("should have errored")
}
if !mock.ProvCalled {
t.Fatal("prov should be called")
}
if mock.ProvRetried {
t.Fatal("prov should NOT be retried")
}
if mock.ProvUi != ui {
t.Fatal("should have proper ui")
}
if mock.ProvCommunicator != comm {
t.Fatal("should have proper comm")
}
}
func TestRetriedProvisionerCancel(t *testing.T) {
topCtx, cancelTopCtx := context.WithCancel(context.Background())
mock := new(packersdk.MockProvisioner)
prov := &RetriedProvisioner{
Provisioner: mock,
}
mock.ProvFunc = func(ctx context.Context) error {
cancelTopCtx()
<-ctx.Done()
return ctx.Err()
}
err := prov.Provision(topCtx, testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
if err == nil {
t.Fatal("should have err")
}
}