github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/configs/module_merge_test.go (about)

     1  package configs
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/hcl/v2/gohcl"
     9  	"github.com/hashicorp/terraform/internal/addrs"
    10  	"github.com/zclconf/go-cty/cty"
    11  )
    12  
    13  func TestModuleOverrideVariable(t *testing.T) {
    14  	mod, diags := testModuleFromDir("testdata/valid-modules/override-variable")
    15  	assertNoDiagnostics(t, diags)
    16  	if mod == nil {
    17  		t.Fatalf("module is nil")
    18  	}
    19  
    20  	got := mod.Variables
    21  	want := map[string]*Variable{
    22  		"fully_overridden": {
    23  			Name:           "fully_overridden",
    24  			Description:    "b_override description",
    25  			DescriptionSet: true,
    26  			Default:        cty.StringVal("b_override"),
    27  			Nullable:       false,
    28  			NullableSet:    true,
    29  			Type:           cty.String,
    30  			ConstraintType: cty.String,
    31  			ParsingMode:    VariableParseLiteral,
    32  			DeclRange: hcl.Range{
    33  				Filename: "testdata/valid-modules/override-variable/primary.tf",
    34  				Start: hcl.Pos{
    35  					Line:   1,
    36  					Column: 1,
    37  					Byte:   0,
    38  				},
    39  				End: hcl.Pos{
    40  					Line:   1,
    41  					Column: 28,
    42  					Byte:   27,
    43  				},
    44  			},
    45  		},
    46  		"partially_overridden": {
    47  			Name:           "partially_overridden",
    48  			Description:    "base description",
    49  			DescriptionSet: true,
    50  			Default:        cty.StringVal("b_override partial"),
    51  			Nullable:       true,
    52  			NullableSet:    false,
    53  			Type:           cty.String,
    54  			ConstraintType: cty.String,
    55  			ParsingMode:    VariableParseLiteral,
    56  			DeclRange: hcl.Range{
    57  				Filename: "testdata/valid-modules/override-variable/primary.tf",
    58  				Start: hcl.Pos{
    59  					Line:   7,
    60  					Column: 1,
    61  					Byte:   103,
    62  				},
    63  				End: hcl.Pos{
    64  					Line:   7,
    65  					Column: 32,
    66  					Byte:   134,
    67  				},
    68  			},
    69  		},
    70  	}
    71  	assertResultDeepEqual(t, got, want)
    72  }
    73  
    74  func TestModuleOverrideModule(t *testing.T) {
    75  	mod, diags := testModuleFromDir("testdata/valid-modules/override-module")
    76  	assertNoDiagnostics(t, diags)
    77  	if mod == nil {
    78  		t.Fatalf("module is nil")
    79  	}
    80  
    81  	if _, exists := mod.ModuleCalls["example"]; !exists {
    82  		t.Fatalf("no module 'example'")
    83  	}
    84  	if len(mod.ModuleCalls) != 1 {
    85  		t.Fatalf("wrong number of module calls in result %d; want 1", len(mod.ModuleCalls))
    86  	}
    87  
    88  	got := mod.ModuleCalls["example"]
    89  	want := &ModuleCall{
    90  		Name:          "example",
    91  		SourceAddr:    addrs.ModuleSourceLocal("./example2-a_override"),
    92  		SourceAddrRaw: "./example2-a_override",
    93  		SourceAddrRange: hcl.Range{
    94  			Filename: "testdata/valid-modules/override-module/a_override.tf",
    95  			Start: hcl.Pos{
    96  				Line:   3,
    97  				Column: 12,
    98  				Byte:   31,
    99  			},
   100  			End: hcl.Pos{
   101  				Line:   3,
   102  				Column: 35,
   103  				Byte:   54,
   104  			},
   105  		},
   106  		SourceSet: true,
   107  		DeclRange: hcl.Range{
   108  			Filename: "testdata/valid-modules/override-module/primary.tf",
   109  			Start: hcl.Pos{
   110  				Line:   2,
   111  				Column: 1,
   112  				Byte:   1,
   113  			},
   114  			End: hcl.Pos{
   115  				Line:   2,
   116  				Column: 17,
   117  				Byte:   17,
   118  			},
   119  		},
   120  		Providers: []PassedProviderConfig{
   121  			{
   122  				InChild: &ProviderConfigRef{
   123  					Name: "test",
   124  					NameRange: hcl.Range{
   125  						Filename: "testdata/valid-modules/override-module/b_override.tf",
   126  						Start:    hcl.Pos{Line: 7, Column: 5, Byte: 97},
   127  						End:      hcl.Pos{Line: 7, Column: 9, Byte: 101},
   128  					},
   129  				},
   130  				InParent: &ProviderConfigRef{
   131  					Name: "test",
   132  					NameRange: hcl.Range{
   133  						Filename: "testdata/valid-modules/override-module/b_override.tf",
   134  						Start:    hcl.Pos{Line: 7, Column: 12, Byte: 104},
   135  						End:      hcl.Pos{Line: 7, Column: 16, Byte: 108},
   136  					},
   137  					Alias: "b_override",
   138  					AliasRange: &hcl.Range{
   139  						Filename: "testdata/valid-modules/override-module/b_override.tf",
   140  						Start:    hcl.Pos{Line: 7, Column: 16, Byte: 108},
   141  						End:      hcl.Pos{Line: 7, Column: 27, Byte: 119},
   142  					},
   143  				},
   144  			},
   145  		},
   146  	}
   147  
   148  	// We're going to extract and nil out our hcl.Body here because DeepEqual
   149  	// is not a useful way to assert on that.
   150  	gotConfig := got.Config
   151  	got.Config = nil
   152  
   153  	assertResultDeepEqual(t, got, want)
   154  
   155  	type content struct {
   156  		Kept  *string `hcl:"kept"`
   157  		Foo   *string `hcl:"foo"`
   158  		New   *string `hcl:"new"`
   159  		Newer *string `hcl:"newer"`
   160  	}
   161  	var gotArgs content
   162  	diags = gohcl.DecodeBody(gotConfig, nil, &gotArgs)
   163  	assertNoDiagnostics(t, diags)
   164  
   165  	wantArgs := content{
   166  		Kept:  stringPtr("primary kept"),
   167  		Foo:   stringPtr("a_override foo"),
   168  		New:   stringPtr("b_override new"),
   169  		Newer: stringPtr("b_override newer"),
   170  	}
   171  
   172  	assertResultDeepEqual(t, gotArgs, wantArgs)
   173  }
   174  
   175  func TestModuleOverrideDynamic(t *testing.T) {
   176  	schema := &hcl.BodySchema{
   177  		Blocks: []hcl.BlockHeaderSchema{
   178  			{Type: "foo"},
   179  			{Type: "dynamic", LabelNames: []string{"type"}},
   180  		},
   181  	}
   182  
   183  	t.Run("base is dynamic", func(t *testing.T) {
   184  		mod, diags := testModuleFromDir("testdata/valid-modules/override-dynamic-block-base")
   185  		assertNoDiagnostics(t, diags)
   186  		if mod == nil {
   187  			t.Fatalf("module is nil")
   188  		}
   189  
   190  		if _, exists := mod.ManagedResources["test.foo"]; !exists {
   191  			t.Fatalf("no module 'example'")
   192  		}
   193  		if len(mod.ManagedResources) != 1 {
   194  			t.Fatalf("wrong number of managed resources in result %d; want 1", len(mod.ManagedResources))
   195  		}
   196  
   197  		body := mod.ManagedResources["test.foo"].Config
   198  		content, diags := body.Content(schema)
   199  		assertNoDiagnostics(t, diags)
   200  
   201  		if len(content.Blocks) != 1 {
   202  			t.Fatalf("wrong number of blocks in result %d; want 1", len(content.Blocks))
   203  		}
   204  		if got, want := content.Blocks[0].Type, "foo"; got != want {
   205  			t.Fatalf("wrong block type %q; want %q", got, want)
   206  		}
   207  	})
   208  	t.Run("override is dynamic", func(t *testing.T) {
   209  		mod, diags := testModuleFromDir("testdata/valid-modules/override-dynamic-block-override")
   210  		assertNoDiagnostics(t, diags)
   211  		if mod == nil {
   212  			t.Fatalf("module is nil")
   213  		}
   214  
   215  		if _, exists := mod.ManagedResources["test.foo"]; !exists {
   216  			t.Fatalf("no module 'example'")
   217  		}
   218  		if len(mod.ManagedResources) != 1 {
   219  			t.Fatalf("wrong number of managed resources in result %d; want 1", len(mod.ManagedResources))
   220  		}
   221  
   222  		body := mod.ManagedResources["test.foo"].Config
   223  		content, diags := body.Content(schema)
   224  		assertNoDiagnostics(t, diags)
   225  
   226  		if len(content.Blocks) != 1 {
   227  			t.Fatalf("wrong number of blocks in result %d; want 1", len(content.Blocks))
   228  		}
   229  		if got, want := content.Blocks[0].Type, "dynamic"; got != want {
   230  			t.Fatalf("wrong block type %q; want %q", got, want)
   231  		}
   232  		if got, want := content.Blocks[0].Labels[0], "foo"; got != want {
   233  			t.Fatalf("wrong dynamic block label %q; want %q", got, want)
   234  		}
   235  	})
   236  }
   237  
   238  func TestModuleOverrideSensitiveVariable(t *testing.T) {
   239  	type testCase struct {
   240  		sensitive    bool
   241  		sensitiveSet bool
   242  	}
   243  	cases := map[string]testCase{
   244  		"false_true": {
   245  			sensitive:    true,
   246  			sensitiveSet: true,
   247  		},
   248  		"true_false": {
   249  			sensitive:    false,
   250  			sensitiveSet: true,
   251  		},
   252  		"false_false_true": {
   253  			sensitive:    true,
   254  			sensitiveSet: true,
   255  		},
   256  		"true_true_false": {
   257  			sensitive:    false,
   258  			sensitiveSet: true,
   259  		},
   260  		"false_true_false": {
   261  			sensitive:    false,
   262  			sensitiveSet: true,
   263  		},
   264  		"true_false_true": {
   265  			sensitive:    true,
   266  			sensitiveSet: true,
   267  		},
   268  	}
   269  
   270  	mod, diags := testModuleFromDir("testdata/valid-modules/override-variable-sensitive")
   271  
   272  	assertNoDiagnostics(t, diags)
   273  
   274  	if mod == nil {
   275  		t.Fatalf("module is nil")
   276  	}
   277  
   278  	got := mod.Variables
   279  
   280  	for v, want := range cases {
   281  		t.Run(fmt.Sprintf("variable %s", v), func(t *testing.T) {
   282  			if got[v].Sensitive != want.sensitive {
   283  				t.Errorf("wrong result for sensitive\ngot: %t want: %t", got[v].Sensitive, want.sensitive)
   284  			}
   285  
   286  			if got[v].SensitiveSet != want.sensitiveSet {
   287  				t.Errorf("wrong result for sensitive set\ngot: %t want: %t", got[v].Sensitive, want.sensitive)
   288  			}
   289  		})
   290  	}
   291  }
   292  
   293  func TestModuleOverrideResourceFQNs(t *testing.T) {
   294  	mod, diags := testModuleFromDir("testdata/valid-modules/override-resource-provider")
   295  	assertNoDiagnostics(t, diags)
   296  
   297  	got := mod.ManagedResources["test_instance.explicit"]
   298  	wantProvider := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "bar", "test")
   299  	wantProviderCfg := &ProviderConfigRef{
   300  		Name: "bar-test",
   301  		NameRange: hcl.Range{
   302  			Filename: "testdata/valid-modules/override-resource-provider/a_override.tf",
   303  			Start:    hcl.Pos{Line: 2, Column: 14, Byte: 51},
   304  			End:      hcl.Pos{Line: 2, Column: 22, Byte: 59},
   305  		},
   306  	}
   307  
   308  	if !got.Provider.Equals(wantProvider) {
   309  		t.Fatalf("wrong provider %s, want %s", got.Provider, wantProvider)
   310  	}
   311  	assertResultDeepEqual(t, got.ProviderConfigRef, wantProviderCfg)
   312  
   313  	// now verify that a resource with no provider config falls back to default
   314  	got = mod.ManagedResources["test_instance.default"]
   315  	wantProvider = addrs.NewDefaultProvider("test")
   316  	if !got.Provider.Equals(wantProvider) {
   317  		t.Fatalf("wrong provider %s, want %s", got.Provider, wantProvider)
   318  	}
   319  	if got.ProviderConfigRef != nil {
   320  		t.Fatalf("wrong result: found provider config ref %s, expected nil", got.ProviderConfigRef)
   321  	}
   322  }
   323  
   324  func TestModuleOverrideIgnoreAllChanges(t *testing.T) {
   325  	mod, diags := testModuleFromDir("testdata/valid-modules/override-ignore-changes")
   326  	assertNoDiagnostics(t, diags)
   327  
   328  	r := mod.ManagedResources["test_instance.foo"]
   329  	if !r.Managed.IgnoreAllChanges {
   330  		t.Fatalf("wrong result: expected r.Managed.IgnoreAllChanges to be true")
   331  	}
   332  }