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  }