github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/builtin/provisioners/remote-exec/resource_provisioner_test.go (about)

     1  package remoteexec
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"testing"
     8  	"time"
     9  
    10  	"strings"
    11  
    12  	"github.com/hashicorp/terraform/communicator"
    13  	"github.com/hashicorp/terraform/communicator/remote"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  	"github.com/hashicorp/terraform/terraform"
    16  )
    17  
    18  func TestResourceProvisioner_impl(t *testing.T) {
    19  	var _ terraform.ResourceProvisioner = Provisioner()
    20  }
    21  
    22  func TestProvisioner(t *testing.T) {
    23  	if err := Provisioner().(*schema.Provisioner).InternalValidate(); err != nil {
    24  		t.Fatalf("err: %s", err)
    25  	}
    26  }
    27  
    28  func TestResourceProvider_Validate_good(t *testing.T) {
    29  	c := testConfig(t, map[string]interface{}{
    30  		"inline": "echo foo",
    31  	})
    32  
    33  	warn, errs := Provisioner().Validate(c)
    34  	if len(warn) > 0 {
    35  		t.Fatalf("Warnings: %v", warn)
    36  	}
    37  	if len(errs) > 0 {
    38  		t.Fatalf("Errors: %v", errs)
    39  	}
    40  }
    41  
    42  func TestResourceProvider_Validate_bad(t *testing.T) {
    43  	c := testConfig(t, map[string]interface{}{
    44  		"invalid": "nope",
    45  	})
    46  
    47  	warn, errs := Provisioner().Validate(c)
    48  	if len(warn) > 0 {
    49  		t.Fatalf("Warnings: %v", warn)
    50  	}
    51  	if len(errs) == 0 {
    52  		t.Fatalf("Should have errors")
    53  	}
    54  }
    55  
    56  var expectedScriptOut = `cd /tmp
    57  wget http://foobar
    58  exit 0
    59  `
    60  
    61  func TestResourceProvider_generateScript(t *testing.T) {
    62  	conf := map[string]interface{}{
    63  		"inline": []interface{}{
    64  			"cd /tmp",
    65  			"wget http://foobar",
    66  			"exit 0",
    67  		},
    68  	}
    69  
    70  	out, err := generateScripts(
    71  		schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf),
    72  	)
    73  	if err != nil {
    74  		t.Fatalf("err: %v", err)
    75  	}
    76  
    77  	if len(out) != 1 {
    78  		t.Fatal("expected 1 out")
    79  	}
    80  
    81  	if out[0] != expectedScriptOut {
    82  		t.Fatalf("bad: %v", out)
    83  	}
    84  }
    85  
    86  func TestResourceProvider_generateScriptEmptyInline(t *testing.T) {
    87  	p := Provisioner().(*schema.Provisioner)
    88  	conf := map[string]interface{}{
    89  		"inline": []interface{}{""},
    90  	}
    91  
    92  	_, err := generateScripts(schema.TestResourceDataRaw(
    93  		t, p.Schema, conf))
    94  	if err == nil {
    95  		t.Fatal("expected error, got none")
    96  	}
    97  
    98  	if !strings.Contains(err.Error(), "Error parsing") {
    99  		t.Fatalf("expected parsing error, got: %s", err)
   100  	}
   101  }
   102  
   103  func TestResourceProvider_CollectScripts_inline(t *testing.T) {
   104  	conf := map[string]interface{}{
   105  		"inline": []interface{}{
   106  			"cd /tmp",
   107  			"wget http://foobar",
   108  			"exit 0",
   109  		},
   110  	}
   111  
   112  	scripts, err := collectScripts(
   113  		schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf),
   114  	)
   115  	if err != nil {
   116  		t.Fatalf("err: %v", err)
   117  	}
   118  
   119  	if len(scripts) != 1 {
   120  		t.Fatalf("bad: %v", scripts)
   121  	}
   122  
   123  	var out bytes.Buffer
   124  	_, err = io.Copy(&out, scripts[0])
   125  	if err != nil {
   126  		t.Fatalf("err: %v", err)
   127  	}
   128  
   129  	if out.String() != expectedScriptOut {
   130  		t.Fatalf("bad: %v", out.String())
   131  	}
   132  }
   133  
   134  func TestResourceProvider_CollectScripts_script(t *testing.T) {
   135  	conf := map[string]interface{}{
   136  		"script": "testdata/script1.sh",
   137  	}
   138  
   139  	scripts, err := collectScripts(
   140  		schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf),
   141  	)
   142  	if err != nil {
   143  		t.Fatalf("err: %v", err)
   144  	}
   145  
   146  	if len(scripts) != 1 {
   147  		t.Fatalf("bad: %v", scripts)
   148  	}
   149  
   150  	var out bytes.Buffer
   151  	_, err = io.Copy(&out, scripts[0])
   152  	if err != nil {
   153  		t.Fatalf("err: %v", err)
   154  	}
   155  
   156  	if out.String() != expectedScriptOut {
   157  		t.Fatalf("bad: %v", out.String())
   158  	}
   159  }
   160  
   161  func TestResourceProvider_CollectScripts_scripts(t *testing.T) {
   162  	conf := map[string]interface{}{
   163  		"scripts": []interface{}{
   164  			"testdata/script1.sh",
   165  			"testdata/script1.sh",
   166  			"testdata/script1.sh",
   167  		},
   168  	}
   169  
   170  	scripts, err := collectScripts(
   171  		schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf),
   172  	)
   173  	if err != nil {
   174  		t.Fatalf("err: %v", err)
   175  	}
   176  
   177  	if len(scripts) != 3 {
   178  		t.Fatalf("bad: %v", scripts)
   179  	}
   180  
   181  	for idx := range scripts {
   182  		var out bytes.Buffer
   183  		_, err = io.Copy(&out, scripts[idx])
   184  		if err != nil {
   185  			t.Fatalf("err: %v", err)
   186  		}
   187  
   188  		if out.String() != expectedScriptOut {
   189  			t.Fatalf("bad: %v", out.String())
   190  		}
   191  	}
   192  }
   193  
   194  func TestResourceProvider_CollectScripts_scriptsEmpty(t *testing.T) {
   195  	p := Provisioner().(*schema.Provisioner)
   196  	conf := map[string]interface{}{
   197  		"scripts": []interface{}{""},
   198  	}
   199  
   200  	_, err := collectScripts(schema.TestResourceDataRaw(
   201  		t, p.Schema, conf))
   202  
   203  	if err == nil {
   204  		t.Fatal("expected error")
   205  	}
   206  
   207  	if !strings.Contains(err.Error(), "Error parsing") {
   208  		t.Fatalf("Expected parsing error, got: %s", err)
   209  	}
   210  }
   211  
   212  func TestProvisionerTimeout(t *testing.T) {
   213  	o := new(terraform.MockUIOutput)
   214  	c := new(communicator.MockCommunicator)
   215  
   216  	disconnected := make(chan struct{})
   217  	c.DisconnectFunc = func() error {
   218  		close(disconnected)
   219  		return nil
   220  	}
   221  
   222  	completed := make(chan struct{})
   223  	c.CommandFunc = func(cmd *remote.Cmd) error {
   224  		defer close(completed)
   225  		cmd.Init()
   226  		time.Sleep(2 * time.Second)
   227  		cmd.SetExitStatus(0, nil)
   228  		return nil
   229  	}
   230  	c.ConnTimeout = time.Second
   231  	c.UploadScripts = map[string]string{"hello": "echo hello"}
   232  	c.RemoteScriptPath = "hello"
   233  
   234  	p := Provisioner().(*schema.Provisioner)
   235  	conf := map[string]interface{}{
   236  		"inline": []interface{}{"echo hello"},
   237  	}
   238  
   239  	scripts, err := collectScripts(schema.TestResourceDataRaw(
   240  		t, p.Schema, conf))
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	ctx := context.Background()
   246  
   247  	done := make(chan struct{})
   248  
   249  	go func() {
   250  		defer close(done)
   251  		if err := runScripts(ctx, o, c, scripts); err != nil {
   252  			t.Fatal(err)
   253  		}
   254  	}()
   255  
   256  	select {
   257  	case <-disconnected:
   258  		t.Fatal("communicator disconnected before command completed")
   259  	case <-completed:
   260  	}
   261  
   262  	<-done
   263  }
   264  
   265  func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
   266  	return terraform.NewResourceConfigRaw(c)
   267  }