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