mirror of
https://github.com/helm/helm.git
synced 2026-05-28 04:35:48 -04:00
Merge 919cbfaac9 into fcdf3854b0
This commit is contained in:
commit
170874b771
20 changed files with 176 additions and 12 deletions
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// UpdateGolden writes out the golden files with the latest values, rather than failing the test.
|
||||
|
|
@ -40,10 +41,10 @@ type HelperT interface {
|
|||
}
|
||||
|
||||
// AssertGoldenString asserts that the given string matches the contents of the given file.
|
||||
func AssertGoldenString(t TestingT, actual, filename string) {
|
||||
func AssertGoldenString(t TestingT, actual, filename string, goldenArgs map[string]string) {
|
||||
t.Helper()
|
||||
|
||||
if err := compare([]byte(actual), path(filename)); err != nil {
|
||||
if err := compare([]byte(actual), path(filename), goldenArgs); err != nil {
|
||||
t.Fatalf("%v\n", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +57,7 @@ func AssertGoldenFile(t TestingT, actualFileName string, expectedFilename string
|
|||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
AssertGoldenString(t, string(actual), expectedFilename)
|
||||
AssertGoldenString(t, string(actual), expectedFilename, map[string]string{})
|
||||
}
|
||||
|
||||
func path(filename string) string {
|
||||
|
|
@ -66,7 +67,7 @@ func path(filename string) string {
|
|||
return filepath.Join("testdata", filename)
|
||||
}
|
||||
|
||||
func compare(actual []byte, filename string) error {
|
||||
func compare(actual []byte, filename string, templates map[string]string) error {
|
||||
actual = normalize(actual)
|
||||
if err := update(filename, actual); err != nil {
|
||||
return err
|
||||
|
|
@ -77,12 +78,34 @@ func compare(actual []byte, filename string) error {
|
|||
return fmt.Errorf("unable to read testdata %s: %w", filename, err)
|
||||
}
|
||||
expected = normalize(expected)
|
||||
|
||||
if len(templates) > 0 {
|
||||
expected, err = templateString(expected, templates)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to template testdata %s: %w", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, actual) {
|
||||
return fmt.Errorf("does not match golden file %s\n\nWANT:\n'%s'\n\nGOT:\n'%s'", filename, expected, actual)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func templateString(content []byte, data map[string]string) ([]byte, error) {
|
||||
tmpl, err := template.New("content").Parse(string(content))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func update(filename string, in []byte) error {
|
||||
if !*updateGolden {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func TestList(t *testing.T) {
|
|||
if err := NewDependency().List(tcase.chart, &buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.AssertGoldenString(t, buf.String(), tcase.golden)
|
||||
test.AssertGoldenString(t, buf.String(), tcase.golden, map[string]string{})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -845,7 +845,7 @@ OUTER:
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dac.Name() == rac.Name() {
|
||||
if dac.Name() == rac.Name() && chartutil.IsCompatibleRange(rac.Version(), dac.Version()) {
|
||||
continue OUTER
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1224,7 +1224,7 @@ func TestInstallCRDs_WaiterError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCheckDependencies(t *testing.T) {
|
||||
dependency := chart.Dependency{Name: "hello"}
|
||||
dependency := chart.Dependency{Name: "hello", Version: "0.1.0"}
|
||||
mockChart := buildChart(withDependency())
|
||||
|
||||
assert.Nil(t, CheckDependencies(mockChart, []ci.Dependency{&dependency}))
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ func (r *v2Accessor) Name() string {
|
|||
return r.chrt.Metadata.Name
|
||||
}
|
||||
|
||||
func (r *v2Accessor) Version() string {
|
||||
return r.chrt.Metadata.Version
|
||||
}
|
||||
|
||||
func (r *v2Accessor) IsRoot() bool {
|
||||
return r.chrt.IsRoot()
|
||||
}
|
||||
|
|
@ -120,6 +124,10 @@ func (r *v3Accessor) Name() string {
|
|||
return r.chrt.Metadata.Name
|
||||
}
|
||||
|
||||
func (r *v3Accessor) Version() string {
|
||||
return r.chrt.Metadata.Version
|
||||
}
|
||||
|
||||
func (r *v3Accessor) IsRoot() bool {
|
||||
return r.chrt.IsRoot()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ func (r *v2DependencyAccessor) Name() string {
|
|||
return r.dep.Name
|
||||
}
|
||||
|
||||
func (r *v2DependencyAccessor) Version() string {
|
||||
return r.dep.Version
|
||||
}
|
||||
|
||||
func (r *v2DependencyAccessor) Alias() string {
|
||||
return r.dep.Alias
|
||||
}
|
||||
|
|
@ -59,6 +63,10 @@ func (r *v3DependencyAccessor) Name() string {
|
|||
return r.dep.Name
|
||||
}
|
||||
|
||||
func (r *v3DependencyAccessor) Version() string {
|
||||
return r.dep.Version
|
||||
}
|
||||
|
||||
func (r *v3DependencyAccessor) Alias() string {
|
||||
return r.dep.Alias
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ type Dependency any
|
|||
|
||||
type Accessor interface {
|
||||
Name() string
|
||||
Version() string
|
||||
IsRoot() bool
|
||||
MetadataAsMap() map[string]any
|
||||
Files() []*common.File
|
||||
|
|
@ -40,5 +41,6 @@ type Accessor interface {
|
|||
|
||||
type DependencyAccessor interface {
|
||||
Name() string
|
||||
Version() string
|
||||
Alias() string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func runTestCmd(t *testing.T, tests []cmdTestCase) {
|
|||
t.Errorf("expected no error, got: '%v'", err)
|
||||
}
|
||||
if tt.golden != "" {
|
||||
test.AssertGoldenString(t, out, tt.golden)
|
||||
test.AssertGoldenString(t, out, tt.golden, tt.goldenArgs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -129,10 +129,11 @@ func executeActionCommandStdinC(store *storage.Storage, in *os.File, cmd string)
|
|||
|
||||
// cmdTestCase describes a test case that works with releases.
|
||||
type cmdTestCase struct {
|
||||
name string
|
||||
cmd string
|
||||
golden string
|
||||
wantError bool
|
||||
name string
|
||||
cmd string
|
||||
golden string
|
||||
goldenArgs map[string]string
|
||||
wantError bool
|
||||
// Rels are the available releases at the start of the test.
|
||||
rels []*release.Release
|
||||
// Number of repeats (in case a feature was previously flaky and the test checks
|
||||
|
|
|
|||
|
|
@ -153,6 +153,15 @@ func TestInstall(t *testing.T) {
|
|||
cmd: "install --dependency-update updeps testdata/testcharts/chart-with-subchart-update",
|
||||
golden: "output/chart-with-subchart-update.txt",
|
||||
},
|
||||
// Install chart with update-dependency
|
||||
{
|
||||
name: "install chart with outdated dependencies",
|
||||
cmd: fmt.Sprintf("install --dependency-update --repository-cache %s --repository-config %s updeps testdata/testcharts/chart-with-outdated-dependency --username username --password password", srv.Root(), repoFile),
|
||||
golden: "output/install-with-outdated-deps.txt",
|
||||
goldenArgs: map[string]string{
|
||||
"repoUrl": srv.URL(),
|
||||
},
|
||||
},
|
||||
// Install, chart with bad dependencies in Chart.yaml in /charts
|
||||
{
|
||||
name: "install chart with bad dependencies in Chart.yaml",
|
||||
|
|
|
|||
6
pkg/cmd/testdata/output/install-with-outdated-deps.txt
vendored
Normal file
6
pkg/cmd/testdata/output/install-with-outdated-deps.txt
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
NAME: updeps
|
||||
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
|
||||
NAMESPACE: default
|
||||
STATUS: deployed
|
||||
REVISION: 1
|
||||
DESCRIPTION: Install complete
|
||||
1
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/.gitignore
vendored
Normal file
1
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
requirements.lock
|
||||
21
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/.helmignore
vendored
Normal file
21
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/.helmignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
8
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/Chart.yaml
vendored
Normal file
8
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/Chart.yaml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
apiVersion: v1
|
||||
description: A Helm chart for Kubernetes
|
||||
name: chart-with-outdated-dependency
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: oci-dependent-chart
|
||||
version: 0.1.0
|
||||
repository: "@test"
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v2
|
||||
appVersion: 1.16.0
|
||||
description: A Helm chart for Kubernetes
|
||||
name: oci-dependent-chart
|
||||
type: application
|
||||
version: 0.0.1
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oci-dependent-chart.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oci-dependent-chart.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oci-dependent-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oci-dependent-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "oci-dependent-chart.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "oci-dependent-chart.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "oci-dependent-chart.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Default values for oci-dependent-chart.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
4
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/values.yaml
vendored
Normal file
4
pkg/cmd/testdata/testcharts/chart-with-outdated-dependency/values.yaml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Default values for reqtest.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare name/value pairs to be passed into your templates.
|
||||
# name: value
|
||||
|
|
@ -19,6 +19,7 @@ package fake
|
|||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -49,6 +50,7 @@ type FailingKubeClient struct {
|
|||
WaitDuration time.Duration
|
||||
// RecordedWaitOptions stores the WaitOptions passed to GetWaiter for testing
|
||||
RecordedWaitOptions []kube.WaitOption
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
var _ kube.Interface = &FailingKubeClient{}
|
||||
|
|
@ -160,7 +162,9 @@ func (f *FailingKubeClient) GetWaiter(ws kube.WaitStrategy) (kube.Waiter, error)
|
|||
|
||||
func (f *FailingKubeClient) GetWaiterWithOptions(ws kube.WaitStrategy, opts ...kube.WaitOption) (kube.Waiter, error) {
|
||||
// Record the WaitOptions for testing
|
||||
f.mu.Lock()
|
||||
f.RecordedWaitOptions = append(f.RecordedWaitOptions, opts...)
|
||||
f.mu.Unlock()
|
||||
waiter, _ := f.PrintingKubeClient.GetWaiterWithOptions(ws, opts...)
|
||||
printingKubeWaiter, _ := waiter.(*PrintingKubeWaiter)
|
||||
return &FailingKubeWaiter{
|
||||
|
|
|
|||
Loading…
Reference in a new issue