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 }