providers subcommand tests (#28744)
* getproviders ParsePlatform: add check for invalid platform strings with too many parts The existing logic would not catch things like a platform string containing multiple underscores. I've added an explicit check for exactly 2 parts and some basic tests to prove it. * command/providers-lock: add tests This commit adds some simple tests for the providers lock command. While adding this test I noticed that there was a mis-copied error message, so I replaced that with a more specific message. I also added .terraform.lock.hcl to our gitignore for hopefully obvious reasons. getproviders.ParsePlatform: use parts in place of slice range, since it's available * command: Providers mirror tests The providers mirror command is already well tested in e2e tests, so this includes only the most absolutely basic test case.
This commit is contained in:
parent
a4ed1405f5
commit
649095c602
|
@ -128,8 +128,8 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||
// current configuration.
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Invalid network mirror URL",
|
||||
"The -net-mirror option requires a valid https: URL as the mirror base URL.",
|
||||
"Invalid provider argument",
|
||||
fmt.Sprintf("The provider %s is not required by the current configuration.", addr.String()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func TestProvidersLock(t *testing.T) {
|
||||
t.Run("noop", func(t *testing.T) {
|
||||
// in the most basic case, running providers lock in a directory with no configuration at all should succeed.
|
||||
// create an empty working directory
|
||||
td := tempDir(t)
|
||||
os.MkdirAll(td, 0755)
|
||||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersLockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
code := c.Run([]string{})
|
||||
if code != 0 {
|
||||
t.Fatalf("wrong exit code; expected 0, got %d", code)
|
||||
}
|
||||
})
|
||||
|
||||
// This test depends on the -fs-mirror argument, so we always know what results to expect
|
||||
t.Run("basic", func(t *testing.T) {
|
||||
td := tempDir(t)
|
||||
testCopyDir(t, testFixturePath("providers-lock/basic"), td)
|
||||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
// Our fixture dir has a generic os_arch dir, which we need to customize
|
||||
// to the actual OS/arch where this test is running in order to get the
|
||||
// desired result.
|
||||
fixtMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch")
|
||||
wantMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
|
||||
err := os.Rename(fixtMachineDir, wantMachineDir)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersLockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{"-fs-mirror=fs-mirror"}
|
||||
code := c.Run(args)
|
||||
if code != 0 {
|
||||
t.Fatalf("wrong exit code; expected 0, got %d", code)
|
||||
}
|
||||
|
||||
lockfile, err := os.ReadFile(".terraform.lock.hcl")
|
||||
if err != nil {
|
||||
t.Fatal("error reading lockfile")
|
||||
}
|
||||
|
||||
expected := `# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/test" {
|
||||
version = "1.0.0"
|
||||
hashes = [
|
||||
"h1:7MjN4eFisdTv4tlhXH5hL4QQd39Jy4baPhFxwAd/EFE=",
|
||||
]
|
||||
}
|
||||
`
|
||||
if string(lockfile) != expected {
|
||||
t.Fatalf("wrong lockfile content")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestProvidersLock_args(t *testing.T) {
|
||||
|
||||
t.Run("mirror collision", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersLockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
// only one of these arguments can be used at a time
|
||||
args := []string{
|
||||
"-fs-mirror=/foo/",
|
||||
"-net-mirror=www.foo.com",
|
||||
}
|
||||
code := c.Run(args)
|
||||
|
||||
if code != 1 {
|
||||
t.Fatalf("wrong exit code; expected 1, got %d", code)
|
||||
}
|
||||
output := ui.ErrorWriter.String()
|
||||
if !strings.Contains(output, "The -fs-mirror and -net-mirror command line options are mutually-exclusive.") {
|
||||
t.Fatalf("missing expected error message: %s", output)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid platform", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersLockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
// not a valid platform
|
||||
args := []string{"-platform=arbitrary_nonsense_that_isnt_valid"}
|
||||
code := c.Run(args)
|
||||
|
||||
if code != 1 {
|
||||
t.Fatalf("wrong exit code; expected 1, got %d", code)
|
||||
}
|
||||
output := ui.ErrorWriter.String()
|
||||
if !strings.Contains(output, "must be two words separated by an underscore.") {
|
||||
t.Fatalf("missing expected error message: %s", output)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid provider argument", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersLockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
// There is no configuration, so it's not valid to use any provider argument
|
||||
args := []string{"hashicorp/random"}
|
||||
code := c.Run(args)
|
||||
|
||||
if code != 1 {
|
||||
t.Fatalf("wrong exit code; expected 1, got %d", code)
|
||||
}
|
||||
output := ui.ErrorWriter.String()
|
||||
if !strings.Contains(output, "The provider registry.terraform.io/hashicorp/random is not required by the\ncurrent configuration.") {
|
||||
t.Fatalf("missing expected error message: %s", output)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// More thorough tests for providers mirror can be found in the e2etest
|
||||
func TestProvidersMirror(t *testing.T) {
|
||||
// noop example
|
||||
t.Run("noop", func(t *testing.T) {
|
||||
c := &ProvidersMirrorCommand{}
|
||||
code := c.Run([]string{"."})
|
||||
if code != 0 {
|
||||
t.Fatalf("wrong exit code. expected 0, got %d", code)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missing arg error", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersMirrorCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
}
|
||||
code := c.Run([]string{})
|
||||
if code != 1 {
|
||||
t.Fatalf("wrong exit code. expected 1, got %d", code)
|
||||
}
|
||||
|
||||
got := ui.ErrorWriter.String()
|
||||
if !strings.Contains(got, "Error: No output directory specified") {
|
||||
t.Fatalf("missing directory error from output, got:\n%s\n", got)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
test = {
|
||||
source = "hashicorp/test"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -137,12 +137,12 @@ func (p Platform) LessThan(other Platform) bool {
|
|||
// ParsePlatform parses a string representation of a platform, like
|
||||
// "linux_amd64", or returns an error if the string is not valid.
|
||||
func ParsePlatform(str string) (Platform, error) {
|
||||
underPos := strings.Index(str, "_")
|
||||
if underPos < 1 || underPos >= len(str)-2 {
|
||||
parts := strings.Split(str, "_")
|
||||
if len(parts) != 2 {
|
||||
return Platform{}, fmt.Errorf("must be two words separated by an underscore")
|
||||
}
|
||||
|
||||
os, arch := str[:underPos], str[underPos+1:]
|
||||
os, arch := parts[0], parts[1]
|
||||
if strings.ContainsAny(os, " \t\n\r") {
|
||||
return Platform{}, fmt.Errorf("OS portion must not contain whitespace")
|
||||
}
|
||||
|
|
|
@ -94,3 +94,48 @@ func TestVersionConstraintsString(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePlatform(t *testing.T) {
|
||||
tests := []struct {
|
||||
Input string
|
||||
Want Platform
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
"",
|
||||
Platform{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"too_many_notes",
|
||||
Platform{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"extra _ whitespaces ",
|
||||
Platform{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"arbitrary_os",
|
||||
Platform{OS: "arbitrary", Arch: "os"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got, err := ParsePlatform(test.Input)
|
||||
if err != nil {
|
||||
if test.Err == false {
|
||||
t.Errorf("unexpected error: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if test.Err {
|
||||
t.Errorf("wrong result: expected error, got none")
|
||||
}
|
||||
}
|
||||
if got != test.Want {
|
||||
t.Errorf("wrong\n got: %q\nwant: %q", got, test.Want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue