275 lines
7.0 KiB
Go
275 lines
7.0 KiB
Go
/*
|
|
Copyright 2022 The Flux authors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package repository
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net/url"
|
|
"path"
|
|
"strings"
|
|
"testing"
|
|
|
|
. "github.com/onsi/gomega"
|
|
"helm.sh/helm/v3/pkg/chart"
|
|
helmgetter "helm.sh/helm/v3/pkg/getter"
|
|
"helm.sh/helm/v3/pkg/registry"
|
|
"helm.sh/helm/v3/pkg/repo"
|
|
)
|
|
|
|
type OCIMockGetter struct {
|
|
Response []byte
|
|
LastCalledURL string
|
|
}
|
|
|
|
func (g *OCIMockGetter) Get(u string, _ ...helmgetter.Option) (*bytes.Buffer, error) {
|
|
r := g.Response
|
|
g.LastCalledURL = u
|
|
return bytes.NewBuffer(r), nil
|
|
}
|
|
|
|
type mockRegistryClient struct {
|
|
tags []string
|
|
LastCalledURL string
|
|
}
|
|
|
|
func (m *mockRegistryClient) Tags(urlStr string) ([]string, error) {
|
|
m.LastCalledURL = urlStr
|
|
return m.tags, nil
|
|
}
|
|
|
|
func (m *mockRegistryClient) Login(url string, opts ...registry.LoginOption) error {
|
|
m.LastCalledURL = url
|
|
return nil
|
|
}
|
|
|
|
func (m *mockRegistryClient) Logout(url string, opts ...registry.LogoutOption) error {
|
|
m.LastCalledURL = url
|
|
return nil
|
|
}
|
|
|
|
func TestNewOCIChartRepository(t *testing.T) {
|
|
registryClient := &mockRegistryClient{}
|
|
url := "oci://localhost:5000/my_repo"
|
|
providers := helmgetter.Providers{
|
|
helmgetter.Provider{
|
|
Schemes: []string{"oci"},
|
|
New: helmgetter.NewOCIGetter,
|
|
},
|
|
}
|
|
options := []helmgetter.Option{helmgetter.WithBasicAuth("username", "password")}
|
|
t.Run("should construct chart registry", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
r, err := NewOCIChartRepository(url, WithOCIGetter(providers), WithOCIGetterOptions(options), WithOCIRegistryClient(registryClient))
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
g.Expect(r).ToNot(BeNil())
|
|
g.Expect(r.URL.Host).To(Equal("localhost:5000"))
|
|
g.Expect(r.Client).ToNot(BeNil())
|
|
g.Expect(r.Options).To(Equal(options))
|
|
g.Expect(r.RegistryClient).To(Equal(registryClient))
|
|
})
|
|
|
|
t.Run("should return error on invalid url", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
r, err := NewOCIChartRepository("oci://localhost:5000 /my_repo", WithOCIGetter(providers), WithOCIGetterOptions(options), WithOCIRegistryClient(registryClient))
|
|
g.Expect(err).To(HaveOccurred())
|
|
g.Expect(r).To(BeNil())
|
|
})
|
|
|
|
}
|
|
|
|
func TestOCIChartRepository_Get(t *testing.T) {
|
|
registryClient := &mockRegistryClient{
|
|
tags: []string{
|
|
"0.0.1",
|
|
"0.1.0",
|
|
"0.1.1",
|
|
"0.1.5+b.min.minute",
|
|
"0.1.5+a.min.hour",
|
|
"0.1.5+c.now",
|
|
"0.2.0",
|
|
"0.9.0",
|
|
"0.10.0",
|
|
"1.0.0",
|
|
"1.1.0-rc.1",
|
|
},
|
|
}
|
|
|
|
providers := helmgetter.Providers{
|
|
helmgetter.Provider{
|
|
Schemes: []string{"oci"},
|
|
New: helmgetter.NewOCIGetter,
|
|
},
|
|
}
|
|
testURL := "oci://localhost:5000/my_repo"
|
|
|
|
testCases := []struct {
|
|
name string
|
|
registryClient RegistryClient
|
|
url string
|
|
version string
|
|
expected string
|
|
expectedErr string
|
|
}{
|
|
{
|
|
name: "should return latest stable version",
|
|
registryClient: registryClient,
|
|
version: "",
|
|
url: testURL,
|
|
expected: "1.0.0",
|
|
},
|
|
{
|
|
name: "should return latest stable version (asterisk)",
|
|
registryClient: registryClient,
|
|
version: "*",
|
|
url: testURL,
|
|
expected: "1.0.0",
|
|
},
|
|
{
|
|
name: "should return latest stable version (semver range)",
|
|
registryClient: registryClient,
|
|
version: ">=0.1.5",
|
|
url: testURL,
|
|
expected: "1.0.0",
|
|
},
|
|
{
|
|
name: "should return 0.2.0 (semver range)",
|
|
registryClient: registryClient,
|
|
version: "0.2.x",
|
|
url: testURL,
|
|
expected: "0.2.0",
|
|
},
|
|
{
|
|
name: "should return a perfect match",
|
|
registryClient: nil,
|
|
version: "0.1.0",
|
|
url: testURL,
|
|
expected: "0.1.0",
|
|
},
|
|
{
|
|
name: "should return 0.10.0",
|
|
registryClient: registryClient,
|
|
version: "0.*",
|
|
url: testURL,
|
|
expected: "0.10.0",
|
|
},
|
|
{
|
|
name: "should an error for unfulfilled range",
|
|
registryClient: registryClient,
|
|
version: ">2.0.0",
|
|
url: testURL,
|
|
expectedErr: "could not locate a version matching provided version string >2.0.0",
|
|
},
|
|
{
|
|
name: "shouldn't error out with trailing slash",
|
|
registryClient: registryClient,
|
|
version: "",
|
|
url: "oci://localhost:5000/my_repo/",
|
|
expected: "1.0.0",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
r, err := NewOCIChartRepository(tc.url, WithOCIRegistryClient(tc.registryClient), WithOCIGetter(providers))
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
g.Expect(r).ToNot(BeNil())
|
|
|
|
chart := "podinfo"
|
|
cv, err := r.GetChartVersion(chart, tc.version)
|
|
if tc.expectedErr != "" {
|
|
g.Expect(err).To(HaveOccurred())
|
|
g.Expect(err.Error()).To(Equal(tc.expectedErr))
|
|
return
|
|
}
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
|
|
u, err := url.Parse(tc.url)
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
u.Path = path.Join(u.Path, chart)
|
|
g.Expect(cv.URLs[0]).To(Equal(fmt.Sprintf("%s:%s", u.String(), tc.expected)))
|
|
g.Expect(registryClient.LastCalledURL).To(Equal(strings.TrimPrefix(u.String(), fmt.Sprintf("%s://", registry.OCIScheme))))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOCIChartRepository_DownloadChart(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
url string
|
|
chartVersion *repo.ChartVersion
|
|
expected string
|
|
expectedErr bool
|
|
}{
|
|
{
|
|
name: "should download chart",
|
|
url: "oci://localhost:5000/my_repo",
|
|
chartVersion: &repo.ChartVersion{
|
|
Metadata: &chart.Metadata{Name: "chart"},
|
|
URLs: []string{"oci://localhost:5000/my_repo/podinfo:1.0.0"},
|
|
},
|
|
expected: "localhost:5000/my_repo/podinfo:1.0.0",
|
|
},
|
|
{
|
|
name: "no chart URL",
|
|
url: "",
|
|
chartVersion: &repo.ChartVersion{Metadata: &chart.Metadata{Name: "chart"}},
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "invalid chart URL",
|
|
url: "oci://localhost:5000/my_repo",
|
|
chartVersion: &repo.ChartVersion{
|
|
Metadata: &chart.Metadata{Name: "chart"},
|
|
URLs: []string{"oci://localhost:5000 /my_repo/podinfo:1.0.0"},
|
|
},
|
|
expectedErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
g := NewWithT(t)
|
|
|
|
u, err := url.Parse(tc.url)
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
|
|
mg := OCIMockGetter{}
|
|
r := OCIChartRepository{
|
|
Client: &mg,
|
|
URL: *u,
|
|
}
|
|
|
|
res, err := r.DownloadChart(tc.chartVersion)
|
|
if tc.expectedErr {
|
|
g.Expect(err).To(HaveOccurred())
|
|
return
|
|
}
|
|
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
g.Expect(mg.LastCalledURL).To(Equal(tc.expected))
|
|
g.Expect(res).ToNot(BeNil())
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
}
|
|
}
|