diff --git a/internal/command/init_run.go b/internal/command/init_run.go index d63013f94e..9fed222133 100644 --- a/internal/command/init_run.go +++ b/internal/command/init_run.go @@ -220,6 +220,35 @@ func (c *InitCommand) run(initArgs *arguments.Init, view views.Init) int { header = true } + // The init command is not allowed to upgrade the provider used for PSS (unless we're reconfiguring the state store). + // Unless users choose to reconfigure, they must upgrade the state store provider separately using `terraform state migrate -upgrade`. + if initArgs.Upgrade && !initArgs.Reconfigure && config.Module.StateStore != nil { + pAddr := config.Module.StateStore.ProviderAddr + old := previousLocks.Provider(pAddr) + new := configLocks.Provider(pAddr) + if old == nil || new == nil { + panic(fmt.Sprintf(`Unexpected missing provider lock for %s during init -upgrade: +prior lock: %#v +new lock: %#v`, pAddr.ForDisplay(), old, new)) + } + if !new.Version().Same((old.Version())) { + // The upgrade has impacted the provider + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Cannot upgrade the provider used for pluggable state storage during \"terraform init -upgrade\"", + fmt.Sprintf(`While upgrading providers Terraform attempted to upgrade the %s (%q) provider, which is used by the state_store block in your configuration. +Please use \"terraform state migrate -upgrade\" to upgrade the state store provider and navigate migrating your state between the two versions. You can then re-attempt \"terraform init -upgrade\" to upgrade the rest of your providers. + +If you do not intend to upgrade the state store provider, please update your configuration to pin to the current version (%s), and re-run \"terraform init -upgrade\" to upgrade the rest of your providers. +`, + pAddr.Type, pAddr.ForDisplay(), old.Version()), + ), + ) + view.Diagnostics(diags) + return 1 + } + } + // If we outputted information, then we need to output a newline // so that our success message is nicely spaced out from prior text. if header { diff --git a/internal/command/init_test.go b/internal/command/init_test.go index 7c07379898..564cf4399e 100644 --- a/internal/command/init_test.go +++ b/internal/command/init_test.go @@ -2297,129 +2297,547 @@ func TestInit_cancelProviders(t *testing.T) { } } +// Test different scenarios when upgrading providers with the -upgrade flag is attempted func TestInit_getUpgradePlugins(t *testing.T) { - // Create a temporary working directory and copy in test fixtures - td := t.TempDir() - testCopyDir(t, testFixturePath("init-get-providers"), td) - t.Chdir(td) - - providerSource, close := newMockProviderSource(t, map[string][]string{ - // looking for an exact version - "exact": {"1.2.3"}, - // config requires >= 2.3.3 - "greater-than": {"2.3.4", "2.3.3", "2.3.0"}, - // config specifies > 1.0.0 , < 3.0.0 - "between": {"3.4.5", "2.3.4", "1.2.3"}, - }) - defer close() + t.Run("the -upgrade flag allows providers to be upgraded to latest versions matching constraints", func(t *testing.T) { + // Create a temporary working directory and copy in test fixtures + td := t.TempDir() + testCopyDir(t, testFixturePath("init-get-providers"), td) + t.Chdir(td) - ui := new(cli.MockUi) - view, done := testView(t) - m := Meta{ - testingOverrides: metaOverridesForProvider(testProvider()), - Ui: ui, - View: view, - ProviderSource: providerSource, - } + providerSource, close := newMockProviderSource(t, map[string][]string{ + // looking for an exact version + "exact": {"1.2.3"}, + // config requires >= 2.3.3 + "greater-than": {"2.3.4", "2.3.3", "2.3.0"}, + // config specifies > 1.0.0 , < 3.0.0 + "between": {"3.4.5", "2.3.4", "1.2.3"}, + }) + t.Cleanup(close) - installFakeProviderPackages(t, &m, map[string][]string{ - "exact": {"0.0.1"}, - "greater-than": {"2.3.3"}, - }) + ui := new(cli.MockUi) + view, done := testView(t) + m := Meta{ + testingOverrides: metaOverridesForProvider(testProvider()), + Ui: ui, + View: view, + ProviderSource: providerSource, + } - c := &InitCommand{ - Meta: m, - } + // Make Terraform believe there are already versions of the providers installed, + // these are what we're upgrading from. + installFakeProviderPackages(t, &m, map[string][]string{ + "exact": {"0.0.1"}, + "greater-than": {"2.3.3"}, + }) - args := []string{ - "-upgrade=true", - } - if code := c.Run(args); code != 0 { - t.Fatalf("command did not complete successfully:\n%s", done(t).All()) - } + c := &InitCommand{ + Meta: m, + } - cacheDir := m.providerLocalCacheDir() - gotPackages := cacheDir.AllAvailablePackages() - wantPackages := map[addrs.Provider][]providercache.CachedProvider{ - // "between" wasn't previously installed at all, so we installed - // the newest available version that matched the version constraints. - addrs.NewDefaultProvider("between"): { - { - Provider: addrs.NewDefaultProvider("between"), - Version: getproviders.MustParseVersion("2.3.4"), - PackageDir: expectedPackageInstallPath("between", "2.3.4", false), + args := []string{ + "-upgrade=true", + } + if code := c.Run(args); code != 0 { + t.Fatalf("command did not complete successfully:\n%s", done(t).All()) + } + + cacheDir := m.providerLocalCacheDir() + gotPackages := cacheDir.AllAvailablePackages() + wantPackages := map[addrs.Provider][]providercache.CachedProvider{ + // "between" wasn't previously installed at all, so we installed + // the newest available version that matched the version constraints. + addrs.NewDefaultProvider("between"): { + { + Provider: addrs.NewDefaultProvider("between"), + Version: getproviders.MustParseVersion("2.3.4"), + PackageDir: expectedPackageInstallPath("between", "2.3.4", false), + }, }, - }, - // The existing version of "exact" did not match the version constraints, - // so we installed what the configuration selected as well. - addrs.NewDefaultProvider("exact"): { - { - Provider: addrs.NewDefaultProvider("exact"), - Version: getproviders.MustParseVersion("1.2.3"), - PackageDir: expectedPackageInstallPath("exact", "1.2.3", false), + // The existing version of "exact" did not match the version constraints, + // so we installed what the configuration selected as well. + addrs.NewDefaultProvider("exact"): { + { + Provider: addrs.NewDefaultProvider("exact"), + Version: getproviders.MustParseVersion("1.2.3"), + PackageDir: expectedPackageInstallPath("exact", "1.2.3", false), + }, + // Previous version is still there, but not selected + { + Provider: addrs.NewDefaultProvider("exact"), + Version: getproviders.MustParseVersion("0.0.1"), + PackageDir: expectedPackageInstallPath("exact", "0.0.1", false), + }, }, - // Previous version is still there, but not selected - { - Provider: addrs.NewDefaultProvider("exact"), - Version: getproviders.MustParseVersion("0.0.1"), - PackageDir: expectedPackageInstallPath("exact", "0.0.1", false), + // The existing version of "greater-than" _did_ match the constraints, + // but a newer version was available and the user specified + // -upgrade and so we upgraded it anyway. + addrs.NewDefaultProvider("greater-than"): { + { + Provider: addrs.NewDefaultProvider("greater-than"), + Version: getproviders.MustParseVersion("2.3.4"), + PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false), + }, + // Previous version is still there, but not selected + { + Provider: addrs.NewDefaultProvider("greater-than"), + Version: getproviders.MustParseVersion("2.3.3"), + PackageDir: expectedPackageInstallPath("greater-than", "2.3.3", false), + }, }, - }, - // The existing version of "greater-than" _did_ match the constraints, - // but a newer version was available and the user specified - // -upgrade and so we upgraded it anyway. - addrs.NewDefaultProvider("greater-than"): { - { - Provider: addrs.NewDefaultProvider("greater-than"), - Version: getproviders.MustParseVersion("2.3.4"), - PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false), + } + if diff := cmp.Diff(wantPackages, gotPackages); diff != "" { + t.Errorf("wrong cache directory contents after upgrade\n%s", diff) + } + + locks, err := m.lockedDependencies() + if err != nil { + t.Fatalf("failed to get locked dependencies: %s", err) + } + gotProviderLocks := locks.AllProviders() + wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{ + addrs.NewDefaultProvider("between"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("between"), + getproviders.MustParseVersion("2.3.4"), + getproviders.MustParseVersionConstraints("> 1.0.0, < 3.0.0"), + []getproviders.Hash{ + getproviders.HashScheme1.New("JVqAvZz88A+hS2wHVtTWQkHaxoA/LrUAz0H3jPBWPIA="), + }, + ), + addrs.NewDefaultProvider("exact"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("exact"), + getproviders.MustParseVersion("1.2.3"), + getproviders.MustParseVersionConstraints("= 1.2.3"), + []getproviders.Hash{ + getproviders.HashScheme1.New("H1TxWF8LyhBb6B4iUdKhLc/S9sC/jdcrCykpkbGcfbg="), + }, + ), + addrs.NewDefaultProvider("greater-than"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("greater-than"), + getproviders.MustParseVersion("2.3.4"), + getproviders.MustParseVersionConstraints(">= 2.3.3"), + []getproviders.Hash{ + getproviders.HashScheme1.New("SJPpXx/yoFE/W+7eCipjJ+G21xbdnTBD7lWodZ8hWkU="), + }, + ), + } + if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" { + t.Errorf("wrong version selections after upgrade\n%s", diff) + } + }) + + t.Run("`init -upgrade` cannot be used to upgrade the state store provider", func(t *testing.T) { + // Create a temporary working directory and copy in test fixtures + td := t.TempDir() + t.Chdir(td) + + // Configuration uses a state store and has other provider requirements. + cfg := ` +terraform { + + required_providers { + test = { + source = "hashicorp/test" + version = "> 1.0.0" + } + } + state_store "test_store" { + provider "test" { + } + + value = "foobar" + } +}` + if err := os.WriteFile("main.tf", []byte(cfg), 0644); err != nil { + t.Fatalf("failed to write main.tf: %s", err) + } + + providerSource, close := newMockProviderSource(t, map[string][]string{ + // config requires > 1.0.0 + "test": {"1.2.3", "9.9.9"}, + }) + t.Cleanup(close) + + // Mock provider to act as "hashicorp/test" + mockProvider := mockPluggableStateStorageProvider() + + ui := new(cli.MockUi) + view, done := testView(t) + m := Meta{ + testingOverrides: metaOverridesForProvider(mockProvider), + Ui: ui, + View: view, + ProviderSource: providerSource, + AllowExperimentalFeatures: true, + } + + // Make Terraform believe that we already have version 1.2.3 installed. + installFakeProviderPackages(t, &m, map[string][]string{ + "test": {"1.2.3"}, + }) + // Create a dependency lock file describing the hashicorp/test provider at version 1.2.3, to simulate a previous init with that version. + locks := depsfile.NewLocks() + locks.SetProvider( + addrs.NewDefaultProvider("test"), + getproviders.MustParseVersion("1.2.3"), + getproviders.MustParseVersionConstraints("> 1.0.0"), + []getproviders.Hash{ + getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="), }, - // Previous version is still there, but not selected - { - Provider: addrs.NewDefaultProvider("greater-than"), - Version: getproviders.MustParseVersion("2.3.3"), - PackageDir: expectedPackageInstallPath("greater-than", "2.3.3", false), + ) + if err := depsfile.SaveLocksToFile(locks, ".terraform.lock.hcl"); err != nil { + t.Fatalf("failed to write provider locks file: %s", err) + } + + c := &InitCommand{ + Meta: m, + } + + args := []string{ + "-upgrade=true", + "-enable-pluggable-state-storage-experiment", + } + code := c.Run(args) + if code == 0 { + t.Fatalf("command was not expected to complete successfully, but it did:\n%s", done(t).All()) + } + output := done(t).Stderr() + expectedError := "Error: Cannot upgrade the provider used for pluggable state storage during \"terraform init -upgrade\"" + if !strings.Contains(output, expectedError) { + t.Fatalf("expected error message not found:\n%s", output) + } + + // Assert that no providers were upgraded. + // + // However, "test" v9.9.9 would be installed in the cache, because the error occurs after the upgrade + // process identifies that provider as a candidate for upgrade. + cacheDir := m.providerLocalCacheDir() + gotPackages := cacheDir.AllAvailablePackages() + wantPackages := map[addrs.Provider][]providercache.CachedProvider{ + addrs.NewDefaultProvider("test"): { + { + Provider: addrs.NewDefaultProvider("test"), + Version: getproviders.MustParseVersion("9.9.9"), + PackageDir: expectedPackageInstallPath("test", "9.9.9", false), + }, + { + Provider: addrs.NewDefaultProvider("test"), + Version: getproviders.MustParseVersion("1.2.3"), + PackageDir: expectedPackageInstallPath("test", "1.2.3", false), + }, }, - }, - } - if diff := cmp.Diff(wantPackages, gotPackages); diff != "" { - t.Errorf("wrong cache directory contents after upgrade\n%s", diff) - } + } + if diff := cmp.Diff(wantPackages, gotPackages); diff != "" { + t.Errorf("wrong cache directory contents after upgrade\n%s", diff) + } - locks, err := m.lockedDependencies() - if err != nil { - t.Fatalf("failed to get locked dependencies: %s", err) - } - gotProviderLocks := locks.AllProviders() - wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{ - addrs.NewDefaultProvider("between"): depsfile.NewProviderLock( - addrs.NewDefaultProvider("between"), - getproviders.MustParseVersion("2.3.4"), - getproviders.MustParseVersionConstraints("> 1.0.0, < 3.0.0"), + // The upgrade process was locked, so the provider locks should not have changed. + locks, err := m.lockedDependencies() + if err != nil { + t.Fatalf("failed to get locked dependencies: %s", err) + } + gotProviderLocks := locks.AllProviders() + wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{ + addrs.NewDefaultProvider("test"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("test"), + getproviders.MustParseVersion("1.2.3"), + getproviders.MustParseVersionConstraints("> 1.0.0"), + []getproviders.Hash{ + getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="), + }, + ), + } + if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" { + t.Errorf("wrong version selections after upgrade\n%s", diff) + } + }) + + t.Run("`init -upgrade -reconfigure` can be used to upgrade the state store provider", func(t *testing.T) { + // Create a temporary working directory and copy in test fixtures + td := t.TempDir() + t.Chdir(td) + + // Configuration uses a state store and has other provider requirements. + cfg := ` +terraform { + + required_providers { + test = { + source = "hashicorp/test" + version = "> 1.0.0" + } + } + state_store "test_store" { + provider "test" { + } + + value = "foobar" + } +}` + if err := os.WriteFile("main.tf", []byte(cfg), 0644); err != nil { + t.Fatalf("failed to write main.tf: %s", err) + } + + providerSource, close := newMockProviderSource(t, map[string][]string{ + // config requires > 1.0.0 + "test": {"1.2.3", "9.9.9"}, + }) + t.Cleanup(close) + + // Mock provider to act as "hashicorp/test" + mockProvider := mockPluggableStateStorageProvider() + + ui := new(cli.MockUi) + view, done := testView(t) + m := Meta{ + testingOverrides: metaOverridesForProvider(mockProvider), + Ui: ui, + View: view, + ProviderSource: providerSource, + AllowExperimentalFeatures: true, + } + + // Make Terraform believe that we already have version 1.2.3 installed. + installFakeProviderPackages(t, &m, map[string][]string{ + "test": {"1.2.3"}, + }) + // Create a dependency lock file describing the hashicorp/test provider at version 1.2.3, to simulate a previous init with that version. + locks := depsfile.NewLocks() + locks.SetProvider( + addrs.NewDefaultProvider("test"), + getproviders.MustParseVersion("1.2.3"), + getproviders.MustParseVersionConstraints("> 1.0.0"), []getproviders.Hash{ - getproviders.HashScheme1.New("JVqAvZz88A+hS2wHVtTWQkHaxoA/LrUAz0H3jPBWPIA="), + getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="), }, - ), - addrs.NewDefaultProvider("exact"): depsfile.NewProviderLock( - addrs.NewDefaultProvider("exact"), + ) + if err := depsfile.SaveLocksToFile(locks, ".terraform.lock.hcl"); err != nil { + t.Fatalf("failed to write provider locks file: %s", err) + } + + c := &InitCommand{ + Meta: m, + } + + args := []string{ + "-upgrade=true", + "-reconfigure", + "-enable-pluggable-state-storage-experiment", + } + code := c.Run(args) + if code != 0 { + t.Fatalf("expected command to complete successfully, but it did not:\n%s", done(t).All()) + } + output := done(t).Stdout() + expectedMsgs := []string{ + "Installed hashicorp/test v9.9.9", + } + for _, msg := range expectedMsgs { + if !strings.Contains(output, msg) { + t.Fatalf("expected message %q not found:\n%s", msg, output) + } + } + + // Assert the provider was upgraded. + cacheDir := m.providerLocalCacheDir() + gotPackages := cacheDir.AllAvailablePackages() + wantPackages := map[addrs.Provider][]providercache.CachedProvider{ + addrs.NewDefaultProvider("test"): { + { + Provider: addrs.NewDefaultProvider("test"), + Version: getproviders.MustParseVersion("9.9.9"), + PackageDir: expectedPackageInstallPath("test", "9.9.9", false), + }, + { + Provider: addrs.NewDefaultProvider("test"), + Version: getproviders.MustParseVersion("1.2.3"), + PackageDir: expectedPackageInstallPath("test", "1.2.3", false), + }, + }, + } + if diff := cmp.Diff(wantPackages, gotPackages); diff != "" { + t.Errorf("wrong cache directory contents after upgrade\n%s", diff) + } + + // The provider locks should have changed. + locks, err := m.lockedDependencies() + if err != nil { + t.Fatalf("failed to get locked dependencies: %s", err) + } + gotProviderLocks := locks.AllProviders() + wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{ + addrs.NewDefaultProvider("test"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("test"), + getproviders.MustParseVersion("9.9.9"), + getproviders.MustParseVersionConstraints("> 1.0.0"), + []getproviders.Hash{ + getproviders.HashScheme1.New("bRxrXpGHyZagKAC5yZZDB9fWBcdllOsFOZzzbJ1VZ0I="), + }, + ), + } + if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" { + t.Errorf("wrong version selections after upgrade\n%s", diff) + } + }) + + t.Run("use of pluggable state storage doesn't block upgrading other providers, if the state store provider is pinned", func(t *testing.T) { + // Create a temporary working directory and copy in test fixtures + td := t.TempDir() + t.Chdir(td) + + // Configuration uses a state store and has other provider requirements. + cfg := ` +terraform { + + required_providers { + test = { + source = "hashicorp/test" + version = "1.2.3" # pinned to v1.2.3 to allow other provider upgrades + } + foobar = { + source = "hashicorp/foobar" + version = "> 1.0.0" + } + } + state_store "test_store" { + provider "test" { + } + + value = "foobar" + } +}` + if err := os.WriteFile("main.tf", []byte(cfg), 0644); err != nil { + t.Fatalf("failed to write main.tf: %s", err) + } + + providerSource, close := newMockProviderSource(t, map[string][]string{ + // config requires > 1.0.0 + "test": {"1.2.3", "9.9.9"}, + "foobar": {"1.2.3", "9.9.9"}, + }) + t.Cleanup(close) + + // Mock provider to act as "hashicorp/test" + mockProvider := mockPluggableStateStorageProvider() + + ui := new(cli.MockUi) + view, done := testView(t) + m := Meta{ + testingOverrides: metaOverridesForProvider(mockProvider), + Ui: ui, + View: view, + ProviderSource: providerSource, + AllowExperimentalFeatures: true, + } + + // Make Terraform believe that we already have version 1.2.3 installed. + installFakeProviderPackages(t, &m, map[string][]string{ + "test": {"1.2.3"}, + "foobar": {"1.2.3"}, + }) + // Create a dependency lock file + locks := depsfile.NewLocks() + locks.SetProvider( + addrs.NewDefaultProvider("test"), getproviders.MustParseVersion("1.2.3"), - getproviders.MustParseVersionConstraints("= 1.2.3"), + getproviders.MustParseVersionConstraints("1.2.3"), []getproviders.Hash{ - getproviders.HashScheme1.New("H1TxWF8LyhBb6B4iUdKhLc/S9sC/jdcrCykpkbGcfbg="), + getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="), }, - ), - addrs.NewDefaultProvider("greater-than"): depsfile.NewProviderLock( - addrs.NewDefaultProvider("greater-than"), - getproviders.MustParseVersion("2.3.4"), - getproviders.MustParseVersionConstraints(">= 2.3.3"), + ) + locks.SetProvider( + addrs.NewDefaultProvider("foobar"), + getproviders.MustParseVersion("1.2.3"), + getproviders.MustParseVersionConstraints("> 1.0.0"), []getproviders.Hash{ - getproviders.HashScheme1.New("SJPpXx/yoFE/W+7eCipjJ+G21xbdnTBD7lWodZ8hWkU="), + getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="), }, - ), - } - if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" { - t.Errorf("wrong version selections after upgrade\n%s", diff) - } + ) + if err := depsfile.SaveLocksToFile(locks, ".terraform.lock.hcl"); err != nil { + t.Fatalf("failed to write provider locks file: %s", err) + } + + c := &InitCommand{ + Meta: m, + } + + args := []string{ + "-upgrade=true", + "-enable-pluggable-state-storage-experiment", + } + code := c.Run(args) + if code != 0 { + t.Fatalf("expected command to succeed, but it did not:\n%s", done(t).All()) + } + output := done(t).Stdout() + expectedMsgs := []string{ + "Using previously-installed hashicorp/test v1.2.3", + "Installed hashicorp/foobar v9.9.9", + "Terraform has made some changes to the provider dependency selections", + } + for _, msg := range expectedMsgs { + if !strings.Contains(output, msg) { + t.Fatalf("expected message %q not found:\n%s", msg, output) + } + } + + // Assert that the non-PSS provider was upgraded. + cacheDir := m.providerLocalCacheDir() + gotPackages := cacheDir.AllAvailablePackages() + wantPackages := map[addrs.Provider][]providercache.CachedProvider{ + addrs.NewDefaultProvider("foobar"): { + // Newly downloaded version + { + Provider: addrs.NewDefaultProvider("foobar"), + Version: getproviders.MustParseVersion("9.9.9"), + PackageDir: expectedPackageInstallPath("foobar", "9.9.9", false), + }, + { + Provider: addrs.NewDefaultProvider("foobar"), + Version: getproviders.MustParseVersion("1.2.3"), + PackageDir: expectedPackageInstallPath("foobar", "1.2.3", false), + }, + }, + addrs.NewDefaultProvider("test"): { + { + Provider: addrs.NewDefaultProvider("test"), + Version: getproviders.MustParseVersion("1.2.3"), + PackageDir: expectedPackageInstallPath("test", "1.2.3", false), + }, + }, + } + if diff := cmp.Diff(wantPackages, gotPackages); diff != "" { + t.Errorf("wrong cache directory contents after upgrade\n%s", diff) + } + + // The upgrade process has updated the lock file. + locks, err := m.lockedDependencies() + if err != nil { + t.Fatalf("failed to get locked dependencies: %s", err) + } + gotProviderLocks := locks.AllProviders() + wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{ + addrs.NewDefaultProvider("foobar"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("foobar"), + getproviders.MustParseVersion("9.9.9"), + getproviders.MustParseVersionConstraints("> 1.0.0"), + []getproviders.Hash{ + getproviders.HashScheme1.New("cHfrPr8b4Wjf8x014vgi4H3qQ6tOd+vEVchLY0PnuFE="), + }, + ), + addrs.NewDefaultProvider("test"): depsfile.NewProviderLock( + addrs.NewDefaultProvider("test"), + getproviders.MustParseVersion("1.2.3"), + getproviders.MustParseVersionConstraints("1.2.3"), + []getproviders.Hash{ + getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="), + }, + ), + } + if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" { + t.Errorf("wrong version selections after upgrade\n%s", diff) + } + }) } func TestInit_getProviderMissing(t *testing.T) {