github.com/mapuri/terraform@v0.7.6-0.20161012203214-7e0408293f97/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 TestLoadJSONAmbiguous(t *testing.T) {
   331  	js := `
   332  {
   333    "variable": {
   334      "first": {
   335        "default": {
   336          "key": "val"
   337        }
   338      },
   339      "second": {
   340        "description": "Described",
   341        "default": {
   342          "key": "val"
   343        }
   344      }
   345    }
   346  }
   347  `
   348  
   349  	c, err := LoadJSON([]byte(js))
   350  	if err != nil {
   351  		t.Fatalf("err: %s", err)
   352  	}
   353  
   354  	if len(c.Variables) != 2 {
   355  		t.Fatal("config should have 2 variables, found", len(c.Variables))
   356  	}
   357  
   358  	first := &Variable{
   359  		Name:    "first",
   360  		Default: map[string]interface{}{"key": "val"},
   361  	}
   362  	second := &Variable{
   363  		Name:        "second",
   364  		Description: "Described",
   365  		Default:     map[string]interface{}{"key": "val"},
   366  	}
   367  
   368  	if !reflect.DeepEqual(first, c.Variables[0]) {
   369  		t.Fatalf("\nexpected: %#v\ngot:      %#v", first, c.Variables[0])
   370  	}
   371  
   372  	if !reflect.DeepEqual(second, c.Variables[1]) {
   373  		t.Fatalf("\nexpected: %#v\ngot:      %#v", second, c.Variables[1])
   374  	}
   375  }
   376  
   377  func TestLoadFileBasic_jsonNoName(t *testing.T) {
   378  	c, err := LoadFile(filepath.Join(fixtureDir, "resource-no-name.tf.json"))
   379  	if err != nil {
   380  		t.Fatalf("err: %s", err)
   381  	}
   382  
   383  	if c == nil {
   384  		t.Fatal("config should not be nil")
   385  	}
   386  
   387  	actual := resourcesStr(c.Resources)
   388  	if actual != strings.TrimSpace(basicJsonNoNameResourcesStr) {
   389  		t.Fatalf("bad:\n%s", actual)
   390  	}
   391  }
   392  
   393  func TestLoadFile_variables(t *testing.T) {
   394  	c, err := LoadFile(filepath.Join(fixtureDir, "variables.tf"))
   395  	if err != nil {
   396  		t.Fatalf("err: %s", err)
   397  	}
   398  	if c == nil {
   399  		t.Fatal("config should not be nil")
   400  	}
   401  
   402  	if c.Dir != "" {
   403  		t.Fatalf("bad: %#v", c.Dir)
   404  	}
   405  
   406  	actual := variablesStr(c.Variables)
   407  	if actual != strings.TrimSpace(variablesVariablesStr) {
   408  		t.Fatalf("bad:\n%s", actual)
   409  	}
   410  }
   411  
   412  func TestLoadDir_basic(t *testing.T) {
   413  	dir := filepath.Join(fixtureDir, "dir-basic")
   414  	c, err := LoadDir(dir)
   415  	if err != nil {
   416  		t.Fatalf("err: %s", err)
   417  	}
   418  
   419  	if c == nil {
   420  		t.Fatal("config should not be nil")
   421  	}
   422  
   423  	dirAbs, err := filepath.Abs(dir)
   424  	if err != nil {
   425  		t.Fatalf("err: %s", err)
   426  	}
   427  	if c.Dir != dirAbs {
   428  		t.Fatalf("bad: %#v", c.Dir)
   429  	}
   430  
   431  	actual := variablesStr(c.Variables)
   432  	if actual != strings.TrimSpace(dirBasicVariablesStr) {
   433  		t.Fatalf("bad:\n%s", actual)
   434  	}
   435  
   436  	actual = providerConfigsStr(c.ProviderConfigs)
   437  	if actual != strings.TrimSpace(dirBasicProvidersStr) {
   438  		t.Fatalf("bad:\n%s", actual)
   439  	}
   440  
   441  	actual = resourcesStr(c.Resources)
   442  	if actual != strings.TrimSpace(dirBasicResourcesStr) {
   443  		t.Fatalf("bad:\n%s", actual)
   444  	}
   445  
   446  	actual = outputsStr(c.Outputs)
   447  	if actual != strings.TrimSpace(dirBasicOutputsStr) {
   448  		t.Fatalf("bad:\n%s", actual)
   449  	}
   450  }
   451  
   452  func TestLoadDir_file(t *testing.T) {
   453  	_, err := LoadDir(filepath.Join(fixtureDir, "variables.tf"))
   454  	if err == nil {
   455  		t.Fatal("should error")
   456  	}
   457  }
   458  
   459  func TestLoadDir_noConfigs(t *testing.T) {
   460  	_, err := LoadDir(filepath.Join(fixtureDir, "dir-empty"))
   461  	if err == nil {
   462  		t.Fatal("should error")
   463  	}
   464  }
   465  
   466  func TestLoadDir_noMerge(t *testing.T) {
   467  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-merge"))
   468  	if err != nil {
   469  		t.Fatalf("err: %s", err)
   470  	}
   471  
   472  	if c == nil {
   473  		t.Fatal("config should not be nil")
   474  	}
   475  
   476  	if err := c.Validate(); err == nil {
   477  		t.Fatal("should not be valid")
   478  	}
   479  }
   480  
   481  func TestLoadDir_override(t *testing.T) {
   482  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-override"))
   483  	if err != nil {
   484  		t.Fatalf("err: %s", err)
   485  	}
   486  
   487  	if c == nil {
   488  		t.Fatal("config should not be nil")
   489  	}
   490  
   491  	actual := variablesStr(c.Variables)
   492  	if actual != strings.TrimSpace(dirOverrideVariablesStr) {
   493  		t.Fatalf("bad:\n%s", actual)
   494  	}
   495  
   496  	actual = providerConfigsStr(c.ProviderConfigs)
   497  	if actual != strings.TrimSpace(dirOverrideProvidersStr) {
   498  		t.Fatalf("bad:\n%s", actual)
   499  	}
   500  
   501  	actual = resourcesStr(c.Resources)
   502  	if actual != strings.TrimSpace(dirOverrideResourcesStr) {
   503  		t.Fatalf("bad:\n%s", actual)
   504  	}
   505  
   506  	actual = outputsStr(c.Outputs)
   507  	if actual != strings.TrimSpace(dirOverrideOutputsStr) {
   508  		t.Fatalf("bad:\n%s", actual)
   509  	}
   510  }
   511  
   512  func TestLoadDir_overrideVar(t *testing.T) {
   513  	c, err := LoadDir(filepath.Join(fixtureDir, "dir-override-var"))
   514  	if err != nil {
   515  		t.Fatalf("err: %s", err)
   516  	}
   517  
   518  	if c == nil {
   519  		t.Fatal("config should not be nil")
   520  	}
   521  
   522  	actual := variablesStr(c.Variables)
   523  	if actual != strings.TrimSpace(dirOverrideVarsVariablesStr) {
   524  		t.Fatalf("bad:\n%s", actual)
   525  	}
   526  }
   527  
   528  func TestLoadFile_mismatchedVariableTypes(t *testing.T) {
   529  	_, err := LoadFile(filepath.Join(fixtureDir, "variable-mismatched-type.tf"))
   530  	if err == nil {
   531  		t.Fatalf("bad: expected error")
   532  	}
   533  
   534  	errorStr := err.Error()
   535  	if !strings.Contains(errorStr, "'not_a_map' has a default value which is not of type 'string'") {
   536  		t.Fatalf("bad: expected error has wrong text: %s", errorStr)
   537  	}
   538  }
   539  
   540  func TestLoadFile_badVariableTypes(t *testing.T) {
   541  	_, err := LoadFile(filepath.Join(fixtureDir, "bad-variable-type.tf"))
   542  	if err == nil {
   543  		t.Fatalf("bad: expected error")
   544  	}
   545  
   546  	errorStr := err.Error()
   547  	if !strings.Contains(errorStr, "'bad_type' must be of type string") {
   548  		t.Fatalf("bad: expected error has wrong text: %s", errorStr)
   549  	}
   550  }
   551  
   552  func TestLoadFile_provisioners(t *testing.T) {
   553  	c, err := LoadFile(filepath.Join(fixtureDir, "provisioners.tf"))
   554  	if err != nil {
   555  		t.Fatalf("err: %s", err)
   556  	}
   557  
   558  	if c == nil {
   559  		t.Fatal("config should not be nil")
   560  	}
   561  
   562  	actual := resourcesStr(c.Resources)
   563  	if actual != strings.TrimSpace(provisionerResourcesStr) {
   564  		t.Fatalf("bad:\n%s", actual)
   565  	}
   566  }
   567  
   568  func TestLoadFile_connections(t *testing.T) {
   569  	c, err := LoadFile(filepath.Join(fixtureDir, "connection.tf"))
   570  	if err != nil {
   571  		t.Fatalf("err: %s", err)
   572  	}
   573  
   574  	if c == nil {
   575  		t.Fatal("config should not be nil")
   576  	}
   577  
   578  	actual := resourcesStr(c.Resources)
   579  	if actual != strings.TrimSpace(connectionResourcesStr) {
   580  		t.Fatalf("bad:\n%s", actual)
   581  	}
   582  
   583  	// Check for the connection info
   584  	r := c.Resources[0]
   585  	if r.Name != "web" && r.Type != "aws_instance" {
   586  		t.Fatalf("Bad: %#v", r)
   587  	}
   588  
   589  	p1 := r.Provisioners[0]
   590  	if p1.ConnInfo == nil || len(p1.ConnInfo.Raw) != 2 {
   591  		t.Fatalf("Bad: %#v", p1.ConnInfo)
   592  	}
   593  	if p1.ConnInfo.Raw["user"] != "nobody" {
   594  		t.Fatalf("Bad: %#v", p1.ConnInfo)
   595  	}
   596  
   597  	p2 := r.Provisioners[1]
   598  	if p2.ConnInfo == nil || len(p2.ConnInfo.Raw) != 2 {
   599  		t.Fatalf("Bad: %#v", p2.ConnInfo)
   600  	}
   601  	if p2.ConnInfo.Raw["user"] != "root" {
   602  		t.Fatalf("Bad: %#v", p2.ConnInfo)
   603  	}
   604  }
   605  
   606  func TestLoadFile_createBeforeDestroy(t *testing.T) {
   607  	c, err := LoadFile(filepath.Join(fixtureDir, "create-before-destroy.tf"))
   608  	if err != nil {
   609  		t.Fatalf("err: %s", err)
   610  	}
   611  
   612  	if c == nil {
   613  		t.Fatal("config should not be nil")
   614  	}
   615  
   616  	actual := resourcesStr(c.Resources)
   617  	if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) {
   618  		t.Fatalf("bad:\n%s", actual)
   619  	}
   620  
   621  	// Check for the flag value
   622  	r := c.Resources[0]
   623  	if r.Name != "web" && r.Type != "aws_instance" {
   624  		t.Fatalf("Bad: %#v", r)
   625  	}
   626  
   627  	// Should enable create before destroy
   628  	if !r.Lifecycle.CreateBeforeDestroy {
   629  		t.Fatalf("Bad: %#v", r)
   630  	}
   631  
   632  	r = c.Resources[1]
   633  	if r.Name != "bar" && r.Type != "aws_instance" {
   634  		t.Fatalf("Bad: %#v", r)
   635  	}
   636  
   637  	// Should not enable create before destroy
   638  	if r.Lifecycle.CreateBeforeDestroy {
   639  		t.Fatalf("Bad: %#v", r)
   640  	}
   641  }
   642  
   643  func TestLoadFile_ignoreChanges(t *testing.T) {
   644  	c, err := LoadFile(filepath.Join(fixtureDir, "ignore-changes.tf"))
   645  	if err != nil {
   646  		t.Fatalf("err: %s", err)
   647  	}
   648  
   649  	if c == nil {
   650  		t.Fatal("config should not be nil")
   651  	}
   652  
   653  	actual := resourcesStr(c.Resources)
   654  	print(actual)
   655  	if actual != strings.TrimSpace(ignoreChangesResourcesStr) {
   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 populate ignore changes
   666  	if len(r.Lifecycle.IgnoreChanges) == 0 {
   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 populate ignore changes
   676  	if len(r.Lifecycle.IgnoreChanges) > 0 {
   677  		t.Fatalf("Bad: %#v", r)
   678  	}
   679  
   680  	r = c.Resources[2]
   681  	if r.Name != "baz" && r.Type != "aws_instance" {
   682  		t.Fatalf("Bad: %#v", r)
   683  	}
   684  
   685  	// Should not populate ignore changes
   686  	if len(r.Lifecycle.IgnoreChanges) > 0 {
   687  		t.Fatalf("Bad: %#v", r)
   688  	}
   689  }
   690  
   691  func TestLoad_preventDestroyString(t *testing.T) {
   692  	c, err := LoadFile(filepath.Join(fixtureDir, "prevent-destroy-string.tf"))
   693  	if err != nil {
   694  		t.Fatalf("err: %s", err)
   695  	}
   696  
   697  	if c == nil {
   698  		t.Fatal("config should not be nil")
   699  	}
   700  
   701  	actual := resourcesStr(c.Resources)
   702  	if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) {
   703  		t.Fatalf("bad:\n%s", actual)
   704  	}
   705  
   706  	// Check for the flag value
   707  	r := c.Resources[0]
   708  	if r.Name != "web" && r.Type != "aws_instance" {
   709  		t.Fatalf("Bad: %#v", r)
   710  	}
   711  
   712  	// Should enable create before destroy
   713  	if !r.Lifecycle.PreventDestroy {
   714  		t.Fatalf("Bad: %#v", r)
   715  	}
   716  
   717  	r = c.Resources[1]
   718  	if r.Name != "bar" && r.Type != "aws_instance" {
   719  		t.Fatalf("Bad: %#v", r)
   720  	}
   721  
   722  	// Should not enable create before destroy
   723  	if r.Lifecycle.PreventDestroy {
   724  		t.Fatalf("Bad: %#v", r)
   725  	}
   726  }
   727  
   728  func TestLoad_temporary_files(t *testing.T) {
   729  	_, err := LoadDir(filepath.Join(fixtureDir, "dir-temporary-files"))
   730  	if err == nil {
   731  		t.Fatalf("Expected to see an error stating no config files found")
   732  	}
   733  }
   734  
   735  func TestLoad_hclAttributes(t *testing.T) {
   736  	c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf"))
   737  	if err != nil {
   738  		t.Fatalf("Bad: %s", err)
   739  	}
   740  
   741  	if c == nil {
   742  		t.Fatal("config should not be nil")
   743  	}
   744  
   745  	actual := resourcesStr(c.Resources)
   746  	print(actual)
   747  	if actual != strings.TrimSpace(jsonAttributeStr) {
   748  		t.Fatalf("bad:\n%s", actual)
   749  	}
   750  
   751  	r := c.Resources[0]
   752  	if r.Name != "test" && r.Type != "cloudstack_firewall" {
   753  		t.Fatalf("Bad: %#v", r)
   754  	}
   755  
   756  	raw := r.RawConfig
   757  	if raw.Raw["ipaddress"] != "192.168.0.1" {
   758  		t.Fatalf("Bad: %s", raw.Raw["ipAddress"])
   759  	}
   760  
   761  	rule := raw.Raw["rule"].([]map[string]interface{})[0]
   762  	if rule["protocol"] != "tcp" {
   763  		t.Fatalf("Bad: %s", rule["protocol"])
   764  	}
   765  
   766  	if rule["source_cidr"] != "10.0.0.0/8" {
   767  		t.Fatalf("Bad: %s", rule["source_cidr"])
   768  	}
   769  
   770  	ports := rule["ports"].([]interface{})
   771  
   772  	if ports[0] != "80" {
   773  		t.Fatalf("Bad ports: %s", ports[0])
   774  	}
   775  	if ports[1] != "1000-2000" {
   776  		t.Fatalf("Bad ports: %s", ports[1])
   777  	}
   778  }
   779  
   780  func TestLoad_jsonAttributes(t *testing.T) {
   781  	c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf.json"))
   782  	if err != nil {
   783  		t.Fatalf("Bad: %s", err)
   784  	}
   785  
   786  	if c == nil {
   787  		t.Fatal("config should not be nil")
   788  	}
   789  
   790  	actual := resourcesStr(c.Resources)
   791  	print(actual)
   792  	if actual != strings.TrimSpace(jsonAttributeStr) {
   793  		t.Fatalf("bad:\n%s", actual)
   794  	}
   795  
   796  	r := c.Resources[0]
   797  	if r.Name != "test" && r.Type != "cloudstack_firewall" {
   798  		t.Fatalf("Bad: %#v", r)
   799  	}
   800  
   801  	raw := r.RawConfig
   802  	if raw.Raw["ipaddress"] != "192.168.0.1" {
   803  		t.Fatalf("Bad: %s", raw.Raw["ipAddress"])
   804  	}
   805  
   806  	rule := raw.Raw["rule"].([]map[string]interface{})[0]
   807  	if rule["protocol"] != "tcp" {
   808  		t.Fatalf("Bad: %s", rule["protocol"])
   809  	}
   810  
   811  	if rule["source_cidr"] != "10.0.0.0/8" {
   812  		t.Fatalf("Bad: %s", rule["source_cidr"])
   813  	}
   814  
   815  	ports := rule["ports"].([]interface{})
   816  
   817  	if ports[0] != "80" {
   818  		t.Fatalf("Bad ports: %s", ports[0])
   819  	}
   820  	if ports[1] != "1000-2000" {
   821  		t.Fatalf("Bad ports: %s", ports[1])
   822  	}
   823  }
   824  
   825  const jsonAttributeStr = `
   826  cloudstack_firewall.test (x1)
   827    ipaddress
   828    rule
   829  `
   830  
   831  const windowsHeredocResourcesStr = `
   832  aws_instance.test (x1)
   833    user_data
   834  `
   835  
   836  const heredocProvidersStr = `
   837  aws
   838    access_key
   839    secret_key
   840  `
   841  
   842  const heredocResourcesStr = `
   843  aws_iam_policy.policy (x1)
   844    description
   845    name
   846    path
   847    policy
   848  aws_instance.heredocwithnumbers (x1)
   849    ami
   850    provisioners
   851      local-exec
   852        command
   853  aws_instance.test (x1)
   854    ami
   855    provisioners
   856      remote-exec
   857        inline
   858  `
   859  
   860  const basicOutputsStr = `
   861  web_ip
   862    vars
   863      resource: aws_instance.web.private_ip
   864  `
   865  
   866  const basicProvidersStr = `
   867  aws
   868    access_key
   869    secret_key
   870  do
   871    api_key
   872    vars
   873      user: var.foo
   874  `
   875  
   876  const basicResourcesStr = `
   877  aws_instance.db (x1)
   878    VPC
   879    security_groups
   880    provisioners
   881      file
   882        destination
   883        source
   884    dependsOn
   885      aws_instance.web
   886    vars
   887      resource: aws_security_group.firewall.*.id
   888  aws_instance.web (x1)
   889    ami
   890    network_interface
   891    security_groups
   892    provisioners
   893      file
   894        destination
   895        source
   896    vars
   897      resource: aws_security_group.firewall.foo
   898      user: var.foo
   899  aws_security_group.firewall (x5)
   900  data.do.depends (x1)
   901    dependsOn
   902      data.do.simple
   903  data.do.simple (x1)
   904    foo
   905  `
   906  
   907  const basicVariablesStr = `
   908  bar (required) (string)
   909    <>
   910    <>
   911  baz (map)
   912    map[key:value]
   913    <>
   914  foo
   915    bar
   916    bar
   917  `
   918  
   919  const basicJsonNoNameResourcesStr = `
   920  aws_security_group.allow_external_http_https (x1)
   921    tags
   922  `
   923  
   924  const dirBasicOutputsStr = `
   925  web_ip
   926    vars
   927      resource: aws_instance.web.private_ip
   928  `
   929  
   930  const dirBasicProvidersStr = `
   931  aws
   932    access_key
   933    secret_key
   934  do
   935    api_key
   936    vars
   937      user: var.foo
   938  `
   939  
   940  const dirBasicResourcesStr = `
   941  aws_instance.db (x1)
   942    security_groups
   943    vars
   944      resource: aws_security_group.firewall.*.id
   945  aws_instance.web (x1)
   946    ami
   947    network_interface
   948    security_groups
   949    vars
   950      resource: aws_security_group.firewall.foo
   951      user: var.foo
   952  aws_security_group.firewall (x5)
   953  data.do.depends (x1)
   954    dependsOn
   955      data.do.simple
   956  data.do.simple (x1)
   957    foo
   958  `
   959  
   960  const dirBasicVariablesStr = `
   961  foo
   962    bar
   963    bar
   964  `
   965  
   966  const dirOverrideOutputsStr = `
   967  web_ip
   968    vars
   969      resource: aws_instance.web.private_ip
   970  `
   971  
   972  const dirOverrideProvidersStr = `
   973  aws
   974    access_key
   975    secret_key
   976  do
   977    api_key
   978    vars
   979      user: var.foo
   980  `
   981  
   982  const dirOverrideResourcesStr = `
   983  aws_instance.db (x1)
   984    ami
   985    security_groups
   986  aws_instance.web (x1)
   987    ami
   988    foo
   989    network_interface
   990    security_groups
   991    vars
   992      resource: aws_security_group.firewall.foo
   993      user: var.foo
   994  aws_security_group.firewall (x5)
   995  data.do.depends (x1)
   996    hello
   997    dependsOn
   998      data.do.simple
   999  data.do.simple (x1)
  1000    foo
  1001  `
  1002  
  1003  const dirOverrideVariablesStr = `
  1004  foo
  1005    bar
  1006    bar
  1007  `
  1008  
  1009  const dirOverrideVarsVariablesStr = `
  1010  foo
  1011    baz
  1012    bar
  1013  `
  1014  
  1015  const importProvidersStr = `
  1016  aws
  1017    bar
  1018    foo
  1019  `
  1020  
  1021  const importResourcesStr = `
  1022  aws_security_group.db (x1)
  1023  aws_security_group.web (x1)
  1024  `
  1025  
  1026  const importVariablesStr = `
  1027  bar (required)
  1028    <>
  1029    <>
  1030  foo
  1031    bar
  1032    bar
  1033  `
  1034  
  1035  const modulesModulesStr = `
  1036  bar
  1037    source = baz
  1038    memory
  1039  `
  1040  
  1041  const provisionerResourcesStr = `
  1042  aws_instance.web (x1)
  1043    ami
  1044    security_groups
  1045    provisioners
  1046      shell
  1047        path
  1048    vars
  1049      resource: aws_security_group.firewall.foo
  1050      user: var.foo
  1051  `
  1052  
  1053  const connectionResourcesStr = `
  1054  aws_instance.web (x1)
  1055    ami
  1056    security_groups
  1057    provisioners
  1058      shell
  1059        path
  1060      shell
  1061        path
  1062    vars
  1063      resource: aws_security_group.firewall.foo
  1064      user: var.foo
  1065  `
  1066  
  1067  const variablesVariablesStr = `
  1068  bar
  1069    <>
  1070    <>
  1071  baz
  1072    foo
  1073    <>
  1074  foo (required)
  1075    <>
  1076    <>
  1077  `
  1078  
  1079  const createBeforeDestroyResourcesStr = `
  1080  aws_instance.bar (x1)
  1081    ami
  1082  aws_instance.web (x1)
  1083    ami
  1084  `
  1085  
  1086  const ignoreChangesResourcesStr = `
  1087  aws_instance.bar (x1)
  1088    ami
  1089  aws_instance.baz (x1)
  1090    ami
  1091  aws_instance.web (x1)
  1092    ami
  1093  `