github.phpd.cn/hashicorp/packer@v1.3.2/provisioner/shell/provisioner_test.go (about) 1 package shell 2 3 import ( 4 "io/ioutil" 5 "os" 6 "regexp" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/packer/packer" 11 ) 12 13 func testConfig() map[string]interface{} { 14 return map[string]interface{}{ 15 "inline": []interface{}{"foo", "bar"}, 16 } 17 } 18 19 func TestProvisioner_Impl(t *testing.T) { 20 var raw interface{} 21 raw = &Provisioner{} 22 if _, ok := raw.(packer.Provisioner); !ok { 23 t.Fatalf("must be a Provisioner") 24 } 25 } 26 27 func TestProvisionerPrepare_Defaults(t *testing.T) { 28 var p Provisioner 29 config := testConfig() 30 31 err := p.Prepare(config) 32 if err != nil { 33 t.Fatalf("err: %s", err) 34 } 35 36 if p.config.ExpectDisconnect != false { 37 t.Errorf("expected ExpectDisconnect to default to false") 38 } 39 40 if p.config.RemotePath == "" { 41 t.Errorf("unexpected remote path: %s", p.config.RemotePath) 42 } 43 } 44 45 func TestProvisionerPrepare_ExpectDisconnect(t *testing.T) { 46 config := testConfig() 47 p := new(Provisioner) 48 config["expect_disconnect"] = false 49 50 err := p.Prepare(config) 51 if err != nil { 52 t.Fatalf("err: %s", err) 53 } 54 55 if p.config.ExpectDisconnect != false { 56 t.Errorf("expected ExpectDisconnect to be false") 57 } 58 59 config["expect_disconnect"] = true 60 p = new(Provisioner) 61 err = p.Prepare(config) 62 if err != nil { 63 t.Fatalf("err: %s", err) 64 } 65 66 if p.config.ExpectDisconnect != true { 67 t.Errorf("expected ExpectDisconnect to be true") 68 } 69 } 70 71 func TestProvisionerPrepare_InlineShebang(t *testing.T) { 72 config := testConfig() 73 74 delete(config, "inline_shebang") 75 p := new(Provisioner) 76 err := p.Prepare(config) 77 if err != nil { 78 t.Fatalf("should not have error: %s", err) 79 } 80 81 if p.config.InlineShebang != "/bin/sh -e" { 82 t.Fatalf("bad value: %s", p.config.InlineShebang) 83 } 84 85 // Test with a good one 86 config["inline_shebang"] = "foo" 87 p = new(Provisioner) 88 err = p.Prepare(config) 89 if err != nil { 90 t.Fatalf("should not have error: %s", err) 91 } 92 93 if p.config.InlineShebang != "foo" { 94 t.Fatalf("bad value: %s", p.config.InlineShebang) 95 } 96 } 97 98 func TestProvisionerPrepare_InvalidKey(t *testing.T) { 99 var p Provisioner 100 config := testConfig() 101 102 // Add a random key 103 config["i_should_not_be_valid"] = true 104 err := p.Prepare(config) 105 if err == nil { 106 t.Fatal("should have error") 107 } 108 } 109 110 func TestProvisionerPrepare_Script(t *testing.T) { 111 config := testConfig() 112 delete(config, "inline") 113 114 config["script"] = "/this/should/not/exist" 115 p := new(Provisioner) 116 err := p.Prepare(config) 117 if err == nil { 118 t.Fatal("should have error") 119 } 120 121 // Test with a good one 122 tf, err := ioutil.TempFile("", "packer") 123 if err != nil { 124 t.Fatalf("error tempfile: %s", err) 125 } 126 defer os.Remove(tf.Name()) 127 128 config["script"] = tf.Name() 129 p = new(Provisioner) 130 err = p.Prepare(config) 131 if err != nil { 132 t.Fatalf("should not have error: %s", err) 133 } 134 } 135 136 func TestProvisionerPrepare_ScriptAndInline(t *testing.T) { 137 var p Provisioner 138 config := testConfig() 139 140 delete(config, "inline") 141 delete(config, "script") 142 err := p.Prepare(config) 143 if err == nil { 144 t.Fatal("should have error") 145 } 146 147 // Test with both 148 tf, err := ioutil.TempFile("", "packer") 149 if err != nil { 150 t.Fatalf("error tempfile: %s", err) 151 } 152 defer os.Remove(tf.Name()) 153 154 config["inline"] = []interface{}{"foo"} 155 config["script"] = tf.Name() 156 err = p.Prepare(config) 157 if err == nil { 158 t.Fatal("should have error") 159 } 160 } 161 162 func TestProvisionerPrepare_ScriptAndScripts(t *testing.T) { 163 var p Provisioner 164 config := testConfig() 165 166 // Test with both 167 tf, err := ioutil.TempFile("", "packer") 168 if err != nil { 169 t.Fatalf("error tempfile: %s", err) 170 } 171 defer os.Remove(tf.Name()) 172 173 config["inline"] = []interface{}{"foo"} 174 config["scripts"] = []string{tf.Name()} 175 err = p.Prepare(config) 176 if err == nil { 177 t.Fatal("should have error") 178 } 179 } 180 181 func TestProvisionerPrepare_Scripts(t *testing.T) { 182 config := testConfig() 183 delete(config, "inline") 184 185 config["scripts"] = []string{} 186 p := new(Provisioner) 187 err := p.Prepare(config) 188 if err == nil { 189 t.Fatal("should have error") 190 } 191 192 // Test with a good one 193 tf, err := ioutil.TempFile("", "packer") 194 if err != nil { 195 t.Fatalf("error tempfile: %s", err) 196 } 197 defer os.Remove(tf.Name()) 198 199 config["scripts"] = []string{tf.Name()} 200 p = new(Provisioner) 201 err = p.Prepare(config) 202 if err != nil { 203 t.Fatalf("should not have error: %s", err) 204 } 205 } 206 207 func TestProvisionerPrepare_EnvironmentVars(t *testing.T) { 208 config := testConfig() 209 210 // Test with a bad case 211 config["environment_vars"] = []string{"badvar", "good=var"} 212 p := new(Provisioner) 213 err := p.Prepare(config) 214 if err == nil { 215 t.Fatal("should have error") 216 } 217 218 // Test with a trickier case 219 config["environment_vars"] = []string{"=bad"} 220 p = new(Provisioner) 221 err = p.Prepare(config) 222 if err == nil { 223 t.Fatal("should have error") 224 } 225 226 // Test with a good case 227 // Note: baz= is a real env variable, just empty 228 config["environment_vars"] = []string{"FOO=bar", "baz="} 229 p = new(Provisioner) 230 err = p.Prepare(config) 231 if err != nil { 232 t.Fatalf("should not have error: %s", err) 233 } 234 235 // Test when the env variable value contains an equals sign 236 config["environment_vars"] = []string{"good=withequals=true"} 237 p = new(Provisioner) 238 err = p.Prepare(config) 239 if err != nil { 240 t.Fatalf("should not have error: %s", err) 241 } 242 243 // Test when the env variable value starts with an equals sign 244 config["environment_vars"] = []string{"good==true"} 245 p = new(Provisioner) 246 err = p.Prepare(config) 247 if err != nil { 248 t.Fatalf("should not have error: %s", err) 249 } 250 } 251 252 func TestProvisioner_createFlattenedEnvVars(t *testing.T) { 253 var flattenedEnvVars string 254 config := testConfig() 255 256 userEnvVarTests := [][]string{ 257 {}, // No user env var 258 {"FOO=bar"}, // Single user env var 259 {"FOO=bar's"}, // User env var with single quote in value 260 {"FOO=bar", "BAZ=qux"}, // Multiple user env vars 261 {"FOO=bar=baz"}, // User env var with value containing equals 262 {"FOO==bar"}, // User env var with value starting with equals 263 } 264 expected := []string{ 265 `PACKER_BUILDER_TYPE='iso' PACKER_BUILD_NAME='vmware' `, 266 `FOO='bar' PACKER_BUILDER_TYPE='iso' PACKER_BUILD_NAME='vmware' `, 267 `FOO='bar'"'"'s' PACKER_BUILDER_TYPE='iso' PACKER_BUILD_NAME='vmware' `, 268 `BAZ='qux' FOO='bar' PACKER_BUILDER_TYPE='iso' PACKER_BUILD_NAME='vmware' `, 269 `FOO='bar=baz' PACKER_BUILDER_TYPE='iso' PACKER_BUILD_NAME='vmware' `, 270 `FOO='=bar' PACKER_BUILDER_TYPE='iso' PACKER_BUILD_NAME='vmware' `, 271 } 272 273 p := new(Provisioner) 274 p.Prepare(config) 275 276 // Defaults provided by Packer 277 p.config.PackerBuildName = "vmware" 278 p.config.PackerBuilderType = "iso" 279 280 for i, expectedValue := range expected { 281 p.config.Vars = userEnvVarTests[i] 282 flattenedEnvVars = p.createFlattenedEnvVars() 283 if flattenedEnvVars != expectedValue { 284 t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars) 285 } 286 } 287 } 288 289 func TestProvisioner_createEnvVarFileContent(t *testing.T) { 290 var flattenedEnvVars string 291 config := testConfig() 292 293 userEnvVarTests := [][]string{ 294 {}, // No user env var 295 {"FOO=bar"}, // Single user env var 296 {"FOO=bar's"}, // User env var with single quote in value 297 {"FOO=bar", "BAZ=qux"}, // Multiple user env vars 298 {"FOO=bar=baz"}, // User env var with value containing equals 299 {"FOO==bar"}, // User env var with value starting with equals 300 } 301 expected := []string{ 302 `export PACKER_BUILDER_TYPE='iso' 303 export PACKER_BUILD_NAME='vmware' 304 `, 305 `export FOO='bar' 306 export PACKER_BUILDER_TYPE='iso' 307 export PACKER_BUILD_NAME='vmware' 308 `, 309 `export FOO='bar'"'"'s' 310 export PACKER_BUILDER_TYPE='iso' 311 export PACKER_BUILD_NAME='vmware' 312 `, 313 `export BAZ='qux' 314 export FOO='bar' 315 export PACKER_BUILDER_TYPE='iso' 316 export PACKER_BUILD_NAME='vmware' 317 `, 318 `export FOO='bar=baz' 319 export PACKER_BUILDER_TYPE='iso' 320 export PACKER_BUILD_NAME='vmware' 321 `, 322 `export FOO='=bar' 323 export PACKER_BUILDER_TYPE='iso' 324 export PACKER_BUILD_NAME='vmware' 325 `, 326 } 327 328 p := new(Provisioner) 329 p.Prepare(config) 330 331 // Defaults provided by Packer 332 p.config.PackerBuildName = "vmware" 333 p.config.PackerBuilderType = "iso" 334 335 for i, expectedValue := range expected { 336 p.config.Vars = userEnvVarTests[i] 337 flattenedEnvVars = p.createEnvVarFileContent() 338 if flattenedEnvVars != expectedValue { 339 t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars) 340 } 341 } 342 } 343 344 func TestProvisioner_RemoteFolderSetSuccessfully(t *testing.T) { 345 config := testConfig() 346 347 expectedRemoteFolder := "/example/path" 348 config["remote_folder"] = expectedRemoteFolder 349 350 p := new(Provisioner) 351 err := p.Prepare(config) 352 if err != nil { 353 t.Fatalf("should not have error: %s", err) 354 } 355 356 if !strings.Contains(p.config.RemotePath, expectedRemoteFolder) { 357 t.Fatalf("remote path does not contain remote_folder") 358 } 359 } 360 361 func TestProvisioner_RemoteFolderDefaultsToTmp(t *testing.T) { 362 config := testConfig() 363 364 p := new(Provisioner) 365 err := p.Prepare(config) 366 if err != nil { 367 t.Fatalf("should not have error: %s", err) 368 } 369 370 if p.config.RemoteFolder != "/tmp" { 371 t.Fatalf("remote_folder did not default to /tmp") 372 } 373 374 if !strings.Contains(p.config.RemotePath, "/tmp") { 375 t.Fatalf("remote path does not contain remote_folder") 376 } 377 } 378 379 func TestProvisioner_RemoteFileSetSuccessfully(t *testing.T) { 380 config := testConfig() 381 382 expectedRemoteFile := "example.sh" 383 config["remote_file"] = expectedRemoteFile 384 385 p := new(Provisioner) 386 err := p.Prepare(config) 387 if err != nil { 388 t.Fatalf("should not have error: %s", err) 389 } 390 391 if !strings.Contains(p.config.RemotePath, expectedRemoteFile) { 392 t.Fatalf("remote path does not contain remote_file") 393 } 394 } 395 396 func TestProvisioner_RemoteFileDefaultsToScriptnnnn(t *testing.T) { 397 config := testConfig() 398 399 p := new(Provisioner) 400 err := p.Prepare(config) 401 if err != nil { 402 t.Fatalf("should not have error: %s", err) 403 } 404 405 remoteFileRegex := regexp.MustCompile("script_[0-9]{4}.sh") 406 407 if !remoteFileRegex.MatchString(p.config.RemoteFile) { 408 t.Fatalf("remote_file did not default to script_nnnn.sh") 409 } 410 411 if !remoteFileRegex.MatchString(p.config.RemotePath) { 412 t.Fatalf("remote_path did not match script_nnnn.sh") 413 } 414 } 415 416 func TestProvisioner_RemotePathSetViaRemotePathAndRemoteFile(t *testing.T) { 417 config := testConfig() 418 419 expectedRemoteFile := "example.sh" 420 expectedRemoteFolder := "/example/path" 421 config["remote_file"] = expectedRemoteFile 422 config["remote_folder"] = expectedRemoteFolder 423 424 p := new(Provisioner) 425 err := p.Prepare(config) 426 if err != nil { 427 t.Fatalf("should not have error: %s", err) 428 } 429 430 if p.config.RemotePath != expectedRemoteFolder+"/"+expectedRemoteFile { 431 t.Fatalf("remote path does not contain remote_file") 432 } 433 } 434 435 func TestProvisioner_RemotePathOverridesRemotePathAndRemoteFile(t *testing.T) { 436 config := testConfig() 437 438 expectedRemoteFile := "example.sh" 439 expectedRemoteFolder := "/example/path" 440 expectedRemotePath := "/example/remote/path/script.sh" 441 config["remote_file"] = expectedRemoteFile 442 config["remote_folder"] = expectedRemoteFolder 443 config["remote_path"] = expectedRemotePath 444 445 p := new(Provisioner) 446 err := p.Prepare(config) 447 if err != nil { 448 t.Fatalf("should not have error: %s", err) 449 } 450 451 if p.config.RemotePath != expectedRemotePath { 452 t.Fatalf("remote path does not contain remote_path") 453 } 454 } 455 456 func TestProvisionerRemotePathDefaultsSuccessfully(t *testing.T) { 457 config := testConfig() 458 459 p := new(Provisioner) 460 err := p.Prepare(config) 461 if err != nil { 462 t.Fatalf("should not have error: %s", err) 463 } 464 465 remotePathRegex := regexp.MustCompile("/tmp/script_[0-9]{4}.sh") 466 467 if !remotePathRegex.MatchString(p.config.RemotePath) { 468 t.Fatalf("remote path does not match the expected default regex") 469 } 470 }