kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/configs/module_test.go (about)

     1  package configs
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"kubeform.dev/terraform-backend-sdk/addrs"
     8  )
     9  
    10  // TestNewModule_provider_fqns exercises module.gatherProviderLocalNames()
    11  func TestNewModule_provider_local_name(t *testing.T) {
    12  	mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
    13  	if diags.HasErrors() {
    14  		t.Fatal(diags.Error())
    15  	}
    16  
    17  	p := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
    18  	if name, exists := mod.ProviderLocalNames[p]; !exists {
    19  		t.Fatal("provider FQN foo/test not found")
    20  	} else {
    21  		if name != "foo-test" {
    22  			t.Fatalf("provider localname mismatch: got %s, want foo-test", name)
    23  		}
    24  	}
    25  
    26  	// ensure the reverse lookup (fqn to local name) works as well
    27  	localName := mod.LocalNameForProvider(p)
    28  	if localName != "foo-test" {
    29  		t.Fatal("provider local name not found")
    30  	}
    31  
    32  	// if there is not a local name for a provider, it should return the type name
    33  	localName = mod.LocalNameForProvider(addrs.NewDefaultProvider("nonexist"))
    34  	if localName != "nonexist" {
    35  		t.Error("wrong local name returned for a non-local provider")
    36  	}
    37  
    38  	// can also look up the "terraform" provider and see that it sources is
    39  	// allowed to be overridden, even though there is a builtin provider
    40  	// called "terraform".
    41  	p = addrs.NewProvider(addrs.DefaultProviderRegistryHost, "not-builtin", "not-terraform")
    42  	if name, exists := mod.ProviderLocalNames[p]; !exists {
    43  		t.Fatal("provider FQN not-builtin/not-terraform not found")
    44  	} else {
    45  		if name != "terraform" {
    46  			t.Fatalf("provider localname mismatch: got %s, want terraform", name)
    47  		}
    48  	}
    49  }
    50  
    51  // This test validates the provider FQNs set in each Resource
    52  func TestNewModule_resource_providers(t *testing.T) {
    53  	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/valid-modules/nested-providers-fqns")
    54  	if diags.HasErrors() {
    55  		t.Fatal(diags.Error())
    56  	}
    57  
    58  	// both the root and child module have two resources, one which should use
    59  	// the default implied provider and one explicitly using a provider set in
    60  	// required_providers
    61  	wantImplicit := addrs.NewDefaultProvider("test")
    62  	wantFoo := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
    63  	wantBar := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "bar", "test")
    64  
    65  	// root module
    66  	if !cfg.Module.ManagedResources["test_instance.explicit"].Provider.Equals(wantFoo) {
    67  		t.Fatalf("wrong provider for \"test_instance.explicit\"\ngot:  %s\nwant: %s",
    68  			cfg.Module.ManagedResources["test_instance.explicit"].Provider,
    69  			wantFoo,
    70  		)
    71  	}
    72  	if !cfg.Module.ManagedResources["test_instance.implicit"].Provider.Equals(wantImplicit) {
    73  		t.Fatalf("wrong provider for \"test_instance.implicit\"\ngot:  %s\nwant: %s",
    74  			cfg.Module.ManagedResources["test_instance.implicit"].Provider,
    75  			wantImplicit,
    76  		)
    77  	}
    78  
    79  	// a data source
    80  	if !cfg.Module.DataResources["data.test_resource.explicit"].Provider.Equals(wantFoo) {
    81  		t.Fatalf("wrong provider for \"module.child.test_instance.explicit\"\ngot:  %s\nwant: %s",
    82  			cfg.Module.ManagedResources["test_instance.explicit"].Provider,
    83  			wantBar,
    84  		)
    85  	}
    86  
    87  	// child module
    88  	cm := cfg.Children["child"].Module
    89  	if !cm.ManagedResources["test_instance.explicit"].Provider.Equals(wantBar) {
    90  		t.Fatalf("wrong provider for \"module.child.test_instance.explicit\"\ngot:  %s\nwant: %s",
    91  			cfg.Module.ManagedResources["test_instance.explicit"].Provider,
    92  			wantBar,
    93  		)
    94  	}
    95  	if !cm.ManagedResources["test_instance.implicit"].Provider.Equals(wantImplicit) {
    96  		t.Fatalf("wrong provider for \"module.child.test_instance.implicit\"\ngot:  %s\nwant: %s",
    97  			cfg.Module.ManagedResources["test_instance.implicit"].Provider,
    98  			wantImplicit,
    99  		)
   100  	}
   101  }
   102  
   103  func TestProviderForLocalConfig(t *testing.T) {
   104  	mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
   105  	if diags.HasErrors() {
   106  		t.Fatal(diags.Error())
   107  	}
   108  	lc := addrs.LocalProviderConfig{LocalName: "foo-test"}
   109  	got := mod.ProviderForLocalConfig(lc)
   110  	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
   111  	if !got.Equals(want) {
   112  		t.Fatalf("wrong result! got %#v, want %#v\n", got, want)
   113  	}
   114  }
   115  
   116  // At most one required_providers block per module is permitted.
   117  func TestModule_required_providers_multiple(t *testing.T) {
   118  	_, diags := testModuleFromDir("testdata/invalid-modules/multiple-required-providers")
   119  	if !diags.HasErrors() {
   120  		t.Fatal("module should have error diags, but does not")
   121  	}
   122  
   123  	want := `Duplicate required providers configuration`
   124  	if got := diags.Error(); !strings.Contains(got, want) {
   125  		t.Fatalf("expected error to contain %q\nerror was:\n%s", want, got)
   126  	}
   127  }
   128  
   129  // A module may have required_providers configured in files loaded later than
   130  // resources. These provider settings should still be reflected in the
   131  // resources' configuration.
   132  func TestModule_required_providers_after_resource(t *testing.T) {
   133  	mod, diags := testModuleFromDir("testdata/valid-modules/required-providers-after-resource")
   134  	if diags.HasErrors() {
   135  		t.Fatal(diags.Error())
   136  	}
   137  
   138  	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
   139  
   140  	req, exists := mod.ProviderRequirements.RequiredProviders["test"]
   141  	if !exists {
   142  		t.Fatal("no provider requirements found for \"test\"")
   143  	}
   144  	if req.Type != want {
   145  		t.Errorf("wrong provider addr for \"test\"\ngot:  %s\nwant: %s",
   146  			req.Type, want,
   147  		)
   148  	}
   149  
   150  	if got := mod.ManagedResources["test_instance.my-instance"].Provider; !got.Equals(want) {
   151  		t.Errorf("wrong provider addr for \"test_instance.my-instance\"\ngot:  %s\nwant: %s",
   152  			got, want,
   153  		)
   154  	}
   155  }
   156  
   157  // We support overrides for required_providers blocks, which should replace the
   158  // entire block for each provider localname, leaving other blocks unaffected.
   159  // This should also be reflected in any resources in the module using this
   160  // provider.
   161  func TestModule_required_provider_overrides(t *testing.T) {
   162  	mod, diags := testModuleFromDir("testdata/valid-modules/required-providers-overrides")
   163  	if diags.HasErrors() {
   164  		t.Fatal(diags.Error())
   165  	}
   166  
   167  	// The foo provider and resource should be unaffected
   168  	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "foo")
   169  	req, exists := mod.ProviderRequirements.RequiredProviders["foo"]
   170  	if !exists {
   171  		t.Fatal("no provider requirements found for \"foo\"")
   172  	}
   173  	if req.Type != want {
   174  		t.Errorf("wrong provider addr for \"foo\"\ngot:  %s\nwant: %s",
   175  			req.Type, want,
   176  		)
   177  	}
   178  	if got := mod.ManagedResources["foo_thing.ft"].Provider; !got.Equals(want) {
   179  		t.Errorf("wrong provider addr for \"foo_thing.ft\"\ngot:  %s\nwant: %s",
   180  			got, want,
   181  		)
   182  	}
   183  
   184  	// The bar provider and resource should be using the override config
   185  	want = addrs.NewProvider(addrs.DefaultProviderRegistryHost, "blorp", "bar")
   186  	req, exists = mod.ProviderRequirements.RequiredProviders["bar"]
   187  	if !exists {
   188  		t.Fatal("no provider requirements found for \"bar\"")
   189  	}
   190  	if req.Type != want {
   191  		t.Errorf("wrong provider addr for \"bar\"\ngot:  %s\nwant: %s",
   192  			req.Type, want,
   193  		)
   194  	}
   195  	if gotVer, wantVer := req.Requirement.Required.String(), "~>2.0.0"; gotVer != wantVer {
   196  		t.Errorf("wrong provider version constraint for \"bar\"\ngot:  %s\nwant: %s",
   197  			gotVer, wantVer,
   198  		)
   199  	}
   200  	if got := mod.ManagedResources["bar_thing.bt"].Provider; !got.Equals(want) {
   201  		t.Errorf("wrong provider addr for \"bar_thing.bt\"\ngot:  %s\nwant: %s",
   202  			got, want,
   203  		)
   204  	}
   205  }
   206  
   207  // Resources without explicit provider configuration are assigned a provider
   208  // implied based on the resource type. For example, this resource:
   209  //
   210  //  resource foo_instance "test" { }
   211  //
   212  // is assigned a provider with type "foo".
   213  //
   214  // To find the correct provider, we first look in the module's provider
   215  // requirements map for a local name matching the resource type, and fall back
   216  // to a default provider if none is found. This applies to both managed and
   217  // data resources.
   218  func TestModule_implied_provider(t *testing.T) {
   219  	mod, diags := testModuleFromDir("testdata/valid-modules/implied-providers")
   220  	if diags.HasErrors() {
   221  		t.Fatal(diags.Error())
   222  	}
   223  
   224  	// The three providers used in the config resources
   225  	foo := addrs.NewProvider("registry.acme.corp", "acme", "foo")
   226  	whatever := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "something")
   227  	bar := addrs.NewDefaultProvider("bar")
   228  
   229  	// Verify that the registry.acme.corp/acme/foo provider is defined in the
   230  	// module provider requirements with local name "foo"
   231  	req, exists := mod.ProviderRequirements.RequiredProviders["foo"]
   232  	if !exists {
   233  		t.Fatal("no provider requirements found for \"foo\"")
   234  	}
   235  	if req.Type != foo {
   236  		t.Errorf("wrong provider addr for \"foo\"\ngot:  %s\nwant: %s",
   237  			req.Type, foo,
   238  		)
   239  	}
   240  
   241  	// Verify that the acme/something provider is defined in the
   242  	// module provider requirements with local name "whatever"
   243  	req, exists = mod.ProviderRequirements.RequiredProviders["whatever"]
   244  	if !exists {
   245  		t.Fatal("no provider requirements found for \"foo\"")
   246  	}
   247  	if req.Type != whatever {
   248  		t.Errorf("wrong provider addr for \"whatever\"\ngot:  %s\nwant: %s",
   249  			req.Type, whatever,
   250  		)
   251  	}
   252  
   253  	// Check that resources are assigned the correct providers: foo_* resources
   254  	// should have the custom foo provider, bar_* resources the default bar
   255  	// provider.
   256  	tests := []struct {
   257  		Address  string
   258  		Provider addrs.Provider
   259  	}{
   260  		{"foo_resource.a", foo},
   261  		{"data.foo_resource.b", foo},
   262  		{"bar_resource.c", bar},
   263  		{"data.bar_resource.d", bar},
   264  		{"whatever_resource.e", whatever},
   265  		{"data.whatever_resource.f", whatever},
   266  	}
   267  	for _, test := range tests {
   268  		resources := mod.ManagedResources
   269  		if strings.HasPrefix(test.Address, "data.") {
   270  			resources = mod.DataResources
   271  		}
   272  		resource, exists := resources[test.Address]
   273  		if !exists {
   274  			t.Errorf("could not find resource %q in %#v", test.Address, resources)
   275  			continue
   276  		}
   277  		if got := resource.Provider; !got.Equals(test.Provider) {
   278  			t.Errorf("wrong provider addr for %q\ngot:  %s\nwant: %s",
   279  				test.Address, got, test.Provider,
   280  			)
   281  		}
   282  	}
   283  }
   284  
   285  func TestImpliedProviderForUnqualifiedType(t *testing.T) {
   286  	mod, diags := testModuleFromDir("testdata/valid-modules/implied-providers")
   287  	if diags.HasErrors() {
   288  		t.Fatal(diags.Error())
   289  	}
   290  
   291  	foo := addrs.NewProvider("registry.acme.corp", "acme", "foo")
   292  	whatever := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "something")
   293  	bar := addrs.NewDefaultProvider("bar")
   294  	tf := addrs.NewBuiltInProvider("terraform")
   295  
   296  	tests := []struct {
   297  		Type     string
   298  		Provider addrs.Provider
   299  	}{
   300  		{"foo", foo},
   301  		{"whatever", whatever},
   302  		{"bar", bar},
   303  		{"terraform", tf},
   304  	}
   305  	for _, test := range tests {
   306  		got := mod.ImpliedProviderForUnqualifiedType(test.Type)
   307  		if !got.Equals(test.Provider) {
   308  			t.Errorf("wrong result for %q: got %#v, want %#v\n", test.Type, got, test.Provider)
   309  		}
   310  	}
   311  }