github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/provisioner/windows-shell/provisioner_test.go (about)

     1  package shell
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"log"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/hashicorp/packer/packer"
    15  )
    16  
    17  func testConfig() map[string]interface{} {
    18  	return map[string]interface{}{
    19  		"inline": []interface{}{"foo", "bar"},
    20  	}
    21  }
    22  
    23  func TestProvisionerPrepare_extractScript(t *testing.T) {
    24  	config := testConfig()
    25  	p := new(Provisioner)
    26  	_ = p.Prepare(config)
    27  	file, err := extractScript(p)
    28  	if err != nil {
    29  		t.Fatalf("Should not be error: %s", err)
    30  	}
    31  	log.Printf("File: %s", file)
    32  	if strings.Index(file, os.TempDir()) != 0 {
    33  		t.Fatalf("Temp file should reside in %s. File location: %s", os.TempDir(), file)
    34  	}
    35  
    36  	// File contents should contain 2 lines concatenated by newlines: foo\nbar
    37  	readFile, err := ioutil.ReadFile(file)
    38  	if err != nil {
    39  		t.Fatalf("Should not be error: %s", err)
    40  	}
    41  	expectedContents := "foo\nbar\n"
    42  	s := string(readFile[:])
    43  	if s != expectedContents {
    44  		t.Fatalf("Expected generated inlineScript to equal '%s', got '%s'", expectedContents, s)
    45  	}
    46  }
    47  
    48  func TestProvisioner_Impl(t *testing.T) {
    49  	var raw interface{}
    50  	raw = &Provisioner{}
    51  	if _, ok := raw.(packer.Provisioner); !ok {
    52  		t.Fatalf("must be a Provisioner")
    53  	}
    54  }
    55  
    56  func TestProvisionerPrepare_Defaults(t *testing.T) {
    57  	var p Provisioner
    58  	config := testConfig()
    59  
    60  	err := p.Prepare(config)
    61  	if err != nil {
    62  		t.Fatalf("err: %s", err)
    63  	}
    64  
    65  	if p.config.RemotePath != DefaultRemotePath {
    66  		t.Errorf("unexpected remote path: %s", p.config.RemotePath)
    67  	}
    68  
    69  	if p.config.ExecuteCommand != "{{.Vars}}\"{{.Path}}\"" {
    70  		t.Fatalf("Default command should be powershell {{.Vars}}\"{{.Path}}\", but got %s", p.config.ExecuteCommand)
    71  	}
    72  }
    73  
    74  func TestProvisionerPrepare_Config(t *testing.T) {
    75  
    76  }
    77  
    78  func TestProvisionerPrepare_InvalidKey(t *testing.T) {
    79  	var p Provisioner
    80  	config := testConfig()
    81  
    82  	// Add a random key
    83  	config["i_should_not_be_valid"] = true
    84  	err := p.Prepare(config)
    85  	if err == nil {
    86  		t.Fatal("should have error")
    87  	}
    88  }
    89  
    90  func TestProvisionerPrepare_Script(t *testing.T) {
    91  	config := testConfig()
    92  	delete(config, "inline")
    93  
    94  	config["script"] = "/this/should/not/exist"
    95  	p := new(Provisioner)
    96  	err := p.Prepare(config)
    97  	if err == nil {
    98  		t.Fatal("should have error")
    99  	}
   100  
   101  	// Test with a good one
   102  	tf, err := ioutil.TempFile("", "packer")
   103  	if err != nil {
   104  		t.Fatalf("error tempfile: %s", err)
   105  	}
   106  	defer os.Remove(tf.Name())
   107  
   108  	config["script"] = tf.Name()
   109  	p = new(Provisioner)
   110  	err = p.Prepare(config)
   111  	if err != nil {
   112  		t.Fatalf("should not have error: %s", err)
   113  	}
   114  }
   115  
   116  func TestProvisionerPrepare_ScriptAndInline(t *testing.T) {
   117  	var p Provisioner
   118  	config := testConfig()
   119  
   120  	delete(config, "inline")
   121  	delete(config, "script")
   122  	err := p.Prepare(config)
   123  	if err == nil {
   124  		t.Fatal("should have error")
   125  	}
   126  
   127  	// Test with both
   128  	tf, err := ioutil.TempFile("", "packer")
   129  	if err != nil {
   130  		t.Fatalf("error tempfile: %s", err)
   131  	}
   132  	defer os.Remove(tf.Name())
   133  
   134  	config["inline"] = []interface{}{"foo"}
   135  	config["script"] = tf.Name()
   136  	err = p.Prepare(config)
   137  	if err == nil {
   138  		t.Fatal("should have error")
   139  	}
   140  }
   141  
   142  func TestProvisionerPrepare_ScriptAndScripts(t *testing.T) {
   143  	var p Provisioner
   144  	config := testConfig()
   145  
   146  	// Test with both
   147  	tf, err := ioutil.TempFile("", "packer")
   148  	if err != nil {
   149  		t.Fatalf("error tempfile: %s", err)
   150  	}
   151  	defer os.Remove(tf.Name())
   152  
   153  	config["inline"] = []interface{}{"foo"}
   154  	config["scripts"] = []string{tf.Name()}
   155  	err = p.Prepare(config)
   156  	if err == nil {
   157  		t.Fatal("should have error")
   158  	}
   159  }
   160  
   161  func TestProvisionerPrepare_Scripts(t *testing.T) {
   162  	config := testConfig()
   163  	delete(config, "inline")
   164  
   165  	config["scripts"] = []string{}
   166  	p := new(Provisioner)
   167  	err := p.Prepare(config)
   168  	if err == nil {
   169  		t.Fatal("should have error")
   170  	}
   171  
   172  	// Test with a good one
   173  	tf, err := ioutil.TempFile("", "packer")
   174  	if err != nil {
   175  		t.Fatalf("error tempfile: %s", err)
   176  	}
   177  	defer os.Remove(tf.Name())
   178  
   179  	config["scripts"] = []string{tf.Name()}
   180  	p = new(Provisioner)
   181  	err = p.Prepare(config)
   182  	if err != nil {
   183  		t.Fatalf("should not have error: %s", err)
   184  	}
   185  }
   186  
   187  func TestProvisionerPrepare_EnvironmentVars(t *testing.T) {
   188  	config := testConfig()
   189  
   190  	// Test with a bad case
   191  	config["environment_vars"] = []string{"badvar", "good=var"}
   192  	p := new(Provisioner)
   193  	err := p.Prepare(config)
   194  	if err == nil {
   195  		t.Fatal("should have error")
   196  	}
   197  
   198  	// Test with a trickier case
   199  	config["environment_vars"] = []string{"=bad"}
   200  	p = new(Provisioner)
   201  	err = p.Prepare(config)
   202  	if err == nil {
   203  		t.Fatal("should have error")
   204  	}
   205  
   206  	// Test with a good case
   207  	// Note: baz= is a real env variable, just empty
   208  	config["environment_vars"] = []string{"FOO=bar", "baz="}
   209  	p = new(Provisioner)
   210  	err = p.Prepare(config)
   211  	if err != nil {
   212  		t.Fatalf("should not have error: %s", err)
   213  	}
   214  
   215  	// Test when the env variable value contains an equals sign
   216  	config["environment_vars"] = []string{"good=withequals=true"}
   217  	p = new(Provisioner)
   218  	err = p.Prepare(config)
   219  	if err != nil {
   220  		t.Fatalf("should not have error: %s", err)
   221  	}
   222  
   223  	// Test when the env variable value starts with an equals sign
   224  	config["environment_vars"] = []string{"good==true"}
   225  	p = new(Provisioner)
   226  	err = p.Prepare(config)
   227  	if err != nil {
   228  		t.Fatalf("should not have error: %s", err)
   229  	}
   230  }
   231  
   232  func TestProvisionerQuote_EnvironmentVars(t *testing.T) {
   233  	config := testConfig()
   234  
   235  	config["environment_vars"] = []string{
   236  		"keyone=valueone",
   237  		"keytwo=value\ntwo",
   238  		"keythree='valuethree'",
   239  		"keyfour='value\nfour'",
   240  		"keyfive='value=five'",
   241  		"keysix='=six'",
   242  	}
   243  
   244  	expected := []string{
   245  		"keyone=valueone",
   246  		"keytwo=value\ntwo",
   247  		"keythree='valuethree'",
   248  		"keyfour='value\nfour'",
   249  		"keyfive='value=five'",
   250  		"keysix='=six'",
   251  	}
   252  
   253  	p := new(Provisioner)
   254  	p.Prepare(config)
   255  
   256  	for i, expectedValue := range expected {
   257  		if p.config.Vars[i] != expectedValue {
   258  			t.Fatalf("%s should be equal to %s", p.config.Vars[i], expectedValue)
   259  		}
   260  	}
   261  
   262  }
   263  
   264  func testUi() *packer.BasicUi {
   265  	return &packer.BasicUi{
   266  		Reader:      new(bytes.Buffer),
   267  		Writer:      new(bytes.Buffer),
   268  		ErrorWriter: new(bytes.Buffer),
   269  	}
   270  }
   271  
   272  func testObjects() (packer.Ui, packer.Communicator) {
   273  	ui := testUi()
   274  	return ui, new(packer.MockCommunicator)
   275  }
   276  
   277  func TestProvisionerProvision_Inline(t *testing.T) {
   278  	config := testConfig()
   279  	delete(config, "inline")
   280  
   281  	// Defaults provided by Packer
   282  	config["remote_path"] = "c:/Windows/Temp/inlineScript.bat"
   283  	config["inline"] = []string{"whoami"}
   284  	ui := testUi()
   285  	p := new(Provisioner)
   286  
   287  	// Defaults provided by Packer
   288  	p.config.PackerBuildName = "vmware"
   289  	p.config.PackerBuilderType = "iso"
   290  	comm := new(packer.MockCommunicator)
   291  	p.Prepare(config)
   292  	err := p.Provision(ui, comm)
   293  	if err != nil {
   294  		t.Fatal("should not have error")
   295  	}
   296  
   297  	expectedCommand := `set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && "c:/Windows/Temp/inlineScript.bat"`
   298  
   299  	// Should run the command without alteration
   300  	if comm.StartCmd.Command != expectedCommand {
   301  		t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command)
   302  	}
   303  
   304  	envVars := make([]string, 2)
   305  	envVars[0] = "FOO=BAR"
   306  	envVars[1] = "BAR=BAZ"
   307  	config["environment_vars"] = envVars
   308  	config["remote_path"] = "c:/Windows/Temp/inlineScript.bat"
   309  
   310  	p.Prepare(config)
   311  	err = p.Provision(ui, comm)
   312  	if err != nil {
   313  		t.Fatal("should not have error")
   314  	}
   315  
   316  	expectedCommand = `set "BAR=BAZ" && set "FOO=BAR" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && "c:/Windows/Temp/inlineScript.bat"`
   317  
   318  	// Should run the command without alteration
   319  	if comm.StartCmd.Command != expectedCommand {
   320  		t.Fatalf("Expect command to be: %s, got: %s", expectedCommand, comm.StartCmd.Command)
   321  	}
   322  }
   323  
   324  func TestProvisionerProvision_Scripts(t *testing.T) {
   325  	tempFile, _ := ioutil.TempFile("", "packer")
   326  	defer os.Remove(tempFile.Name())
   327  	config := testConfig()
   328  	delete(config, "inline")
   329  	config["scripts"] = []string{tempFile.Name()}
   330  	config["packer_build_name"] = "foobuild"
   331  	config["packer_builder_type"] = "footype"
   332  	ui := testUi()
   333  
   334  	p := new(Provisioner)
   335  	comm := new(packer.MockCommunicator)
   336  	p.Prepare(config)
   337  	err := p.Provision(ui, comm)
   338  	if err != nil {
   339  		t.Fatal("should not have error")
   340  	}
   341  
   342  	//powershell -Command "$env:PACKER_BUILDER_TYPE=''"; powershell -Command "$env:PACKER_BUILD_NAME='foobuild'";  powershell -Command c:/Windows/Temp/script.ps1
   343  	expectedCommand := `set "PACKER_BUILDER_TYPE=footype" && set "PACKER_BUILD_NAME=foobuild" && "c:/Windows/Temp/script.bat"`
   344  
   345  	// Should run the command without alteration
   346  	if comm.StartCmd.Command != expectedCommand {
   347  		t.Fatalf("Expect command to be %s NOT %s", expectedCommand, comm.StartCmd.Command)
   348  	}
   349  }
   350  
   351  func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) {
   352  	tempFile, _ := ioutil.TempFile("", "packer")
   353  	config := testConfig()
   354  	ui := testUi()
   355  	defer os.Remove(tempFile.Name())
   356  	delete(config, "inline")
   357  
   358  	config["scripts"] = []string{tempFile.Name()}
   359  	config["packer_build_name"] = "foobuild"
   360  	config["packer_builder_type"] = "footype"
   361  
   362  	// Env vars - currently should not effect them
   363  	envVars := make([]string, 2)
   364  	envVars[0] = "FOO=BAR"
   365  	envVars[1] = "BAR=BAZ"
   366  	config["environment_vars"] = envVars
   367  
   368  	p := new(Provisioner)
   369  	comm := new(packer.MockCommunicator)
   370  	p.Prepare(config)
   371  	err := p.Provision(ui, comm)
   372  	if err != nil {
   373  		t.Fatal("should not have error")
   374  	}
   375  
   376  	expectedCommand := `set "BAR=BAZ" && set "FOO=BAR" && set "PACKER_BUILDER_TYPE=footype" && set "PACKER_BUILD_NAME=foobuild" && "c:/Windows/Temp/script.bat"`
   377  
   378  	// Should run the command without alteration
   379  	if comm.StartCmd.Command != expectedCommand {
   380  		t.Fatalf("Expect command to be %s NOT %s", expectedCommand, comm.StartCmd.Command)
   381  	}
   382  }
   383  
   384  func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
   385  	var flattenedEnvVars string
   386  	config := testConfig()
   387  
   388  	userEnvVarTests := [][]string{
   389  		{},                     // No user env var
   390  		{"FOO=bar"},            // Single user env var
   391  		{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
   392  		{"FOO=bar=baz"},        // User env var with value containing equals
   393  		{"FOO==bar"},           // User env var with value starting with equals
   394  	}
   395  	expected := []string{
   396  		`set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && `,
   397  		`set "FOO=bar" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && `,
   398  		`set "BAZ=qux" && set "FOO=bar" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && `,
   399  		`set "FOO=bar=baz" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && `,
   400  		`set "FOO==bar" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && `,
   401  	}
   402  
   403  	p := new(Provisioner)
   404  	p.Prepare(config)
   405  
   406  	// Defaults provided by Packer
   407  	p.config.PackerBuildName = "vmware"
   408  	p.config.PackerBuilderType = "iso"
   409  
   410  	for i, expectedValue := range expected {
   411  		p.config.Vars = userEnvVarTests[i]
   412  		flattenedEnvVars = p.createFlattenedEnvVars()
   413  		if flattenedEnvVars != expectedValue {
   414  			t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars)
   415  		}
   416  	}
   417  }
   418  
   419  func TestRetryable(t *testing.T) {
   420  	config := testConfig()
   421  
   422  	count := 0
   423  	retryMe := func() error {
   424  		log.Printf("RetryMe, attempt number %d", count)
   425  		if count == 2 {
   426  			return nil
   427  		}
   428  		count++
   429  		return errors.New(fmt.Sprintf("Still waiting %d more times...", 2-count))
   430  	}
   431  	retryableSleep = 50 * time.Millisecond
   432  	p := new(Provisioner)
   433  	p.config.StartRetryTimeout = 155 * time.Millisecond
   434  	err := p.Prepare(config)
   435  	err = p.retryable(retryMe)
   436  	if err != nil {
   437  		t.Fatalf("should not have error retrying funuction")
   438  	}
   439  
   440  	count = 0
   441  	p.config.StartRetryTimeout = 10 * time.Millisecond
   442  	err = p.Prepare(config)
   443  	err = p.retryable(retryMe)
   444  	if err == nil {
   445  		t.Fatalf("should have error retrying funuction")
   446  	}
   447  }
   448  
   449  func TestCancel(t *testing.T) {
   450  	// Don't actually call Cancel() as it performs an os.Exit(0)
   451  	// which kills the 'go test' tool
   452  }