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