github.com/hashicorp/packer@v1.14.3/packer/provisioner_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package packer
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"testing"
    11  	"time"
    12  
    13  	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
    14  )
    15  
    16  func TestProvisionHook_Impl(t *testing.T) {
    17  	var raw interface{}
    18  	raw = &ProvisionHook{}
    19  	if _, ok := raw.(packersdk.Hook); !ok {
    20  		t.Fatalf("must be a Hook")
    21  	}
    22  }
    23  
    24  func TestProvisionHook(t *testing.T) {
    25  	pA := &packersdk.MockProvisioner{}
    26  	pB := &packersdk.MockProvisioner{}
    27  
    28  	ui := testUi()
    29  	var comm packersdk.Communicator = new(packersdk.MockCommunicator)
    30  	var data interface{} = nil
    31  
    32  	hook := &ProvisionHook{
    33  		Provisioners: []*HookedProvisioner{
    34  			{pA, nil, ""},
    35  			{pB, nil, ""},
    36  		},
    37  	}
    38  
    39  	hook.Run(context.Background(), "foo", ui, comm, data)
    40  
    41  	if !pA.ProvCalled {
    42  		t.Error("provision should be called on pA")
    43  	}
    44  
    45  	if !pB.ProvCalled {
    46  		t.Error("provision should be called on pB")
    47  	}
    48  }
    49  
    50  func TestProvisionHook_nilComm(t *testing.T) {
    51  	pA := &packersdk.MockProvisioner{}
    52  	pB := &packersdk.MockProvisioner{}
    53  
    54  	ui := testUi()
    55  	var comm packersdk.Communicator = nil
    56  	var data interface{} = nil
    57  
    58  	hook := &ProvisionHook{
    59  		Provisioners: []*HookedProvisioner{
    60  			{pA, nil, ""},
    61  			{pB, nil, ""},
    62  		},
    63  	}
    64  
    65  	err := hook.Run(context.Background(), "foo", ui, comm, data)
    66  	if err == nil {
    67  		t.Fatal("should error")
    68  	}
    69  }
    70  
    71  func TestProvisionHook_cancel(t *testing.T) {
    72  	topCtx, topCtxCancel := context.WithCancel(context.Background())
    73  
    74  	p := &packersdk.MockProvisioner{
    75  		ProvFunc: func(ctx context.Context) error {
    76  			topCtxCancel()
    77  			<-ctx.Done()
    78  			return ctx.Err()
    79  		},
    80  	}
    81  
    82  	hook := &ProvisionHook{
    83  		Provisioners: []*HookedProvisioner{
    84  			{p, nil, ""},
    85  		},
    86  	}
    87  
    88  	err := hook.Run(topCtx, "foo", nil, new(packersdk.MockCommunicator), nil)
    89  	if err == nil {
    90  		t.Fatal("should have err")
    91  	}
    92  }
    93  
    94  // TODO(mitchellh): Test that they're run in the proper order
    95  
    96  func TestPausedProvisioner_impl(t *testing.T) {
    97  	var _ packersdk.Provisioner = new(PausedProvisioner)
    98  }
    99  
   100  func TestPausedProvisionerPrepare(t *testing.T) {
   101  	mock := new(packersdk.MockProvisioner)
   102  	prov := &PausedProvisioner{
   103  		Provisioner: mock,
   104  	}
   105  
   106  	prov.Prepare(42)
   107  	if !mock.PrepCalled {
   108  		t.Fatal("prepare should be called")
   109  	}
   110  	if mock.PrepConfigs[0] != 42 {
   111  		t.Fatal("should have proper configs")
   112  	}
   113  }
   114  
   115  func TestPausedProvisionerProvision(t *testing.T) {
   116  	mock := new(packersdk.MockProvisioner)
   117  	prov := &PausedProvisioner{
   118  		Provisioner: mock,
   119  	}
   120  
   121  	ui := testUi()
   122  	comm := new(packersdk.MockCommunicator)
   123  	prov.Provision(context.Background(), ui, comm, make(map[string]interface{}))
   124  	if !mock.ProvCalled {
   125  		t.Fatal("prov should be called")
   126  	}
   127  	if mock.ProvUi != ui {
   128  		t.Fatal("should have proper ui")
   129  	}
   130  	if mock.ProvCommunicator != comm {
   131  		t.Fatal("should have proper comm")
   132  	}
   133  }
   134  
   135  func TestPausedProvisionerProvision_waits(t *testing.T) {
   136  	startTime := time.Now()
   137  	waitTime := 50 * time.Millisecond
   138  
   139  	prov := &PausedProvisioner{
   140  		PauseBefore: waitTime,
   141  		Provisioner: &packersdk.MockProvisioner{
   142  			ProvFunc: func(context.Context) error {
   143  				timeSinceStartTime := time.Since(startTime)
   144  				if timeSinceStartTime < waitTime {
   145  					return fmt.Errorf("Spent not enough time waiting: %s", timeSinceStartTime)
   146  				}
   147  				return nil
   148  			},
   149  		},
   150  	}
   151  
   152  	err := prov.Provision(context.Background(), testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
   153  
   154  	if err != nil {
   155  		t.Fatalf("prov failed: %v", err)
   156  	}
   157  }
   158  
   159  func TestPausedProvisionerCancel(t *testing.T) {
   160  	topCtx, cancelTopCtx := context.WithCancel(context.Background())
   161  
   162  	mock := new(packersdk.MockProvisioner)
   163  	prov := &PausedProvisioner{
   164  		Provisioner: mock,
   165  	}
   166  
   167  	mock.ProvFunc = func(ctx context.Context) error {
   168  		cancelTopCtx()
   169  		<-ctx.Done()
   170  		return ctx.Err()
   171  	}
   172  
   173  	err := prov.Provision(topCtx, testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
   174  	if err == nil {
   175  		t.Fatal("should have err")
   176  	}
   177  }
   178  
   179  func TestDebuggedProvisioner_impl(t *testing.T) {
   180  	var _ packersdk.Provisioner = new(DebuggedProvisioner)
   181  }
   182  
   183  func TestDebuggedProvisionerPrepare(t *testing.T) {
   184  	mock := new(packersdk.MockProvisioner)
   185  	prov := &DebuggedProvisioner{
   186  		Provisioner: mock,
   187  	}
   188  
   189  	prov.Prepare(42)
   190  	if !mock.PrepCalled {
   191  		t.Fatal("prepare should be called")
   192  	}
   193  	if mock.PrepConfigs[0] != 42 {
   194  		t.Fatal("should have proper configs")
   195  	}
   196  }
   197  
   198  func TestDebuggedProvisionerProvision(t *testing.T) {
   199  	mock := new(packersdk.MockProvisioner)
   200  	prov := &DebuggedProvisioner{
   201  		Provisioner: mock,
   202  	}
   203  
   204  	ui := testUi()
   205  	comm := new(packersdk.MockCommunicator)
   206  	writeReader(ui, "\n")
   207  	prov.Provision(context.Background(), ui, comm, make(map[string]interface{}))
   208  	if !mock.ProvCalled {
   209  		t.Fatal("prov should be called")
   210  	}
   211  	if mock.ProvUi != ui {
   212  		t.Fatal("should have proper ui")
   213  	}
   214  	if mock.ProvCommunicator != comm {
   215  		t.Fatal("should have proper comm")
   216  	}
   217  }
   218  
   219  func TestDebuggedProvisionerCancel(t *testing.T) {
   220  	topCtx, topCtxCancel := context.WithCancel(context.Background())
   221  
   222  	mock := new(packersdk.MockProvisioner)
   223  	prov := &DebuggedProvisioner{
   224  		Provisioner: mock,
   225  	}
   226  
   227  	mock.ProvFunc = func(ctx context.Context) error {
   228  		topCtxCancel()
   229  		<-ctx.Done()
   230  		return ctx.Err()
   231  	}
   232  
   233  	err := prov.Provision(topCtx, testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
   234  	if err == nil {
   235  		t.Fatal("should have error")
   236  	}
   237  }
   238  
   239  func TestRetriedProvisioner_impl(t *testing.T) {
   240  	var _ packersdk.Provisioner = new(RetriedProvisioner)
   241  }
   242  
   243  func TestRetriedProvisionerPrepare(t *testing.T) {
   244  	mock := new(packersdk.MockProvisioner)
   245  	prov := &RetriedProvisioner{
   246  		Provisioner: mock,
   247  	}
   248  
   249  	err := prov.Prepare(42)
   250  	if err != nil {
   251  		t.Fatal("should not have errored")
   252  	}
   253  	if !mock.PrepCalled {
   254  		t.Fatal("prepare should be called")
   255  	}
   256  	if mock.PrepConfigs[0] != 42 {
   257  		t.Fatal("should have proper configs")
   258  	}
   259  }
   260  
   261  func TestRetriedProvisionerProvision(t *testing.T) {
   262  	mock := &packersdk.MockProvisioner{
   263  		ProvFunc: func(ctx context.Context) error {
   264  			return errors.New("failed")
   265  		},
   266  	}
   267  
   268  	prov := &RetriedProvisioner{
   269  		MaxRetries:  2,
   270  		Provisioner: mock,
   271  	}
   272  
   273  	ui := testUi()
   274  	comm := new(packersdk.MockCommunicator)
   275  	err := prov.Provision(context.Background(), ui, comm, make(map[string]interface{}))
   276  	if err != nil {
   277  		t.Fatal("should not have errored")
   278  	}
   279  	if !mock.ProvCalled {
   280  		t.Fatal("prov should be called")
   281  	}
   282  	if !mock.ProvRetried {
   283  		t.Fatal("prov should be retried")
   284  	}
   285  	if mock.ProvUi != ui {
   286  		t.Fatal("should have proper ui")
   287  	}
   288  	if mock.ProvCommunicator != comm {
   289  		t.Fatal("should have proper comm")
   290  	}
   291  }
   292  
   293  func TestRetriedProvisionerCancelledProvision(t *testing.T) {
   294  	// Don't retry if context is cancelled
   295  	ctx, topCtxCancel := context.WithCancel(context.Background())
   296  
   297  	mock := &packersdk.MockProvisioner{
   298  		ProvFunc: func(ctx context.Context) error {
   299  			topCtxCancel()
   300  			<-ctx.Done()
   301  			return ctx.Err()
   302  		},
   303  	}
   304  
   305  	prov := &RetriedProvisioner{
   306  		MaxRetries:  2,
   307  		Provisioner: mock,
   308  	}
   309  
   310  	ui := testUi()
   311  	comm := new(packersdk.MockCommunicator)
   312  	err := prov.Provision(ctx, ui, comm, make(map[string]interface{}))
   313  	if err == nil {
   314  		t.Fatal("should have errored")
   315  	}
   316  	if !mock.ProvCalled {
   317  		t.Fatal("prov should be called")
   318  	}
   319  	if mock.ProvRetried {
   320  		t.Fatal("prov should NOT be retried")
   321  	}
   322  	if mock.ProvUi != ui {
   323  		t.Fatal("should have proper ui")
   324  	}
   325  	if mock.ProvCommunicator != comm {
   326  		t.Fatal("should have proper comm")
   327  	}
   328  }
   329  
   330  func TestRetriedProvisionerCancel(t *testing.T) {
   331  	topCtx, cancelTopCtx := context.WithCancel(context.Background())
   332  
   333  	mock := new(packersdk.MockProvisioner)
   334  	prov := &RetriedProvisioner{
   335  		Provisioner: mock,
   336  	}
   337  
   338  	mock.ProvFunc = func(ctx context.Context) error {
   339  		cancelTopCtx()
   340  		<-ctx.Done()
   341  		return ctx.Err()
   342  	}
   343  
   344  	err := prov.Provision(topCtx, testUi(), new(packersdk.MockCommunicator), make(map[string]interface{}))
   345  	if err == nil {
   346  		t.Fatal("should have err")
   347  	}
   348  }