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 }