github.com/rsyabuta/packer@v1.1.4-0.20180119234903-5ef0c2280f0b/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_RemoteFolderSetSuccessfully(t *testing.T) { 290 config := testConfig() 291 292 expectedRemoteFolder := "/example/path" 293 config["remote_folder"] = expectedRemoteFolder 294 295 p := new(Provisioner) 296 err := p.Prepare(config) 297 if err != nil { 298 t.Fatalf("should not have error: %s", err) 299 } 300 301 if !strings.Contains(p.config.RemotePath, expectedRemoteFolder) { 302 t.Fatalf("remote path does not contain remote_folder") 303 } 304 } 305 306 func TestProvisioner_RemoteFolderDefaultsToTmp(t *testing.T) { 307 config := testConfig() 308 309 p := new(Provisioner) 310 err := p.Prepare(config) 311 if err != nil { 312 t.Fatalf("should not have error: %s", err) 313 } 314 315 if p.config.RemoteFolder != "/tmp" { 316 t.Fatalf("remote_folder did not default to /tmp") 317 } 318 319 if !strings.Contains(p.config.RemotePath, "/tmp") { 320 t.Fatalf("remote path does not contain remote_folder") 321 } 322 } 323 324 func TestProvisioner_RemoteFileSetSuccessfully(t *testing.T) { 325 config := testConfig() 326 327 expectedRemoteFile := "example.sh" 328 config["remote_file"] = expectedRemoteFile 329 330 p := new(Provisioner) 331 err := p.Prepare(config) 332 if err != nil { 333 t.Fatalf("should not have error: %s", err) 334 } 335 336 if !strings.Contains(p.config.RemotePath, expectedRemoteFile) { 337 t.Fatalf("remote path does not contain remote_file") 338 } 339 } 340 341 func TestProvisioner_RemoteFileDefaultsToScriptnnnn(t *testing.T) { 342 config := testConfig() 343 344 p := new(Provisioner) 345 err := p.Prepare(config) 346 if err != nil { 347 t.Fatalf("should not have error: %s", err) 348 } 349 350 remoteFileRegex := regexp.MustCompile("script_[0-9]{4}.sh") 351 352 if !remoteFileRegex.MatchString(p.config.RemoteFile) { 353 t.Fatalf("remote_file did not default to script_nnnn.sh") 354 } 355 356 if !remoteFileRegex.MatchString(p.config.RemotePath) { 357 t.Fatalf("remote_path did not match script_nnnn.sh") 358 } 359 } 360 361 func TestProvisioner_RemotePathSetViaRemotePathAndRemoteFile(t *testing.T) { 362 config := testConfig() 363 364 expectedRemoteFile := "example.sh" 365 expectedRemoteFolder := "/example/path" 366 config["remote_file"] = expectedRemoteFile 367 config["remote_folder"] = expectedRemoteFolder 368 369 p := new(Provisioner) 370 err := p.Prepare(config) 371 if err != nil { 372 t.Fatalf("should not have error: %s", err) 373 } 374 375 if p.config.RemotePath != expectedRemoteFolder+"/"+expectedRemoteFile { 376 t.Fatalf("remote path does not contain remote_file") 377 } 378 } 379 380 func TestProvisioner_RemotePathOverridesRemotePathAndRemoteFile(t *testing.T) { 381 config := testConfig() 382 383 expectedRemoteFile := "example.sh" 384 expectedRemoteFolder := "/example/path" 385 expectedRemotePath := "/example/remote/path/script.sh" 386 config["remote_file"] = expectedRemoteFile 387 config["remote_folder"] = expectedRemoteFolder 388 config["remote_path"] = expectedRemotePath 389 390 p := new(Provisioner) 391 err := p.Prepare(config) 392 if err != nil { 393 t.Fatalf("should not have error: %s", err) 394 } 395 396 if p.config.RemotePath != expectedRemotePath { 397 t.Fatalf("remote path does not contain remote_path") 398 } 399 } 400 401 func TestProvisionerRemotePathDefaultsSuccessfully(t *testing.T) { 402 config := testConfig() 403 404 p := new(Provisioner) 405 err := p.Prepare(config) 406 if err != nil { 407 t.Fatalf("should not have error: %s", err) 408 } 409 410 remotePathRegex := regexp.MustCompile("/tmp/script_[0-9]{4}.sh") 411 412 if !remotePathRegex.MatchString(p.config.RemotePath) { 413 t.Fatalf("remote path does not match the expected default regex") 414 } 415 }