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