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 }