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  }