...

Source file src/helm.sh/helm/v3/pkg/action/action_test.go

Documentation: helm.sh/helm/v3/pkg/action

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  package action
    17  
    18  import (
    19  	"flag"
    20  	"io"
    21  	"testing"
    22  
    23  	fakeclientset "k8s.io/client-go/kubernetes/fake"
    24  
    25  	"helm.sh/helm/v3/pkg/chart"
    26  	"helm.sh/helm/v3/pkg/chartutil"
    27  	kubefake "helm.sh/helm/v3/pkg/kube/fake"
    28  	"helm.sh/helm/v3/pkg/registry"
    29  	"helm.sh/helm/v3/pkg/release"
    30  	"helm.sh/helm/v3/pkg/storage"
    31  	"helm.sh/helm/v3/pkg/storage/driver"
    32  	"helm.sh/helm/v3/pkg/time"
    33  )
    34  
    35  var verbose = flag.Bool("test.log", false, "enable test logging")
    36  
    37  func actionConfigFixture(t *testing.T) *Configuration {
    38  	t.Helper()
    39  
    40  	registryClient, err := registry.NewClient()
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  
    45  	return &Configuration{
    46  		Releases:       storage.Init(driver.NewMemory()),
    47  		KubeClient:     &kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}},
    48  		Capabilities:   chartutil.DefaultCapabilities,
    49  		RegistryClient: registryClient,
    50  		Log: func(format string, v ...interface{}) {
    51  			t.Helper()
    52  			if *verbose {
    53  				t.Logf(format, v...)
    54  			}
    55  		},
    56  	}
    57  }
    58  
    59  var manifestWithHook = `kind: ConfigMap
    60  metadata:
    61    name: test-cm
    62    annotations:
    63      "helm.sh/hook": post-install,pre-delete,post-upgrade
    64  data:
    65    name: value`
    66  
    67  var manifestWithTestHook = `kind: Pod
    68    metadata:
    69  	name: finding-nemo,
    70  	annotations:
    71  	  "helm.sh/hook": test
    72    spec:
    73  	containers:
    74  	- name: nemo-test
    75  	  image: fake-image
    76  	  cmd: fake-command
    77    `
    78  
    79  var rbacManifests = `apiVersion: rbac.authorization.k8s.io/v1
    80  kind: Role
    81  metadata:
    82    name: schedule-agents
    83  rules:
    84  - apiGroups: [""]
    85    resources: ["pods", "pods/exec", "pods/log"]
    86    verbs: ["*"]
    87  
    88  ---
    89  
    90  apiVersion: rbac.authorization.k8s.io/v1
    91  kind: RoleBinding
    92  metadata:
    93    name: schedule-agents
    94    namespace: {{ default .Release.Namespace}}
    95  roleRef:
    96    apiGroup: rbac.authorization.k8s.io
    97    kind: Role
    98    name: schedule-agents
    99  subjects:
   100  - kind: ServiceAccount
   101    name: schedule-agents
   102    namespace: {{ .Release.Namespace }}
   103  `
   104  
   105  type chartOptions struct {
   106  	*chart.Chart
   107  }
   108  
   109  type chartOption func(*chartOptions)
   110  
   111  func buildChart(opts ...chartOption) *chart.Chart {
   112  	c := &chartOptions{
   113  		Chart: &chart.Chart{
   114  			// TODO: This should be more complete.
   115  			Metadata: &chart.Metadata{
   116  				APIVersion: "v1",
   117  				Name:       "hello",
   118  				Version:    "0.1.0",
   119  			},
   120  			// This adds a basic template and hooks.
   121  			Templates: []*chart.File{
   122  				{Name: "templates/hello", Data: []byte("hello: world")},
   123  				{Name: "templates/hooks", Data: []byte(manifestWithHook)},
   124  			},
   125  		},
   126  	}
   127  
   128  	for _, opt := range opts {
   129  		opt(c)
   130  	}
   131  
   132  	return c.Chart
   133  }
   134  
   135  func withName(name string) chartOption {
   136  	return func(opts *chartOptions) {
   137  		opts.Metadata.Name = name
   138  	}
   139  }
   140  
   141  func withSampleValues() chartOption {
   142  	values := map[string]interface{}{
   143  		"someKey": "someValue",
   144  		"nestedKey": map[string]interface{}{
   145  			"simpleKey": "simpleValue",
   146  			"anotherNestedKey": map[string]interface{}{
   147  				"yetAnotherNestedKey": map[string]interface{}{
   148  					"youReadyForAnotherNestedKey": "No",
   149  				},
   150  			},
   151  		},
   152  	}
   153  	return func(opts *chartOptions) {
   154  		opts.Values = values
   155  	}
   156  }
   157  
   158  func withValues(values map[string]interface{}) chartOption {
   159  	return func(opts *chartOptions) {
   160  		opts.Values = values
   161  	}
   162  }
   163  
   164  func withNotes(notes string) chartOption {
   165  	return func(opts *chartOptions) {
   166  		opts.Templates = append(opts.Templates, &chart.File{
   167  			Name: "templates/NOTES.txt",
   168  			Data: []byte(notes),
   169  		})
   170  	}
   171  }
   172  
   173  func withDependency(dependencyOpts ...chartOption) chartOption {
   174  	return func(opts *chartOptions) {
   175  		opts.AddDependency(buildChart(dependencyOpts...))
   176  	}
   177  }
   178  
   179  func withMetadataDependency(dependency chart.Dependency) chartOption {
   180  	return func(opts *chartOptions) {
   181  		opts.Metadata.Dependencies = append(opts.Metadata.Dependencies, &dependency)
   182  	}
   183  }
   184  
   185  func withSampleTemplates() chartOption {
   186  	return func(opts *chartOptions) {
   187  		sampleTemplates := []*chart.File{
   188  			// This adds basic templates and partials.
   189  			{Name: "templates/goodbye", Data: []byte("goodbye: world")},
   190  			{Name: "templates/empty", Data: []byte("")},
   191  			{Name: "templates/with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)},
   192  			{Name: "templates/partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)},
   193  		}
   194  		opts.Templates = append(opts.Templates, sampleTemplates...)
   195  	}
   196  }
   197  
   198  func withSampleSecret() chartOption {
   199  	return func(opts *chartOptions) {
   200  		sampleSecret := &chart.File{Name: "templates/secret.yaml", Data: []byte("apiVersion: v1\nkind: Secret\n")}
   201  		opts.Templates = append(opts.Templates, sampleSecret)
   202  	}
   203  }
   204  
   205  func withSampleIncludingIncorrectTemplates() chartOption {
   206  	return func(opts *chartOptions) {
   207  		sampleTemplates := []*chart.File{
   208  			// This adds basic templates and partials.
   209  			{Name: "templates/goodbye", Data: []byte("goodbye: world")},
   210  			{Name: "templates/empty", Data: []byte("")},
   211  			{Name: "templates/incorrect", Data: []byte("{{ .Values.bad.doh }}")},
   212  			{Name: "templates/with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)},
   213  			{Name: "templates/partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)},
   214  		}
   215  		opts.Templates = append(opts.Templates, sampleTemplates...)
   216  	}
   217  }
   218  
   219  func withMultipleManifestTemplate() chartOption {
   220  	return func(opts *chartOptions) {
   221  		sampleTemplates := []*chart.File{
   222  			{Name: "templates/rbac", Data: []byte(rbacManifests)},
   223  		}
   224  		opts.Templates = append(opts.Templates, sampleTemplates...)
   225  	}
   226  }
   227  
   228  func withKube(version string) chartOption {
   229  	return func(opts *chartOptions) {
   230  		opts.Metadata.KubeVersion = version
   231  	}
   232  }
   233  
   234  // releaseStub creates a release stub, complete with the chartStub as its chart.
   235  func releaseStub() *release.Release {
   236  	return namedReleaseStub("angry-panda", release.StatusDeployed)
   237  }
   238  
   239  func namedReleaseStub(name string, status release.Status) *release.Release {
   240  	now := time.Now()
   241  	return &release.Release{
   242  		Name: name,
   243  		Info: &release.Info{
   244  			FirstDeployed: now,
   245  			LastDeployed:  now,
   246  			Status:        status,
   247  			Description:   "Named Release Stub",
   248  		},
   249  		Chart:   buildChart(withSampleTemplates()),
   250  		Config:  map[string]interface{}{"name": "value"},
   251  		Version: 1,
   252  		Hooks: []*release.Hook{
   253  			{
   254  				Name:     "test-cm",
   255  				Kind:     "ConfigMap",
   256  				Path:     "test-cm",
   257  				Manifest: manifestWithHook,
   258  				Events: []release.HookEvent{
   259  					release.HookPostInstall,
   260  					release.HookPreDelete,
   261  				},
   262  			},
   263  			{
   264  				Name:     "finding-nemo",
   265  				Kind:     "Pod",
   266  				Path:     "finding-nemo",
   267  				Manifest: manifestWithTestHook,
   268  				Events: []release.HookEvent{
   269  					release.HookTest,
   270  				},
   271  			},
   272  		},
   273  	}
   274  }
   275  
   276  func TestGetVersionSet(t *testing.T) {
   277  	client := fakeclientset.NewSimpleClientset()
   278  
   279  	vs, err := GetVersionSet(client.Discovery())
   280  	if err != nil {
   281  		t.Error(err)
   282  	}
   283  
   284  	if !vs.Has("v1") {
   285  		t.Errorf("Expected supported versions to at least include v1.")
   286  	}
   287  	if vs.Has("nosuchversion/v1") {
   288  		t.Error("Non-existent version is reported found.")
   289  	}
   290  }
   291  

View as plain text