github.com/opentofu/opentofu@v1.7.1/internal/encryption/config/config_merge_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package config 7 8 import ( 9 "reflect" 10 "testing" 11 12 "github.com/davecgh/go-spew/spew" 13 "github.com/hashicorp/hcl/v2" 14 "github.com/hashicorp/hcl/v2/hcltest" 15 "github.com/opentofu/opentofu/internal/configs/hcl2shim" 16 "github.com/zclconf/go-cty/cty" 17 ) 18 19 func TestMergeMethodConfigs(t *testing.T) { 20 makeMethodConfig := func(typeName, name, key, value string) MethodConfig { 21 return MethodConfig{ 22 Type: typeName, 23 Name: name, 24 Body: hcl2shim.SynthBody("method", map[string]cty.Value{ 25 key: cty.StringVal(value), 26 }), 27 } 28 } 29 30 schema := &hcl.BodySchema{Attributes: []hcl.AttributeSchema{{Name: "key"}}} 31 32 tests := []struct { 33 name string 34 configSchema *hcl.BodySchema 35 input []MethodConfig 36 override []MethodConfig 37 expected []MethodConfig 38 }{ 39 { 40 name: "empty", 41 configSchema: nil, 42 input: []MethodConfig{}, 43 override: []MethodConfig{}, 44 expected: []MethodConfig{}, 45 }, 46 { 47 name: "override one method config body", 48 configSchema: schema, 49 input: []MethodConfig{ 50 makeMethodConfig("type", "name", "key", "value"), 51 }, 52 override: []MethodConfig{ 53 makeMethodConfig("type", "name", "key", "override"), 54 }, 55 expected: []MethodConfig{ 56 makeMethodConfig("type", "name", "key", "override"), 57 }, 58 }, 59 { 60 name: "initial config is empty", 61 configSchema: schema, 62 input: []MethodConfig{}, 63 override: []MethodConfig{ 64 makeMethodConfig("type", "name", "key", "override"), 65 }, 66 expected: []MethodConfig{ 67 makeMethodConfig("type", "name", "key", "override"), 68 }, 69 }, 70 { 71 name: "override multiple method configs", 72 configSchema: schema, 73 input: []MethodConfig{ 74 makeMethodConfig("type", "name", "key", "value"), 75 makeMethodConfig("type", "name2", "key", "value"), 76 makeMethodConfig("type", "name3", "key", "value"), 77 }, 78 override: []MethodConfig{ 79 makeMethodConfig("type", "name", "key", "override1"), 80 makeMethodConfig("type", "name2", "key", "override2"), 81 }, 82 expected: []MethodConfig{ 83 makeMethodConfig("type", "name", "key", "override1"), 84 makeMethodConfig("type", "name2", "key", "override2"), 85 makeMethodConfig("type", "name3", "key", "value"), 86 }, 87 }, 88 { 89 name: "override config is empty", 90 configSchema: schema, 91 input: []MethodConfig{ 92 makeMethodConfig("type", "name", "key", "value"), 93 }, 94 override: []MethodConfig{}, 95 expected: []MethodConfig{ 96 makeMethodConfig("type", "name", "key", "value"), 97 }, 98 }, 99 } 100 101 for _, test := range tests { 102 t.Run(test.name, func(t *testing.T) { 103 output := mergeMethodConfigs(test.input, test.override) 104 105 // for each of the expected methods, check if it exists in the output 106 for _, expectedMethod := range test.expected { 107 found := false 108 for _, method := range output { 109 if method.Type == expectedMethod.Type && method.Name == expectedMethod.Name { 110 found = true 111 expectedContent, _ := expectedMethod.Body.Content(test.configSchema) 112 actualContent, diags := method.Body.Content(test.configSchema) 113 if diags.HasErrors() { 114 t.Fatalf("unexpected diagnostics: %v", diags) 115 } 116 // Only compare the attributes here, so that we don't look at things like the MissingItemRange on the hcl.Body 117 if !reflect.DeepEqual(expectedContent.Attributes, actualContent.Attributes) { 118 t.Errorf("expected %v, got %v", spew.Sdump(expectedContent.Attributes), spew.Sdump(actualContent.Attributes)) 119 } 120 } 121 } 122 if !found { 123 t.Errorf("expected method %v not found in output", spew.Sdump(expectedMethod)) 124 } 125 } 126 }) 127 } 128 } 129 130 func TestMergeKeyProviderConfigs(t *testing.T) { 131 makeKeyProviderConfig := func(typeName, name, key, value string) KeyProviderConfig { 132 return KeyProviderConfig{ 133 Type: typeName, 134 Name: name, 135 Body: hcl2shim.SynthBody("key_provider", map[string]cty.Value{ 136 key: cty.StringVal(value), 137 }), 138 } 139 } 140 141 schema := &hcl.BodySchema{Attributes: []hcl.AttributeSchema{{Name: "key"}}} 142 143 tests := []struct { 144 name string 145 configSchema *hcl.BodySchema 146 input []KeyProviderConfig 147 override []KeyProviderConfig 148 expected []KeyProviderConfig 149 }{ 150 { 151 name: "empty", 152 configSchema: nil, 153 input: []KeyProviderConfig{}, 154 override: []KeyProviderConfig{}, 155 expected: []KeyProviderConfig{}, 156 }, 157 { 158 name: "override one key provider config body", 159 configSchema: schema, 160 input: []KeyProviderConfig{ 161 makeKeyProviderConfig("type", "name", "key", "value"), 162 }, 163 override: []KeyProviderConfig{ 164 makeKeyProviderConfig("type", "name", "key", "override"), 165 }, 166 expected: []KeyProviderConfig{ 167 makeKeyProviderConfig("type", "name", "key", "override"), 168 }, 169 }, 170 { 171 name: "initial config is empty", 172 configSchema: schema, 173 input: []KeyProviderConfig{}, 174 override: []KeyProviderConfig{ 175 makeKeyProviderConfig("type", "name", "key", "override"), 176 }, 177 expected: []KeyProviderConfig{ 178 makeKeyProviderConfig("type", "name", "key", "override"), 179 }, 180 }, 181 { 182 name: "override multiple key provider configs", 183 configSchema: schema, 184 input: []KeyProviderConfig{ 185 makeKeyProviderConfig("type", "name", "key", "value"), 186 makeKeyProviderConfig("type", "name2", "key", "value"), 187 }, 188 override: []KeyProviderConfig{ 189 makeKeyProviderConfig("type", "name", "key", "override1"), 190 makeKeyProviderConfig("type", "name2", "key", "override2"), 191 }, 192 expected: []KeyProviderConfig{ 193 makeKeyProviderConfig("type", "name", "key", "override1"), 194 makeKeyProviderConfig("type", "name2", "key", "override2"), 195 }, 196 }, 197 { 198 name: "override config is empty", 199 configSchema: schema, 200 input: []KeyProviderConfig{ 201 makeKeyProviderConfig("type", "name", "key", "value"), 202 }, 203 override: []KeyProviderConfig{}, 204 expected: []KeyProviderConfig{ 205 makeKeyProviderConfig("type", "name", "key", "value"), 206 }, 207 }, 208 } 209 210 for _, test := range tests { 211 t.Run(test.name, func(t *testing.T) { 212 output := mergeKeyProviderConfigs(test.input, test.override) 213 214 // for each of the expected key providers, check if it exists in the output 215 for _, expectedKeyProvider := range test.expected { 216 found := false 217 for _, keyProvider := range output { 218 if keyProvider.Type == expectedKeyProvider.Type && keyProvider.Name == expectedKeyProvider.Name { 219 found = true 220 expectedContent, _ := expectedKeyProvider.Body.Content(test.configSchema) 221 actualContent, diags := keyProvider.Body.Content(test.configSchema) 222 if diags.HasErrors() { 223 t.Fatalf("unexpected diagnostics: %v", diags) 224 } 225 // Only compare the attributes here, so that we don't look at things like the MissingItemRange on the hcl.Body 226 if !reflect.DeepEqual(expectedContent.Attributes, actualContent.Attributes) { 227 t.Errorf("expected %v, got %v", spew.Sdump(expectedContent.Attributes), spew.Sdump(actualContent.Attributes)) 228 } 229 } 230 } 231 if !found { 232 t.Errorf("expected key provider %v not found in output", spew.Sdump(expectedKeyProvider)) 233 } 234 } 235 }) 236 } 237 } 238 239 func TestMergeTargetConfigs(t *testing.T) { 240 makeTargetConfig := func(enforced bool, method hcl.Expression, fallback *TargetConfig) *TargetConfig { 241 return &TargetConfig{ 242 Method: method, 243 Fallback: fallback, 244 } 245 } 246 247 makeEnforcableTargetConfig := func(enforced bool, method hcl.Expression, fallback *TargetConfig) *EnforcableTargetConfig { 248 return &EnforcableTargetConfig{ 249 Enforced: enforced, 250 Method: method, 251 Fallback: fallback, 252 } 253 } 254 255 expressionOne := hcltest.MockExprLiteral(cty.UnknownVal(cty.Set(cty.String))) 256 expressionTwo := hcltest.MockExprLiteral(cty.UnknownVal(cty.Set(cty.Bool))) 257 258 tests := []struct { 259 name string 260 input *EnforcableTargetConfig 261 override *EnforcableTargetConfig 262 expected *EnforcableTargetConfig 263 }{ 264 { 265 name: "both nil", 266 input: nil, 267 override: nil, 268 expected: nil, 269 }, 270 { 271 name: "input is nil", 272 input: nil, 273 override: makeEnforcableTargetConfig(true, expressionOne, nil), 274 expected: makeEnforcableTargetConfig(true, expressionOne, nil), 275 }, 276 { 277 name: "override is nil", 278 input: makeEnforcableTargetConfig(true, expressionOne, nil), 279 override: nil, 280 expected: makeEnforcableTargetConfig(true, expressionOne, nil), 281 }, 282 { 283 name: "override target config method", 284 input: makeEnforcableTargetConfig(true, expressionOne, nil), 285 override: makeEnforcableTargetConfig(true, expressionTwo, nil), 286 expected: makeEnforcableTargetConfig(true, expressionTwo, nil), 287 }, 288 { 289 name: "override target config fallback", 290 input: makeEnforcableTargetConfig(true, expressionOne, makeTargetConfig(true, expressionOne, nil)), 291 override: makeEnforcableTargetConfig(true, expressionOne, makeTargetConfig(true, expressionTwo, nil)), 292 expected: makeEnforcableTargetConfig(true, expressionOne, makeTargetConfig(true, expressionTwo, nil)), 293 }, 294 { 295 name: "override target config fallback", 296 input: makeEnforcableTargetConfig(true, expressionOne, nil), 297 override: makeEnforcableTargetConfig(true, expressionOne, makeTargetConfig(true, expressionTwo, nil)), 298 expected: makeEnforcableTargetConfig(true, expressionOne, makeTargetConfig(true, expressionTwo, nil)), 299 }, 300 { 301 name: "override target config enforced - should be true if any are true", 302 input: makeEnforcableTargetConfig(true, expressionOne, nil), 303 override: makeEnforcableTargetConfig(false, expressionOne, nil), 304 expected: makeEnforcableTargetConfig(true, expressionOne, nil), 305 }, 306 { 307 name: "override target config enforced - should be true if any are true", 308 input: makeEnforcableTargetConfig(false, expressionOne, nil), 309 override: makeEnforcableTargetConfig(true, expressionOne, nil), 310 expected: makeEnforcableTargetConfig(true, expressionOne, nil), 311 }, 312 { 313 name: "override target config enforced - should be false if both are false", 314 input: makeEnforcableTargetConfig(false, expressionOne, nil), 315 override: makeEnforcableTargetConfig(false, expressionOne, nil), 316 expected: makeEnforcableTargetConfig(false, expressionOne, nil), 317 }, 318 { 319 name: "override enforced, method and fallback", 320 input: makeEnforcableTargetConfig(false, expressionOne, makeTargetConfig(true, expressionOne, nil)), 321 override: makeEnforcableTargetConfig(true, expressionTwo, makeTargetConfig(true, expressionTwo, nil)), 322 expected: makeEnforcableTargetConfig(true, expressionTwo, makeTargetConfig(true, expressionTwo, nil)), 323 }, 324 } 325 326 for _, test := range tests { 327 t.Run(test.name, func(t *testing.T) { 328 output := mergeEnforcableTargetConfigs(test.input, test.override) 329 330 if !reflect.DeepEqual(output, test.expected) { 331 t.Errorf("expected %v, got %v", spew.Sdump(test.expected), spew.Sdump(output)) 332 } 333 }) 334 } 335 }