github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/configs/module_merge_test.go (about)

     1  package configs
     2  
     3  import (
     4  	"testing"
     5  
     6  	version "github.com/hashicorp/go-version"
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/hcl/v2/gohcl"
     9  	"github.com/hashicorp/terraform/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  			Type:           cty.String,
    28  			ParsingMode:    VariableParseLiteral,
    29  			DeclRange: hcl.Range{
    30  				Filename: "testdata/valid-modules/override-variable/primary.tf",
    31  				Start: hcl.Pos{
    32  					Line:   1,
    33  					Column: 1,
    34  					Byte:   0,
    35  				},
    36  				End: hcl.Pos{
    37  					Line:   1,
    38  					Column: 28,
    39  					Byte:   27,
    40  				},
    41  			},
    42  		},
    43  		"partially_overridden": {
    44  			Name:           "partially_overridden",
    45  			Description:    "base description",
    46  			DescriptionSet: true,
    47  			Default:        cty.StringVal("b_override partial"),
    48  			Type:           cty.String,
    49  			ParsingMode:    VariableParseLiteral,
    50  			DeclRange: hcl.Range{
    51  				Filename: "testdata/valid-modules/override-variable/primary.tf",
    52  				Start: hcl.Pos{
    53  					Line:   7,
    54  					Column: 1,
    55  					Byte:   103,
    56  				},
    57  				End: hcl.Pos{
    58  					Line:   7,
    59  					Column: 32,
    60  					Byte:   134,
    61  				},
    62  			},
    63  		},
    64  	}
    65  	assertResultDeepEqual(t, got, want)
    66  }
    67  
    68  func TestModuleOverrideModule(t *testing.T) {
    69  	mod, diags := testModuleFromDir("testdata/valid-modules/override-module")
    70  	assertNoDiagnostics(t, diags)
    71  	if mod == nil {
    72  		t.Fatalf("module is nil")
    73  	}
    74  
    75  	if _, exists := mod.ModuleCalls["example"]; !exists {
    76  		t.Fatalf("no module 'example'")
    77  	}
    78  	if len(mod.ModuleCalls) != 1 {
    79  		t.Fatalf("wrong number of module calls in result %d; want 1", len(mod.ModuleCalls))
    80  	}
    81  
    82  	got := mod.ModuleCalls["example"]
    83  	want := &ModuleCall{
    84  		Name:       "example",
    85  		SourceAddr: "./example2-a_override",
    86  		SourceAddrRange: hcl.Range{
    87  			Filename: "testdata/valid-modules/override-module/a_override.tf",
    88  			Start: hcl.Pos{
    89  				Line:   3,
    90  				Column: 12,
    91  				Byte:   31,
    92  			},
    93  			End: hcl.Pos{
    94  				Line:   3,
    95  				Column: 35,
    96  				Byte:   54,
    97  			},
    98  		},
    99  		SourceSet: true,
   100  		DeclRange: hcl.Range{
   101  			Filename: "testdata/valid-modules/override-module/primary.tf",
   102  			Start: hcl.Pos{
   103  				Line:   2,
   104  				Column: 1,
   105  				Byte:   1,
   106  			},
   107  			End: hcl.Pos{
   108  				Line:   2,
   109  				Column: 17,
   110  				Byte:   17,
   111  			},
   112  		},
   113  	}
   114  
   115  	// We're going to extract and nil out our hcl.Body here because DeepEqual
   116  	// is not a useful way to assert on that.
   117  	gotConfig := got.Config
   118  	got.Config = nil
   119  
   120  	assertResultDeepEqual(t, got, want)
   121  
   122  	type content struct {
   123  		Kept  *string `hcl:"kept"`
   124  		Foo   *string `hcl:"foo"`
   125  		New   *string `hcl:"new"`
   126  		Newer *string `hcl:"newer"`
   127  	}
   128  	var gotArgs content
   129  	diags = gohcl.DecodeBody(gotConfig, nil, &gotArgs)
   130  	assertNoDiagnostics(t, diags)
   131  
   132  	wantArgs := content{
   133  		Kept:  stringPtr("primary kept"),
   134  		Foo:   stringPtr("a_override foo"),
   135  		New:   stringPtr("b_override new"),
   136  		Newer: stringPtr("b_override newer"),
   137  	}
   138  
   139  	assertResultDeepEqual(t, gotArgs, wantArgs)
   140  }
   141  
   142  func TestModuleOverrideDynamic(t *testing.T) {
   143  	schema := &hcl.BodySchema{
   144  		Blocks: []hcl.BlockHeaderSchema{
   145  			{Type: "foo"},
   146  			{Type: "dynamic", LabelNames: []string{"type"}},
   147  		},
   148  	}
   149  
   150  	t.Run("base is dynamic", func(t *testing.T) {
   151  		mod, diags := testModuleFromDir("testdata/valid-modules/override-dynamic-block-base")
   152  		assertNoDiagnostics(t, diags)
   153  		if mod == nil {
   154  			t.Fatalf("module is nil")
   155  		}
   156  
   157  		if _, exists := mod.ManagedResources["test.foo"]; !exists {
   158  			t.Fatalf("no module 'example'")
   159  		}
   160  		if len(mod.ManagedResources) != 1 {
   161  			t.Fatalf("wrong number of managed resources in result %d; want 1", len(mod.ManagedResources))
   162  		}
   163  
   164  		body := mod.ManagedResources["test.foo"].Config
   165  		content, diags := body.Content(schema)
   166  		assertNoDiagnostics(t, diags)
   167  
   168  		if len(content.Blocks) != 1 {
   169  			t.Fatalf("wrong number of blocks in result %d; want 1", len(content.Blocks))
   170  		}
   171  		if got, want := content.Blocks[0].Type, "foo"; got != want {
   172  			t.Fatalf("wrong block type %q; want %q", got, want)
   173  		}
   174  	})
   175  	t.Run("override is dynamic", func(t *testing.T) {
   176  		mod, diags := testModuleFromDir("testdata/valid-modules/override-dynamic-block-override")
   177  		assertNoDiagnostics(t, diags)
   178  		if mod == nil {
   179  			t.Fatalf("module is nil")
   180  		}
   181  
   182  		if _, exists := mod.ManagedResources["test.foo"]; !exists {
   183  			t.Fatalf("no module 'example'")
   184  		}
   185  		if len(mod.ManagedResources) != 1 {
   186  			t.Fatalf("wrong number of managed resources in result %d; want 1", len(mod.ManagedResources))
   187  		}
   188  
   189  		body := mod.ManagedResources["test.foo"].Config
   190  		content, diags := body.Content(schema)
   191  		assertNoDiagnostics(t, diags)
   192  
   193  		if len(content.Blocks) != 1 {
   194  			t.Fatalf("wrong number of blocks in result %d; want 1", len(content.Blocks))
   195  		}
   196  		if got, want := content.Blocks[0].Type, "dynamic"; got != want {
   197  			t.Fatalf("wrong block type %q; want %q", got, want)
   198  		}
   199  		if got, want := content.Blocks[0].Labels[0], "foo"; got != want {
   200  			t.Fatalf("wrong dynamic block label %q; want %q", got, want)
   201  		}
   202  	})
   203  }
   204  
   205  func TestMergeProviderVersionConstraints(t *testing.T) {
   206  	v1, _ := version.NewConstraint("1.0.0")
   207  	vc1 := VersionConstraint{
   208  		Required: v1,
   209  	}
   210  	v2, _ := version.NewConstraint("2.0.0")
   211  	vc2 := VersionConstraint{
   212  		Required: v2,
   213  	}
   214  
   215  	tests := map[string]struct {
   216  		Input    map[string]ProviderRequirements
   217  		Override []*RequiredProvider
   218  		Want     map[string]ProviderRequirements
   219  	}{
   220  		"basic merge": {
   221  			map[string]ProviderRequirements{
   222  				"random": ProviderRequirements{
   223  					Type:               addrs.Provider{Type: "random"},
   224  					VersionConstraints: []VersionConstraint{},
   225  				},
   226  			},
   227  			[]*RequiredProvider{
   228  				&RequiredProvider{
   229  					Name:        "null",
   230  					Requirement: VersionConstraint{},
   231  				},
   232  			},
   233  			map[string]ProviderRequirements{
   234  				"random": ProviderRequirements{
   235  					Type:               addrs.Provider{Type: "random"},
   236  					VersionConstraints: []VersionConstraint{},
   237  				},
   238  				"null": ProviderRequirements{
   239  					Type: addrs.NewLegacyProvider("null"),
   240  					VersionConstraints: []VersionConstraint{
   241  						VersionConstraint{
   242  							Required:  version.Constraints(nil),
   243  							DeclRange: hcl.Range{},
   244  						},
   245  					},
   246  				},
   247  			},
   248  		},
   249  		"override version constraint": {
   250  			map[string]ProviderRequirements{
   251  				"random": ProviderRequirements{
   252  					Type:               addrs.Provider{Type: "random"},
   253  					VersionConstraints: []VersionConstraint{vc1},
   254  				},
   255  			},
   256  			[]*RequiredProvider{
   257  				&RequiredProvider{
   258  					Name:        "random",
   259  					Requirement: vc2,
   260  				},
   261  			},
   262  			map[string]ProviderRequirements{
   263  				"random": ProviderRequirements{
   264  					Type:               addrs.NewLegacyProvider("random"),
   265  					VersionConstraints: []VersionConstraint{vc2},
   266  				},
   267  			},
   268  		},
   269  	}
   270  
   271  	for name, test := range tests {
   272  		t.Run(name, func(t *testing.T) {
   273  			mergeProviderVersionConstraints(test.Input, test.Override)
   274  			assertResultDeepEqual(t, test.Input, test.Want)
   275  		})
   276  	}
   277  }