github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/action/action_test.go (about)

     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/ioutil"
    21  	"testing"
    22  
    23  	fakeclientset "k8s.io/client-go/kubernetes/fake"
    24  
    25  	"github.com/stefanmcshane/helm/pkg/chart"
    26  	"github.com/stefanmcshane/helm/pkg/chartutil"
    27  	kubefake "github.com/stefanmcshane/helm/pkg/kube/fake"
    28  	"github.com/stefanmcshane/helm/pkg/registry"
    29  	"github.com/stefanmcshane/helm/pkg/release"
    30  	"github.com/stefanmcshane/helm/pkg/storage"
    31  	"github.com/stefanmcshane/helm/pkg/storage/driver"
    32  	"github.com/stefanmcshane/helm/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: ioutil.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 withSampleIncludingIncorrectTemplates() chartOption {
   199  	return func(opts *chartOptions) {
   200  		sampleTemplates := []*chart.File{
   201  			// This adds basic templates and partials.
   202  			{Name: "templates/goodbye", Data: []byte("goodbye: world")},
   203  			{Name: "templates/empty", Data: []byte("")},
   204  			{Name: "templates/incorrect", Data: []byte("{{ .Values.bad.doh }}")},
   205  			{Name: "templates/with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)},
   206  			{Name: "templates/partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)},
   207  		}
   208  		opts.Templates = append(opts.Templates, sampleTemplates...)
   209  	}
   210  }
   211  
   212  func withMultipleManifestTemplate() chartOption {
   213  	return func(opts *chartOptions) {
   214  		sampleTemplates := []*chart.File{
   215  			{Name: "templates/rbac", Data: []byte(rbacManifests)},
   216  		}
   217  		opts.Templates = append(opts.Templates, sampleTemplates...)
   218  	}
   219  }
   220  
   221  func withKube(version string) chartOption {
   222  	return func(opts *chartOptions) {
   223  		opts.Metadata.KubeVersion = version
   224  	}
   225  }
   226  
   227  // releaseStub creates a release stub, complete with the chartStub as its chart.
   228  func releaseStub() *release.Release {
   229  	return namedReleaseStub("angry-panda", release.StatusDeployed)
   230  }
   231  
   232  func namedReleaseStub(name string, status release.Status) *release.Release {
   233  	now := time.Now()
   234  	return &release.Release{
   235  		Name: name,
   236  		Info: &release.Info{
   237  			FirstDeployed: now,
   238  			LastDeployed:  now,
   239  			Status:        status,
   240  			Description:   "Named Release Stub",
   241  		},
   242  		Chart:   buildChart(withSampleTemplates()),
   243  		Config:  map[string]interface{}{"name": "value"},
   244  		Version: 1,
   245  		Hooks: []*release.Hook{
   246  			{
   247  				Name:     "test-cm",
   248  				Kind:     "ConfigMap",
   249  				Path:     "test-cm",
   250  				Manifest: manifestWithHook,
   251  				Events: []release.HookEvent{
   252  					release.HookPostInstall,
   253  					release.HookPreDelete,
   254  				},
   255  			},
   256  			{
   257  				Name:     "finding-nemo",
   258  				Kind:     "Pod",
   259  				Path:     "finding-nemo",
   260  				Manifest: manifestWithTestHook,
   261  				Events: []release.HookEvent{
   262  					release.HookTest,
   263  				},
   264  			},
   265  		},
   266  	}
   267  }
   268  
   269  func TestGetVersionSet(t *testing.T) {
   270  	client := fakeclientset.NewSimpleClientset()
   271  
   272  	vs, err := GetVersionSet(client.Discovery())
   273  	if err != nil {
   274  		t.Error(err)
   275  	}
   276  
   277  	if !vs.Has("v1") {
   278  		t.Errorf("Expected supported versions to at least include v1.")
   279  	}
   280  	if vs.Has("nosuchversion/v1") {
   281  		t.Error("Non-existent version is reported found.")
   282  	}
   283  }