github.com/opentofu/opentofu@v1.7.1/internal/depsfile/locks_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 depsfile
     7  
     8  import (
     9  	"testing"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  	"github.com/opentofu/opentofu/internal/addrs"
    13  	"github.com/opentofu/opentofu/internal/getproviders"
    14  )
    15  
    16  func TestLocksEqual(t *testing.T) {
    17  	boopProvider := addrs.NewDefaultProvider("boop")
    18  	v2 := getproviders.MustParseVersion("2.0.0")
    19  	v2LocalBuild := getproviders.MustParseVersion("2.0.0+awesomecorp.1")
    20  	v2GtConstraints := getproviders.MustParseVersionConstraints(">= 2.0.0")
    21  	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
    22  	hash1 := getproviders.HashScheme("test").New("1")
    23  	hash2 := getproviders.HashScheme("test").New("2")
    24  	hash3 := getproviders.HashScheme("test").New("3")
    25  
    26  	equalBothWays := func(t *testing.T, a, b *Locks) {
    27  		t.Helper()
    28  		if !a.Equal(b) {
    29  			t.Errorf("a should be equal to b")
    30  		}
    31  		if !b.Equal(a) {
    32  			t.Errorf("b should be equal to a")
    33  		}
    34  	}
    35  	nonEqualBothWays := func(t *testing.T, a, b *Locks) {
    36  		t.Helper()
    37  		if a.Equal(b) {
    38  			t.Errorf("a should be equal to b")
    39  		}
    40  		if b.Equal(a) {
    41  			t.Errorf("b should be equal to a")
    42  		}
    43  	}
    44  
    45  	t.Run("both empty", func(t *testing.T) {
    46  		a := NewLocks()
    47  		b := NewLocks()
    48  		equalBothWays(t, a, b)
    49  	})
    50  	t.Run("an extra provider lock", func(t *testing.T) {
    51  		a := NewLocks()
    52  		b := NewLocks()
    53  		b.SetProvider(boopProvider, v2, v2GtConstraints, nil)
    54  		nonEqualBothWays(t, a, b)
    55  	})
    56  	t.Run("both have boop provider with same version", func(t *testing.T) {
    57  		a := NewLocks()
    58  		b := NewLocks()
    59  		// Note: the constraints are not part of the definition of "Equal", so they can differ
    60  		a.SetProvider(boopProvider, v2, v2GtConstraints, nil)
    61  		b.SetProvider(boopProvider, v2, v2EqConstraints, nil)
    62  		equalBothWays(t, a, b)
    63  	})
    64  	t.Run("both have boop provider with different versions", func(t *testing.T) {
    65  		a := NewLocks()
    66  		b := NewLocks()
    67  		a.SetProvider(boopProvider, v2, v2EqConstraints, nil)
    68  		b.SetProvider(boopProvider, v2LocalBuild, v2EqConstraints, nil)
    69  		nonEqualBothWays(t, a, b)
    70  	})
    71  	t.Run("both have boop provider with same version and same hashes", func(t *testing.T) {
    72  		a := NewLocks()
    73  		b := NewLocks()
    74  		hashes := []getproviders.Hash{hash1, hash2, hash3}
    75  		a.SetProvider(boopProvider, v2, v2EqConstraints, hashes)
    76  		b.SetProvider(boopProvider, v2, v2EqConstraints, hashes)
    77  		equalBothWays(t, a, b)
    78  	})
    79  	t.Run("both have boop provider with same version but different hashes", func(t *testing.T) {
    80  		a := NewLocks()
    81  		b := NewLocks()
    82  		hashesA := []getproviders.Hash{hash1, hash2}
    83  		hashesB := []getproviders.Hash{hash1, hash3}
    84  		a.SetProvider(boopProvider, v2, v2EqConstraints, hashesA)
    85  		b.SetProvider(boopProvider, v2, v2EqConstraints, hashesB)
    86  		nonEqualBothWays(t, a, b)
    87  	})
    88  }
    89  
    90  func TestLocksEqualProviderAddress(t *testing.T) {
    91  	boopProvider := addrs.NewDefaultProvider("boop")
    92  	v2 := getproviders.MustParseVersion("2.0.0")
    93  	v2LocalBuild := getproviders.MustParseVersion("2.0.0+awesomecorp.1")
    94  	v2GtConstraints := getproviders.MustParseVersionConstraints(">= 2.0.0")
    95  	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
    96  	hash1 := getproviders.HashScheme("test").New("1")
    97  	hash2 := getproviders.HashScheme("test").New("2")
    98  	hash3 := getproviders.HashScheme("test").New("3")
    99  
   100  	equalProviderAddressBothWays := func(t *testing.T, a, b *Locks) {
   101  		t.Helper()
   102  		if !a.EqualProviderAddress(b) {
   103  			t.Errorf("a should be equal to b")
   104  		}
   105  		if !b.EqualProviderAddress(a) {
   106  			t.Errorf("b should be equal to a")
   107  		}
   108  	}
   109  	nonEqualProviderAddressBothWays := func(t *testing.T, a, b *Locks) {
   110  		t.Helper()
   111  		if a.EqualProviderAddress(b) {
   112  			t.Errorf("a should be equal to b")
   113  		}
   114  		if b.EqualProviderAddress(a) {
   115  			t.Errorf("b should be equal to a")
   116  		}
   117  	}
   118  
   119  	t.Run("both empty", func(t *testing.T) {
   120  		a := NewLocks()
   121  		b := NewLocks()
   122  		equalProviderAddressBothWays(t, a, b)
   123  	})
   124  	t.Run("an extra provider lock", func(t *testing.T) {
   125  		a := NewLocks()
   126  		b := NewLocks()
   127  		b.SetProvider(boopProvider, v2, v2GtConstraints, nil)
   128  		nonEqualProviderAddressBothWays(t, a, b)
   129  	})
   130  	t.Run("both have boop provider with different versions", func(t *testing.T) {
   131  		a := NewLocks()
   132  		b := NewLocks()
   133  		a.SetProvider(boopProvider, v2, v2EqConstraints, nil)
   134  		b.SetProvider(boopProvider, v2LocalBuild, v2EqConstraints, nil)
   135  		equalProviderAddressBothWays(t, a, b)
   136  	})
   137  	t.Run("both have boop provider with same version but different hashes", func(t *testing.T) {
   138  		a := NewLocks()
   139  		b := NewLocks()
   140  		hashesA := []getproviders.Hash{hash1, hash2}
   141  		hashesB := []getproviders.Hash{hash1, hash3}
   142  		a.SetProvider(boopProvider, v2, v2EqConstraints, hashesA)
   143  		b.SetProvider(boopProvider, v2, v2EqConstraints, hashesB)
   144  		equalProviderAddressBothWays(t, a, b)
   145  	})
   146  }
   147  
   148  func TestLocksProviderSetRemove(t *testing.T) {
   149  	beepProvider := addrs.NewDefaultProvider("beep")
   150  	boopProvider := addrs.NewDefaultProvider("boop")
   151  	v2 := getproviders.MustParseVersion("2.0.0")
   152  	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
   153  	v2GtConstraints := getproviders.MustParseVersionConstraints(">= 2.0.0")
   154  	hash := getproviders.HashScheme("test").New("1")
   155  
   156  	locks := NewLocks()
   157  	if got, want := len(locks.AllProviders()), 0; got != want {
   158  		t.Fatalf("fresh locks object already has providers")
   159  	}
   160  
   161  	locks.SetProvider(boopProvider, v2, v2EqConstraints, []getproviders.Hash{hash})
   162  	{
   163  		got := locks.AllProviders()
   164  		want := map[addrs.Provider]*ProviderLock{
   165  			boopProvider: {
   166  				addr:               boopProvider,
   167  				version:            v2,
   168  				versionConstraints: v2EqConstraints,
   169  				hashes:             []getproviders.Hash{hash},
   170  			},
   171  		}
   172  		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
   173  			t.Fatalf("wrong providers after SetProvider boop\n%s", diff)
   174  		}
   175  	}
   176  
   177  	locks.SetProvider(beepProvider, v2, v2GtConstraints, []getproviders.Hash{hash})
   178  	{
   179  		got := locks.AllProviders()
   180  		want := map[addrs.Provider]*ProviderLock{
   181  			boopProvider: {
   182  				addr:               boopProvider,
   183  				version:            v2,
   184  				versionConstraints: v2EqConstraints,
   185  				hashes:             []getproviders.Hash{hash},
   186  			},
   187  			beepProvider: {
   188  				addr:               beepProvider,
   189  				version:            v2,
   190  				versionConstraints: v2GtConstraints,
   191  				hashes:             []getproviders.Hash{hash},
   192  			},
   193  		}
   194  		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
   195  			t.Fatalf("wrong providers after SetProvider beep\n%s", diff)
   196  		}
   197  	}
   198  
   199  	locks.RemoveProvider(boopProvider)
   200  	{
   201  		got := locks.AllProviders()
   202  		want := map[addrs.Provider]*ProviderLock{
   203  			beepProvider: {
   204  				addr:               beepProvider,
   205  				version:            v2,
   206  				versionConstraints: v2GtConstraints,
   207  				hashes:             []getproviders.Hash{hash},
   208  			},
   209  		}
   210  		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
   211  			t.Fatalf("wrong providers after RemoveProvider boop\n%s", diff)
   212  		}
   213  	}
   214  
   215  	locks.RemoveProvider(beepProvider)
   216  	{
   217  		got := locks.AllProviders()
   218  		want := map[addrs.Provider]*ProviderLock{}
   219  		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
   220  			t.Fatalf("wrong providers after RemoveProvider beep\n%s", diff)
   221  		}
   222  	}
   223  }
   224  
   225  func TestProviderLockContainsAll(t *testing.T) {
   226  	provider := addrs.NewDefaultProvider("provider")
   227  	v2 := getproviders.MustParseVersion("2.0.0")
   228  	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
   229  
   230  	t.Run("non-symmetric", func(t *testing.T) {
   231  		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   232  			"9r3i9a9QmASqMnQM",
   233  			"K43RHM2klOoywtyW",
   234  			"swJPXfuCNhJsTM5c",
   235  		})
   236  
   237  		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   238  			"9r3i9a9QmASqMnQM",
   239  			"1ZAChGWUMWn4zmIk",
   240  			"K43RHM2klOoywtyW",
   241  			"HWjRvIuWZ1LVatnc",
   242  			"swJPXfuCNhJsTM5c",
   243  			"KwhJK4p/U2dqbKhI",
   244  		})
   245  
   246  		if !original.ContainsAll(target) {
   247  			t.Errorf("orginal should contain all hashes in target")
   248  		}
   249  		if target.ContainsAll(original) {
   250  			t.Errorf("target should not contain all hashes in orginal")
   251  		}
   252  	})
   253  
   254  	t.Run("symmetric", func(t *testing.T) {
   255  		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   256  			"9r3i9a9QmASqMnQM",
   257  			"K43RHM2klOoywtyW",
   258  			"swJPXfuCNhJsTM5c",
   259  		})
   260  
   261  		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   262  			"9r3i9a9QmASqMnQM",
   263  			"K43RHM2klOoywtyW",
   264  			"swJPXfuCNhJsTM5c",
   265  		})
   266  
   267  		if !original.ContainsAll(target) {
   268  			t.Errorf("orginal should contain all hashes in target")
   269  		}
   270  		if !target.ContainsAll(original) {
   271  			t.Errorf("target should not contain all hashes in orginal")
   272  		}
   273  	})
   274  
   275  	t.Run("edge case - null", func(t *testing.T) {
   276  		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   277  			"9r3i9a9QmASqMnQM",
   278  			"K43RHM2klOoywtyW",
   279  			"swJPXfuCNhJsTM5c",
   280  		})
   281  
   282  		if !original.ContainsAll(nil) {
   283  			t.Fatalf("orginal should report true on nil")
   284  		}
   285  	})
   286  
   287  	t.Run("edge case - empty", func(t *testing.T) {
   288  		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   289  			"9r3i9a9QmASqMnQM",
   290  			"K43RHM2klOoywtyW",
   291  			"swJPXfuCNhJsTM5c",
   292  		})
   293  
   294  		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{})
   295  
   296  		if !original.ContainsAll(target) {
   297  			t.Fatalf("orginal should report true on empty")
   298  		}
   299  	})
   300  
   301  	t.Run("edge case - original empty", func(t *testing.T) {
   302  		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{})
   303  
   304  		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
   305  			"9r3i9a9QmASqMnQM",
   306  			"K43RHM2klOoywtyW",
   307  			"swJPXfuCNhJsTM5c",
   308  		})
   309  
   310  		if original.ContainsAll(target) {
   311  			t.Fatalf("orginal should report false when empty")
   312  		}
   313  	})
   314  }