github.com/ddnomad/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 }