github.com/tomaszheflik/terraform@v0.7.3-0.20160827060421-32f990b41594/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 TestLoadFile_lifecycleKeyCheck(t *testing.T) {
    49  	_, err := LoadFile(filepath.Join(fixtureDir, "lifecycle_cbd_typo.tf"))
    50  	if err == nil {
    51  		t.Fatal("should have error")
    52  	}
    53  
    54  	t.Logf("err: %s", err)
    55  }
    56  
    57  func TestLoadFile_resourceArityMistake(t *testing.T) {
    58  	_, err := LoadFile(filepath.Join(fixtureDir, "resource-arity-mistake.tf"))
    59  	if err == nil {
    60  		t.Fatal("should have error")
    61  	}
    62  	expected := "Error loading test-fixtures/resource-arity-mistake.tf: position 2:10: resource must be followed by exactly two strings, a type and a name"
    63  	if err.Error() != expected {
    64  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, err)
    65  	}
    66  }
    67  
    68  func TestLoadFile_dataSourceArityMistake(t *testing.T) {
    69  	_, err := LoadFile(filepath.Join(fixtureDir, "data-source-arity-mistake.tf"))
    70  	if err == nil {
    71  		t.Fatal("should have error")
    72  	}
    73  	expected := "Error loading test-fixtures/data-source-arity-mistake.tf: position 2:6: 'data' must be followed by exactly two strings: a type and a name"
    74  	if err.Error() != expected {
    75  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, err)
    76  	}
    77  }
    78  
    79  func TestLoadFileWindowsLineEndings(t *testing.T) {
    80  	testFile := filepath.Join(fixtureDir, "windows-line-endings.tf")
    81  
    82  	contents, err := ioutil.ReadFile(testFile)
    83  	if err != nil {
    84  		t.Fatalf("err: %s", err)
    85  	}
    86  	if !strings.Contains(string(contents), "\r\n") {
    87  		t.Fatalf("Windows line endings test file %s contains no windows line endings - this may be an autocrlf related issue.", testFile)
    88  	}
    89  
    90  	c, err := LoadFile(testFile)
    91  	if err != nil {
    92  		t.Fatalf("err: %s", err)
    93  	}
    94  
    95  	if c == nil {
    96  		t.Fatal("config should not be nil")
    97  	}
    98  
    99  	if c.Dir != "" {
   100  		t.Fatalf("bad: %#v", c.Dir)
   101  	}
   102  
   103  	actual := resourcesStr(c.Resources)
   104  	if actual != strings.TrimSpace(windowsHeredocResourcesStr) {
   105  		t.Fatalf("bad:\n%s", actual)
   106  	}
   107  }
   108  
   109  func TestLoadFileHeredoc(t *testing.T) {
   110  	c, err := LoadFile(filepath.Join(fixtureDir, "heredoc.tf"))
   111  	if err != nil {
   112  		t.Fatalf("err: %s", err)
   113  	}
   114  
   115  	if c == nil {
   116  		t.Fatal("config should not be nil")
   117  	}
   118  
   119  	if c.Dir != "" {
   120  		t.Fatalf("bad: %#v", c.Dir)
   121  	}
   122  
   123  	actual := providerConfigsStr(c.ProviderConfigs)
   124  	if actual != strings.TrimSpace(heredocProvidersStr) {
   125  		t.Fatalf("bad:\n%s", actual)
   126  	}
   127  
   128  	actual = resourcesStr(c.Resources)
   129  	if actual != strings.TrimSpace(heredocResourcesStr) {
   130  		t.Fatalf("bad:\n%s", actual)
   131  	}
   132  }
   133  
   134  func TestLoadFileEscapedQuotes(t *testing.T) {
   135  	_, err := LoadFile(filepath.Join(fixtureDir, "escapedquotes.tf"))
   136  	if err == nil {
   137  		t.Fatalf("expected syntax error as escaped quotes are no longer supported")
   138  	}
   139  
   140  	if !strings.Contains(err.Error(), "syntax error") {
   141  		t.Fatalf("expected \"syntax error\", got: %s", err)
   142  	}
   143  }
   144  
   145  func TestLoadFileBasic(t *testing.T) {
   146  	c, err := LoadFile(filepath.Join(fixtureDir, "basic.tf"))
   147  	if err != nil {
   148  		t.Fatalf("err: %s", err)
   149  	}
   150  
   151  	if c == nil {
   152  		t.Fatal("config should not be nil")
   153  	}
   154  
   155  	if c.Dir != "" {
   156  		t.Fatalf("bad: %#v", c.Dir)
   157  	}
   158  
   159  	expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"}
   160  	if !reflect.DeepEqual(c.Atlas, expectedAtlas) {
   161  		t.Fatalf("bad: %#v", c.Atlas)
   162  	}
   163  
   164  	actual := variablesStr(c.Variables)
   165  	if actual != strings.TrimSpace(basicVariablesStr) {
   166  		t.Fatalf("bad:\n%s", actual)
   167  	}
   168  
   169  	actual = providerConfigsStr(c.ProviderConfigs)
   170  	if actual != strings.TrimSpace(basicProvidersStr) {
   171  		t.Fatalf("bad:\n%s", actual)
   172  	}
   173  
   174  	actual = resourcesStr(c.Resources)
   175  	if actual != strings.TrimSpace(basicResourcesStr) {
   176  		t.Fatalf("bad:\n%s", actual)
   177  	}
   178  
   179  	actual = outputsStr(c.Outputs)
   180  	if actual != strings.TrimSpace(basicOutputsStr) {
   181  		t.Fatalf("bad:\n%s", actual)
   182  	}
   183  }
   184  
   185  func TestLoadFileBasic_empty(t *testing.T) {
   186  	c, err := LoadFile(filepath.Join(fixtureDir, "empty.tf"))
   187  	if err != nil {
   188  		t.Fatalf("err: %s", err)
   189  	}
   190  
   191  	if c == nil {
   192  		t.Fatal("config should not be nil")
   193  	}
   194  }
   195  
   196  func TestLoadFileBasic_import(t *testing.T) {
   197  	// Skip because we disabled importing
   198  	t.Skip()
   199  
   200  	c, err := LoadFile(filepath.Join(fixtureDir, "import.tf"))
   201  	if err != nil {
   202  		t.Fatalf("err: %s", err)
   203  	}
   204  
   205  	if c == nil {
   206  		t.Fatal("config should not be nil")
   207  	}
   208  
   209  	actual := variablesStr(c.Variables)
   210  	if actual != strings.TrimSpace(importVariablesStr) {
   211  		t.Fatalf("bad:\n%s", actual)
   212  	}
   213  
   214  	actual = providerConfigsStr(c.ProviderConfigs)
   215  	if actual != strings.TrimSpace(importProvidersStr) {
   216  		t.Fatalf("bad:\n%s", actual)
   217  	}
   218  
   219  	actual = resourcesStr(c.Resources)
   220  	if actual != strings.TrimSpace(importResourcesStr) {
   221  		t.Fatalf("bad:\n%s", actual)
   222  	}
   223  }
   224  
   225  func TestLoadFileBasic_json(t *testing.T) {
   226  	c, err := LoadFile(filepath.Join(fixtureDir, "basic.tf.json"))
   227  	if err != nil {
   228  		t.Fatalf("err: %s", err)
   229  	}
   230  
   231  	if c == nil {
   232  		t.Fatal("config should not be nil")
   233  	}
   234  
   235  	if c.Dir != "" {
   236  		t.Fatalf("bad: %#v", c.Dir)
   237  	}
   238  
   239  	expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"}
   240  	if !reflect.DeepEqual(c.Atlas, expectedAtlas) {
   241  		t.Fatalf("bad: %#v", c.Atlas)
   242  	}
   243  
   244  	actual := variablesStr(c.Variables)
   245  	if actual != strings.TrimSpace(basicVariablesStr) {
   246  		t.Fatalf("bad:\n%s", actual)
   247  	}
   248  
   249  	actual = providerConfigsStr(c.ProviderConfigs)
   250  	if actual != strings.TrimSpace(basicProvidersStr) {
   251  		t.Fatalf("bad:\n%s", actual)
   252  	}
   253  
   254  	actual = resourcesStr(c.Resources)
   255  	if actual != strings.TrimSpace(basicResourcesStr) {
   256  		t.Fatalf("bad:\n%s", actual)
   257  	}
   258  
   259  	actual = outputsStr(c.Outputs)
   260  	if actual != strings.TrimSpace(basicOutputsStr) {
   261  		t.Fatalf("bad:\n%s", actual)
   262  	}
   263  }
   264  
   265  func TestLoadFileBasic_modules(t *testing.T) {
   266  	c, err := LoadFile(filepath.Join(fixtureDir, "modules.tf"))
   267  	if err != nil {
   268  		t.Fatalf("err: %s", err)
   269  	}
   270  
   271  	if c == nil {
   272  		t.Fatal("config should not be nil")
   273  	}
   274  
   275  	if c.Dir != "" {
   276  		t.Fatalf("bad: %#v", c.Dir)
   277  	}
   278  
   279  	actual := modulesStr(c.Modules)
   280  	if actual != strings.TrimSpace(modulesModulesStr) {
   281  		t.Fatalf("bad:\n%s", actual)
   282  	}
   283  }
   284  
   285  func TestLoadJSONBasic(t *testing.T) {
   286  	raw, err := ioutil.ReadFile(filepath.Join(fixtureDir, "basic.tf.json"))
   287  	if err != nil {
   288  		t.Fatalf("err: %s", err)
   289  	}
   290  
   291  	c, err := LoadJSON(raw)
   292  	if err != nil {
   293  		t.Fatalf("err: %s", err)
   294  	}
   295  
   296  	if c == nil {
   297  		t.Fatal("config should not be nil")
   298  	}
   299  
   300  	if c.Dir != "" {
   301  		t.Fatalf("bad: %#v", c.Dir)
   302  	}
   303  
   304  	expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"}
   305  	if !reflect.DeepEqual(c.Atlas, expectedAtlas) {
   306  		t.Fatalf("bad: %#v", c.Atlas)
   307  	}
   308  
   309  	actual := variablesStr(c.Variables)
   310  	if actual != strings.TrimSpace(basicVariablesStr) {
   311  		t.Fatalf("bad:\n%s", actual)
   312  	}
   313  
   314  	actual = providerConfigsStr(c.ProviderConfigs)
   315  	if actual != strings.TrimSpace(basicProvidersStr) {
   316  		t.Fatalf("bad:\n%s", actual)
   317  	}
   318  
   319  	actual = resourcesStr(c.Resources)
   320  	if actual != strings.TrimSpace(basicResourcesStr) {
   321  		t.Fatalf("bad:\n%s", actual)
   322  	}
   323  
   324  	actual = outputsStr(c.Outputs)
   325  	if actual != strings.TrimSpace(basicOutputsStr) {
   326  		t.Fatalf("bad:\n%s", actual)
   327  	}
   328  }
   329  
   330  func TestLoadFileBasic_jsonNoName(t *testing.T) {
   331  	c, err := LoadFile(filepath.Join(fixtureDir, "resource-no-name.tf.json"))
   332  	if err != nil {
   333  		t.Fatalf("err: %s", err)
   334  	}
   335  
   336  	if c == nil {
   337  		t.Fatal("config should not be nil")
   338  	}
   339  
   340  	actual := resourcesStr(c.Resources)
   341  	if actual != strings.TrimSpace(basicJsonNoNameResourcesStr) {
   342  		t.Fatalf("bad:\n%s", actual)
   343  	}
   344  }
   345  
   346  func TestLoadFile_variables(t *testing.T) {
   347  	c, err := LoadFile(filepath.Join(fixtureDir, "variables.tf"))
   348  	if err != nil {
   349  		t.Fatalf("err: %s", err)
   350  	}
   351  	if c == nil {
   352  		t.Fatal("config should not be nil")
   353  	}
   354  
   355  	if c.Dir != "" {
   356  		t.Fatalf("bad: %#v", c.Dir)
   357  	}
   358  
   359  	actual := variablesStr(c.Variables)
   360  	if actual != strings.TrimSpace(variablesVariablesStr) {
   361  		t.Fatalf("bad:\n%s", actual)
   362  	}
   363  }
   364  
   365  func TestLoadDir_basic(t *testing.T) {
   366  	dir := filepath.Join(fixtureDir, "dir-basic")
   367  	c, err := LoadDir(dir)
   368  	if err != nil {
   369  		t.Fatalf("err: %s", err)
   370  	}
   371  
   372  	if c == nil {
   373  		t.Fatal("config should not be nil")
   374  	}
   375  
   376  	dirAbs, err := filepath.Abs(dir)
   377  	if err != nil {
   378  		t.Fatalf("err: %s", err)
   379  	}
   380  	if c.Dir != dirAbs {
   381  		t.Fatalf("bad: %#v", c.Dir)
   382  	}
   383  
   384  	actual := variablesStr(c.Variables)
   385  	if actual != strings.TrimSpace(dirBasicVariablesStr) {
   386  		t.Fatalf("bad:\n%s", actual)
   387  	}
   388  
   389  	actual = providerConfigsStr(c.ProviderConfigs)
   390  	if actual != strings.TrimSpace(dirBasicProvidersStr) {
   391  		t.Fatalf("bad:\n%s", actual)
   392  	}
   393  
   394  	actual = resourcesStr(c.Resources)
   395  	if actual != strings.TrimSpace(dirBasicResourcesStr) {
   396  		t.Fatalf("bad:\n%s", actual)
   397  	}
   398  
   399  	actual = outputsStr(c.Outputs)
   400  	if actual != strings.TrimSpace(dirBasicOutputsStr) {
   401  		t.Fatalf("bad:\n%s", actual)
   402  	}
   403  }
   404  
   405  func TestLoadDir_file(t *testing.T) {
   406  	_, err := LoadDir(filepath.Join(fixtureDir, "variables.tf"))
   407  	if err == nil {
   408  		t.Fatal("should error")
   409  	}
   410  }
   411  
   412  func TestLoadDir_noConfigs(t *testing.T) {
   413  	_, err := LoadDir(filepath.Join(fixtureDir, "dir-empty"))
   414  	if err == nil {
   415  		t.Fatal("should error")
   416  	}
   417  }
   418  
   419  func TestLoadDir_noMerge(t *testing.T) {
   420  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-merge"))
   421  	if err != nil {
   422  		t.Fatalf("err: %s", err)
   423  	}
   424  
   425  	if c == nil {
   426  		t.Fatal("config should not be nil")
   427  	}
   428  
   429  	if err := c.Validate(); err == nil {
   430  		t.Fatal("should not be valid")
   431  	}
   432  }
   433  
   434  func TestLoadDir_override(t *testing.T) {
   435  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-override"))
   436  	if err != nil {
   437  		t.Fatalf("err: %s", err)
   438  	}
   439  
   440  	if c == nil {
   441  		t.Fatal("config should not be nil")
   442  	}
   443  
   444  	actual := variablesStr(c.Variables)
   445  	if actual != strings.TrimSpace(dirOverrideVariablesStr) {
   446  		t.Fatalf("bad:\n%s", actual)
   447  	}
   448  
   449  	actual = providerConfigsStr(c.ProviderConfigs)
   450  	if actual != strings.TrimSpace(dirOverrideProvidersStr) {
   451  		t.Fatalf("bad:\n%s", actual)
   452  	}
   453  
   454  	actual = resourcesStr(c.Resources)
   455  	if actual != strings.TrimSpace(dirOverrideResourcesStr) {
   456  		t.Fatalf("bad:\n%s", actual)
   457  	}
   458  
   459  	actual = outputsStr(c.Outputs)
   460  	if actual != strings.TrimSpace(dirOverrideOutputsStr) {
   461  		t.Fatalf("bad:\n%s", actual)
   462  	}
   463  }
   464  
   465  func TestLoadDir_overrideVar(t *testing.T) {
   466  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-override-var"))
   467  	if err != nil {
   468  		t.Fatalf("err: %s", err)
   469  	}
   470  
   471  	if c == nil {
   472  		t.Fatal("config should not be nil")
   473  	}
   474  
   475  	actual := variablesStr(c.Variables)
   476  	if actual != strings.TrimSpace(dirOverrideVarsVariablesStr) {
   477  		t.Fatalf("bad:\n%s", actual)
   478  	}
   479  }
   480  
   481  func TestLoadFile_mismatchedVariableTypes(t *testing.T) {
   482  	_, err := LoadFile(filepath.Join(fixtureDir, "variable-mismatched-type.tf"))
   483  	if err == nil {
   484  		t.Fatalf("bad: expected error")
   485  	}
   486  
   487  	errorStr := err.Error()
   488  	if !strings.Contains(errorStr, "'not_a_map' has a default value which is not of type 'string'") {
   489  		t.Fatalf("bad: expected error has wrong text: %s", errorStr)
   490  	}
   491  }
   492  
   493  func TestLoadFile_badVariableTypes(t *testing.T) {
   494  	_, err := LoadFile(filepath.Join(fixtureDir, "bad-variable-type.tf"))
   495  	if err == nil {
   496  		t.Fatalf("bad: expected error")
   497  	}
   498  
   499  	errorStr := err.Error()
   500  	if !strings.Contains(errorStr, "'bad_type' must be of type string") {
   501  		t.Fatalf("bad: expected error has wrong text: %s", errorStr)
   502  	}
   503  }
   504  
   505  func TestLoadFile_provisioners(t *testing.T) {
   506  	c, err := LoadFile(filepath.Join(fixtureDir, "provisioners.tf"))
   507  	if err != nil {
   508  		t.Fatalf("err: %s", err)
   509  	}
   510  
   511  	if c == nil {
   512  		t.Fatal("config should not be nil")
   513  	}
   514  
   515  	actual := resourcesStr(c.Resources)
   516  	if actual != strings.TrimSpace(provisionerResourcesStr) {
   517  		t.Fatalf("bad:\n%s", actual)
   518  	}
   519  }
   520  
   521  func TestLoadFile_connections(t *testing.T) {
   522  	c, err := LoadFile(filepath.Join(fixtureDir, "connection.tf"))
   523  	if err != nil {
   524  		t.Fatalf("err: %s", err)
   525  	}
   526  
   527  	if c == nil {
   528  		t.Fatal("config should not be nil")
   529  	}
   530  
   531  	actual := resourcesStr(c.Resources)
   532  	if actual != strings.TrimSpace(connectionResourcesStr) {
   533  		t.Fatalf("bad:\n%s", actual)
   534  	}
   535  
   536  	// Check for the connection info
   537  	r := c.Resources[0]
   538  	if r.Name != "web" && r.Type != "aws_instance" {
   539  		t.Fatalf("Bad: %#v", r)
   540  	}
   541  
   542  	p1 := r.Provisioners[0]
   543  	if p1.ConnInfo == nil || len(p1.ConnInfo.Raw) != 2 {
   544  		t.Fatalf("Bad: %#v", p1.ConnInfo)
   545  	}
   546  	if p1.ConnInfo.Raw["user"] != "nobody" {
   547  		t.Fatalf("Bad: %#v", p1.ConnInfo)
   548  	}
   549  
   550  	p2 := r.Provisioners[1]
   551  	if p2.ConnInfo == nil || len(p2.ConnInfo.Raw) != 2 {
   552  		t.Fatalf("Bad: %#v", p2.ConnInfo)
   553  	}
   554  	if p2.ConnInfo.Raw["user"] != "root" {
   555  		t.Fatalf("Bad: %#v", p2.ConnInfo)
   556  	}
   557  }
   558  
   559  func TestLoadFile_createBeforeDestroy(t *testing.T) {
   560  	c, err := LoadFile(filepath.Join(fixtureDir, "create-before-destroy.tf"))
   561  	if err != nil {
   562  		t.Fatalf("err: %s", err)
   563  	}
   564  
   565  	if c == nil {
   566  		t.Fatal("config should not be nil")
   567  	}
   568  
   569  	actual := resourcesStr(c.Resources)
   570  	if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) {
   571  		t.Fatalf("bad:\n%s", actual)
   572  	}
   573  
   574  	// Check for the flag value
   575  	r := c.Resources[0]
   576  	if r.Name != "web" && r.Type != "aws_instance" {
   577  		t.Fatalf("Bad: %#v", r)
   578  	}
   579  
   580  	// Should enable create before destroy
   581  	if !r.Lifecycle.CreateBeforeDestroy {
   582  		t.Fatalf("Bad: %#v", r)
   583  	}
   584  
   585  	r = c.Resources[1]
   586  	if r.Name != "bar" && r.Type != "aws_instance" {
   587  		t.Fatalf("Bad: %#v", r)
   588  	}
   589  
   590  	// Should not enable create before destroy
   591  	if r.Lifecycle.CreateBeforeDestroy {
   592  		t.Fatalf("Bad: %#v", r)
   593  	}
   594  }
   595  
   596  func TestLoadFile_ignoreChanges(t *testing.T) {
   597  	c, err := LoadFile(filepath.Join(fixtureDir, "ignore-changes.tf"))
   598  	if err != nil {
   599  		t.Fatalf("err: %s", err)
   600  	}
   601  
   602  	if c == nil {
   603  		t.Fatal("config should not be nil")
   604  	}
   605  
   606  	actual := resourcesStr(c.Resources)
   607  	print(actual)
   608  	if actual != strings.TrimSpace(ignoreChangesResourcesStr) {
   609  		t.Fatalf("bad:\n%s", actual)
   610  	}
   611  
   612  	// Check for the flag value
   613  	r := c.Resources[0]
   614  	if r.Name != "web" && r.Type != "aws_instance" {
   615  		t.Fatalf("Bad: %#v", r)
   616  	}
   617  
   618  	// Should populate ignore changes
   619  	if len(r.Lifecycle.IgnoreChanges) == 0 {
   620  		t.Fatalf("Bad: %#v", r)
   621  	}
   622  
   623  	r = c.Resources[1]
   624  	if r.Name != "bar" && r.Type != "aws_instance" {
   625  		t.Fatalf("Bad: %#v", r)
   626  	}
   627  
   628  	// Should not populate ignore changes
   629  	if len(r.Lifecycle.IgnoreChanges) > 0 {
   630  		t.Fatalf("Bad: %#v", r)
   631  	}
   632  
   633  	r = c.Resources[2]
   634  	if r.Name != "baz" && r.Type != "aws_instance" {
   635  		t.Fatalf("Bad: %#v", r)
   636  	}
   637  
   638  	// Should not populate ignore changes
   639  	if len(r.Lifecycle.IgnoreChanges) > 0 {
   640  		t.Fatalf("Bad: %#v", r)
   641  	}
   642  }
   643  
   644  func TestLoad_preventDestroyString(t *testing.T) {
   645  	c, err := LoadFile(filepath.Join(fixtureDir, "prevent-destroy-string.tf"))
   646  	if err != nil {
   647  		t.Fatalf("err: %s", err)
   648  	}
   649  
   650  	if c == nil {
   651  		t.Fatal("config should not be nil")
   652  	}
   653  
   654  	actual := resourcesStr(c.Resources)
   655  	if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) {
   656  		t.Fatalf("bad:\n%s", actual)
   657  	}
   658  
   659  	// Check for the flag value
   660  	r := c.Resources[0]
   661  	if r.Name != "web" && r.Type != "aws_instance" {
   662  		t.Fatalf("Bad: %#v", r)
   663  	}
   664  
   665  	// Should enable create before destroy
   666  	if !r.Lifecycle.PreventDestroy {
   667  		t.Fatalf("Bad: %#v", r)
   668  	}
   669  
   670  	r = c.Resources[1]
   671  	if r.Name != "bar" && r.Type != "aws_instance" {
   672  		t.Fatalf("Bad: %#v", r)
   673  	}
   674  
   675  	// Should not enable create before destroy
   676  	if r.Lifecycle.PreventDestroy {
   677  		t.Fatalf("Bad: %#v", r)
   678  	}
   679  }
   680  
   681  func TestLoad_temporary_files(t *testing.T) {
   682  	_, err := LoadDir(filepath.Join(fixtureDir, "dir-temporary-files"))
   683  	if err == nil {
   684  		t.Fatalf("Expected to see an error stating no config files found")
   685  	}
   686  }
   687  
   688  func TestLoad_hclAttributes(t *testing.T) {
   689  	c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf"))
   690  	if err != nil {
   691  		t.Fatalf("Bad: %s", err)
   692  	}
   693  
   694  	if c == nil {
   695  		t.Fatal("config should not be nil")
   696  	}
   697  
   698  	actual := resourcesStr(c.Resources)
   699  	print(actual)
   700  	if actual != strings.TrimSpace(jsonAttributeStr) {
   701  		t.Fatalf("bad:\n%s", actual)
   702  	}
   703  
   704  	r := c.Resources[0]
   705  	if r.Name != "test" && r.Type != "cloudstack_firewall" {
   706  		t.Fatalf("Bad: %#v", r)
   707  	}
   708  
   709  	raw := r.RawConfig
   710  	if raw.Raw["ipaddress"] != "192.168.0.1" {
   711  		t.Fatalf("Bad: %s", raw.Raw["ipAddress"])
   712  	}
   713  
   714  	rule := raw.Raw["rule"].([]map[string]interface{})[0]
   715  	if rule["protocol"] != "tcp" {
   716  		t.Fatalf("Bad: %s", rule["protocol"])
   717  	}
   718  
   719  	if rule["source_cidr"] != "10.0.0.0/8" {
   720  		t.Fatalf("Bad: %s", rule["source_cidr"])
   721  	}
   722  
   723  	ports := rule["ports"].([]interface{})
   724  
   725  	if ports[0] != "80" {
   726  		t.Fatalf("Bad ports: %s", ports[0])
   727  	}
   728  	if ports[1] != "1000-2000" {
   729  		t.Fatalf("Bad ports: %s", ports[1])
   730  	}
   731  }
   732  
   733  func TestLoad_jsonAttributes(t *testing.T) {
   734  	c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf.json"))
   735  	if err != nil {
   736  		t.Fatalf("Bad: %s", err)
   737  	}
   738  
   739  	if c == nil {
   740  		t.Fatal("config should not be nil")
   741  	}
   742  
   743  	actual := resourcesStr(c.Resources)
   744  	print(actual)
   745  	if actual != strings.TrimSpace(jsonAttributeStr) {
   746  		t.Fatalf("bad:\n%s", actual)
   747  	}
   748  
   749  	r := c.Resources[0]
   750  	if r.Name != "test" && r.Type != "cloudstack_firewall" {
   751  		t.Fatalf("Bad: %#v", r)
   752  	}
   753  
   754  	raw := r.RawConfig
   755  	if raw.Raw["ipaddress"] != "192.168.0.1" {
   756  		t.Fatalf("Bad: %s", raw.Raw["ipAddress"])
   757  	}
   758  
   759  	rule := raw.Raw["rule"].([]map[string]interface{})[0]
   760  	if rule["protocol"] != "tcp" {
   761  		t.Fatalf("Bad: %s", rule["protocol"])
   762  	}
   763  
   764  	if rule["source_cidr"] != "10.0.0.0/8" {
   765  		t.Fatalf("Bad: %s", rule["source_cidr"])
   766  	}
   767  
   768  	ports := rule["ports"].([]interface{})
   769  
   770  	if ports[0] != "80" {
   771  		t.Fatalf("Bad ports: %s", ports[0])
   772  	}
   773  	if ports[1] != "1000-2000" {
   774  		t.Fatalf("Bad ports: %s", ports[1])
   775  	}
   776  }
   777  
   778  const jsonAttributeStr = `
   779  cloudstack_firewall.test (x1)
   780    ipaddress
   781    rule
   782  `
   783  
   784  const windowsHeredocResourcesStr = `
   785  aws_instance.test (x1)
   786    user_data
   787  `
   788  
   789  const heredocProvidersStr = `
   790  aws
   791    access_key
   792    secret_key
   793  `
   794  
   795  const heredocResourcesStr = `
   796  aws_iam_policy.policy (x1)
   797    description
   798    name
   799    path
   800    policy
   801  aws_instance.heredocwithnumbers (x1)
   802    ami
   803    provisioners
   804      local-exec
   805        command
   806  aws_instance.test (x1)
   807    ami
   808    provisioners
   809      remote-exec
   810        inline
   811  `
   812  
   813  const basicOutputsStr = `
   814  web_ip
   815    vars
   816      resource: aws_instance.web.private_ip
   817  `
   818  
   819  const basicProvidersStr = `
   820  aws
   821    access_key
   822    secret_key
   823  do
   824    api_key
   825    vars
   826      user: var.foo
   827  `
   828  
   829  const basicResourcesStr = `
   830  aws_instance.db (x1)
   831    VPC
   832    security_groups
   833    provisioners
   834      file
   835        destination
   836        source
   837    dependsOn
   838      aws_instance.web
   839    vars
   840      resource: aws_security_group.firewall.*.id
   841  aws_instance.web (x1)
   842    ami
   843    network_interface
   844    security_groups
   845    provisioners
   846      file
   847        destination
   848        source
   849    vars
   850      resource: aws_security_group.firewall.foo
   851      user: var.foo
   852  aws_security_group.firewall (x5)
   853  data.do.depends (x1)
   854    dependsOn
   855      data.do.simple
   856  data.do.simple (x1)
   857    foo
   858  `
   859  
   860  const basicVariablesStr = `
   861  bar (required) (string)
   862    <>
   863    <>
   864  baz (map)
   865    map[key:value]
   866    <>
   867  foo
   868    bar
   869    bar
   870  `
   871  
   872  const basicJsonNoNameResourcesStr = `
   873  aws_security_group.allow_external_http_https (x1)
   874    tags
   875  `
   876  
   877  const dirBasicOutputsStr = `
   878  web_ip
   879    vars
   880      resource: aws_instance.web.private_ip
   881  `
   882  
   883  const dirBasicProvidersStr = `
   884  aws
   885    access_key
   886    secret_key
   887  do
   888    api_key
   889    vars
   890      user: var.foo
   891  `
   892  
   893  const dirBasicResourcesStr = `
   894  aws_instance.db (x1)
   895    security_groups
   896    vars
   897      resource: aws_security_group.firewall.*.id
   898  aws_instance.web (x1)
   899    ami
   900    network_interface
   901    security_groups
   902    vars
   903      resource: aws_security_group.firewall.foo
   904      user: var.foo
   905  aws_security_group.firewall (x5)
   906  data.do.depends (x1)
   907    dependsOn
   908      data.do.simple
   909  data.do.simple (x1)
   910    foo
   911  `
   912  
   913  const dirBasicVariablesStr = `
   914  foo
   915    bar
   916    bar
   917  `
   918  
   919  const dirOverrideOutputsStr = `
   920  web_ip
   921    vars
   922      resource: aws_instance.web.private_ip
   923  `
   924  
   925  const dirOverrideProvidersStr = `
   926  aws
   927    access_key
   928    secret_key
   929  do
   930    api_key
   931    vars
   932      user: var.foo
   933  `
   934  
   935  const dirOverrideResourcesStr = `
   936  aws_instance.db (x1)
   937    ami
   938    security_groups
   939  aws_instance.web (x1)
   940    ami
   941    foo
   942    network_interface
   943    security_groups
   944    vars
   945      resource: aws_security_group.firewall.foo
   946      user: var.foo
   947  aws_security_group.firewall (x5)
   948  data.do.depends (x1)
   949    hello
   950    dependsOn
   951      data.do.simple
   952  data.do.simple (x1)
   953    foo
   954  `
   955  
   956  const dirOverrideVariablesStr = `
   957  foo
   958    bar
   959    bar
   960  `
   961  
   962  const dirOverrideVarsVariablesStr = `
   963  foo
   964    baz
   965    bar
   966  `
   967  
   968  const importProvidersStr = `
   969  aws
   970    bar
   971    foo
   972  `
   973  
   974  const importResourcesStr = `
   975  aws_security_group.db (x1)
   976  aws_security_group.web (x1)
   977  `
   978  
   979  const importVariablesStr = `
   980  bar (required)
   981    <>
   982    <>
   983  foo
   984    bar
   985    bar
   986  `
   987  
   988  const modulesModulesStr = `
   989  bar
   990    source = baz
   991    memory
   992  `
   993  
   994  const provisionerResourcesStr = `
   995  aws_instance.web (x1)
   996    ami
   997    security_groups
   998    provisioners
   999      shell
  1000        path
  1001    vars
  1002      resource: aws_security_group.firewall.foo
  1003      user: var.foo
  1004  `
  1005  
  1006  const connectionResourcesStr = `
  1007  aws_instance.web (x1)
  1008    ami
  1009    security_groups
  1010    provisioners
  1011      shell
  1012        path
  1013      shell
  1014        path
  1015    vars
  1016      resource: aws_security_group.firewall.foo
  1017      user: var.foo
  1018  `
  1019  
  1020  const variablesVariablesStr = `
  1021  bar
  1022    <>
  1023    <>
  1024  baz
  1025    foo
  1026    <>
  1027  foo (required)
  1028    <>
  1029    <>
  1030  `
  1031  
  1032  const createBeforeDestroyResourcesStr = `
  1033  aws_instance.bar (x1)
  1034    ami
  1035  aws_instance.web (x1)
  1036    ami
  1037  `
  1038  
  1039  const ignoreChangesResourcesStr = `
  1040  aws_instance.bar (x1)
  1041    ami
  1042  aws_instance.baz (x1)
  1043    ami
  1044  aws_instance.web (x1)
  1045    ami
  1046  `