| package getproviders |
| |
| import ( |
| "context" |
| "fmt" |
| "regexp" |
| "strings" |
| "testing" |
| |
| "github.com/apparentlymart/go-versions/versions" |
| "github.com/google/go-cmp/cmp" |
| svchost "github.com/hashicorp/terraform-svchost" |
| |
| "github.com/hashicorp/terraform/internal/addrs" |
| ) |
| |
| func TestSourceAvailableVersions(t *testing.T) { |
| source, baseURL, close := testRegistrySource(t) |
| defer close() |
| |
| tests := []struct { |
| provider string |
| wantVersions []string |
| wantErr string |
| }{ |
| // These test cases are relying on behaviors of the fake provider |
| // registry server implemented in registry_client_test.go. |
| { |
| "example.com/awesomesauce/happycloud", |
| []string{"0.1.0", "1.0.0", "1.2.0", "2.0.0"}, |
| ``, |
| }, |
| { |
| "example.com/weaksauce/no-versions", |
| nil, |
| ``, // having no versions is not an error, it's just odd |
| }, |
| { |
| "example.com/nonexist/nonexist", |
| nil, |
| `provider registry example.com does not have a provider named example.com/nonexist/nonexist`, |
| }, |
| { |
| "not.example.com/foo/bar", |
| nil, |
| `host not.example.com does not offer a Terraform provider registry`, |
| }, |
| { |
| "too-new.example.com/foo/bar", |
| nil, |
| `host too-new.example.com does not support the provider registry protocol required by this Terraform version, but may be compatible with a different Terraform version`, |
| }, |
| { |
| "fails.example.com/foo/bar", |
| nil, |
| `could not query provider registry for fails.example.com/foo/bar: the request failed after 2 attempts, please try again later: Get "` + baseURL + `/fails-immediately/foo/bar/versions": EOF`, |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run(test.provider, func(t *testing.T) { |
| provider := addrs.MustParseProviderSourceString(test.provider) |
| gotVersions, _, err := source.AvailableVersions(context.Background(), provider) |
| |
| if err != nil { |
| if test.wantErr == "" { |
| t.Fatalf("wrong error\ngot: %s\nwant: <nil>", err.Error()) |
| } |
| if got, want := err.Error(), test.wantErr; got != want { |
| t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) |
| } |
| return |
| } |
| |
| if test.wantErr != "" { |
| t.Fatalf("wrong error\ngot: <nil>\nwant: %s", test.wantErr) |
| } |
| |
| var gotVersionsStr []string |
| if gotVersions != nil { |
| gotVersionsStr = make([]string, len(gotVersions)) |
| for i, v := range gotVersions { |
| gotVersionsStr[i] = v.String() |
| } |
| } |
| |
| if diff := cmp.Diff(test.wantVersions, gotVersionsStr); diff != "" { |
| t.Errorf("wrong result\n%s", diff) |
| } |
| }) |
| } |
| } |
| |
| func TestSourceAvailableVersions_warnings(t *testing.T) { |
| source, _, close := testRegistrySource(t) |
| defer close() |
| |
| provider := addrs.MustParseProviderSourceString("example.com/weaksauce/no-versions") |
| _, warnings, err := source.AvailableVersions(context.Background(), provider) |
| if err != nil { |
| t.Fatalf("unexpected error: %s", err.Error()) |
| } |
| |
| if len(warnings) != 1 { |
| t.Fatalf("wrong number of warnings. Expected 1, got %d", len(warnings)) |
| } |
| |
| } |
| |
| func TestSourcePackageMeta(t *testing.T) { |
| source, baseURL, close := testRegistrySource(t) |
| defer close() |
| |
| tests := []struct { |
| provider string |
| version string |
| os, arch string |
| want PackageMeta |
| wantHashes []Hash |
| wantErr string |
| }{ |
| // These test cases are relying on behaviors of the fake provider |
| // registry server implemented in registry_client_test.go. |
| { |
| "example.com/awesomesauce/happycloud", |
| "1.2.0", |
| "linux", "amd64", |
| PackageMeta{ |
| Provider: addrs.NewProvider( |
| svchost.Hostname("example.com"), "awesomesauce", "happycloud", |
| ), |
| Version: versions.MustParseVersion("1.2.0"), |
| ProtocolVersions: VersionList{versions.MustParseVersion("5.0.0")}, |
| TargetPlatform: Platform{"linux", "amd64"}, |
| Filename: "happycloud_1.2.0.zip", |
| Location: PackageHTTPURL(baseURL + "/pkg/awesomesauce/happycloud_1.2.0.zip"), |
| Authentication: PackageAuthenticationAll( |
| NewMatchingChecksumAuthentication( |
| []byte("000000000000000000000000000000000000000000000000000000000000f00d happycloud_1.2.0.zip\n000000000000000000000000000000000000000000000000000000000000face happycloud_1.2.0_face.zip\n"), |
| "happycloud_1.2.0.zip", |
| [32]byte{30: 0xf0, 31: 0x0d}, |
| ), |
| NewArchiveChecksumAuthentication(Platform{"linux", "amd64"}, [32]byte{30: 0xf0, 31: 0x0d}), |
| NewSignatureAuthentication( |
| []byte("000000000000000000000000000000000000000000000000000000000000f00d happycloud_1.2.0.zip\n000000000000000000000000000000000000000000000000000000000000face happycloud_1.2.0_face.zip\n"), |
| []byte("GPG signature"), |
| []SigningKey{ |
| {ASCIIArmor: HashicorpPublicKey}, |
| }, |
| ), |
| ), |
| }, |
| []Hash{ |
| "zh:000000000000000000000000000000000000000000000000000000000000f00d", |
| "zh:000000000000000000000000000000000000000000000000000000000000face", |
| }, |
| ``, |
| }, |
| { |
| "example.com/awesomesauce/happycloud", |
| "1.2.0", |
| "nonexist", "amd64", |
| PackageMeta{}, |
| nil, |
| `provider example.com/awesomesauce/happycloud 1.2.0 is not available for nonexist_amd64`, |
| }, |
| { |
| "not.example.com/awesomesauce/happycloud", |
| "1.2.0", |
| "linux", "amd64", |
| PackageMeta{}, |
| nil, |
| `host not.example.com does not offer a Terraform provider registry`, |
| }, |
| { |
| "too-new.example.com/awesomesauce/happycloud", |
| "1.2.0", |
| "linux", "amd64", |
| PackageMeta{}, |
| nil, |
| `host too-new.example.com does not support the provider registry protocol required by this Terraform version, but may be compatible with a different Terraform version`, |
| }, |
| { |
| "fails.example.com/awesomesauce/happycloud", |
| "1.2.0", |
| "linux", "amd64", |
| PackageMeta{}, |
| nil, |
| `could not query provider registry for fails.example.com/awesomesauce/happycloud: the request failed after 2 attempts, please try again later: Get "http://placeholder-origin/fails-immediately/awesomesauce/happycloud/1.2.0/download/linux/amd64": EOF`, |
| }, |
| } |
| |
| // Sometimes error messages contain specific HTTP endpoint URLs, but |
| // since our test server is on a random port we'd not be able to |
| // consistently match those. Instead, we'll normalize the URLs. |
| urlPattern := regexp.MustCompile(`http://[^/]+/`) |
| |
| cmpOpts := cmp.Comparer(Version.Same) |
| |
| for _, test := range tests { |
| t.Run(fmt.Sprintf("%s for %s_%s", test.provider, test.os, test.arch), func(t *testing.T) { |
| // TEMP: We don't yet have a function for parsing provider |
| // source addresses so we'll just fake it in here for now. |
| parts := strings.Split(test.provider, "/") |
| providerAddr := addrs.Provider{ |
| Hostname: svchost.Hostname(parts[0]), |
| Namespace: parts[1], |
| Type: parts[2], |
| } |
| |
| version := versions.MustParseVersion(test.version) |
| |
| got, err := source.PackageMeta(context.Background(), providerAddr, version, Platform{test.os, test.arch}) |
| |
| if err != nil { |
| if test.wantErr == "" { |
| t.Fatalf("wrong error\ngot: %s\nwant: <nil>", err.Error()) |
| } |
| gotErr := urlPattern.ReplaceAllLiteralString(err.Error(), "http://placeholder-origin/") |
| if got, want := gotErr, test.wantErr; got != want { |
| t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) |
| } |
| return |
| } |
| |
| if test.wantErr != "" { |
| t.Fatalf("wrong error\ngot: <nil>\nwant: %s", test.wantErr) |
| } |
| |
| if diff := cmp.Diff(test.want, got, cmpOpts); diff != "" { |
| t.Errorf("wrong result\n%s", diff) |
| } |
| if diff := cmp.Diff(test.wantHashes, got.AcceptableHashes()); diff != "" { |
| t.Errorf("wrong AcceptableHashes result\n%s", diff) |
| } |
| }) |
| } |
| |
| } |