github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/config/loader_test.go (about)

     1  package config
     2  
     3  import (
     4  	"io/ioutil"
     5  	"path/filepath"
     6  	"reflect"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  func TestIsEmptyDir(t *testing.T) {
    12  	val, err := IsEmptyDir(fixtureDir)
    13  	if err != nil {
    14  		t.Fatalf("err: %s", err)
    15  	}
    16  	if val {
    17  		t.Fatal("should not be empty")
    18  	}
    19  }
    20  
    21  func TestIsEmptyDir_noExist(t *testing.T) {
    22  	val, err := IsEmptyDir(filepath.Join(fixtureDir, "nopenopenope"))
    23  	if err != nil {
    24  		t.Fatalf("err: %s", err)
    25  	}
    26  	if !val {
    27  		t.Fatal("should be empty")
    28  	}
    29  }
    30  
    31  func TestIsEmptyDir_noConfigs(t *testing.T) {
    32  	val, err := IsEmptyDir(filepath.Join(fixtureDir, "dir-empty"))
    33  	if err != nil {
    34  		t.Fatalf("err: %s", err)
    35  	}
    36  	if !val {
    37  		t.Fatal("should be empty")
    38  	}
    39  }
    40  
    41  func TestLoadFile_badType(t *testing.T) {
    42  	_, err := LoadFile(filepath.Join(fixtureDir, "bad_type.tf.nope"))
    43  	if err == nil {
    44  		t.Fatal("should have error")
    45  	}
    46  }
    47  
    48  func TestLoadFileBasic(t *testing.T) {
    49  	c, err := LoadFile(filepath.Join(fixtureDir, "basic.tf"))
    50  	if err != nil {
    51  		t.Fatalf("err: %s", err)
    52  	}
    53  
    54  	if c == nil {
    55  		t.Fatal("config should not be nil")
    56  	}
    57  
    58  	if c.Dir != "" {
    59  		t.Fatalf("bad: %#v", c.Dir)
    60  	}
    61  
    62  	expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"}
    63  	if !reflect.DeepEqual(c.Atlas, expectedAtlas) {
    64  		t.Fatalf("bad: %#v", c.Atlas)
    65  	}
    66  
    67  	actual := variablesStr(c.Variables)
    68  	if actual != strings.TrimSpace(basicVariablesStr) {
    69  		t.Fatalf("bad:\n%s", actual)
    70  	}
    71  
    72  	actual = providerConfigsStr(c.ProviderConfigs)
    73  	if actual != strings.TrimSpace(basicProvidersStr) {
    74  		t.Fatalf("bad:\n%s", actual)
    75  	}
    76  
    77  	actual = resourcesStr(c.Resources)
    78  	if actual != strings.TrimSpace(basicResourcesStr) {
    79  		t.Fatalf("bad:\n%s", actual)
    80  	}
    81  
    82  	actual = outputsStr(c.Outputs)
    83  	if actual != strings.TrimSpace(basicOutputsStr) {
    84  		t.Fatalf("bad:\n%s", actual)
    85  	}
    86  }
    87  
    88  func TestLoadFileBasic_empty(t *testing.T) {
    89  	c, err := LoadFile(filepath.Join(fixtureDir, "empty.tf"))
    90  	if err != nil {
    91  		t.Fatalf("err: %s", err)
    92  	}
    93  
    94  	if c == nil {
    95  		t.Fatal("config should not be nil")
    96  	}
    97  }
    98  
    99  func TestLoadFileBasic_import(t *testing.T) {
   100  	// Skip because we disabled importing
   101  	t.Skip()
   102  
   103  	c, err := LoadFile(filepath.Join(fixtureDir, "import.tf"))
   104  	if err != nil {
   105  		t.Fatalf("err: %s", err)
   106  	}
   107  
   108  	if c == nil {
   109  		t.Fatal("config should not be nil")
   110  	}
   111  
   112  	actual := variablesStr(c.Variables)
   113  	if actual != strings.TrimSpace(importVariablesStr) {
   114  		t.Fatalf("bad:\n%s", actual)
   115  	}
   116  
   117  	actual = providerConfigsStr(c.ProviderConfigs)
   118  	if actual != strings.TrimSpace(importProvidersStr) {
   119  		t.Fatalf("bad:\n%s", actual)
   120  	}
   121  
   122  	actual = resourcesStr(c.Resources)
   123  	if actual != strings.TrimSpace(importResourcesStr) {
   124  		t.Fatalf("bad:\n%s", actual)
   125  	}
   126  }
   127  
   128  func TestLoadFileBasic_json(t *testing.T) {
   129  	c, err := LoadFile(filepath.Join(fixtureDir, "basic.tf.json"))
   130  	if err != nil {
   131  		t.Fatalf("err: %s", err)
   132  	}
   133  
   134  	if c == nil {
   135  		t.Fatal("config should not be nil")
   136  	}
   137  
   138  	if c.Dir != "" {
   139  		t.Fatalf("bad: %#v", c.Dir)
   140  	}
   141  
   142  	expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"}
   143  	if !reflect.DeepEqual(c.Atlas, expectedAtlas) {
   144  		t.Fatalf("bad: %#v", c.Atlas)
   145  	}
   146  
   147  	actual := variablesStr(c.Variables)
   148  	if actual != strings.TrimSpace(basicVariablesStr) {
   149  		t.Fatalf("bad:\n%s", actual)
   150  	}
   151  
   152  	actual = providerConfigsStr(c.ProviderConfigs)
   153  	if actual != strings.TrimSpace(basicProvidersStr) {
   154  		t.Fatalf("bad:\n%s", actual)
   155  	}
   156  
   157  	actual = resourcesStr(c.Resources)
   158  	if actual != strings.TrimSpace(basicResourcesStr) {
   159  		t.Fatalf("bad:\n%s", actual)
   160  	}
   161  
   162  	actual = outputsStr(c.Outputs)
   163  	if actual != strings.TrimSpace(basicOutputsStr) {
   164  		t.Fatalf("bad:\n%s", actual)
   165  	}
   166  }
   167  
   168  func TestLoadFileBasic_modules(t *testing.T) {
   169  	c, err := LoadFile(filepath.Join(fixtureDir, "modules.tf"))
   170  	if err != nil {
   171  		t.Fatalf("err: %s", err)
   172  	}
   173  
   174  	if c == nil {
   175  		t.Fatal("config should not be nil")
   176  	}
   177  
   178  	if c.Dir != "" {
   179  		t.Fatalf("bad: %#v", c.Dir)
   180  	}
   181  
   182  	actual := modulesStr(c.Modules)
   183  	if actual != strings.TrimSpace(modulesModulesStr) {
   184  		t.Fatalf("bad:\n%s", actual)
   185  	}
   186  }
   187  
   188  func TestLoadJSONBasic(t *testing.T) {
   189  	raw, err := ioutil.ReadFile(filepath.Join(fixtureDir, "basic.tf.json"))
   190  	if err != nil {
   191  		t.Fatalf("err: %s", err)
   192  	}
   193  
   194  	c, err := LoadJSON(raw)
   195  	if err != nil {
   196  		t.Fatalf("err: %s", err)
   197  	}
   198  
   199  	if c == nil {
   200  		t.Fatal("config should not be nil")
   201  	}
   202  
   203  	if c.Dir != "" {
   204  		t.Fatalf("bad: %#v", c.Dir)
   205  	}
   206  
   207  	expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"}
   208  	if !reflect.DeepEqual(c.Atlas, expectedAtlas) {
   209  		t.Fatalf("bad: %#v", c.Atlas)
   210  	}
   211  
   212  	actual := variablesStr(c.Variables)
   213  	if actual != strings.TrimSpace(basicVariablesStr) {
   214  		t.Fatalf("bad:\n%s", actual)
   215  	}
   216  
   217  	actual = providerConfigsStr(c.ProviderConfigs)
   218  	if actual != strings.TrimSpace(basicProvidersStr) {
   219  		t.Fatalf("bad:\n%s", actual)
   220  	}
   221  
   222  	actual = resourcesStr(c.Resources)
   223  	if actual != strings.TrimSpace(basicResourcesStr) {
   224  		t.Fatalf("bad:\n%s", actual)
   225  	}
   226  
   227  	actual = outputsStr(c.Outputs)
   228  	if actual != strings.TrimSpace(basicOutputsStr) {
   229  		t.Fatalf("bad:\n%s", actual)
   230  	}
   231  }
   232  
   233  func TestLoadFile_variables(t *testing.T) {
   234  	c, err := LoadFile(filepath.Join(fixtureDir, "variables.tf"))
   235  	if err != nil {
   236  		t.Fatalf("err: %s", err)
   237  	}
   238  	if c == nil {
   239  		t.Fatal("config should not be nil")
   240  	}
   241  
   242  	if c.Dir != "" {
   243  		t.Fatalf("bad: %#v", c.Dir)
   244  	}
   245  
   246  	actual := variablesStr(c.Variables)
   247  	if actual != strings.TrimSpace(variablesVariablesStr) {
   248  		t.Fatalf("bad:\n%s", actual)
   249  	}
   250  }
   251  
   252  func TestLoadDir_basic(t *testing.T) {
   253  	dir := filepath.Join(fixtureDir, "dir-basic")
   254  	c, err := LoadDir(dir)
   255  	if err != nil {
   256  		t.Fatalf("err: %s", err)
   257  	}
   258  
   259  	if c == nil {
   260  		t.Fatal("config should not be nil")
   261  	}
   262  
   263  	dirAbs, err := filepath.Abs(dir)
   264  	if err != nil {
   265  		t.Fatalf("err: %s", err)
   266  	}
   267  	if c.Dir != dirAbs {
   268  		t.Fatalf("bad: %#v", c.Dir)
   269  	}
   270  
   271  	actual := variablesStr(c.Variables)
   272  	if actual != strings.TrimSpace(dirBasicVariablesStr) {
   273  		t.Fatalf("bad:\n%s", actual)
   274  	}
   275  
   276  	actual = providerConfigsStr(c.ProviderConfigs)
   277  	if actual != strings.TrimSpace(dirBasicProvidersStr) {
   278  		t.Fatalf("bad:\n%s", actual)
   279  	}
   280  
   281  	actual = resourcesStr(c.Resources)
   282  	if actual != strings.TrimSpace(dirBasicResourcesStr) {
   283  		t.Fatalf("bad:\n%s", actual)
   284  	}
   285  
   286  	actual = outputsStr(c.Outputs)
   287  	if actual != strings.TrimSpace(dirBasicOutputsStr) {
   288  		t.Fatalf("bad:\n%s", actual)
   289  	}
   290  }
   291  
   292  func TestLoadDir_file(t *testing.T) {
   293  	_, err := LoadDir(filepath.Join(fixtureDir, "variables.tf"))
   294  	if err == nil {
   295  		t.Fatal("should error")
   296  	}
   297  }
   298  
   299  func TestLoadDir_noConfigs(t *testing.T) {
   300  	_, err := LoadDir(filepath.Join(fixtureDir, "dir-empty"))
   301  	if err == nil {
   302  		t.Fatal("should error")
   303  	}
   304  }
   305  
   306  func TestLoadDir_noMerge(t *testing.T) {
   307  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-merge"))
   308  	if err != nil {
   309  		t.Fatalf("err: %s", err)
   310  	}
   311  
   312  	if c == nil {
   313  		t.Fatal("config should not be nil")
   314  	}
   315  
   316  	if err := c.Validate(); err == nil {
   317  		t.Fatal("should not be valid")
   318  	}
   319  }
   320  
   321  func TestLoadDir_override(t *testing.T) {
   322  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-override"))
   323  	if err != nil {
   324  		t.Fatalf("err: %s", err)
   325  	}
   326  
   327  	if c == nil {
   328  		t.Fatal("config should not be nil")
   329  	}
   330  
   331  	actual := variablesStr(c.Variables)
   332  	if actual != strings.TrimSpace(dirOverrideVariablesStr) {
   333  		t.Fatalf("bad:\n%s", actual)
   334  	}
   335  
   336  	actual = providerConfigsStr(c.ProviderConfigs)
   337  	if actual != strings.TrimSpace(dirOverrideProvidersStr) {
   338  		t.Fatalf("bad:\n%s", actual)
   339  	}
   340  
   341  	actual = resourcesStr(c.Resources)
   342  	if actual != strings.TrimSpace(dirOverrideResourcesStr) {
   343  		t.Fatalf("bad:\n%s", actual)
   344  	}
   345  
   346  	actual = outputsStr(c.Outputs)
   347  	if actual != strings.TrimSpace(dirOverrideOutputsStr) {
   348  		t.Fatalf("bad:\n%s", actual)
   349  	}
   350  }
   351  
   352  func TestLoadFile_provisioners(t *testing.T) {
   353  	c, err := LoadFile(filepath.Join(fixtureDir, "provisioners.tf"))
   354  	if err != nil {
   355  		t.Fatalf("err: %s", err)
   356  	}
   357  
   358  	if c == nil {
   359  		t.Fatal("config should not be nil")
   360  	}
   361  
   362  	actual := resourcesStr(c.Resources)
   363  	if actual != strings.TrimSpace(provisionerResourcesStr) {
   364  		t.Fatalf("bad:\n%s", actual)
   365  	}
   366  }
   367  
   368  func TestLoadFile_connections(t *testing.T) {
   369  	c, err := LoadFile(filepath.Join(fixtureDir, "connection.tf"))
   370  	if err != nil {
   371  		t.Fatalf("err: %s", err)
   372  	}
   373  
   374  	if c == nil {
   375  		t.Fatal("config should not be nil")
   376  	}
   377  
   378  	actual := resourcesStr(c.Resources)
   379  	if actual != strings.TrimSpace(connectionResourcesStr) {
   380  		t.Fatalf("bad:\n%s", actual)
   381  	}
   382  
   383  	// Check for the connection info
   384  	r := c.Resources[0]
   385  	if r.Name != "web" && r.Type != "aws_instance" {
   386  		t.Fatalf("Bad: %#v", r)
   387  	}
   388  
   389  	p1 := r.Provisioners[0]
   390  	if p1.ConnInfo == nil || len(p1.ConnInfo.Raw) != 2 {
   391  		t.Fatalf("Bad: %#v", p1.ConnInfo)
   392  	}
   393  	if p1.ConnInfo.Raw["user"] != "nobody" {
   394  		t.Fatalf("Bad: %#v", p1.ConnInfo)
   395  	}
   396  
   397  	p2 := r.Provisioners[1]
   398  	if p2.ConnInfo == nil || len(p2.ConnInfo.Raw) != 2 {
   399  		t.Fatalf("Bad: %#v", p2.ConnInfo)
   400  	}
   401  	if p2.ConnInfo.Raw["user"] != "root" {
   402  		t.Fatalf("Bad: %#v", p2.ConnInfo)
   403  	}
   404  }
   405  
   406  func TestLoadFile_createBeforeDestroy(t *testing.T) {
   407  	c, err := LoadFile(filepath.Join(fixtureDir, "create-before-destroy.tf"))
   408  	if err != nil {
   409  		t.Fatalf("err: %s", err)
   410  	}
   411  
   412  	if c == nil {
   413  		t.Fatal("config should not be nil")
   414  	}
   415  
   416  	actual := resourcesStr(c.Resources)
   417  	if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) {
   418  		t.Fatalf("bad:\n%s", actual)
   419  	}
   420  
   421  	// Check for the flag value
   422  	r := c.Resources[0]
   423  	if r.Name != "web" && r.Type != "aws_instance" {
   424  		t.Fatalf("Bad: %#v", r)
   425  	}
   426  
   427  	// Should enable create before destroy
   428  	if !r.Lifecycle.CreateBeforeDestroy {
   429  		t.Fatalf("Bad: %#v", r)
   430  	}
   431  
   432  	r = c.Resources[1]
   433  	if r.Name != "bar" && r.Type != "aws_instance" {
   434  		t.Fatalf("Bad: %#v", r)
   435  	}
   436  
   437  	// Should not enable create before destroy
   438  	if r.Lifecycle.CreateBeforeDestroy {
   439  		t.Fatalf("Bad: %#v", r)
   440  	}
   441  }
   442  
   443  func TestLoadFile_ignoreChanges(t *testing.T) {
   444  	c, err := LoadFile(filepath.Join(fixtureDir, "ignore-changes.tf"))
   445  	if err != nil {
   446  		t.Fatalf("err: %s", err)
   447  	}
   448  
   449  	if c == nil {
   450  		t.Fatal("config should not be nil")
   451  	}
   452  
   453  	actual := resourcesStr(c.Resources)
   454  	print(actual)
   455  	if actual != strings.TrimSpace(ignoreChangesResourcesStr) {
   456  		t.Fatalf("bad:\n%s", actual)
   457  	}
   458  
   459  	// Check for the flag value
   460  	r := c.Resources[0]
   461  	if r.Name != "web" && r.Type != "aws_instance" {
   462  		t.Fatalf("Bad: %#v", r)
   463  	}
   464  
   465  	// Should populate ignore changes
   466  	if len(r.Lifecycle.IgnoreChanges) == 0 {
   467  		t.Fatalf("Bad: %#v", r)
   468  	}
   469  
   470  	r = c.Resources[1]
   471  	if r.Name != "bar" && r.Type != "aws_instance" {
   472  		t.Fatalf("Bad: %#v", r)
   473  	}
   474  
   475  	// Should not populate ignore changes
   476  	if len(r.Lifecycle.IgnoreChanges) > 0 {
   477  		t.Fatalf("Bad: %#v", r)
   478  	}
   479  
   480  	r = c.Resources[2]
   481  	if r.Name != "baz" && r.Type != "aws_instance" {
   482  		t.Fatalf("Bad: %#v", r)
   483  	}
   484  
   485  	// Should not populate ignore changes
   486  	if len(r.Lifecycle.IgnoreChanges) > 0 {
   487  		t.Fatalf("Bad: %#v", r)
   488  	}
   489  }
   490  
   491  func TestLoad_preventDestroyString(t *testing.T) {
   492  	c, err := LoadFile(filepath.Join(fixtureDir, "prevent-destroy-string.tf"))
   493  	if err != nil {
   494  		t.Fatalf("err: %s", err)
   495  	}
   496  
   497  	if c == nil {
   498  		t.Fatal("config should not be nil")
   499  	}
   500  
   501  	actual := resourcesStr(c.Resources)
   502  	if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) {
   503  		t.Fatalf("bad:\n%s", actual)
   504  	}
   505  
   506  	// Check for the flag value
   507  	r := c.Resources[0]
   508  	if r.Name != "web" && r.Type != "aws_instance" {
   509  		t.Fatalf("Bad: %#v", r)
   510  	}
   511  
   512  	// Should enable create before destroy
   513  	if !r.Lifecycle.PreventDestroy {
   514  		t.Fatalf("Bad: %#v", r)
   515  	}
   516  
   517  	r = c.Resources[1]
   518  	if r.Name != "bar" && r.Type != "aws_instance" {
   519  		t.Fatalf("Bad: %#v", r)
   520  	}
   521  
   522  	// Should not enable create before destroy
   523  	if r.Lifecycle.PreventDestroy {
   524  		t.Fatalf("Bad: %#v", r)
   525  	}
   526  }
   527  
   528  func TestLoad_temporary_files(t *testing.T) {
   529  	_, err := LoadDir(filepath.Join(fixtureDir, "dir-temporary-files"))
   530  	if err == nil {
   531  		t.Fatalf("Expected to see an error stating no config files found")
   532  	}
   533  }
   534  
   535  const basicOutputsStr = `
   536  web_ip
   537    vars
   538      resource: aws_instance.web.private_ip
   539  `
   540  
   541  const basicProvidersStr = `
   542  aws
   543    access_key
   544    secret_key
   545  do
   546    api_key
   547    vars
   548      user: var.foo
   549  `
   550  
   551  const basicResourcesStr = `
   552  aws_instance[db] (x1)
   553    VPC
   554    security_groups
   555    provisioners
   556      file
   557        destination
   558        source
   559    dependsOn
   560      aws_instance.web
   561    vars
   562      resource: aws_security_group.firewall.*.id
   563  aws_instance[web] (x1)
   564    ami
   565    network_interface
   566    security_groups
   567    provisioners
   568      file
   569        destination
   570        source
   571    vars
   572      resource: aws_security_group.firewall.foo
   573      user: var.foo
   574  aws_security_group[firewall] (x5)
   575  `
   576  
   577  const basicVariablesStr = `
   578  foo
   579    bar
   580    bar
   581  `
   582  
   583  const dirBasicOutputsStr = `
   584  web_ip
   585    vars
   586      resource: aws_instance.web.private_ip
   587  `
   588  
   589  const dirBasicProvidersStr = `
   590  aws
   591    access_key
   592    secret_key
   593  do
   594    api_key
   595    vars
   596      user: var.foo
   597  `
   598  
   599  const dirBasicResourcesStr = `
   600  aws_instance[db] (x1)
   601    security_groups
   602    vars
   603      resource: aws_security_group.firewall.*.id
   604  aws_instance[web] (x1)
   605    ami
   606    network_interface
   607    security_groups
   608    vars
   609      resource: aws_security_group.firewall.foo
   610      user: var.foo
   611  aws_security_group[firewall] (x5)
   612  `
   613  
   614  const dirBasicVariablesStr = `
   615  foo
   616    bar
   617    bar
   618  `
   619  
   620  const dirOverrideOutputsStr = `
   621  web_ip
   622    vars
   623      resource: aws_instance.web.private_ip
   624  `
   625  
   626  const dirOverrideProvidersStr = `
   627  aws
   628    access_key
   629    secret_key
   630  do
   631    api_key
   632    vars
   633      user: var.foo
   634  `
   635  
   636  const dirOverrideResourcesStr = `
   637  aws_instance[db] (x1)
   638    ami
   639    security_groups
   640  aws_instance[web] (x1)
   641    ami
   642    foo
   643    network_interface
   644    security_groups
   645    vars
   646      resource: aws_security_group.firewall.foo
   647      user: var.foo
   648  aws_security_group[firewall] (x5)
   649  `
   650  
   651  const dirOverrideVariablesStr = `
   652  foo
   653    bar
   654    bar
   655  `
   656  
   657  const importProvidersStr = `
   658  aws
   659    bar
   660    foo
   661  `
   662  
   663  const importResourcesStr = `
   664  aws_security_group[db] (x1)
   665  aws_security_group[web] (x1)
   666  `
   667  
   668  const importVariablesStr = `
   669  bar (required)
   670    <>
   671    <>
   672  foo
   673    bar
   674    bar
   675  `
   676  
   677  const modulesModulesStr = `
   678  bar
   679    source = baz
   680    memory
   681  `
   682  
   683  const provisionerResourcesStr = `
   684  aws_instance[web] (x1)
   685    ami
   686    security_groups
   687    provisioners
   688      shell
   689        path
   690    vars
   691      resource: aws_security_group.firewall.foo
   692      user: var.foo
   693  `
   694  
   695  const connectionResourcesStr = `
   696  aws_instance[web] (x1)
   697    ami
   698    security_groups
   699    provisioners
   700      shell
   701        path
   702      shell
   703        path
   704    vars
   705      resource: aws_security_group.firewall.foo
   706      user: var.foo
   707  `
   708  
   709  const variablesVariablesStr = `
   710  bar
   711    <>
   712    <>
   713  baz
   714    foo
   715    <>
   716  foo (required)
   717    <>
   718    <>
   719  `
   720  
   721  const createBeforeDestroyResourcesStr = `
   722  aws_instance[bar] (x1)
   723    ami
   724  aws_instance[web] (x1)
   725    ami
   726  `
   727  
   728  const ignoreChangesResourcesStr = `
   729  aws_instance[bar] (x1)
   730    ami
   731  aws_instance[baz] (x1)
   732    ami
   733  aws_instance[web] (x1)
   734    ami
   735  `