github.com/kevinklinger/open_terraform@v1.3.6/noninternal/configs/provider_requirements_test.go (about)

     1  package configs
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/go-cmp/cmp"
     7  	"github.com/google/go-cmp/cmp/cmpopts"
     8  	version "github.com/hashicorp/go-version"
     9  	"github.com/hashicorp/hcl/v2"
    10  	"github.com/hashicorp/hcl/v2/hcltest"
    11  	"github.com/kevinklinger/open_terraform/noninternal/addrs"
    12  	"github.com/zclconf/go-cty/cty"
    13  )
    14  
    15  var (
    16  	ignoreUnexported = cmpopts.IgnoreUnexported(version.Constraint{})
    17  	comparer         = cmp.Comparer(func(x, y RequiredProvider) bool {
    18  		if x.Name != y.Name {
    19  			return false
    20  		}
    21  		if x.Type != y.Type {
    22  			return false
    23  		}
    24  		if x.Source != y.Source {
    25  			return false
    26  		}
    27  		if x.Requirement.Required.String() != y.Requirement.Required.String() {
    28  			return false
    29  		}
    30  		if x.DeclRange != y.DeclRange {
    31  			return false
    32  		}
    33  		return true
    34  	})
    35  	blockRange = hcl.Range{
    36  		Filename: "mock.tf",
    37  		Start:    hcl.Pos{Line: 3, Column: 12, Byte: 27},
    38  		End:      hcl.Pos{Line: 3, Column: 19, Byte: 34},
    39  	}
    40  	mockRange = hcl.Range{
    41  		Filename: "MockExprLiteral",
    42  	}
    43  )
    44  
    45  func TestDecodeRequiredProvidersBlock(t *testing.T) {
    46  	tests := map[string]struct {
    47  		Block *hcl.Block
    48  		Want  *RequiredProviders
    49  		Error string
    50  	}{
    51  		"legacy": {
    52  			Block: &hcl.Block{
    53  				Type: "required_providers",
    54  				Body: hcltest.MockBody(&hcl.BodyContent{
    55  					Attributes: hcl.Attributes{
    56  						"default": {
    57  							Name: "default",
    58  							Expr: hcltest.MockExprLiteral(cty.StringVal("1.0.0")),
    59  						},
    60  					},
    61  				}),
    62  				DefRange: blockRange,
    63  			},
    64  			Want: &RequiredProviders{
    65  				RequiredProviders: map[string]*RequiredProvider{
    66  					"default": {
    67  						Name:        "default",
    68  						Type:        addrs.NewDefaultProvider("default"),
    69  						Requirement: testVC("1.0.0"),
    70  						DeclRange:   mockRange,
    71  					},
    72  				},
    73  				DeclRange: blockRange,
    74  			},
    75  		},
    76  		"provider source": {
    77  			Block: &hcl.Block{
    78  				Type: "required_providers",
    79  				Body: hcltest.MockBody(&hcl.BodyContent{
    80  					Attributes: hcl.Attributes{
    81  						"my-test": {
    82  							Name: "my-test",
    83  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
    84  								"source":  cty.StringVal("mycloud/test"),
    85  								"version": cty.StringVal("2.0.0"),
    86  							})),
    87  						},
    88  					},
    89  				}),
    90  				DefRange: blockRange,
    91  			},
    92  			Want: &RequiredProviders{
    93  				RequiredProviders: map[string]*RequiredProvider{
    94  					"my-test": {
    95  						Name:        "my-test",
    96  						Source:      "mycloud/test",
    97  						Type:        addrs.NewProvider(addrs.DefaultProviderRegistryHost, "mycloud", "test"),
    98  						Requirement: testVC("2.0.0"),
    99  						DeclRange:   mockRange,
   100  					},
   101  				},
   102  				DeclRange: blockRange,
   103  			},
   104  		},
   105  		"mixed": {
   106  			Block: &hcl.Block{
   107  				Type: "required_providers",
   108  				Body: hcltest.MockBody(&hcl.BodyContent{
   109  					Attributes: hcl.Attributes{
   110  						"legacy": {
   111  							Name: "legacy",
   112  							Expr: hcltest.MockExprLiteral(cty.StringVal("1.0.0")),
   113  						},
   114  						"my-test": {
   115  							Name: "my-test",
   116  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   117  								"source":  cty.StringVal("mycloud/test"),
   118  								"version": cty.StringVal("2.0.0"),
   119  							})),
   120  						},
   121  					},
   122  				}),
   123  				DefRange: blockRange,
   124  			},
   125  			Want: &RequiredProviders{
   126  				RequiredProviders: map[string]*RequiredProvider{
   127  					"legacy": {
   128  						Name:        "legacy",
   129  						Type:        addrs.NewDefaultProvider("legacy"),
   130  						Requirement: testVC("1.0.0"),
   131  						DeclRange:   mockRange,
   132  					},
   133  					"my-test": {
   134  						Name:        "my-test",
   135  						Source:      "mycloud/test",
   136  						Type:        addrs.NewProvider(addrs.DefaultProviderRegistryHost, "mycloud", "test"),
   137  						Requirement: testVC("2.0.0"),
   138  						DeclRange:   mockRange,
   139  					},
   140  				},
   141  				DeclRange: blockRange,
   142  			},
   143  		},
   144  		"version-only block": {
   145  			Block: &hcl.Block{
   146  				Type: "required_providers",
   147  				Body: hcltest.MockBody(&hcl.BodyContent{
   148  					Attributes: hcl.Attributes{
   149  						"test": {
   150  							Name: "test",
   151  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   152  								"version": cty.StringVal("~>2.0.0"),
   153  							})),
   154  						},
   155  					},
   156  				}),
   157  				DefRange: blockRange,
   158  			},
   159  			Want: &RequiredProviders{
   160  				RequiredProviders: map[string]*RequiredProvider{
   161  					"test": {
   162  						Name:        "test",
   163  						Type:        addrs.NewDefaultProvider("test"),
   164  						Requirement: testVC("~>2.0.0"),
   165  						DeclRange:   mockRange,
   166  					},
   167  				},
   168  				DeclRange: blockRange,
   169  			},
   170  		},
   171  		"invalid source": {
   172  			Block: &hcl.Block{
   173  				Type: "required_providers",
   174  				Body: hcltest.MockBody(&hcl.BodyContent{
   175  					Attributes: hcl.Attributes{
   176  						"my-test": {
   177  							Name: "my-test",
   178  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   179  								"source":  cty.StringVal("some/invalid/provider/source/test"),
   180  								"version": cty.StringVal("~>2.0.0"),
   181  							})),
   182  						},
   183  					},
   184  				}),
   185  				DefRange: blockRange,
   186  			},
   187  			Want: &RequiredProviders{
   188  				RequiredProviders: map[string]*RequiredProvider{},
   189  				DeclRange:         blockRange,
   190  			},
   191  			Error: "Invalid provider source string",
   192  		},
   193  		"invalid localname": {
   194  			Block: &hcl.Block{
   195  				Type: "required_providers",
   196  				Body: hcltest.MockBody(&hcl.BodyContent{
   197  					Attributes: hcl.Attributes{
   198  						"my_test": {
   199  							Name: "my_test",
   200  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   201  								"version": cty.StringVal("~>2.0.0"),
   202  							})),
   203  						},
   204  					},
   205  				}),
   206  				DefRange: blockRange,
   207  			},
   208  			Want: &RequiredProviders{
   209  				RequiredProviders: map[string]*RequiredProvider{},
   210  				DeclRange:         blockRange,
   211  			},
   212  			Error: "Invalid provider local name",
   213  		},
   214  		"invalid localname caps": {
   215  			Block: &hcl.Block{
   216  				Type: "required_providers",
   217  				Body: hcltest.MockBody(&hcl.BodyContent{
   218  					Attributes: hcl.Attributes{
   219  						"MYTEST": {
   220  							Name: "MYTEST",
   221  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   222  								"version": cty.StringVal("~>2.0.0"),
   223  							})),
   224  						},
   225  					},
   226  				}),
   227  				DefRange: blockRange,
   228  			},
   229  			Want: &RequiredProviders{
   230  				RequiredProviders: map[string]*RequiredProvider{},
   231  				DeclRange:         blockRange,
   232  			},
   233  			Error: "Invalid provider local name",
   234  		},
   235  		"version constraint error": {
   236  			Block: &hcl.Block{
   237  				Type: "required_providers",
   238  				Body: hcltest.MockBody(&hcl.BodyContent{
   239  					Attributes: hcl.Attributes{
   240  						"my-test": {
   241  							Name: "my-test",
   242  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   243  								"source":  cty.StringVal("mycloud/test"),
   244  								"version": cty.StringVal("invalid"),
   245  							})),
   246  						},
   247  					},
   248  				}),
   249  				DefRange: blockRange,
   250  			},
   251  			Want: &RequiredProviders{
   252  				RequiredProviders: map[string]*RequiredProvider{},
   253  				DeclRange:         blockRange,
   254  			},
   255  			Error: "Invalid version constraint",
   256  		},
   257  		"invalid required_providers attribute value": {
   258  			Block: &hcl.Block{
   259  				Type: "required_providers",
   260  				Body: hcltest.MockBody(&hcl.BodyContent{
   261  					Attributes: hcl.Attributes{
   262  						"test": {
   263  							Name: "test",
   264  							Expr: hcltest.MockExprLiteral(cty.ListVal([]cty.Value{cty.StringVal("2.0.0")})),
   265  						},
   266  					},
   267  				}),
   268  				DefRange: blockRange,
   269  			},
   270  			Want: &RequiredProviders{
   271  				RequiredProviders: map[string]*RequiredProvider{},
   272  				DeclRange:         blockRange,
   273  			},
   274  			Error: "Invalid required_providers object",
   275  		},
   276  		"invalid source attribute type": {
   277  			Block: &hcl.Block{
   278  				Type: "required_providers",
   279  				Body: hcltest.MockBody(&hcl.BodyContent{
   280  					Attributes: hcl.Attributes{
   281  						"my-test": {
   282  							Name: "my-test",
   283  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   284  								"source": cty.DynamicVal,
   285  							})),
   286  						},
   287  					},
   288  				}),
   289  				DefRange: blockRange,
   290  			},
   291  			Want: &RequiredProviders{
   292  				RequiredProviders: map[string]*RequiredProvider{},
   293  				DeclRange:         blockRange,
   294  			},
   295  			Error: "Invalid source",
   296  		},
   297  		"additional attributes": {
   298  			Block: &hcl.Block{
   299  				Type: "required_providers",
   300  				Body: hcltest.MockBody(&hcl.BodyContent{
   301  					Attributes: hcl.Attributes{
   302  						"my-test": {
   303  							Name: "my-test",
   304  							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
   305  								"source":  cty.StringVal("mycloud/test"),
   306  								"version": cty.StringVal("2.0.0"),
   307  								"invalid": cty.BoolVal(true),
   308  							})),
   309  						},
   310  					},
   311  				}),
   312  				DefRange: blockRange,
   313  			},
   314  			Want: &RequiredProviders{
   315  				RequiredProviders: map[string]*RequiredProvider{},
   316  				DeclRange:         blockRange,
   317  			},
   318  			Error: "Invalid required_providers object",
   319  		},
   320  	}
   321  
   322  	for name, test := range tests {
   323  		t.Run(name, func(t *testing.T) {
   324  			got, diags := decodeRequiredProvidersBlock(test.Block)
   325  			if diags.HasErrors() {
   326  				if test.Error == "" {
   327  					t.Fatalf("unexpected error: %v", diags)
   328  				}
   329  				if gotErr := diags[0].Summary; gotErr != test.Error {
   330  					t.Errorf("wrong error, got %q, want %q", gotErr, test.Error)
   331  				}
   332  			} else if test.Error != "" {
   333  				t.Fatalf("expected error")
   334  			}
   335  
   336  			if !cmp.Equal(got, test.Want, ignoreUnexported, comparer) {
   337  				t.Fatalf("wrong result:\n %s", cmp.Diff(got, test.Want, ignoreUnexported, comparer))
   338  			}
   339  		})
   340  	}
   341  }
   342  
   343  func testVC(ver string) VersionConstraint {
   344  	constraint, _ := version.NewConstraint(ver)
   345  	return VersionConstraint{
   346  		Required:  constraint,
   347  		DeclRange: hcl.Range{},
   348  	}
   349  }