internal/helm: local builder & dep manager test
Add more chart local builder and dependency manager tests. Signed-off-by: Sunny <darkowlzz@protonmail.com>
This commit is contained in:
parent
32e19ebcd0
commit
7c910e37a2
1
go.mod
1
go.mod
|
@ -38,6 +38,7 @@ require (
|
|||
github.com/minio/minio-go/v7 v7.0.10
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.14.0
|
||||
github.com/otiai10/copy v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 // indirect
|
||||
github.com/yvasiyarov/gorelic v0.0.7 // indirect
|
||||
|
|
7
go.sum
7
go.sum
|
@ -738,6 +738,13 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
|
|||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
|
||||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
|
|
|
@ -17,14 +17,225 @@ limitations under the License.
|
|||
package chart
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/otiai10/copy"
|
||||
helmchart "helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
"github.com/fluxcd/source-controller/internal/helm/getter"
|
||||
"github.com/fluxcd/source-controller/internal/helm/repository"
|
||||
)
|
||||
|
||||
func TestLocalBuilder_Build(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
// Prepare chart repositories to be used for charts with remote dependency.
|
||||
chartB, err := os.ReadFile("./../testdata/charts/helmchart-0.1.0.tgz")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(chartB).ToNot(BeEmpty())
|
||||
mockRepo := func() *repository.ChartRepository {
|
||||
return &repository.ChartRepository{
|
||||
Client: &getter.MockGetter{
|
||||
Response: chartB,
|
||||
},
|
||||
Index: &repo.IndexFile{
|
||||
Entries: map[string]repo.ChartVersions{
|
||||
"grafana": {
|
||||
&repo.ChartVersion{
|
||||
Metadata: &helmchart.Metadata{
|
||||
Name: "grafana",
|
||||
Version: "6.17.4",
|
||||
},
|
||||
URLs: []string{"https://example.com/grafana.tgz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RWMutex: &sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
reference Reference
|
||||
buildOpts BuildOptions
|
||||
valueFiles []helmchart.File
|
||||
repositories map[string]*repository.ChartRepository
|
||||
dependentChartPaths []string
|
||||
wantValues chartutil.Values
|
||||
wantVersion string
|
||||
wantPackaged bool
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "invalid reference",
|
||||
reference: RemoteReference{},
|
||||
wantErr: "expected local chart reference",
|
||||
},
|
||||
{
|
||||
name: "invalid local reference - no path",
|
||||
reference: LocalReference{},
|
||||
wantErr: "no path set for local chart reference",
|
||||
},
|
||||
{
|
||||
name: "invalid local reference - no file",
|
||||
reference: LocalReference{Path: "/tmp/non-existent-path.xyz"},
|
||||
wantErr: "no such file or directory",
|
||||
},
|
||||
{
|
||||
name: "invalid version metadata",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchart"},
|
||||
buildOpts: BuildOptions{VersionMetadata: "^"},
|
||||
wantErr: "Invalid Metadata string",
|
||||
},
|
||||
{
|
||||
name: "with version metadata",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchart"},
|
||||
buildOpts: BuildOptions{VersionMetadata: "foo"},
|
||||
wantVersion: "0.1.0+foo",
|
||||
wantPackaged: true,
|
||||
},
|
||||
// TODO: Test setting BuildOptions CachedChart and Force.
|
||||
{
|
||||
name: "already packaged chart",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchart-0.1.0.tgz"},
|
||||
wantVersion: "0.1.0",
|
||||
wantPackaged: false,
|
||||
},
|
||||
{
|
||||
name: "default values",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchart"},
|
||||
wantValues: chartutil.Values{
|
||||
"replicaCount": float64(1),
|
||||
},
|
||||
wantVersion: "0.1.0",
|
||||
wantPackaged: true,
|
||||
},
|
||||
{
|
||||
name: "with value files",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchart"},
|
||||
buildOpts: BuildOptions{
|
||||
ValueFiles: []string{"custom-values1.yaml", "custom-values2.yaml"},
|
||||
},
|
||||
valueFiles: []helmchart.File{
|
||||
{
|
||||
Name: "custom-values1.yaml",
|
||||
Data: []byte(`replicaCount: 11
|
||||
nameOverride: "foo-name-override"`),
|
||||
},
|
||||
{
|
||||
Name: "custom-values2.yaml",
|
||||
Data: []byte(`replicaCount: 20
|
||||
fullnameOverride: "full-foo-name-override"`),
|
||||
},
|
||||
},
|
||||
wantValues: chartutil.Values{
|
||||
"replicaCount": float64(20),
|
||||
"nameOverride": "foo-name-override",
|
||||
"fullnameOverride": "full-foo-name-override",
|
||||
},
|
||||
wantVersion: "0.1.0",
|
||||
wantPackaged: true,
|
||||
},
|
||||
{
|
||||
name: "chart with dependencies",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchartwithdeps"},
|
||||
repositories: map[string]*repository.ChartRepository{
|
||||
"https://grafana.github.io/helm-charts/": mockRepo(),
|
||||
},
|
||||
dependentChartPaths: []string{"./../testdata/charts/helmchart"},
|
||||
wantVersion: "0.1.0",
|
||||
wantPackaged: true,
|
||||
},
|
||||
{
|
||||
name: "v1 chart",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchart-v1"},
|
||||
wantValues: chartutil.Values{
|
||||
"replicaCount": float64(1),
|
||||
},
|
||||
wantVersion: "0.2.0",
|
||||
wantPackaged: true,
|
||||
},
|
||||
{
|
||||
name: "v1 chart with dependencies",
|
||||
reference: LocalReference{Path: "./../testdata/charts/helmchartwithdeps-v1"},
|
||||
repositories: map[string]*repository.ChartRepository{
|
||||
"https://grafana.github.io/helm-charts/": mockRepo(),
|
||||
},
|
||||
dependentChartPaths: []string{"./../testdata/charts/helmchart-v1"},
|
||||
wantVersion: "0.3.0",
|
||||
wantPackaged: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
workDir, err := os.MkdirTemp("", "local-builder-")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(workDir)
|
||||
|
||||
// Only if the reference is a LocalReference, set the WorkDir.
|
||||
localRef, ok := tt.reference.(LocalReference)
|
||||
if ok {
|
||||
localRef.WorkDir = workDir
|
||||
tt.reference = localRef
|
||||
}
|
||||
|
||||
// Write value file in the base dir.
|
||||
for _, f := range tt.valueFiles {
|
||||
vPath := filepath.Join(workDir, f.Name)
|
||||
g.Expect(os.WriteFile(vPath, f.Data, 0644)).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// Write chart dependencies in the base dir.
|
||||
for _, dcp := range tt.dependentChartPaths {
|
||||
// Construct the chart path relative to the testdata chart.
|
||||
helmchartDir := filepath.Join(workDir, "testdata", "charts", filepath.Base(dcp))
|
||||
g.Expect(copy.Copy(dcp, helmchartDir)).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// Target path with name similar to the workDir.
|
||||
targetPath := workDir + ".tgz"
|
||||
defer os.RemoveAll(targetPath)
|
||||
|
||||
dm := NewDependencyManager(
|
||||
WithRepositories(tt.repositories),
|
||||
)
|
||||
|
||||
b := NewLocalBuilder(dm)
|
||||
cb, err := b.Build(context.TODO(), tt.reference, targetPath, tt.buildOpts)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
g.Expect(err.Error()).To(ContainSubstring(tt.wantErr))
|
||||
g.Expect(cb).To(BeZero())
|
||||
return
|
||||
}
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(cb.Packaged).To(Equal(tt.wantPackaged), "unexpected Build.Packaged value")
|
||||
g.Expect(cb.Path).ToNot(BeEmpty(), "empty Build.Path")
|
||||
|
||||
// Load the resulting chart and verify the values.
|
||||
resultChart, err := loader.Load(cb.Path)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(resultChart.Metadata.Version).To(Equal(tt.wantVersion))
|
||||
|
||||
for k, v := range tt.wantValues {
|
||||
g.Expect(v).To(Equal(resultChart.Values[k]))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mergeFileValues(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
@ -35,6 +35,36 @@ import (
|
|||
)
|
||||
|
||||
func TestDependencyManager_Build(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
// Mock chart used as grafana chart in the test below. The cached repository
|
||||
// takes care of the actual grafana related details in the chart index.
|
||||
chartGrafana, err := os.ReadFile("./../testdata/charts/helmchart-0.1.0.tgz")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(chartGrafana).ToNot(BeEmpty())
|
||||
|
||||
mockRepo := func() *repository.ChartRepository {
|
||||
return &repository.ChartRepository{
|
||||
Client: &getter.MockGetter{
|
||||
Response: chartGrafana,
|
||||
},
|
||||
Index: &repo.IndexFile{
|
||||
Entries: map[string]repo.ChartVersions{
|
||||
"grafana": {
|
||||
&repo.ChartVersion{
|
||||
Metadata: &helmchart.Metadata{
|
||||
Name: "grafana",
|
||||
Version: "6.17.4",
|
||||
},
|
||||
URLs: []string{"https://example.com/grafana.tgz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RWMutex: &sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
baseDir string
|
||||
|
@ -45,12 +75,6 @@ func TestDependencyManager_Build(t *testing.T) {
|
|||
wantChartFunc func(g *WithT, c *helmchart.Chart)
|
||||
wantErr string
|
||||
}{
|
||||
//{
|
||||
// // TODO(hidde): add various happy paths
|
||||
//},
|
||||
//{
|
||||
// // TODO(hidde): test Chart.lock
|
||||
//},
|
||||
{
|
||||
name: "build failure returns error",
|
||||
baseDir: "./../testdata/charts",
|
||||
|
@ -61,7 +85,44 @@ func TestDependencyManager_Build(t *testing.T) {
|
|||
name: "no dependencies returns zero",
|
||||
baseDir: "./../testdata/charts",
|
||||
path: "helmchart",
|
||||
want: 0,
|
||||
wantChartFunc: func(g *WithT, c *helmchart.Chart) {
|
||||
g.Expect(c.Dependencies()).To(HaveLen(0))
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "no dependency returns zero - v1",
|
||||
baseDir: "./../testdata/charts",
|
||||
path: "helmchart-v1",
|
||||
wantChartFunc: func(g *WithT, c *helmchart.Chart) {
|
||||
g.Expect(c.Dependencies()).To(HaveLen(0))
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "build with dependencies using lock file",
|
||||
baseDir: "./../testdata/charts",
|
||||
path: "helmchartwithdeps",
|
||||
repositories: map[string]*repository.ChartRepository{
|
||||
"https://grafana.github.io/helm-charts/": mockRepo(),
|
||||
},
|
||||
getChartRepositoryCallback: func(url string) (*repository.ChartRepository, error) {
|
||||
return &repository.ChartRepository{URL: "https://grafana.github.io/helm-charts/"}, nil
|
||||
},
|
||||
wantChartFunc: func(g *WithT, c *helmchart.Chart) {
|
||||
g.Expect(c.Dependencies()).To(HaveLen(2))
|
||||
g.Expect(c.Lock.Dependencies).To(HaveLen(3))
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "build with dependencies - v1",
|
||||
baseDir: "./../testdata/charts",
|
||||
path: "helmchartwithdeps-v1",
|
||||
wantChartFunc: func(g *WithT, c *helmchart.Chart) {
|
||||
g.Expect(c.Dependencies()).To(HaveLen(1))
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -71,10 +132,11 @@ func TestDependencyManager_Build(t *testing.T) {
|
|||
chart, err := loader.Load(filepath.Join(tt.baseDir, tt.path))
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
got, err := NewDependencyManager(
|
||||
dm := NewDependencyManager(
|
||||
WithRepositories(tt.repositories),
|
||||
WithRepositoryCallback(tt.getChartRepositoryCallback),
|
||||
).Build(context.TODO(), LocalReference{WorkDir: tt.baseDir, Path: tt.path}, chart)
|
||||
)
|
||||
got, err := dm.Build(context.TODO(), LocalReference{WorkDir: tt.baseDir, Path: tt.path}, chart)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
|
@ -198,6 +260,10 @@ func TestDependencyManager_addLocalDependency(t *testing.T) {
|
|||
return
|
||||
}
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
if tt.wantFunc != nil {
|
||||
tt.wantFunc(g, chart)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue