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