github.com/ddnomad/packer@v1.3.2/provisioner/powershell/provisioner_test.go (about)

     1  package powershell
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"regexp"
    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 init() {
    24  	//log.SetOutput(ioutil.Discard)
    25  }
    26  
    27  func TestProvisionerPrepare_extractScript(t *testing.T) {
    28  	config := testConfig()
    29  	p := new(Provisioner)
    30  	_ = p.Prepare(config)
    31  	file, err := extractScript(p)
    32  	defer os.Remove(file)
    33  	if err != nil {
    34  		t.Fatalf("Should not be error: %s", err)
    35  	}
    36  	t.Logf("File: %s", file)
    37  	if strings.Index(file, os.TempDir()) != 0 {
    38  		t.Fatalf("Temp file should reside in %s. File location: %s", os.TempDir(), file)
    39  	}
    40  
    41  	// File contents should contain 2 lines concatenated by newlines: foo\nbar
    42  	readFile, err := ioutil.ReadFile(file)
    43  	expectedContents := "foo\nbar\n"
    44  	if err != nil {
    45  		t.Fatalf("Should not be error: %s", err)
    46  	}
    47  	s := string(readFile[:])
    48  	if s != expectedContents {
    49  		t.Fatalf("Expected generated inlineScript to equal '%s', got '%s'", expectedContents, s)
    50  	}
    51  }
    52  
    53  func TestProvisioner_Impl(t *testing.T) {
    54  	var raw interface{}
    55  	raw = &Provisioner{}
    56  	if _, ok := raw.(packer.Provisioner); !ok {
    57  		t.Fatalf("must be a Provisioner")
    58  	}
    59  }
    60  
    61  func TestProvisionerPrepare_Defaults(t *testing.T) {
    62  	var p Provisioner
    63  	config := testConfig()
    64  
    65  	err := p.Prepare(config)
    66  	if err != nil {
    67  		t.Fatalf("err: %s", err)
    68  	}
    69  
    70  	matched, _ := regexp.MatchString("c:/Windows/Temp/script-.*.ps1", p.config.RemotePath)
    71  	if !matched {
    72  		t.Errorf("unexpected remote path: %s", p.config.RemotePath)
    73  	}
    74  
    75  	if p.config.ElevatedUser != "" {
    76  		t.Error("expected elevated_user to be empty")
    77  	}
    78  	if p.config.ElevatedPassword != "" {
    79  		t.Error("expected elevated_password to be empty")
    80  	}
    81  
    82  	if p.config.ExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` {
    83  		t.Fatalf(`Default command should be 'powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"', but got '%s'`, p.config.ExecuteCommand)
    84  	}
    85  
    86  	if p.config.ElevatedExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` {
    87  		t.Fatalf(`Default command should be 'powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"', but got '%s'`, p.config.ElevatedExecuteCommand)
    88  	}
    89  
    90  	if p.config.ValidExitCodes == nil {
    91  		t.Fatalf("ValidExitCodes should not be nil")
    92  	}
    93  	if p.config.ValidExitCodes != nil {
    94  		expCodes := []int{0}
    95  		for i, v := range p.config.ValidExitCodes {
    96  			if v != expCodes[i] {
    97  				t.Fatalf("Expected ValidExitCodes don't match actual")
    98  			}
    99  		}
   100  	}
   101  
   102  	if p.config.ElevatedEnvVarFormat != `$env:%s="%s"; ` {
   103  		t.Fatalf(`Default command should be powershell '$env:%%s="%%s"; ', but got %s`, p.config.ElevatedEnvVarFormat)
   104  	}
   105  }
   106  
   107  func TestProvisionerPrepare_Config(t *testing.T) {
   108  	config := testConfig()
   109  	config["elevated_user"] = "{{user `user`}}"
   110  	config["elevated_password"] = "{{user `password`}}"
   111  	config[packer.UserVariablesConfigKey] = map[string]string{
   112  		"user":     "myusername",
   113  		"password": "mypassword",
   114  	}
   115  
   116  	var p Provisioner
   117  	err := p.Prepare(config)
   118  	if err != nil {
   119  		t.Fatalf("err: %s", err)
   120  	}
   121  
   122  	if p.config.ElevatedUser != "myusername" {
   123  		t.Fatalf("Expected 'myusername' for key `elevated_user`: %s", p.config.ElevatedUser)
   124  	}
   125  	if p.config.ElevatedPassword != "mypassword" {
   126  		t.Fatalf("Expected 'mypassword' for key `elevated_password`: %s", p.config.ElevatedPassword)
   127  	}
   128  
   129  }
   130  
   131  func TestProvisionerPrepare_InvalidKey(t *testing.T) {
   132  	var p Provisioner
   133  	config := testConfig()
   134  
   135  	// Add a random key
   136  	config["i_should_not_be_valid"] = true
   137  	err := p.Prepare(config)
   138  	if err == nil {
   139  		t.Fatal("should have error")
   140  	}
   141  }
   142  
   143  func TestProvisionerPrepare_Elevated(t *testing.T) {
   144  	var p Provisioner
   145  	config := testConfig()
   146  
   147  	// Add a random key
   148  	config["elevated_user"] = "vagrant"
   149  	err := p.Prepare(config)
   150  
   151  	if err == nil {
   152  		t.Fatal("should have error (only provided elevated_user)")
   153  	}
   154  
   155  	config["elevated_password"] = "vagrant"
   156  	err = p.Prepare(config)
   157  
   158  	if err != nil {
   159  		t.Fatal("should not have error")
   160  	}
   161  }
   162  
   163  func TestProvisionerPrepare_Script(t *testing.T) {
   164  	config := testConfig()
   165  	delete(config, "inline")
   166  
   167  	config["script"] = "/this/should/not/exist"
   168  	p := new(Provisioner)
   169  	err := p.Prepare(config)
   170  	if err == nil {
   171  		t.Fatal("should have error")
   172  	}
   173  
   174  	// Test with a good one
   175  	tf, err := ioutil.TempFile("", "packer")
   176  	if err != nil {
   177  		t.Fatalf("error tempfile: %s", err)
   178  	}
   179  	defer os.Remove(tf.Name())
   180  	defer tf.Close()
   181  
   182  	config["script"] = tf.Name()
   183  	p = new(Provisioner)
   184  	err = p.Prepare(config)
   185  	if err != nil {
   186  		t.Fatalf("should not have error: %s", err)
   187  	}
   188  }
   189  
   190  func TestProvisionerPrepare_ScriptAndInline(t *testing.T) {
   191  	var p Provisioner
   192  	config := testConfig()
   193  
   194  	delete(config, "inline")
   195  	delete(config, "script")
   196  	err := p.Prepare(config)
   197  	if err == nil {
   198  		t.Fatal("should have error")
   199  	}
   200  
   201  	// Test with both
   202  	tf, err := ioutil.TempFile("", "packer")
   203  	if err != nil {
   204  		t.Fatalf("error tempfile: %s", err)
   205  	}
   206  	defer os.Remove(tf.Name())
   207  	defer tf.Close()
   208  
   209  	config["inline"] = []interface{}{"foo"}
   210  	config["script"] = tf.Name()
   211  	err = p.Prepare(config)
   212  	if err == nil {
   213  		t.Fatal("should have error")
   214  	}
   215  }
   216  
   217  func TestProvisionerPrepare_ScriptAndScripts(t *testing.T) {
   218  	var p Provisioner
   219  	config := testConfig()
   220  
   221  	// Test with both
   222  	tf, err := ioutil.TempFile("", "packer")
   223  	if err != nil {
   224  		t.Fatalf("error tempfile: %s", err)
   225  	}
   226  	defer os.Remove(tf.Name())
   227  	defer tf.Close()
   228  
   229  	config["inline"] = []interface{}{"foo"}
   230  	config["scripts"] = []string{tf.Name()}
   231  	err = p.Prepare(config)
   232  	if err == nil {
   233  		t.Fatal("should have error")
   234  	}
   235  }
   236  
   237  func TestProvisionerPrepare_Scripts(t *testing.T) {
   238  	config := testConfig()
   239  	delete(config, "inline")
   240  
   241  	config["scripts"] = []string{}
   242  	p := new(Provisioner)
   243  	err := p.Prepare(config)
   244  	if err == nil {
   245  		t.Fatal("should have error")
   246  	}
   247  
   248  	// Test with a good one
   249  	tf, err := ioutil.TempFile("", "packer")
   250  	if err != nil {
   251  		t.Fatalf("error tempfile: %s", err)
   252  	}
   253  	defer os.Remove(tf.Name())
   254  	defer tf.Close()
   255  
   256  	config["scripts"] = []string{tf.Name()}
   257  	p = new(Provisioner)
   258  	err = p.Prepare(config)
   259  	if err != nil {
   260  		t.Fatalf("should not have error: %s", err)
   261  	}
   262  }
   263  
   264  func TestProvisionerPrepare_EnvironmentVars(t *testing.T) {
   265  	config := testConfig()
   266  
   267  	// Test with a bad case
   268  	config["environment_vars"] = []string{"badvar", "good=var"}
   269  	p := new(Provisioner)
   270  	err := p.Prepare(config)
   271  	if err == nil {
   272  		t.Fatal("should have error")
   273  	}
   274  
   275  	// Test with a trickier case
   276  	config["environment_vars"] = []string{"=bad"}
   277  	p = new(Provisioner)
   278  	err = p.Prepare(config)
   279  	if err == nil {
   280  		t.Fatal("should have error")
   281  	}
   282  
   283  	// Test with a good case
   284  	// Note: baz= is a real env variable, just empty
   285  	config["environment_vars"] = []string{"FOO=bar", "baz="}
   286  	p = new(Provisioner)
   287  	err = p.Prepare(config)
   288  	if err != nil {
   289  		t.Fatalf("should not have error: %s", err)
   290  	}
   291  
   292  	// Test when the env variable value contains an equals sign
   293  	config["environment_vars"] = []string{"good=withequals=true"}
   294  	p = new(Provisioner)
   295  	err = p.Prepare(config)
   296  	if err != nil {
   297  		t.Fatalf("should not have error: %s", err)
   298  	}
   299  
   300  	// Test when the env variable value starts with an equals sign
   301  	config["environment_vars"] = []string{"good==true"}
   302  	p = new(Provisioner)
   303  	err = p.Prepare(config)
   304  	if err != nil {
   305  		t.Fatalf("should not have error: %s", err)
   306  	}
   307  
   308  }
   309  
   310  func TestProvisionerQuote_EnvironmentVars(t *testing.T) {
   311  	config := testConfig()
   312  
   313  	config["environment_vars"] = []string{
   314  		"keyone=valueone",
   315  		"keytwo=value\ntwo",
   316  		"keythree='valuethree'",
   317  		"keyfour='value\nfour'",
   318  		"keyfive='value=five'",
   319  		"keysix='=six'",
   320  	}
   321  
   322  	expected := []string{
   323  		"keyone=valueone",
   324  		"keytwo=value\ntwo",
   325  		"keythree='valuethree'",
   326  		"keyfour='value\nfour'",
   327  		"keyfive='value=five'",
   328  		"keysix='=six'",
   329  	}
   330  
   331  	p := new(Provisioner)
   332  	p.Prepare(config)
   333  
   334  	for i, expectedValue := range expected {
   335  		if p.config.Vars[i] != expectedValue {
   336  			t.Fatalf("%s should be equal to %s", p.config.Vars[i], expectedValue)
   337  		}
   338  	}
   339  }
   340  
   341  func testUi() *packer.BasicUi {
   342  	return &packer.BasicUi{
   343  		Reader:      new(bytes.Buffer),
   344  		Writer:      new(bytes.Buffer),
   345  		ErrorWriter: new(bytes.Buffer),
   346  	}
   347  }
   348  
   349  func testObjects() (packer.Ui, packer.Communicator) {
   350  	ui := testUi()
   351  	return ui, new(packer.MockCommunicator)
   352  }
   353  
   354  func TestProvisionerProvision_ValidExitCodes(t *testing.T) {
   355  	config := testConfig()
   356  	delete(config, "inline")
   357  
   358  	// Defaults provided by Packer
   359  	config["remote_path"] = "c:/Windows/Temp/inlineScript.ps1"
   360  	config["inline"] = []string{"whoami"}
   361  	ui := testUi()
   362  	p := new(Provisioner)
   363  
   364  	// Defaults provided by Packer
   365  	p.config.PackerBuildName = "vmware"
   366  	p.config.PackerBuilderType = "iso"
   367  	p.config.ValidExitCodes = []int{0, 200}
   368  	comm := new(packer.MockCommunicator)
   369  	comm.StartExitStatus = 200
   370  	p.Prepare(config)
   371  	err := p.Provision(ui, comm)
   372  	if err != nil {
   373  		t.Fatal("should not have error")
   374  	}
   375  }
   376  
   377  func TestProvisionerProvision_InvalidExitCodes(t *testing.T) {
   378  	config := testConfig()
   379  	delete(config, "inline")
   380  
   381  	// Defaults provided by Packer
   382  	config["remote_path"] = "c:/Windows/Temp/inlineScript.ps1"
   383  	config["inline"] = []string{"whoami"}
   384  	ui := testUi()
   385  	p := new(Provisioner)
   386  
   387  	// Defaults provided by Packer
   388  	p.config.PackerBuildName = "vmware"
   389  	p.config.PackerBuilderType = "iso"
   390  	p.config.ValidExitCodes = []int{0, 200}
   391  	comm := new(packer.MockCommunicator)
   392  	comm.StartExitStatus = 201 // Invalid!
   393  	p.Prepare(config)
   394  	err := p.Provision(ui, comm)
   395  	if err == nil {
   396  		t.Fatal("should have error")
   397  	}
   398  }
   399  
   400  func TestProvisionerProvision_Inline(t *testing.T) {
   401  	config := testConfig()
   402  	delete(config, "inline")
   403  
   404  	// Defaults provided by Packer
   405  	config["remote_path"] = "c:/Windows/Temp/inlineScript.ps1"
   406  	config["inline"] = []string{"whoami"}
   407  	ui := testUi()
   408  	p := new(Provisioner)
   409  
   410  	// Defaults provided by Packer - env vars should not appear in cmd
   411  	p.config.PackerBuildName = "vmware"
   412  	p.config.PackerBuilderType = "iso"
   413  	comm := new(packer.MockCommunicator)
   414  	p.Prepare(config)
   415  	err := p.Provision(ui, comm)
   416  	if err != nil {
   417  		t.Fatal("should not have error")
   418  	}
   419  
   420  	cmd := comm.StartCmd.Command
   421  	re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};\. c:/Windows/Temp/packer-ps-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/inlineScript.ps1'; exit \$LastExitCode }"`)
   422  	matched := re.MatchString(cmd)
   423  	if !matched {
   424  		t.Fatalf("Got unexpected command: %s", cmd)
   425  	}
   426  
   427  	// User supplied env vars should not change things
   428  	envVars := make([]string, 2)
   429  	envVars[0] = "FOO=BAR"
   430  	envVars[1] = "BAR=BAZ"
   431  	config["environment_vars"] = envVars
   432  	config["remote_path"] = "c:/Windows/Temp/inlineScript.ps1"
   433  
   434  	p.Prepare(config)
   435  	err = p.Provision(ui, comm)
   436  	if err != nil {
   437  		t.Fatal("should not have error")
   438  	}
   439  
   440  	cmd = comm.StartCmd.Command
   441  	re = regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};\. c:/Windows/Temp/packer-ps-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/inlineScript.ps1'; exit \$LastExitCode }"`)
   442  	matched = re.MatchString(cmd)
   443  	if !matched {
   444  		t.Fatalf("Got unexpected command: %s", cmd)
   445  	}
   446  }
   447  
   448  func TestProvisionerProvision_Scripts(t *testing.T) {
   449  	tempFile, _ := ioutil.TempFile("", "packer")
   450  	defer os.Remove(tempFile.Name())
   451  	defer tempFile.Close()
   452  
   453  	config := testConfig()
   454  	delete(config, "inline")
   455  	config["scripts"] = []string{tempFile.Name()}
   456  	config["packer_build_name"] = "foobuild"
   457  	config["packer_builder_type"] = "footype"
   458  	config["remote_path"] = "c:/Windows/Temp/script.ps1"
   459  	ui := testUi()
   460  
   461  	p := new(Provisioner)
   462  	comm := new(packer.MockCommunicator)
   463  	p.Prepare(config)
   464  	err := p.Provision(ui, comm)
   465  	if err != nil {
   466  		t.Fatal("should not have error")
   467  	}
   468  
   469  	cmd := comm.StartCmd.Command
   470  	re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};\. c:/Windows/Temp/packer-ps-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/script.ps1'; exit \$LastExitCode }"`)
   471  	matched := re.MatchString(cmd)
   472  	if !matched {
   473  		t.Fatalf("Got unexpected command: %s", cmd)
   474  	}
   475  }
   476  
   477  func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) {
   478  	tempFile, _ := ioutil.TempFile("", "packer")
   479  	config := testConfig()
   480  	ui := testUi()
   481  	defer os.Remove(tempFile.Name())
   482  	defer tempFile.Close()
   483  
   484  	delete(config, "inline")
   485  
   486  	config["scripts"] = []string{tempFile.Name()}
   487  	config["packer_build_name"] = "foobuild"
   488  	config["packer_builder_type"] = "footype"
   489  
   490  	// Env vars - currently should not effect them
   491  	envVars := make([]string, 2)
   492  	envVars[0] = "FOO=BAR"
   493  	envVars[1] = "BAR=BAZ"
   494  	config["environment_vars"] = envVars
   495  	config["remote_path"] = "c:/Windows/Temp/script.ps1"
   496  
   497  	p := new(Provisioner)
   498  	comm := new(packer.MockCommunicator)
   499  	p.Prepare(config)
   500  	err := p.Provision(ui, comm)
   501  	if err != nil {
   502  		t.Fatal("should not have error")
   503  	}
   504  
   505  	cmd := comm.StartCmd.Command
   506  	re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};\. c:/Windows/Temp/packer-ps-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/script.ps1'; exit \$LastExitCode }"`)
   507  	matched := re.MatchString(cmd)
   508  	if !matched {
   509  		t.Fatalf("Got unexpected command: %s", cmd)
   510  	}
   511  }
   512  
   513  func TestProvisionerProvision_UISlurp(t *testing.T) {
   514  	// UI should be called n times
   515  
   516  	// UI should receive following messages / output
   517  }
   518  
   519  func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
   520  	var flattenedEnvVars string
   521  	config := testConfig()
   522  
   523  	userEnvVarTests := [][]string{
   524  		{},                     // No user env var
   525  		{"FOO=bar"},            // Single user env var
   526  		{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
   527  		{"FOO=bar=baz"},        // User env var with value containing equals
   528  		{"FOO==bar"},           // User env var with value starting with equals
   529  		// Test escaping of characters special to PowerShell
   530  		{"FOO=bar$baz"},  // User env var with value containing dollar
   531  		{"FOO=bar\"baz"}, // User env var with value containing a double quote
   532  		{"FOO=bar'baz"},  // User env var with value containing a single quote
   533  		{"FOO=bar`baz"},  // User env var with value containing a backtick
   534  
   535  	}
   536  	expected := []string{
   537  		`$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   538  		`$env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   539  		`$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   540  		`$env:FOO="bar=baz"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   541  		`$env:FOO="=bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   542  		"$env:FOO=\"bar`$baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   543  		"$env:FOO=\"bar`\"baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   544  		"$env:FOO=\"bar`'baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   545  		"$env:FOO=\"bar``baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   546  	}
   547  
   548  	p := new(Provisioner)
   549  	p.Prepare(config)
   550  
   551  	// Defaults provided by Packer
   552  	p.config.PackerBuildName = "vmware"
   553  	p.config.PackerBuilderType = "iso"
   554  
   555  	for i, expectedValue := range expected {
   556  		p.config.Vars = userEnvVarTests[i]
   557  		flattenedEnvVars = p.createFlattenedEnvVars(true)
   558  		if flattenedEnvVars != expectedValue {
   559  			t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars)
   560  		}
   561  	}
   562  }
   563  
   564  func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
   565  	var flattenedEnvVars string
   566  	config := testConfig()
   567  
   568  	userEnvVarTests := [][]string{
   569  		{},                     // No user env var
   570  		{"FOO=bar"},            // Single user env var
   571  		{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
   572  		{"FOO=bar=baz"},        // User env var with value containing equals
   573  		{"FOO==bar"},           // User env var with value starting with equals
   574  		// Test escaping of characters special to PowerShell
   575  		{"FOO=bar$baz"},  // User env var with value containing dollar
   576  		{"FOO=bar\"baz"}, // User env var with value containing a double quote
   577  		{"FOO=bar'baz"},  // User env var with value containing a single quote
   578  		{"FOO=bar`baz"},  // User env var with value containing a backtick
   579  	}
   580  	expected := []string{
   581  		`$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   582  		`$env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   583  		`$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   584  		`$env:FOO="bar=baz"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   585  		`$env:FOO="=bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
   586  		"$env:FOO=\"bar`$baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   587  		"$env:FOO=\"bar`\"baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   588  		"$env:FOO=\"bar`'baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   589  		"$env:FOO=\"bar``baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
   590  	}
   591  
   592  	p := new(Provisioner)
   593  	p.Prepare(config)
   594  
   595  	// Defaults provided by Packer
   596  	p.config.PackerBuildName = "vmware"
   597  	p.config.PackerBuilderType = "iso"
   598  
   599  	for i, expectedValue := range expected {
   600  		p.config.Vars = userEnvVarTests[i]
   601  		flattenedEnvVars = p.createFlattenedEnvVars(false)
   602  		if flattenedEnvVars != expectedValue {
   603  			t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars)
   604  		}
   605  	}
   606  }
   607  
   608  func TestProvision_createCommandText(t *testing.T) {
   609  	config := testConfig()
   610  	config["remote_path"] = "c:/Windows/Temp/script.ps1"
   611  	p := new(Provisioner)
   612  	comm := new(packer.MockCommunicator)
   613  	p.communicator = comm
   614  	_ = p.Prepare(config)
   615  
   616  	// Defaults provided by Packer
   617  	p.config.PackerBuildName = "vmware"
   618  	p.config.PackerBuilderType = "iso"
   619  
   620  	// Non-elevated
   621  	cmd, _ := p.createCommandText()
   622  
   623  	re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};\. c:/Windows/Temp/packer-ps-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/script.ps1'; exit \$LastExitCode }"`)
   624  	matched := re.MatchString(cmd)
   625  	if !matched {
   626  		t.Fatalf("Got unexpected command: %s", cmd)
   627  	}
   628  
   629  	// Elevated
   630  	p.config.ElevatedUser = "vagrant"
   631  	p.config.ElevatedPassword = "vagrant"
   632  	cmd, _ = p.createCommandText()
   633  	re = regexp.MustCompile(`powershell -executionpolicy bypass -file "C:/Windows/Temp/packer-elevated-shell-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1"`)
   634  	matched = re.MatchString(cmd)
   635  	if !matched {
   636  		t.Fatalf("Got unexpected elevated command: %s", cmd)
   637  	}
   638  }
   639  
   640  func TestProvision_uploadEnvVars(t *testing.T) {
   641  	p := new(Provisioner)
   642  	comm := new(packer.MockCommunicator)
   643  	p.communicator = comm
   644  
   645  	flattenedEnvVars := `$env:PACKER_BUILDER_TYPE="footype"; $env:PACKER_BUILD_NAME="foobuild";`
   646  
   647  	err := p.uploadEnvVars(flattenedEnvVars)
   648  	if err != nil {
   649  		t.Fatalf("Did not expect error: %s", err.Error())
   650  	}
   651  
   652  	if comm.UploadCalled != true {
   653  		t.Fatalf("Failed to upload env var file")
   654  	}
   655  }
   656  
   657  func TestProvision_generateElevatedShellRunner(t *testing.T) {
   658  
   659  	// Non-elevated
   660  	config := testConfig()
   661  	p := new(Provisioner)
   662  	p.Prepare(config)
   663  	comm := new(packer.MockCommunicator)
   664  	p.communicator = comm
   665  	path, err := p.generateElevatedRunner("whoami")
   666  
   667  	if err != nil {
   668  		t.Fatalf("Did not expect error: %s", err.Error())
   669  	}
   670  
   671  	if comm.UploadCalled != true {
   672  		t.Fatalf("Should have uploaded file")
   673  	}
   674  
   675  	matched, _ := regexp.MatchString("C:/Windows/Temp/packer-elevated-shell.*", path)
   676  	if !matched {
   677  		t.Fatalf("Got unexpected file: %s", path)
   678  	}
   679  }
   680  
   681  func TestRetryable(t *testing.T) {
   682  	config := testConfig()
   683  
   684  	count := 0
   685  	retryMe := func() error {
   686  		t.Logf("RetryMe, attempt number %d", count)
   687  		if count == 2 {
   688  			return nil
   689  		}
   690  		count++
   691  		return errors.New(fmt.Sprintf("Still waiting %d more times...", 2-count))
   692  	}
   693  	retryableSleep = 50 * time.Millisecond
   694  	p := new(Provisioner)
   695  	p.config.StartRetryTimeout = 155 * time.Millisecond
   696  	err := p.Prepare(config)
   697  	err = p.retryable(retryMe)
   698  	if err != nil {
   699  		t.Fatalf("should not have error retrying function")
   700  	}
   701  
   702  	count = 0
   703  	p.config.StartRetryTimeout = 10 * time.Millisecond
   704  	err = p.Prepare(config)
   705  	err = p.retryable(retryMe)
   706  	if err == nil {
   707  		t.Fatalf("should have error retrying function")
   708  	}
   709  }
   710  
   711  func TestCancel(t *testing.T) {
   712  	// Don't actually call Cancel() as it performs an os.Exit(0)
   713  	// which kills the 'go test' tool
   714  }