github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/builtin/provisioners/local-exec/resource_provisioner_test.go (about)

     1  package localexec
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/hashicorp/terraform/internal/provisioners"
    12  	"github.com/mitchellh/cli"
    13  	"github.com/zclconf/go-cty/cty"
    14  )
    15  
    16  func TestResourceProvider_Apply(t *testing.T) {
    17  	defer os.Remove("test_out")
    18  	output := cli.NewMockUi()
    19  	p := New()
    20  	schema := p.GetSchema().Provisioner
    21  	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
    22  		"command": cty.StringVal("echo foo > test_out"),
    23  	}))
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
    29  		Config:   c,
    30  		UIOutput: output,
    31  	})
    32  
    33  	if resp.Diagnostics.HasErrors() {
    34  		t.Fatalf("err: %v", resp.Diagnostics.Err())
    35  	}
    36  
    37  	// Check the file
    38  	raw, err := ioutil.ReadFile("test_out")
    39  	if err != nil {
    40  		t.Fatalf("err: %v", err)
    41  	}
    42  
    43  	actual := strings.TrimSpace(string(raw))
    44  	expected := "foo"
    45  	if actual != expected {
    46  		t.Fatalf("bad: %#v", actual)
    47  	}
    48  }
    49  
    50  func TestResourceProvider_stop(t *testing.T) {
    51  	output := cli.NewMockUi()
    52  	p := New()
    53  	schema := p.GetSchema().Provisioner
    54  
    55  	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
    56  		// bash/zsh/ksh will exec a single command in the same process. This
    57  		// makes certain there's a subprocess in the shell.
    58  		"command": cty.StringVal("sleep 30; sleep 30"),
    59  	}))
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	doneCh := make(chan struct{})
    65  	startTime := time.Now()
    66  	go func() {
    67  		defer close(doneCh)
    68  		// The functionality of p.Apply is tested in TestResourceProvider_Apply.
    69  		// Because p.Apply is called in a goroutine, trying to t.Fatal() on its
    70  		// result would be ignored or would cause a panic if the parent goroutine
    71  		// has already completed.
    72  		_ = p.ProvisionResource(provisioners.ProvisionResourceRequest{
    73  			Config:   c,
    74  			UIOutput: output,
    75  		})
    76  	}()
    77  
    78  	mustExceed := (50 * time.Millisecond)
    79  	select {
    80  	case <-doneCh:
    81  		t.Fatalf("expected to finish sometime after %s finished in %s", mustExceed, time.Since(startTime))
    82  	case <-time.After(mustExceed):
    83  		t.Logf("correctly took longer than %s", mustExceed)
    84  	}
    85  
    86  	// Stop it
    87  	stopTime := time.Now()
    88  	p.Stop()
    89  
    90  	maxTempl := "expected to finish under %s, finished in %s"
    91  	finishWithin := (2 * time.Second)
    92  	select {
    93  	case <-doneCh:
    94  		t.Logf(maxTempl, finishWithin, time.Since(stopTime))
    95  	case <-time.After(finishWithin):
    96  		t.Fatalf(maxTempl, finishWithin, time.Since(stopTime))
    97  	}
    98  }
    99  
   100  func TestResourceProvider_ApplyCustomInterpreter(t *testing.T) {
   101  	output := cli.NewMockUi()
   102  	p := New()
   103  
   104  	schema := p.GetSchema().Provisioner
   105  
   106  	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
   107  		"interpreter": cty.ListVal([]cty.Value{cty.StringVal("echo"), cty.StringVal("is")}),
   108  		"command":     cty.StringVal("not really an interpreter"),
   109  	}))
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  
   114  	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
   115  		Config:   c,
   116  		UIOutput: output,
   117  	})
   118  
   119  	if resp.Diagnostics.HasErrors() {
   120  		t.Fatal(resp.Diagnostics.Err())
   121  	}
   122  
   123  	got := strings.TrimSpace(output.OutputWriter.String())
   124  	want := `Executing: ["echo" "is" "not really an interpreter"]
   125  is not really an interpreter`
   126  	if got != want {
   127  		t.Errorf("wrong output\ngot:  %s\nwant: %s", got, want)
   128  	}
   129  }
   130  
   131  func TestResourceProvider_ApplyCustomWorkingDirectory(t *testing.T) {
   132  	testdir := "working_dir_test"
   133  	os.Mkdir(testdir, 0755)
   134  	defer os.Remove(testdir)
   135  
   136  	output := cli.NewMockUi()
   137  	p := New()
   138  	schema := p.GetSchema().Provisioner
   139  
   140  	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
   141  		"working_dir": cty.StringVal(testdir),
   142  		"command":     cty.StringVal("echo `pwd`"),
   143  	}))
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  
   148  	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
   149  		Config:   c,
   150  		UIOutput: output,
   151  	})
   152  
   153  	if resp.Diagnostics.HasErrors() {
   154  		t.Fatal(resp.Diagnostics.Err())
   155  	}
   156  
   157  	dir, err := os.Getwd()
   158  	if err != nil {
   159  		t.Fatalf("err: %v", err)
   160  	}
   161  
   162  	got := strings.TrimSpace(output.OutputWriter.String())
   163  	want := "Executing: [\"/bin/sh\" \"-c\" \"echo `pwd`\"]\n" + dir + "/" + testdir
   164  	if got != want {
   165  		t.Errorf("wrong output\ngot:  %s\nwant: %s", got, want)
   166  	}
   167  }
   168  
   169  func TestResourceProvider_ApplyCustomEnv(t *testing.T) {
   170  	output := cli.NewMockUi()
   171  	p := New()
   172  	schema := p.GetSchema().Provisioner
   173  
   174  	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
   175  		"command": cty.StringVal("echo $FOO $BAR $BAZ"),
   176  		"environment": cty.MapVal(map[string]cty.Value{
   177  			"FOO": cty.StringVal("BAR"),
   178  			"BAR": cty.StringVal("1"),
   179  			"BAZ": cty.StringVal("true"),
   180  		}),
   181  	}))
   182  	if err != nil {
   183  		t.Fatal(err)
   184  	}
   185  
   186  	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
   187  		Config:   c,
   188  		UIOutput: output,
   189  	})
   190  	if resp.Diagnostics.HasErrors() {
   191  		t.Fatal(resp.Diagnostics.Err())
   192  	}
   193  
   194  	got := strings.TrimSpace(output.OutputWriter.String())
   195  	want := `Executing: ["/bin/sh" "-c" "echo $FOO $BAR $BAZ"]
   196  BAR 1 true`
   197  	if got != want {
   198  		t.Errorf("wrong output\ngot:  %s\nwant: %s", got, want)
   199  	}
   200  }
   201  
   202  // Validate that Stop can Close can be called even when not provisioning.
   203  func TestResourceProvisioner_StopClose(t *testing.T) {
   204  	p := New()
   205  	p.Stop()
   206  	p.Close()
   207  }
   208  
   209  func TestResourceProvisioner_nullsInOptionals(t *testing.T) {
   210  	output := cli.NewMockUi()
   211  	p := New()
   212  	schema := p.GetSchema().Provisioner
   213  
   214  	for i, cfg := range []cty.Value{
   215  		cty.ObjectVal(map[string]cty.Value{
   216  			"command": cty.StringVal("echo OK"),
   217  			"environment": cty.MapVal(map[string]cty.Value{
   218  				"FOO": cty.NullVal(cty.String),
   219  			}),
   220  		}),
   221  		cty.ObjectVal(map[string]cty.Value{
   222  			"command":     cty.StringVal("echo OK"),
   223  			"environment": cty.NullVal(cty.Map(cty.String)),
   224  		}),
   225  		cty.ObjectVal(map[string]cty.Value{
   226  			"command":     cty.StringVal("echo OK"),
   227  			"interpreter": cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
   228  		}),
   229  		cty.ObjectVal(map[string]cty.Value{
   230  			"command":     cty.StringVal("echo OK"),
   231  			"interpreter": cty.NullVal(cty.List(cty.String)),
   232  		}),
   233  		cty.ObjectVal(map[string]cty.Value{
   234  			"command":     cty.StringVal("echo OK"),
   235  			"working_dir": cty.NullVal(cty.String),
   236  		}),
   237  	} {
   238  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   239  
   240  			cfg, err := schema.CoerceValue(cfg)
   241  			if err != nil {
   242  				t.Fatal(err)
   243  			}
   244  
   245  			// verifying there are no panics
   246  			p.ProvisionResource(provisioners.ProvisionResourceRequest{
   247  				Config:   cfg,
   248  				UIOutput: output,
   249  			})
   250  		})
   251  	}
   252  }