Files
opentf/internal/getproviders/filesystem_mirror_source_test.go
Martin Atkins 55855fca70 getproviders: Unify package authentication with hash lock selection
As discussed in opentofu/opentofu#2656, this consolidates the two concerns
of the PackageAuthentication interface into a single function that deals
both with package authentication _and_ with reporting all of the package
hashes that were used to make the authentication decision.

This means that any .zip archive that OpenTofu directly verifies during
installation can now have its hash recorded in the dependency lock file
even if that package didn't come from the provider's origin registry, which
is beneficial when the first installation of a provider comes from a
secondary ("mirror") source because it creates an additional hook by which
that dependency lock file entry can be "upgraded" to be complete in a
future "tofu init" run against the origin registry, or by the
"tofu providers lock" command.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-04-14 08:31:40 -07:00

229 lines
7.7 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package getproviders
import (
"context"
"strings"
"testing"
"github.com/apparentlymart/go-versions/versions"
"github.com/google/go-cmp/cmp"
svchost "github.com/hashicorp/terraform-svchost"
"github.com/opentofu/opentofu/internal/addrs"
)
func TestFilesystemMirrorSourceAllAvailablePackages(t *testing.T) {
source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
got, err := source.AllAvailablePackages()
if err != nil {
t.Fatal(err)
}
want := map[addrs.Provider]PackageMetaList{
nullProvider: {
{
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
TargetPlatform: Platform{"darwin", "amd64"},
Filename: "terraform-provider-null_2.0.0_darwin_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/null/2.0.0/darwin_amd64"),
},
{
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
TargetPlatform: Platform{"linux", "amd64"},
Filename: "terraform-provider-null_2.0.0_linux_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/null/2.0.0/linux_amd64"),
},
{
Provider: nullProvider,
Version: versions.MustParseVersion("2.1.0"),
TargetPlatform: Platform{"linux", "amd64"},
Filename: "terraform-provider-null_2.1.0_linux_amd64.zip",
Location: PackageLocalArchive("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip"),
},
{
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
TargetPlatform: Platform{"windows", "amd64"},
Filename: "terraform-provider-null_2.0.0_windows_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/null/2.0.0/windows_amd64"),
},
},
randomBetaProvider: {
{
Provider: randomBetaProvider,
Version: versions.MustParseVersion("1.2.0"),
TargetPlatform: Platform{"linux", "amd64"},
Filename: "terraform-provider-random-beta_1.2.0_linux_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/random-beta/1.2.0/linux_amd64"),
},
},
randomProvider: {
{
Provider: randomProvider,
Version: versions.MustParseVersion("1.2.0"),
TargetPlatform: Platform{"linux", "amd64"},
Filename: "terraform-provider-random_1.2.0_linux_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/random/1.2.0/linux_amd64"),
},
},
happycloudProvider: {
{
Provider: happycloudProvider,
Version: versions.MustParseVersion("0.1.0-alpha.2"),
TargetPlatform: Platform{"darwin", "amd64"},
Filename: "terraform-provider-happycloud_0.1.0-alpha.2_darwin_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64"),
},
},
legacyProvider: {
{
Provider: legacyProvider,
Version: versions.MustParseVersion("1.0.0"),
TargetPlatform: Platform{"linux", "amd64"},
Filename: "terraform-provider-legacy_1.0.0_linux_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/-/legacy/1.0.0/linux_amd64"),
},
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("incorrect result\n%s", diff)
}
}
// In this test the directory layout is invalid (missing the hostname
// subdirectory). The provider installer should ignore the invalid directory.
func TestFilesystemMirrorSourceAllAvailablePackages_invalid(t *testing.T) {
source := NewFilesystemMirrorSource("testdata/filesystem-mirror-invalid")
_, err := source.AllAvailablePackages()
if err != nil {
t.Fatal(err)
}
}
func TestFilesystemMirrorSourceAvailableVersions(t *testing.T) {
source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
got, _, err := source.AvailableVersions(context.Background(), nullProvider)
if err != nil {
t.Fatal(err)
}
want := VersionList{
versions.MustParseVersion("2.0.0"),
versions.MustParseVersion("2.1.0"),
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("incorrect result\n%s", diff)
}
}
func TestFilesystemMirrorSourceAvailableVersions_Unspecified(t *testing.T) {
unspecifiedProvider := addrs.Provider{
Hostname: svchost.Hostname("registry.opentofu.org"),
Namespace: "testnamespace",
Type: "unspecified",
}
source := NewFilesystemMirrorSource("testdata/filesystem-mirror-unspecified")
got, warn, err := source.AvailableVersions(context.Background(), unspecifiedProvider)
if err != nil {
t.Fatal(err)
}
// Check that we got the unspecified version
if len(got) != 1 || got[0] != versions.Unspecified {
t.Fatalf("expected unspecified version, got %v", got)
}
// We should have unspecified (0.0.0) version warning
if len(warn) != 1 {
t.Fatalf("expected 1 warning, got %v", warn)
}
warningBit := "unspecified (0.0.0) version available in the filesystem mirror"
if !strings.Contains(warn[0], warningBit) {
t.Fatalf("expected warning to contain %q, got %q", warningBit, warn[0])
}
}
func TestFilesystemMirrorSourcePackageMeta(t *testing.T) {
t.Run("available platform", func(t *testing.T) {
source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
got, err := source.PackageMeta(
context.Background(),
nullProvider,
versions.MustParseVersion("2.0.0"),
Platform{"linux", "amd64"},
)
if err != nil {
t.Fatal(err)
}
want := PackageMeta{
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
TargetPlatform: Platform{"linux", "amd64"},
Filename: "terraform-provider-null_2.0.0_linux_amd64.zip",
Location: PackageLocalDir("testdata/filesystem-mirror/registry.opentofu.org/hashicorp/null/2.0.0/linux_amd64"),
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("incorrect result\n%s", diff)
}
})
t.Run("unavailable platform", func(t *testing.T) {
source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
// We'll request a version that does exist in the fixture directory,
// but for a platform that isn't supported.
_, err := source.PackageMeta(
context.Background(),
nullProvider,
versions.MustParseVersion("2.0.0"),
Platform{"nonexist", "nonexist"},
)
if err == nil {
t.Fatalf("succeeded; want error")
}
// This specific error type is important so callers can use it to
// generate an actionable error message e.g. by checking to see if
// _any_ versions of this provider support the given platform, or
// similar helpful hints.
wantErr := ErrPlatformNotSupported{
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
Platform: Platform{"nonexist", "nonexist"},
}
if diff := cmp.Diff(wantErr, err); diff != "" {
t.Errorf("incorrect error\n%s", diff)
}
})
}
var nullProvider = addrs.Provider{
Hostname: svchost.Hostname("registry.opentofu.org"),
Namespace: "hashicorp",
Type: "null",
}
var randomProvider = addrs.Provider{
Hostname: svchost.Hostname("registry.opentofu.org"),
Namespace: "hashicorp",
Type: "random",
}
var randomBetaProvider = addrs.Provider{
Hostname: svchost.Hostname("registry.opentofu.org"),
Namespace: "hashicorp",
Type: "random-beta",
}
var happycloudProvider = addrs.Provider{
Hostname: svchost.Hostname("tfe.example.com"),
Namespace: "awesomecorp",
Type: "happycloud",
}
var legacyProvider = addrs.NewLegacyProvider("legacy")