github.com/koderover/helm@v2.17.0+incompatible/pkg/tiller/hooks_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  
    17  package tiller
    18  
    19  import (
    20  	"bytes"
    21  	"reflect"
    22  	"testing"
    23  	"text/template"
    24  
    25  	"github.com/ghodss/yaml"
    26  
    27  	"k8s.io/helm/pkg/chartutil"
    28  	"k8s.io/helm/pkg/proto/hapi/release"
    29  	util "k8s.io/helm/pkg/releaseutil"
    30  )
    31  
    32  func TestSortManifests(t *testing.T) {
    33  
    34  	data := []struct {
    35  		name     []string
    36  		path     string
    37  		kind     []string
    38  		hooks    map[string][]release.Hook_Event
    39  		manifest string
    40  	}{
    41  		{
    42  			name:  []string{"first"},
    43  			path:  "one",
    44  			kind:  []string{"Job"},
    45  			hooks: map[string][]release.Hook_Event{"first": {release.Hook_PRE_INSTALL}},
    46  			manifest: `apiVersion: v1
    47  kind: Job
    48  metadata:
    49    name: first
    50    labels:
    51      doesnot: matter
    52    annotations:
    53      "helm.sh/hook": pre-install
    54  `,
    55  		},
    56  		{
    57  			name:  []string{"second"},
    58  			path:  "two",
    59  			kind:  []string{"ReplicaSet"},
    60  			hooks: map[string][]release.Hook_Event{"second": {release.Hook_POST_INSTALL}},
    61  			manifest: `kind: ReplicaSet
    62  apiVersion: v1beta1
    63  metadata:
    64    name: second
    65    annotations:
    66      "helm.sh/hook": post-install
    67  `,
    68  		}, {
    69  			name:  []string{"third"},
    70  			path:  "three",
    71  			kind:  []string{"ReplicaSet"},
    72  			hooks: map[string][]release.Hook_Event{"third": nil},
    73  			manifest: `kind: ReplicaSet
    74  apiVersion: v1beta1
    75  metadata:
    76    name: third
    77    annotations:
    78      "helm.sh/hook": no-such-hook
    79  `,
    80  		}, {
    81  			name:  []string{"fourth"},
    82  			path:  "four",
    83  			kind:  []string{"Pod"},
    84  			hooks: map[string][]release.Hook_Event{"fourth": nil},
    85  			manifest: `kind: Pod
    86  apiVersion: v1
    87  metadata:
    88    name: fourth
    89    annotations:
    90      nothing: here`,
    91  		}, {
    92  			name:  []string{"fifth"},
    93  			path:  "five",
    94  			kind:  []string{"ReplicaSet"},
    95  			hooks: map[string][]release.Hook_Event{"fifth": {release.Hook_POST_DELETE, release.Hook_POST_INSTALL}},
    96  			manifest: `kind: ReplicaSet
    97  apiVersion: v1beta1
    98  metadata:
    99    name: fifth
   100    annotations:
   101      "helm.sh/hook": post-delete, post-install
   102  `,
   103  		}, {
   104  			// Regression test: files with an underscore in the base name should be skipped.
   105  			name:     []string{"sixth"},
   106  			path:     "six/_six",
   107  			kind:     []string{"ReplicaSet"},
   108  			hooks:    map[string][]release.Hook_Event{"sixth": nil},
   109  			manifest: `invalid manifest`, // This will fail if partial is not skipped.
   110  		}, {
   111  			// Regression test: files with no content should be skipped.
   112  			name:     []string{"seventh"},
   113  			path:     "seven",
   114  			kind:     []string{"ReplicaSet"},
   115  			hooks:    map[string][]release.Hook_Event{"seventh": nil},
   116  			manifest: "",
   117  		},
   118  		{
   119  			name:  []string{"eighth", "example-test"},
   120  			path:  "eight",
   121  			kind:  []string{"ConfigMap", "Pod"},
   122  			hooks: map[string][]release.Hook_Event{"eighth": nil, "example-test": {release.Hook_RELEASE_TEST_SUCCESS}},
   123  			manifest: `kind: ConfigMap
   124  apiVersion: v1
   125  metadata:
   126    name: eighth
   127  data:
   128    name: value
   129  ---
   130  apiVersion: v1
   131  kind: Pod
   132  metadata:
   133    name: example-test
   134    annotations:
   135      "helm.sh/hook": test-success
   136  `,
   137  		},
   138  	}
   139  
   140  	manifests := make(map[string]string, len(data))
   141  	for _, o := range data {
   142  		manifests[o.path] = o.manifest
   143  	}
   144  
   145  	hs, generic, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
   146  	if err != nil {
   147  		t.Fatalf("Unexpected error: %s", err)
   148  	}
   149  
   150  	// This test will fail if 'six' or 'seven' was added.
   151  	if len(generic) != 2 {
   152  		t.Errorf("Expected 2 generic manifests, got %d", len(generic))
   153  	}
   154  
   155  	if len(hs) != 4 {
   156  		t.Errorf("Expected 4 hooks, got %d", len(hs))
   157  	}
   158  
   159  	for _, out := range hs {
   160  		found := false
   161  		for _, expect := range data {
   162  			if out.Path == expect.path {
   163  				found = true
   164  				if out.Path != expect.path {
   165  					t.Errorf("Expected path %s, got %s", expect.path, out.Path)
   166  				}
   167  				nameFound := false
   168  				for _, expectedName := range expect.name {
   169  					if out.Name == expectedName {
   170  						nameFound = true
   171  					}
   172  				}
   173  				if !nameFound {
   174  					t.Errorf("Got unexpected name %s", out.Name)
   175  				}
   176  				kindFound := false
   177  				for _, expectedKind := range expect.kind {
   178  					if out.Kind == expectedKind {
   179  						kindFound = true
   180  					}
   181  				}
   182  				if !kindFound {
   183  					t.Errorf("Got unexpected kind %s", out.Kind)
   184  				}
   185  
   186  				expectedHooks := expect.hooks[out.Name]
   187  				if !reflect.DeepEqual(expectedHooks, out.Events) {
   188  					t.Errorf("expected events: %v but got: %v", expectedHooks, out.Events)
   189  				}
   190  
   191  			}
   192  		}
   193  		if !found {
   194  			t.Errorf("Result not found: %v", out)
   195  		}
   196  	}
   197  
   198  	// Verify the sort order
   199  	sorted := []Manifest{}
   200  	for _, s := range data {
   201  		manifests := util.SplitManifests(s.manifest)
   202  
   203  		for _, m := range manifests {
   204  			var sh util.SimpleHead
   205  			err := yaml.Unmarshal([]byte(m), &sh)
   206  			if err != nil {
   207  				// This is expected for manifests that are corrupt or empty.
   208  				t.Log(err)
   209  				continue
   210  			}
   211  
   212  			name := sh.Metadata.Name
   213  
   214  			//only keep track of non-hook manifests
   215  			if err == nil && s.hooks[name] == nil {
   216  				another := Manifest{
   217  					Content: m,
   218  					Name:    name,
   219  					Head:    &sh,
   220  				}
   221  				sorted = append(sorted, another)
   222  			}
   223  		}
   224  	}
   225  
   226  	sorted = sortByKind(sorted, InstallOrder)
   227  	for i, m := range generic {
   228  		if m.Content != sorted[i].Content {
   229  			t.Errorf("Expected %q, got %q", m.Content, sorted[i].Content)
   230  		}
   231  	}
   232  }
   233  
   234  var manifestTemplate = `
   235  apiVersion: apiextensions.k8s.io/v1beta1
   236  kind: CustomResourceDefinition
   237  metadata:
   238    name: example.com
   239    labels:
   240      app: example-crd
   241    annotations:
   242      helm.sh/hook: crd-install
   243  {{- if .HookDeletePolicy}}
   244      {{ .HookDeletePolicy }}
   245  {{- end }}
   246  {{- if .HookDeleteTimeout}}
   247      {{ .HookDeleteTimeout }}
   248  {{- end }}
   249  spec:
   250    group: example.com
   251    version: v1alpha1
   252    names:
   253      kind: example
   254      plural: examples
   255    scope: Cluster
   256  `
   257  
   258  type manifestTemplateData struct {
   259  	HookDeletePolicy, HookDeleteTimeout string
   260  }
   261  
   262  func TestSortManifestsHookDeletion(t *testing.T) {
   263  	testCases := map[string]struct {
   264  		templateData    manifestTemplateData
   265  		hasDeletePolicy bool
   266  		deletePolicy    release.Hook_DeletePolicy
   267  		deleteTimeout   int64
   268  	}{
   269  		"No delete policy": {
   270  			templateData:    manifestTemplateData{},
   271  			hasDeletePolicy: false,
   272  			deletePolicy:    release.Hook_BEFORE_HOOK_CREATION,
   273  			deleteTimeout:   0,
   274  		},
   275  		"Delete policy, no delete timeout": {
   276  			templateData: manifestTemplateData{
   277  				HookDeletePolicy: "helm.sh/hook-delete-policy: before-hook-creation",
   278  			},
   279  			hasDeletePolicy: true,
   280  			deletePolicy:    release.Hook_BEFORE_HOOK_CREATION,
   281  			deleteTimeout:   defaultHookDeleteTimeoutInSeconds,
   282  		},
   283  		"Delete policy and delete timeout": {
   284  			templateData: manifestTemplateData{
   285  				HookDeletePolicy:  "helm.sh/hook-delete-policy: hook-succeeded",
   286  				HookDeleteTimeout: `helm.sh/hook-delete-timeout: "420"`,
   287  			},
   288  			hasDeletePolicy: true,
   289  			deletePolicy:    release.Hook_SUCCEEDED,
   290  			deleteTimeout:   420,
   291  		},
   292  	}
   293  
   294  	for tn, tc := range testCases {
   295  		t.Run(tn, func(t *testing.T) {
   296  			tmpl := template.Must(template.New("manifest").Parse(manifestTemplate))
   297  			var buf bytes.Buffer
   298  			err := tmpl.Execute(&buf, tc.templateData)
   299  			if err != nil {
   300  				t.Error(err)
   301  			}
   302  
   303  			manifests := map[string]string{
   304  				"exampleManifest": buf.String(),
   305  			}
   306  
   307  			hs, _, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
   308  			if err != nil {
   309  				t.Error(err)
   310  			}
   311  
   312  			if got, want := len(hs), 1; got != want {
   313  				t.Errorf("expected %d hooks, but got %d", want, got)
   314  			}
   315  			hook := hs[0]
   316  
   317  			if len(hook.DeletePolicies) == 0 {
   318  				if tc.hasDeletePolicy {
   319  					t.Errorf("expected a policy, but got zero")
   320  				}
   321  			} else {
   322  				if !tc.hasDeletePolicy {
   323  					t.Errorf("expected no delete policies, but got one")
   324  				}
   325  				policy := hook.DeletePolicies[0]
   326  				if got, want := policy, tc.deletePolicy; got != want {
   327  					t.Errorf("expected delete policy %q, but got %q", want, got)
   328  				}
   329  			}
   330  
   331  			if got, want := hook.DeleteTimeout, tc.deleteTimeout; got != want {
   332  				t.Errorf("expected timeout %d, but got %d", want, got)
   333  			}
   334  		})
   335  	}
   336  }
   337  
   338  func TestVersionSet(t *testing.T) {
   339  	vs := chartutil.NewVersionSet("v1", "v1beta1", "extensions/alpha5", "batch/v1")
   340  
   341  	if l := len(vs); l != 4 {
   342  		t.Errorf("Expected 4, got %d", l)
   343  	}
   344  
   345  	if !vs.Has("extensions/alpha5") {
   346  		t.Error("No match for alpha5")
   347  	}
   348  
   349  	if vs.Has("nosuch/extension") {
   350  		t.Error("Found nonexistent extension")
   351  	}
   352  }