github.com/magodo/terraform@v0.11.12-beta1/config/config_test.go (about)

     1  package config
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"log"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/hashicorp/hil/ast"
    15  	"github.com/hashicorp/terraform/helper/logging"
    16  )
    17  
    18  // This is the directory where our test fixtures are.
    19  const fixtureDir = "./test-fixtures"
    20  
    21  func TestMain(m *testing.M) {
    22  	flag.Parse()
    23  	if testing.Verbose() {
    24  		// if we're verbose, use the logging requested by TF_LOG
    25  		logging.SetOutput()
    26  	} else {
    27  		// otherwise silence all logs
    28  		log.SetOutput(ioutil.Discard)
    29  	}
    30  
    31  	os.Exit(m.Run())
    32  }
    33  
    34  func TestConfigCopy(t *testing.T) {
    35  	c := testConfig(t, "copy-basic")
    36  	rOrig := c.Resources[0]
    37  	rCopy := rOrig.Copy()
    38  
    39  	if rCopy.Name != rOrig.Name {
    40  		t.Fatalf("Expected names to equal: %q <=> %q", rCopy.Name, rOrig.Name)
    41  	}
    42  
    43  	if rCopy.Type != rOrig.Type {
    44  		t.Fatalf("Expected types to equal: %q <=> %q", rCopy.Type, rOrig.Type)
    45  	}
    46  
    47  	origCount := rOrig.RawCount.Config()["count"]
    48  	rCopy.RawCount.Config()["count"] = "5"
    49  	if rOrig.RawCount.Config()["count"] != origCount {
    50  		t.Fatalf("Expected RawCount to be copied, but it behaves like a ref!")
    51  	}
    52  
    53  	rCopy.RawConfig.Config()["newfield"] = "hello"
    54  	if rOrig.RawConfig.Config()["newfield"] == "hello" {
    55  		t.Fatalf("Expected RawConfig to be copied, but it behaves like a ref!")
    56  	}
    57  
    58  	rCopy.Provisioners = append(rCopy.Provisioners, &Provisioner{})
    59  	if len(rOrig.Provisioners) == len(rCopy.Provisioners) {
    60  		t.Fatalf("Expected Provisioners to be copied, but it behaves like a ref!")
    61  	}
    62  
    63  	if rCopy.Provider != rOrig.Provider {
    64  		t.Fatalf("Expected providers to equal: %q <=> %q",
    65  			rCopy.Provider, rOrig.Provider)
    66  	}
    67  
    68  	rCopy.DependsOn[0] = "gotchya"
    69  	if rOrig.DependsOn[0] == rCopy.DependsOn[0] {
    70  		t.Fatalf("Expected DependsOn to be copied, but it behaves like a ref!")
    71  	}
    72  
    73  	rCopy.Lifecycle.IgnoreChanges[0] = "gotchya"
    74  	if rOrig.Lifecycle.IgnoreChanges[0] == rCopy.Lifecycle.IgnoreChanges[0] {
    75  		t.Fatalf("Expected Lifecycle to be copied, but it behaves like a ref!")
    76  	}
    77  
    78  }
    79  
    80  func TestConfigCount(t *testing.T) {
    81  	c := testConfig(t, "count-int")
    82  	actual, err := c.Resources[0].Count()
    83  	if err != nil {
    84  		t.Fatalf("err: %s", err)
    85  	}
    86  	if actual != 5 {
    87  		t.Fatalf("bad: %#v", actual)
    88  	}
    89  }
    90  
    91  func TestConfigCount_string(t *testing.T) {
    92  	c := testConfig(t, "count-string")
    93  	actual, err := c.Resources[0].Count()
    94  	if err != nil {
    95  		t.Fatalf("err: %s", err)
    96  	}
    97  	if actual != 5 {
    98  		t.Fatalf("bad: %#v", actual)
    99  	}
   100  }
   101  
   102  // Terraform GH-11800
   103  func TestConfigCount_list(t *testing.T) {
   104  	c := testConfig(t, "count-list")
   105  
   106  	// The key is to interpolate so it doesn't fail parsing
   107  	c.Resources[0].RawCount.Interpolate(map[string]ast.Variable{
   108  		"var.list": ast.Variable{
   109  			Value: []ast.Variable{},
   110  			Type:  ast.TypeList,
   111  		},
   112  	})
   113  
   114  	_, err := c.Resources[0].Count()
   115  	if err == nil {
   116  		t.Fatal("should error")
   117  	}
   118  }
   119  
   120  func TestConfigCount_var(t *testing.T) {
   121  	c := testConfig(t, "count-var")
   122  	_, err := c.Resources[0].Count()
   123  	if err == nil {
   124  		t.Fatalf("should error")
   125  	}
   126  }
   127  
   128  func TestConfig_emptyCollections(t *testing.T) {
   129  	c := testConfig(t, "empty-collections")
   130  	if len(c.Variables) != 3 {
   131  		t.Fatalf("bad: expected 3 variables, got %d", len(c.Variables))
   132  	}
   133  	for _, variable := range c.Variables {
   134  		switch variable.Name {
   135  		case "empty_string":
   136  			if variable.Default != "" {
   137  				t.Fatalf("bad: wrong default %q for variable empty_string", variable.Default)
   138  			}
   139  		case "empty_map":
   140  			if !reflect.DeepEqual(variable.Default, map[string]interface{}{}) {
   141  				t.Fatalf("bad: wrong default %#v for variable empty_map", variable.Default)
   142  			}
   143  		case "empty_list":
   144  			if !reflect.DeepEqual(variable.Default, []interface{}{}) {
   145  				t.Fatalf("bad: wrong default %#v for variable empty_list", variable.Default)
   146  			}
   147  		default:
   148  			t.Fatalf("Unexpected variable: %s", variable.Name)
   149  		}
   150  	}
   151  }
   152  
   153  // This table test is the preferred way to test validation of configuration.
   154  // There are dozens of functions below which do not follow this that are
   155  // there mostly historically. They should be converted at some point.
   156  func TestConfigValidate_table(t *testing.T) {
   157  	cases := []struct {
   158  		Name      string
   159  		Fixture   string
   160  		Err       bool
   161  		ErrString string
   162  	}{
   163  		{
   164  			"basic good",
   165  			"validate-good",
   166  			false,
   167  			"",
   168  		},
   169  
   170  		{
   171  			"depends on module",
   172  			"validate-depends-on-module",
   173  			false,
   174  			"",
   175  		},
   176  
   177  		{
   178  			"depends on non-existent module",
   179  			"validate-depends-on-bad-module",
   180  			true,
   181  			"non-existent module 'foo'",
   182  		},
   183  
   184  		{
   185  			"data source with provisioners",
   186  			"validate-data-provisioner",
   187  			true,
   188  			"data sources cannot have",
   189  		},
   190  
   191  		{
   192  			"basic provisioners",
   193  			"validate-basic-provisioners",
   194  			false,
   195  			"",
   196  		},
   197  
   198  		{
   199  			"backend config with interpolations",
   200  			"validate-backend-interpolate",
   201  			true,
   202  			"cannot contain interp",
   203  		},
   204  		{
   205  			"nested types in variable default",
   206  			"validate-var-nested",
   207  			false,
   208  			"",
   209  		},
   210  		{
   211  			"provider with valid version constraint",
   212  			"provider-version",
   213  			false,
   214  			"",
   215  		},
   216  		{
   217  			"provider with invalid version constraint",
   218  			"provider-version-invalid",
   219  			true,
   220  			"not a valid version constraint",
   221  		},
   222  		{
   223  			"invalid provider name in module block",
   224  			"validate-missing-provider",
   225  			true,
   226  			"cannot pass non-existent provider",
   227  		},
   228  	}
   229  
   230  	for i, tc := range cases {
   231  		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
   232  			c := testConfig(t, tc.Fixture)
   233  			diags := c.Validate()
   234  			if diags.HasErrors() != tc.Err {
   235  				t.Fatalf("err: %s", diags.Err().Error())
   236  			}
   237  			if diags.HasErrors() {
   238  				gotErr := diags.Err().Error()
   239  				if tc.ErrString != "" && !strings.Contains(gotErr, tc.ErrString) {
   240  					t.Fatalf("expected err to contain: %s\n\ngot: %s", tc.ErrString, gotErr)
   241  				}
   242  
   243  				return
   244  			}
   245  		})
   246  	}
   247  
   248  }
   249  
   250  func TestConfigValidate_tfVersion(t *testing.T) {
   251  	c := testConfig(t, "validate-tf-version")
   252  	if err := c.Validate(); err != nil {
   253  		t.Fatalf("err: %s", err)
   254  	}
   255  }
   256  
   257  func TestConfigValidate_tfVersionBad(t *testing.T) {
   258  	c := testConfig(t, "validate-bad-tf-version")
   259  	if err := c.Validate(); err == nil {
   260  		t.Fatal("should not be valid")
   261  	}
   262  }
   263  
   264  func TestConfigValidate_tfVersionInterpolations(t *testing.T) {
   265  	c := testConfig(t, "validate-tf-version-interp")
   266  	if err := c.Validate(); err == nil {
   267  		t.Fatal("should not be valid")
   268  	}
   269  }
   270  
   271  func TestConfigValidate_badDependsOn(t *testing.T) {
   272  	c := testConfig(t, "validate-bad-depends-on")
   273  	if err := c.Validate(); err == nil {
   274  		t.Fatal("should not be valid")
   275  	}
   276  }
   277  
   278  func TestConfigValidate_countInt(t *testing.T) {
   279  	c := testConfig(t, "validate-count-int")
   280  	if err := c.Validate(); err != nil {
   281  		t.Fatalf("err: %s", err)
   282  	}
   283  }
   284  
   285  func TestConfigValidate_countInt_HCL2(t *testing.T) {
   286  	c := testConfigHCL2(t, "validate-count-int")
   287  	if err := c.Validate(); err != nil {
   288  		t.Fatalf("unexpected error: %s", err)
   289  	}
   290  }
   291  
   292  func TestConfigValidate_countBadContext(t *testing.T) {
   293  	c := testConfig(t, "validate-count-bad-context")
   294  
   295  	diags := c.Validate()
   296  
   297  	expected := []string{
   298  		"output \"no_count_in_output\": count variables are only valid within resources",
   299  		"module \"no_count_in_module\": count variables are only valid within resources",
   300  	}
   301  	for _, exp := range expected {
   302  		errStr := diags.Err().Error()
   303  		if !strings.Contains(errStr, exp) {
   304  			t.Errorf("expected: %q,\nto contain: %q", errStr, exp)
   305  		}
   306  	}
   307  }
   308  
   309  func TestConfigValidate_countCountVar(t *testing.T) {
   310  	c := testConfig(t, "validate-count-count-var")
   311  	if err := c.Validate(); err == nil {
   312  		t.Fatal("should not be valid")
   313  	}
   314  }
   315  
   316  func TestConfigValidate_countNotInt(t *testing.T) {
   317  	c := testConfig(t, "validate-count-not-int")
   318  	if err := c.Validate(); err == nil {
   319  		t.Fatal("should not be valid")
   320  	}
   321  }
   322  
   323  func TestConfigValidate_countNotInt_HCL2(t *testing.T) {
   324  	c := testConfigHCL2(t, "validate-count-not-int-const")
   325  	if err := c.Validate(); err == nil {
   326  		t.Fatal("should not be valid")
   327  	}
   328  }
   329  
   330  func TestConfigValidate_countNotIntUnknown_HCL2(t *testing.T) {
   331  	c := testConfigHCL2(t, "validate-count-not-int")
   332  	// In HCL2 this is not an error because the unknown variable interpolates
   333  	// to produce an unknown string, which we assume (incorrectly, it turns out)
   334  	// will become a string containing only digits. This is okay because
   335  	// the config validation is only a "best effort" and we'll get a definitive
   336  	// result during the validation graph walk.
   337  	if err := c.Validate(); err != nil {
   338  		t.Fatalf("unexpected error: %s", err)
   339  	}
   340  }
   341  
   342  func TestConfigValidate_countUserVar(t *testing.T) {
   343  	c := testConfig(t, "validate-count-user-var")
   344  	if err := c.Validate(); err != nil {
   345  		t.Fatalf("err: %s", err)
   346  	}
   347  }
   348  
   349  func TestConfigValidate_countUserVar_HCL2(t *testing.T) {
   350  	c := testConfigHCL2(t, "validate-count-user-var")
   351  	if err := c.Validate(); err != nil {
   352  		t.Fatalf("err: %s", err)
   353  	}
   354  }
   355  
   356  func TestConfigValidate_countLocalValue(t *testing.T) {
   357  	c := testConfig(t, "validate-local-value-count")
   358  	if err := c.Validate(); err != nil {
   359  		t.Fatalf("err: %s", err)
   360  	}
   361  }
   362  
   363  func TestConfigValidate_countVar(t *testing.T) {
   364  	c := testConfig(t, "validate-count-var")
   365  	if err := c.Validate(); err != nil {
   366  		t.Fatalf("err: %s", err)
   367  	}
   368  }
   369  
   370  func TestConfigValidate_countVarInvalid(t *testing.T) {
   371  	c := testConfig(t, "validate-count-var-invalid")
   372  	if err := c.Validate(); err == nil {
   373  		t.Fatal("should not be valid")
   374  	}
   375  }
   376  
   377  func TestConfigValidate_countVarUnknown(t *testing.T) {
   378  	c := testConfig(t, "validate-count-var-unknown")
   379  	if err := c.Validate(); err == nil {
   380  		t.Fatal("should not be valid")
   381  	}
   382  }
   383  
   384  func TestConfigValidate_dependsOnVar(t *testing.T) {
   385  	c := testConfig(t, "validate-depends-on-var")
   386  	if err := c.Validate(); err == nil {
   387  		t.Fatal("should not be valid")
   388  	}
   389  }
   390  
   391  func TestConfigValidate_dupModule(t *testing.T) {
   392  	c := testConfig(t, "validate-dup-module")
   393  	if err := c.Validate(); err == nil {
   394  		t.Fatal("should not be valid")
   395  	}
   396  }
   397  
   398  func TestConfigValidate_dupResource(t *testing.T) {
   399  	c := testConfig(t, "validate-dup-resource")
   400  	if err := c.Validate(); err == nil {
   401  		t.Fatal("should not be valid")
   402  	}
   403  }
   404  
   405  func TestConfigValidate_ignoreChanges(t *testing.T) {
   406  	c := testConfig(t, "validate-ignore-changes")
   407  	if err := c.Validate(); err != nil {
   408  		t.Fatalf("err: %s", err)
   409  	}
   410  }
   411  
   412  func TestConfigValidate_ignoreChangesBad(t *testing.T) {
   413  	c := testConfig(t, "validate-ignore-changes-bad")
   414  	if err := c.Validate(); err == nil {
   415  		t.Fatal("should not be valid")
   416  	}
   417  }
   418  
   419  func TestConfigValidate_ignoreChangesInterpolate(t *testing.T) {
   420  	c := testConfig(t, "validate-ignore-changes-interpolate")
   421  	if err := c.Validate(); err == nil {
   422  		t.Fatal("should not be valid")
   423  	}
   424  }
   425  
   426  func TestConfigValidate_moduleNameBad(t *testing.T) {
   427  	c := testConfig(t, "validate-module-name-bad")
   428  	if err := c.Validate(); err == nil {
   429  		t.Fatal("should not be valid")
   430  	}
   431  }
   432  
   433  func TestConfigValidate_moduleSourceVar(t *testing.T) {
   434  	c := testConfig(t, "validate-module-source-var")
   435  	if err := c.Validate(); err == nil {
   436  		t.Fatal("should not be valid")
   437  	}
   438  }
   439  
   440  func TestConfigValidate_moduleVarInt(t *testing.T) {
   441  	c := testConfig(t, "validate-module-var-int")
   442  	if err := c.Validate(); err != nil {
   443  		t.Fatalf("should be valid: %s", err)
   444  	}
   445  }
   446  
   447  func TestConfigValidate_moduleVarMap(t *testing.T) {
   448  	c := testConfig(t, "validate-module-var-map")
   449  	if err := c.Validate(); err != nil {
   450  		t.Fatalf("should be valid: %s", err)
   451  	}
   452  }
   453  
   454  func TestConfigValidate_moduleVarList(t *testing.T) {
   455  	c := testConfig(t, "validate-module-var-list")
   456  	if err := c.Validate(); err != nil {
   457  		t.Fatalf("should be valid: %s", err)
   458  	}
   459  }
   460  
   461  func TestConfigValidate_moduleVarSelf(t *testing.T) {
   462  	c := testConfig(t, "validate-module-var-self")
   463  	if err := c.Validate(); err == nil {
   464  		t.Fatal("should be invalid")
   465  	}
   466  }
   467  
   468  func TestConfigValidate_nil(t *testing.T) {
   469  	var c Config
   470  	if err := c.Validate(); err != nil {
   471  		t.Fatalf("err: %s", err)
   472  	}
   473  }
   474  
   475  func TestConfigValidate_outputBadField(t *testing.T) {
   476  	c := testConfig(t, "validate-output-bad-field")
   477  	if err := c.Validate(); err == nil {
   478  		t.Fatal("should not be valid")
   479  	}
   480  }
   481  
   482  func TestConfigValidate_outputDescription(t *testing.T) {
   483  	c := testConfig(t, "validate-output-description")
   484  	if err := c.Validate(); err != nil {
   485  		t.Fatalf("err: %s", err)
   486  	}
   487  	if len(c.Outputs) != 1 {
   488  		t.Fatalf("got %d outputs; want 1", len(c.Outputs))
   489  	}
   490  	if got, want := "Number 5", c.Outputs[0].Description; got != want {
   491  		t.Fatalf("got description %q; want %q", got, want)
   492  	}
   493  }
   494  
   495  func TestConfigValidate_outputDuplicate(t *testing.T) {
   496  	c := testConfig(t, "validate-output-dup")
   497  	if err := c.Validate(); err == nil {
   498  		t.Fatal("should not be valid")
   499  	}
   500  }
   501  
   502  func TestConfigValidate_pathVar(t *testing.T) {
   503  	c := testConfig(t, "validate-path-var")
   504  	if err := c.Validate(); err != nil {
   505  		t.Fatalf("err: %s", err)
   506  	}
   507  }
   508  
   509  func TestConfigValidate_pathVarInvalid(t *testing.T) {
   510  	c := testConfig(t, "validate-path-var-invalid")
   511  	if err := c.Validate(); err == nil {
   512  		t.Fatal("should not be valid")
   513  	}
   514  }
   515  
   516  func TestConfigValidate_providerMulti(t *testing.T) {
   517  	c := testConfig(t, "validate-provider-multi")
   518  	if err := c.Validate(); err == nil {
   519  		t.Fatal("should not be valid")
   520  	}
   521  }
   522  
   523  func TestConfigValidate_providerMultiGood(t *testing.T) {
   524  	c := testConfig(t, "validate-provider-multi-good")
   525  	if err := c.Validate(); err != nil {
   526  		t.Fatalf("should be valid: %s", err)
   527  	}
   528  }
   529  
   530  func TestConfigValidate_providerMultiRefGood(t *testing.T) {
   531  	c := testConfig(t, "validate-provider-multi-ref-good")
   532  	if err := c.Validate(); err != nil {
   533  		t.Fatalf("should be valid: %s", err)
   534  	}
   535  }
   536  
   537  func TestConfigValidate_provConnSplatOther(t *testing.T) {
   538  	c := testConfig(t, "validate-prov-conn-splat-other")
   539  	if err := c.Validate(); err != nil {
   540  		t.Fatalf("should be valid: %s", err)
   541  	}
   542  }
   543  
   544  func TestConfigValidate_provConnSplatSelf(t *testing.T) {
   545  	c := testConfig(t, "validate-prov-conn-splat-self")
   546  	if err := c.Validate(); err == nil {
   547  		t.Fatal("should not be valid")
   548  	}
   549  }
   550  
   551  func TestConfigValidate_provSplatOther(t *testing.T) {
   552  	c := testConfig(t, "validate-prov-splat-other")
   553  	if err := c.Validate(); err != nil {
   554  		t.Fatalf("should be valid: %s", err)
   555  	}
   556  }
   557  
   558  func TestConfigValidate_provSplatSelf(t *testing.T) {
   559  	c := testConfig(t, "validate-prov-splat-self")
   560  	if err := c.Validate(); err == nil {
   561  		t.Fatal("should not be valid")
   562  	}
   563  }
   564  
   565  func TestConfigValidate_resourceProvVarSelf(t *testing.T) {
   566  	c := testConfig(t, "validate-resource-prov-self")
   567  	if err := c.Validate(); err != nil {
   568  		t.Fatalf("should be valid: %s", err)
   569  	}
   570  }
   571  
   572  func TestConfigValidate_resourceVarSelf(t *testing.T) {
   573  	c := testConfig(t, "validate-resource-self")
   574  	if err := c.Validate(); err == nil {
   575  		t.Fatal("should not be valid")
   576  	}
   577  }
   578  
   579  func TestConfigValidate_unknownThing(t *testing.T) {
   580  	c := testConfig(t, "validate-unknownthing")
   581  	if err := c.Validate(); err == nil {
   582  		t.Fatal("should not be valid")
   583  	}
   584  }
   585  
   586  func TestConfigValidate_unknownResourceVar(t *testing.T) {
   587  	c := testConfig(t, "validate-unknown-resource-var")
   588  	if err := c.Validate(); err == nil {
   589  		t.Fatal("should not be valid")
   590  	}
   591  }
   592  
   593  func TestConfigValidate_unknownResourceVar_output(t *testing.T) {
   594  	c := testConfig(t, "validate-unknown-resource-var-output")
   595  	if err := c.Validate(); err == nil {
   596  		t.Fatal("should not be valid")
   597  	}
   598  }
   599  
   600  func TestConfigValidate_unknownVar(t *testing.T) {
   601  	c := testConfig(t, "validate-unknownvar")
   602  	if err := c.Validate(); err == nil {
   603  		t.Fatal("should not be valid")
   604  	}
   605  }
   606  
   607  func TestConfigValidate_unknownVarCount(t *testing.T) {
   608  	c := testConfig(t, "validate-unknownvar-count")
   609  	if err := c.Validate(); err == nil {
   610  		t.Fatal("should not be valid")
   611  	}
   612  }
   613  
   614  func TestConfigValidate_varDefault(t *testing.T) {
   615  	c := testConfig(t, "validate-var-default")
   616  	if err := c.Validate(); err != nil {
   617  		t.Fatalf("should be valid: %s", err)
   618  	}
   619  }
   620  
   621  func TestConfigValidate_varDefaultListType(t *testing.T) {
   622  	c := testConfig(t, "validate-var-default-list-type")
   623  	if err := c.Validate(); err != nil {
   624  		t.Fatalf("should be valid: %s", err)
   625  	}
   626  }
   627  
   628  func TestConfigValidate_varDefaultInterpolate(t *testing.T) {
   629  	c := testConfig(t, "validate-var-default-interpolate")
   630  	if err := c.Validate(); err == nil {
   631  		t.Fatal("should not be valid")
   632  	}
   633  }
   634  
   635  func TestConfigValidate_varDefaultInterpolateEscaped(t *testing.T) {
   636  	c := testConfig(t, "validate-var-default-interpolate-escaped")
   637  	if err := c.Validate(); err != nil {
   638  		t.Fatalf("should be valid, but got err: %s", err)
   639  	}
   640  }
   641  
   642  func TestConfigValidate_varDup(t *testing.T) {
   643  	c := testConfig(t, "validate-var-dup")
   644  	if err := c.Validate(); err == nil {
   645  		t.Fatal("should not be valid")
   646  	}
   647  }
   648  
   649  func TestConfigValidate_varMultiExactNonSlice(t *testing.T) {
   650  	c := testConfig(t, "validate-var-multi-exact-non-slice")
   651  	if err := c.Validate(); err != nil {
   652  		t.Fatalf("should be valid: %s", err)
   653  	}
   654  }
   655  
   656  func TestConfigValidate_varMultiFunctionCall(t *testing.T) {
   657  	c := testConfig(t, "validate-var-multi-func")
   658  	if err := c.Validate(); err != nil {
   659  		t.Fatalf("should be valid: %s", err)
   660  	}
   661  }
   662  
   663  func TestConfigValidate_varModule(t *testing.T) {
   664  	c := testConfig(t, "validate-var-module")
   665  	if err := c.Validate(); err != nil {
   666  		t.Fatalf("err: %s", err)
   667  	}
   668  }
   669  
   670  func TestConfigValidate_varModuleInvalid(t *testing.T) {
   671  	c := testConfig(t, "validate-var-module-invalid")
   672  	if err := c.Validate(); err == nil {
   673  		t.Fatal("should not be valid")
   674  	}
   675  }
   676  
   677  func TestConfigValidate_varProviderVersionInvalid(t *testing.T) {
   678  	c := testConfig(t, "validate-provider-version-invalid")
   679  	if err := c.Validate(); err == nil {
   680  		t.Fatal("should not be valid")
   681  	}
   682  }
   683  
   684  func TestNameRegexp(t *testing.T) {
   685  	cases := []struct {
   686  		Input string
   687  		Match bool
   688  	}{
   689  		{"hello", true},
   690  		{"foo-bar", true},
   691  		{"foo_bar", true},
   692  		{"_hello", true},
   693  		{"foo bar", false},
   694  		{"foo.bar", false},
   695  	}
   696  
   697  	for _, tc := range cases {
   698  		if NameRegexp.Match([]byte(tc.Input)) != tc.Match {
   699  			t.Fatalf("Input: %s\n\nExpected: %#v", tc.Input, tc.Match)
   700  		}
   701  	}
   702  }
   703  
   704  func TestConfigValidate_localValuesMultiFile(t *testing.T) {
   705  	c, err := LoadDir(filepath.Join(fixtureDir, "validate-local-multi-file"))
   706  	if err != nil {
   707  		t.Fatalf("unexpected error during load: %s", err)
   708  	}
   709  	if err := c.Validate(); err != nil {
   710  		t.Fatalf("unexpected error from validate: %s", err)
   711  	}
   712  	if len(c.Locals) != 1 {
   713  		t.Fatalf("got 0 locals; want 1")
   714  	}
   715  	if got, want := c.Locals[0].Name, "test"; got != want {
   716  		t.Errorf("wrong local name\ngot:  %#v\nwant: %#v", got, want)
   717  	}
   718  }
   719  
   720  func TestProviderConfigName(t *testing.T) {
   721  	pcs := []*ProviderConfig{
   722  		&ProviderConfig{Name: "aw"},
   723  		&ProviderConfig{Name: "aws"},
   724  		&ProviderConfig{Name: "a"},
   725  		&ProviderConfig{Name: "gce_"},
   726  	}
   727  
   728  	n := ProviderConfigName("aws_instance", pcs)
   729  	if n != "aws" {
   730  		t.Fatalf("bad: %s", n)
   731  	}
   732  }
   733  
   734  func testConfig(t *testing.T, name string) *Config {
   735  	c, err := LoadFile(filepath.Join(fixtureDir, name, "main.tf"))
   736  	if err != nil {
   737  		t.Fatalf("file: %s\n\nerr: %s", name, err)
   738  	}
   739  
   740  	return c
   741  }
   742  
   743  // testConfigHCL loads a config, forcing it to be processed with the HCL2
   744  // loader even if it doesn't explicitly opt in to the HCL2 experiment.
   745  func testConfigHCL2(t *testing.T, name string) *Config {
   746  	t.Helper()
   747  	cer, _, err := globalHCL2Loader.loadFile(filepath.Join(fixtureDir, name, "main.tf"))
   748  	if err != nil {
   749  		t.Fatalf("failed to load %s: %s", name, err)
   750  	}
   751  
   752  	cfg, err := cer.Config()
   753  	if err != nil {
   754  		t.Fatalf("failed to decode %s: %s", name, err)
   755  	}
   756  
   757  	return cfg
   758  }
   759  
   760  func TestConfigDataCount(t *testing.T) {
   761  	c := testConfig(t, "data-count")
   762  	actual, err := c.Resources[0].Count()
   763  	if err != nil {
   764  		t.Fatalf("err: %s", err)
   765  	}
   766  	if actual != 5 {
   767  		t.Fatalf("bad: %#v", actual)
   768  	}
   769  
   770  	// we need to make sure "count" has been removed from the RawConfig, since
   771  	// it's not a real key and won't validate.
   772  	if _, ok := c.Resources[0].RawConfig.Raw["count"]; ok {
   773  		t.Fatal("count key still exists in RawConfig")
   774  	}
   775  }
   776  
   777  func TestConfigProviderVersion(t *testing.T) {
   778  	c := testConfig(t, "provider-version")
   779  
   780  	if len(c.ProviderConfigs) != 1 {
   781  		t.Fatal("expected 1 provider")
   782  	}
   783  
   784  	p := c.ProviderConfigs[0]
   785  	if p.Name != "aws" {
   786  		t.Fatalf("expected provider name 'aws', got %q", p.Name)
   787  	}
   788  
   789  	if p.Version != "0.0.1" {
   790  		t.Fatalf("expected providers version '0.0.1', got %q", p.Version)
   791  	}
   792  
   793  	if _, ok := p.RawConfig.Raw["version"]; ok {
   794  		t.Fatal("'version' should not exist in raw config")
   795  	}
   796  }
   797  
   798  func TestResourceProviderFullName(t *testing.T) {
   799  	type testCase struct {
   800  		ResourceName string
   801  		Alias        string
   802  		Expected     string
   803  	}
   804  
   805  	tests := []testCase{
   806  		{
   807  			// If no alias is provided, the first underscore-separated segment
   808  			// is assumed to be the provider name.
   809  			ResourceName: "aws_thing",
   810  			Alias:        "",
   811  			Expected:     "aws",
   812  		},
   813  		{
   814  			// If we have more than one underscore then it's the first one that we'll use.
   815  			ResourceName: "aws_thingy_thing",
   816  			Alias:        "",
   817  			Expected:     "aws",
   818  		},
   819  		{
   820  			// A provider can export a resource whose name is just the bare provider name,
   821  			// e.g. because the provider only has one resource and so any additional
   822  			// parts would be redundant.
   823  			ResourceName: "external",
   824  			Alias:        "",
   825  			Expected:     "external",
   826  		},
   827  		{
   828  			// Alias always overrides the default extraction of the name
   829  			ResourceName: "aws_thing",
   830  			Alias:        "tls.baz",
   831  			Expected:     "tls.baz",
   832  		},
   833  	}
   834  
   835  	for _, test := range tests {
   836  		got := ResourceProviderFullName(test.ResourceName, test.Alias)
   837  		if got != test.Expected {
   838  			t.Errorf(
   839  				"(%q, %q) produced %q; want %q",
   840  				test.ResourceName, test.Alias,
   841  				got,
   842  				test.Expected,
   843  			)
   844  		}
   845  	}
   846  }
   847  
   848  func TestConfigModuleProviders(t *testing.T) {
   849  	c := testConfig(t, "module-providers")
   850  
   851  	if len(c.Modules) != 1 {
   852  		t.Fatalf("expected 1 module, got %d", len(c.Modules))
   853  	}
   854  
   855  	expected := map[string]string{
   856  		"aws": "aws.foo",
   857  	}
   858  
   859  	got := c.Modules[0].Providers
   860  
   861  	if !reflect.DeepEqual(expected, got) {
   862  		t.Fatalf("exptected providers %#v, got providers %#v", expected, got)
   863  	}
   864  }
   865  
   866  func TestValidateOutputErrorWarnings(t *testing.T) {
   867  	// TODO: remove this in 0.12
   868  	c := testConfig(t, "output-warnings")
   869  
   870  	diags := c.Validate()
   871  	if diags.HasErrors() {
   872  		t.Fatal("config should not have errors:", diags)
   873  	}
   874  	if len(diags) != 2 {
   875  		t.Fatalf("should have 2 warnings, got %d:\n%s", len(diags), diags)
   876  	}
   877  
   878  	// this fixture has no explicit count, and should have no warning
   879  	c = testConfig(t, "output-no-warnings")
   880  	if err := c.Validate(); err != nil {
   881  		t.Fatal("config should have no warnings or errors")
   882  	}
   883  }