github.com/opentofu/opentofu@v1.7.1/internal/plugin/discovery/meta_set_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 discovery
     7  
     8  import (
     9  	"fmt"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestPluginMetaSetManipulation(t *testing.T) {
    15  	metas := []PluginMeta{
    16  		{
    17  			Name:    "foo",
    18  			Version: "1.0.0",
    19  			Path:    "test-foo",
    20  		},
    21  		{
    22  			Name:    "bar",
    23  			Version: "2.0.0",
    24  			Path:    "test-bar",
    25  		},
    26  		{
    27  			Name:    "baz",
    28  			Version: "2.0.0",
    29  			Path:    "test-bar",
    30  		},
    31  	}
    32  	s := make(PluginMetaSet)
    33  
    34  	if count := s.Count(); count != 0 {
    35  		t.Fatalf("set has Count %d before any items added", count)
    36  	}
    37  
    38  	// Can we add metas?
    39  	for _, p := range metas {
    40  		s.Add(p)
    41  		if !s.Has(p) {
    42  			t.Fatalf("%q not in set after adding it", p.Name)
    43  		}
    44  	}
    45  
    46  	if got, want := s.Count(), len(metas); got != want {
    47  		t.Fatalf("set has Count %d after all items added; want %d", got, want)
    48  	}
    49  
    50  	// Can we still retrieve earlier ones after we added later ones?
    51  	for _, p := range metas {
    52  		if !s.Has(p) {
    53  			t.Fatalf("%q not in set after all adds", p.Name)
    54  		}
    55  	}
    56  
    57  	// Can we remove metas?
    58  	for _, p := range metas {
    59  		s.Remove(p)
    60  		if s.Has(p) {
    61  			t.Fatalf("%q still in set after removing it", p.Name)
    62  		}
    63  	}
    64  
    65  	if count := s.Count(); count != 0 {
    66  		t.Fatalf("set has Count %d after all items removed", count)
    67  	}
    68  }
    69  
    70  func TestPluginMetaSetValidateVersions(t *testing.T) {
    71  	metas := []PluginMeta{
    72  		{
    73  			Name:    "foo",
    74  			Version: "1.0.0",
    75  			Path:    "test-foo",
    76  		},
    77  		{
    78  			Name:    "bar",
    79  			Version: "0.0.1",
    80  			Path:    "test-bar",
    81  		},
    82  		{
    83  			Name:    "baz",
    84  			Version: "bananas",
    85  			Path:    "test-bar",
    86  		},
    87  	}
    88  	s := make(PluginMetaSet)
    89  
    90  	for _, p := range metas {
    91  		s.Add(p)
    92  	}
    93  
    94  	valid, invalid := s.ValidateVersions()
    95  	if count := valid.Count(); count != 2 {
    96  		t.Errorf("valid set has %d metas; want 2", count)
    97  	}
    98  	if count := invalid.Count(); count != 1 {
    99  		t.Errorf("valid set has %d metas; want 1", count)
   100  	}
   101  
   102  	if !valid.Has(metas[0]) {
   103  		t.Errorf("'foo' not in valid set")
   104  	}
   105  	if !valid.Has(metas[1]) {
   106  		t.Errorf("'bar' not in valid set")
   107  	}
   108  	if !invalid.Has(metas[2]) {
   109  		t.Errorf("'baz' not in invalid set")
   110  	}
   111  
   112  	if invalid.Has(metas[0]) {
   113  		t.Errorf("'foo' in invalid set")
   114  	}
   115  	if invalid.Has(metas[1]) {
   116  		t.Errorf("'bar' in invalid set")
   117  	}
   118  	if valid.Has(metas[2]) {
   119  		t.Errorf("'baz' in valid set")
   120  	}
   121  
   122  }
   123  
   124  func TestPluginMetaSetWithName(t *testing.T) {
   125  	tests := []struct {
   126  		metas     []PluginMeta
   127  		name      string
   128  		wantCount int
   129  	}{
   130  		{
   131  			[]PluginMeta{},
   132  			"foo",
   133  			0,
   134  		},
   135  		{
   136  			[]PluginMeta{
   137  				{
   138  					Name:    "foo",
   139  					Version: "0.0.1",
   140  					Path:    "foo",
   141  				},
   142  			},
   143  			"foo",
   144  			1,
   145  		},
   146  		{
   147  			[]PluginMeta{
   148  				{
   149  					Name:    "foo",
   150  					Version: "0.0.1",
   151  					Path:    "foo",
   152  				},
   153  			},
   154  			"bar",
   155  			0,
   156  		},
   157  	}
   158  
   159  	for i, test := range tests {
   160  		t.Run(fmt.Sprintf("Test%02d", i), func(t *testing.T) {
   161  			s := make(PluginMetaSet)
   162  			for _, p := range test.metas {
   163  				s.Add(p)
   164  			}
   165  			filtered := s.WithName(test.name)
   166  			if gotCount := filtered.Count(); gotCount != test.wantCount {
   167  				t.Errorf("got count %d in %#v; want %d", gotCount, filtered, test.wantCount)
   168  			}
   169  		})
   170  	}
   171  }
   172  
   173  func TestPluginMetaSetByName(t *testing.T) {
   174  	metas := []PluginMeta{
   175  		{
   176  			Name:    "foo",
   177  			Version: "1.0.0",
   178  			Path:    "test-foo",
   179  		},
   180  		{
   181  			Name:    "foo",
   182  			Version: "2.0.0",
   183  			Path:    "test-foo-2",
   184  		},
   185  		{
   186  			Name:    "bar",
   187  			Version: "0.0.1",
   188  			Path:    "test-bar",
   189  		},
   190  		{
   191  			Name:    "baz",
   192  			Version: "1.2.0",
   193  			Path:    "test-bar",
   194  		},
   195  	}
   196  	s := make(PluginMetaSet)
   197  
   198  	for _, p := range metas {
   199  		s.Add(p)
   200  	}
   201  
   202  	byName := s.ByName()
   203  	if got, want := len(byName), 3; got != want {
   204  		t.Errorf("%d keys in ByName map; want %d", got, want)
   205  	}
   206  	if got, want := len(byName["foo"]), 2; got != want {
   207  		t.Errorf("%d metas for 'foo'; want %d", got, want)
   208  	}
   209  	if got, want := len(byName["bar"]), 1; got != want {
   210  		t.Errorf("%d metas for 'bar'; want %d", got, want)
   211  	}
   212  	if got, want := len(byName["baz"]), 1; got != want {
   213  		t.Errorf("%d metas for 'baz'; want %d", got, want)
   214  	}
   215  
   216  	if !byName["foo"].Has(metas[0]) {
   217  		t.Errorf("%#v missing from 'foo' set", metas[0])
   218  	}
   219  	if !byName["foo"].Has(metas[1]) {
   220  		t.Errorf("%#v missing from 'foo' set", metas[1])
   221  	}
   222  	if !byName["bar"].Has(metas[2]) {
   223  		t.Errorf("%#v missing from 'bar' set", metas[2])
   224  	}
   225  	if !byName["baz"].Has(metas[3]) {
   226  		t.Errorf("%#v missing from 'baz' set", metas[3])
   227  	}
   228  }
   229  
   230  func TestPluginMetaSetNewest(t *testing.T) {
   231  	tests := []struct {
   232  		versions []string
   233  		want     string
   234  	}{
   235  		{
   236  			[]string{
   237  				"0.0.1",
   238  			},
   239  			"0.0.1",
   240  		},
   241  		{
   242  			[]string{
   243  				"0.0.1",
   244  				"0.0.2",
   245  			},
   246  			"0.0.2",
   247  		},
   248  		{
   249  			[]string{
   250  				"1.0.0",
   251  				"1.0.0-beta1",
   252  			},
   253  			"1.0.0",
   254  		},
   255  		{
   256  			[]string{
   257  				"0.0.1",
   258  				"1.0.0",
   259  			},
   260  			"1.0.0",
   261  		},
   262  	}
   263  
   264  	for _, test := range tests {
   265  		t.Run(strings.Join(test.versions, "|"), func(t *testing.T) {
   266  			s := make(PluginMetaSet)
   267  			for _, version := range test.versions {
   268  				s.Add(PluginMeta{
   269  					Name:    "foo",
   270  					Version: VersionStr(version),
   271  					Path:    "foo-V" + version,
   272  				})
   273  			}
   274  
   275  			newest := s.Newest()
   276  			if newest.Version != VersionStr(test.want) {
   277  				t.Errorf("version is %q; want %q", newest.Version, test.want)
   278  			}
   279  		})
   280  	}
   281  }
   282  
   283  func TestPluginMetaSetConstrainVersions(t *testing.T) {
   284  	metas := []PluginMeta{
   285  		{
   286  			Name:    "foo",
   287  			Version: "1.0.0",
   288  			Path:    "test-foo",
   289  		},
   290  		{
   291  			Name:    "foo",
   292  			Version: "2.0.0",
   293  			Path:    "test-foo-2",
   294  		},
   295  		{
   296  			Name:    "foo",
   297  			Version: "3.0.0",
   298  			Path:    "test-foo-2",
   299  		},
   300  		{
   301  			Name:    "bar",
   302  			Version: "0.0.5",
   303  			Path:    "test-bar",
   304  		},
   305  		{
   306  			Name:    "baz",
   307  			Version: "0.0.1",
   308  			Path:    "test-bar",
   309  		},
   310  	}
   311  	s := make(PluginMetaSet)
   312  
   313  	for _, p := range metas {
   314  		s.Add(p)
   315  	}
   316  
   317  	byName := s.ConstrainVersions(PluginRequirements{
   318  		"foo": &PluginConstraints{Versions: ConstraintStr(">=2.0.0").MustParse()},
   319  		"bar": &PluginConstraints{Versions: ConstraintStr(">=0.0.0").MustParse()},
   320  		"baz": &PluginConstraints{Versions: ConstraintStr(">=1.0.0").MustParse()},
   321  		"fun": &PluginConstraints{Versions: ConstraintStr(">5.0.0").MustParse()},
   322  	})
   323  	if got, want := len(byName), 3; got != want {
   324  		t.Errorf("%d keys in map; want %d", got, want)
   325  	}
   326  
   327  	if got, want := len(byName["foo"]), 2; got != want {
   328  		t.Errorf("%d metas for 'foo'; want %d", got, want)
   329  	}
   330  	if got, want := len(byName["bar"]), 1; got != want {
   331  		t.Errorf("%d metas for 'bar'; want %d", got, want)
   332  	}
   333  	if got, want := len(byName["baz"]), 0; got != want {
   334  		t.Errorf("%d metas for 'baz'; want %d", got, want)
   335  	}
   336  	// "fun" is not in the map at all, because we have no metas for that name
   337  
   338  	if !byName["foo"].Has(metas[1]) {
   339  		t.Errorf("%#v missing from 'foo' set", metas[1])
   340  	}
   341  	if !byName["foo"].Has(metas[2]) {
   342  		t.Errorf("%#v missing from 'foo' set", metas[2])
   343  	}
   344  	if !byName["bar"].Has(metas[3]) {
   345  		t.Errorf("%#v missing from 'bar' set", metas[3])
   346  	}
   347  
   348  }
   349  
   350  func TestPluginMetaSetOverridePaths(t *testing.T) {
   351  
   352  	metas := []PluginMeta{
   353  		{
   354  			Name:    "foo",
   355  			Version: "1.0.0",
   356  			Path:    "test-foo-1",
   357  		},
   358  		{
   359  			Name:    "foo",
   360  			Version: "2.0.0",
   361  			Path:    "test-foo-2",
   362  		},
   363  		{
   364  			Name:    "foo",
   365  			Version: "3.0.0",
   366  			Path:    "test-foo-3",
   367  		},
   368  		{
   369  			Name:    "bar",
   370  			Version: "0.0.5",
   371  			Path:    "test-bar-5",
   372  		},
   373  		{
   374  			Name:    "bar",
   375  			Version: "0.0.6",
   376  			Path:    "test-bar-6",
   377  		},
   378  		{
   379  			Name:    "baz",
   380  			Version: "0.0.1",
   381  			Path:    "test-bar",
   382  		},
   383  	}
   384  	s := make(PluginMetaSet)
   385  
   386  	for _, p := range metas {
   387  		s.Add(p)
   388  	}
   389  
   390  	ns := s.OverridePaths(map[string]string{
   391  		"foo": "override-foo",
   392  		"fun": "override-fun",
   393  	})
   394  
   395  	if got, want := ns.Count(), 5; got != want {
   396  		t.Errorf("got %d metas; want %d", got, want)
   397  	}
   398  
   399  	if !ns.Has(metas[3]) {
   400  		t.Errorf("new set is missing %#v", metas[3])
   401  	}
   402  	if !ns.Has(metas[4]) {
   403  		t.Errorf("new set is missing %#v", metas[4])
   404  	}
   405  	if !ns.Has(metas[5]) {
   406  		t.Errorf("new set is missing %#v", metas[5])
   407  	}
   408  	if !ns.Has(PluginMeta{
   409  		Name:    "foo",
   410  		Version: VersionZero,
   411  		Path:    "override-foo",
   412  	}) {
   413  		t.Errorf("new set is missing 'foo' override")
   414  	}
   415  	if !ns.Has(PluginMeta{
   416  		Name:    "fun",
   417  		Version: VersionZero,
   418  		Path:    "override-fun",
   419  	}) {
   420  		t.Errorf("new set is missing 'fun' override")
   421  	}
   422  }