github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/cmd/helm/upgrade_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 main
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/stefanmcshane/helm/internal/test/ensure"
    28  	"github.com/stefanmcshane/helm/pkg/chart"
    29  	"github.com/stefanmcshane/helm/pkg/chart/loader"
    30  	"github.com/stefanmcshane/helm/pkg/chartutil"
    31  	"github.com/stefanmcshane/helm/pkg/release"
    32  )
    33  
    34  func TestUpgradeCmd(t *testing.T) {
    35  
    36  	tmpChart := ensure.TempDir(t)
    37  	cfile := &chart.Chart{
    38  		Metadata: &chart.Metadata{
    39  			APIVersion:  chart.APIVersionV1,
    40  			Name:        "testUpgradeChart",
    41  			Description: "A Helm chart for Kubernetes",
    42  			Version:     "0.1.0",
    43  		},
    44  	}
    45  	chartPath := filepath.Join(tmpChart, cfile.Metadata.Name)
    46  	if err := chartutil.SaveDir(cfile, tmpChart); err != nil {
    47  		t.Fatalf("Error creating chart for upgrade: %v", err)
    48  	}
    49  	ch, err := loader.Load(chartPath)
    50  	if err != nil {
    51  		t.Fatalf("Error loading chart: %v", err)
    52  	}
    53  	_ = release.Mock(&release.MockReleaseOptions{
    54  		Name:  "funny-bunny",
    55  		Chart: ch,
    56  	})
    57  
    58  	// update chart version
    59  	cfile.Metadata.Version = "0.1.2"
    60  
    61  	if err := chartutil.SaveDir(cfile, tmpChart); err != nil {
    62  		t.Fatalf("Error creating chart: %v", err)
    63  	}
    64  	ch, err = loader.Load(chartPath)
    65  	if err != nil {
    66  		t.Fatalf("Error loading updated chart: %v", err)
    67  	}
    68  
    69  	// update chart version again
    70  	cfile.Metadata.Version = "0.1.3"
    71  
    72  	if err := chartutil.SaveDir(cfile, tmpChart); err != nil {
    73  		t.Fatalf("Error creating chart: %v", err)
    74  	}
    75  	var ch2 *chart.Chart
    76  	ch2, err = loader.Load(chartPath)
    77  	if err != nil {
    78  		t.Fatalf("Error loading updated chart: %v", err)
    79  	}
    80  
    81  	missingDepsPath := "testdata/testcharts/chart-missing-deps"
    82  	badDepsPath := "testdata/testcharts/chart-bad-requirements"
    83  	presentDepsPath := "testdata/testcharts/chart-with-subchart-update"
    84  
    85  	relWithStatusMock := func(n string, v int, ch *chart.Chart, status release.Status) *release.Release {
    86  		return release.Mock(&release.MockReleaseOptions{Name: n, Version: v, Chart: ch, Status: status})
    87  	}
    88  
    89  	relMock := func(n string, v int, ch *chart.Chart) *release.Release {
    90  		return release.Mock(&release.MockReleaseOptions{Name: n, Version: v, Chart: ch})
    91  	}
    92  
    93  	tests := []cmdTestCase{
    94  		{
    95  			name:   "upgrade a release",
    96  			cmd:    fmt.Sprintf("upgrade funny-bunny '%s'", chartPath),
    97  			golden: "output/upgrade.txt",
    98  			rels:   []*release.Release{relMock("funny-bunny", 2, ch)},
    99  		},
   100  		{
   101  			name:   "upgrade a release with timeout",
   102  			cmd:    fmt.Sprintf("upgrade funny-bunny --timeout 120s '%s'", chartPath),
   103  			golden: "output/upgrade-with-timeout.txt",
   104  			rels:   []*release.Release{relMock("funny-bunny", 3, ch2)},
   105  		},
   106  		{
   107  			name:   "upgrade a release with --reset-values",
   108  			cmd:    fmt.Sprintf("upgrade funny-bunny --reset-values '%s'", chartPath),
   109  			golden: "output/upgrade-with-reset-values.txt",
   110  			rels:   []*release.Release{relMock("funny-bunny", 4, ch2)},
   111  		},
   112  		{
   113  			name:   "upgrade a release with --reuse-values",
   114  			cmd:    fmt.Sprintf("upgrade funny-bunny --reuse-values '%s'", chartPath),
   115  			golden: "output/upgrade-with-reset-values2.txt",
   116  			rels:   []*release.Release{relMock("funny-bunny", 5, ch2)},
   117  		},
   118  		{
   119  			name:   "install a release with 'upgrade --install'",
   120  			cmd:    fmt.Sprintf("upgrade zany-bunny -i '%s'", chartPath),
   121  			golden: "output/upgrade-with-install.txt",
   122  			rels:   []*release.Release{relMock("zany-bunny", 1, ch)},
   123  		},
   124  		{
   125  			name:   "install a release with 'upgrade --install' and timeout",
   126  			cmd:    fmt.Sprintf("upgrade crazy-bunny -i --timeout 120s '%s'", chartPath),
   127  			golden: "output/upgrade-with-install-timeout.txt",
   128  			rels:   []*release.Release{relMock("crazy-bunny", 1, ch)},
   129  		},
   130  		{
   131  			name:   "upgrade a release with wait",
   132  			cmd:    fmt.Sprintf("upgrade crazy-bunny --wait '%s'", chartPath),
   133  			golden: "output/upgrade-with-wait.txt",
   134  			rels:   []*release.Release{relMock("crazy-bunny", 2, ch2)},
   135  		},
   136  		{
   137  			name:   "upgrade a release with wait-for-jobs",
   138  			cmd:    fmt.Sprintf("upgrade crazy-bunny --wait --wait-for-jobs '%s'", chartPath),
   139  			golden: "output/upgrade-with-wait-for-jobs.txt",
   140  			rels:   []*release.Release{relMock("crazy-bunny", 2, ch2)},
   141  		},
   142  		{
   143  			name:      "upgrade a release with missing dependencies",
   144  			cmd:       fmt.Sprintf("upgrade bonkers-bunny %s", missingDepsPath),
   145  			golden:    "output/upgrade-with-missing-dependencies.txt",
   146  			wantError: true,
   147  		},
   148  		{
   149  			name:      "upgrade a release with bad dependencies",
   150  			cmd:       fmt.Sprintf("upgrade bonkers-bunny '%s'", badDepsPath),
   151  			golden:    "output/upgrade-with-bad-dependencies.txt",
   152  			wantError: true,
   153  		},
   154  		{
   155  			name:   "upgrade a release with resolving missing dependencies",
   156  			cmd:    fmt.Sprintf("upgrade --dependency-update funny-bunny %s", presentDepsPath),
   157  			golden: "output/upgrade-with-dependency-update.txt",
   158  			rels:   []*release.Release{relMock("funny-bunny", 2, ch2)},
   159  		},
   160  		{
   161  			name:      "upgrade a non-existent release",
   162  			cmd:       fmt.Sprintf("upgrade funny-bunny '%s'", chartPath),
   163  			golden:    "output/upgrade-with-bad-or-missing-existing-release.txt",
   164  			wantError: true,
   165  		},
   166  		{
   167  			name:   "upgrade a failed release",
   168  			cmd:    fmt.Sprintf("upgrade funny-bunny '%s'", chartPath),
   169  			golden: "output/upgrade.txt",
   170  			rels:   []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusFailed)},
   171  		},
   172  		{
   173  			name:      "upgrade a pending install release",
   174  			cmd:       fmt.Sprintf("upgrade funny-bunny '%s'", chartPath),
   175  			golden:    "output/upgrade-with-pending-install.txt",
   176  			wantError: true,
   177  			rels:      []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusPendingInstall)},
   178  		},
   179  	}
   180  	runTestCmd(t, tests)
   181  }
   182  
   183  func TestUpgradeWithValue(t *testing.T) {
   184  	releaseName := "funny-bunny-v2"
   185  	relMock, ch, chartPath := prepareMockRelease(releaseName, t)
   186  
   187  	defer resetEnv()()
   188  
   189  	store := storageFixture()
   190  
   191  	store.Create(relMock(releaseName, 3, ch))
   192  
   193  	cmd := fmt.Sprintf("upgrade %s --set favoriteDrink=tea '%s'", releaseName, chartPath)
   194  	_, _, err := executeActionCommandC(store, cmd)
   195  	if err != nil {
   196  		t.Errorf("unexpected error, got '%v'", err)
   197  	}
   198  
   199  	updatedRel, err := store.Get(releaseName, 4)
   200  	if err != nil {
   201  		t.Errorf("unexpected error, got '%v'", err)
   202  	}
   203  
   204  	if !strings.Contains(updatedRel.Manifest, "drink: tea") {
   205  		t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest)
   206  	}
   207  
   208  }
   209  
   210  func TestUpgradeWithStringValue(t *testing.T) {
   211  	releaseName := "funny-bunny-v3"
   212  	relMock, ch, chartPath := prepareMockRelease(releaseName, t)
   213  
   214  	defer resetEnv()()
   215  
   216  	store := storageFixture()
   217  
   218  	store.Create(relMock(releaseName, 3, ch))
   219  
   220  	cmd := fmt.Sprintf("upgrade %s --set-string favoriteDrink=coffee '%s'", releaseName, chartPath)
   221  	_, _, err := executeActionCommandC(store, cmd)
   222  	if err != nil {
   223  		t.Errorf("unexpected error, got '%v'", err)
   224  	}
   225  
   226  	updatedRel, err := store.Get(releaseName, 4)
   227  	if err != nil {
   228  		t.Errorf("unexpected error, got '%v'", err)
   229  	}
   230  
   231  	if !strings.Contains(updatedRel.Manifest, "drink: coffee") {
   232  		t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest)
   233  	}
   234  
   235  }
   236  
   237  func TestUpgradeInstallWithSubchartNotes(t *testing.T) {
   238  
   239  	releaseName := "wacky-bunny-v1"
   240  	relMock, ch, _ := prepareMockRelease(releaseName, t)
   241  
   242  	defer resetEnv()()
   243  
   244  	store := storageFixture()
   245  
   246  	store.Create(relMock(releaseName, 1, ch))
   247  
   248  	cmd := fmt.Sprintf("upgrade %s -i --render-subchart-notes '%s'", releaseName, "testdata/testcharts/chart-with-subchart-notes")
   249  	_, _, err := executeActionCommandC(store, cmd)
   250  	if err != nil {
   251  		t.Errorf("unexpected error, got '%v'", err)
   252  	}
   253  
   254  	upgradedRel, err := store.Get(releaseName, 2)
   255  	if err != nil {
   256  		t.Errorf("unexpected error, got '%v'", err)
   257  	}
   258  
   259  	if !strings.Contains(upgradedRel.Info.Notes, "PARENT NOTES") {
   260  		t.Errorf("The parent notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes)
   261  	}
   262  
   263  	if !strings.Contains(upgradedRel.Info.Notes, "SUBCHART NOTES") {
   264  		t.Errorf("The subchart notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes)
   265  	}
   266  
   267  }
   268  
   269  func TestUpgradeWithValuesFile(t *testing.T) {
   270  
   271  	releaseName := "funny-bunny-v4"
   272  	relMock, ch, chartPath := prepareMockRelease(releaseName, t)
   273  
   274  	defer resetEnv()()
   275  
   276  	store := storageFixture()
   277  
   278  	store.Create(relMock(releaseName, 3, ch))
   279  
   280  	cmd := fmt.Sprintf("upgrade %s --values testdata/testcharts/upgradetest/values.yaml '%s'", releaseName, chartPath)
   281  	_, _, err := executeActionCommandC(store, cmd)
   282  	if err != nil {
   283  		t.Errorf("unexpected error, got '%v'", err)
   284  	}
   285  
   286  	updatedRel, err := store.Get(releaseName, 4)
   287  	if err != nil {
   288  		t.Errorf("unexpected error, got '%v'", err)
   289  	}
   290  
   291  	if !strings.Contains(updatedRel.Manifest, "drink: beer") {
   292  		t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest)
   293  	}
   294  
   295  }
   296  
   297  func TestUpgradeWithValuesFromStdin(t *testing.T) {
   298  
   299  	releaseName := "funny-bunny-v5"
   300  	relMock, ch, chartPath := prepareMockRelease(releaseName, t)
   301  
   302  	defer resetEnv()()
   303  
   304  	store := storageFixture()
   305  
   306  	store.Create(relMock(releaseName, 3, ch))
   307  
   308  	in, err := os.Open("testdata/testcharts/upgradetest/values.yaml")
   309  	if err != nil {
   310  		t.Errorf("unexpected error, got '%v'", err)
   311  	}
   312  
   313  	cmd := fmt.Sprintf("upgrade %s --values - '%s'", releaseName, chartPath)
   314  	_, _, err = executeActionCommandStdinC(store, in, cmd)
   315  	if err != nil {
   316  		t.Errorf("unexpected error, got '%v'", err)
   317  	}
   318  
   319  	updatedRel, err := store.Get(releaseName, 4)
   320  	if err != nil {
   321  		t.Errorf("unexpected error, got '%v'", err)
   322  	}
   323  
   324  	if !strings.Contains(updatedRel.Manifest, "drink: beer") {
   325  		t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest)
   326  	}
   327  }
   328  
   329  func TestUpgradeInstallWithValuesFromStdin(t *testing.T) {
   330  
   331  	releaseName := "funny-bunny-v6"
   332  	_, _, chartPath := prepareMockRelease(releaseName, t)
   333  
   334  	defer resetEnv()()
   335  
   336  	store := storageFixture()
   337  
   338  	in, err := os.Open("testdata/testcharts/upgradetest/values.yaml")
   339  	if err != nil {
   340  		t.Errorf("unexpected error, got '%v'", err)
   341  	}
   342  
   343  	cmd := fmt.Sprintf("upgrade %s -f - --install '%s'", releaseName, chartPath)
   344  	_, _, err = executeActionCommandStdinC(store, in, cmd)
   345  	if err != nil {
   346  		t.Errorf("unexpected error, got '%v'", err)
   347  	}
   348  
   349  	updatedRel, err := store.Get(releaseName, 1)
   350  	if err != nil {
   351  		t.Errorf("unexpected error, got '%v'", err)
   352  	}
   353  
   354  	if !strings.Contains(updatedRel.Manifest, "drink: beer") {
   355  		t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest)
   356  	}
   357  
   358  }
   359  
   360  func prepareMockRelease(releaseName string, t *testing.T) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) {
   361  	tmpChart := ensure.TempDir(t)
   362  	configmapData, err := ioutil.ReadFile("testdata/testcharts/upgradetest/templates/configmap.yaml")
   363  	if err != nil {
   364  		t.Fatalf("Error loading template yaml %v", err)
   365  	}
   366  	cfile := &chart.Chart{
   367  		Metadata: &chart.Metadata{
   368  			APIVersion:  chart.APIVersionV1,
   369  			Name:        "testUpgradeChart",
   370  			Description: "A Helm chart for Kubernetes",
   371  			Version:     "0.1.0",
   372  		},
   373  		Templates: []*chart.File{{Name: "templates/configmap.yaml", Data: configmapData}},
   374  	}
   375  	chartPath := filepath.Join(tmpChart, cfile.Metadata.Name)
   376  	if err := chartutil.SaveDir(cfile, tmpChart); err != nil {
   377  		t.Fatalf("Error creating chart for upgrade: %v", err)
   378  	}
   379  	ch, err := loader.Load(chartPath)
   380  	if err != nil {
   381  		t.Fatalf("Error loading chart: %v", err)
   382  	}
   383  	_ = release.Mock(&release.MockReleaseOptions{
   384  		Name:  releaseName,
   385  		Chart: ch,
   386  	})
   387  
   388  	relMock := func(n string, v int, ch *chart.Chart) *release.Release {
   389  		return release.Mock(&release.MockReleaseOptions{Name: n, Version: v, Chart: ch})
   390  	}
   391  
   392  	return relMock, ch, chartPath
   393  }
   394  
   395  func TestUpgradeOutputCompletion(t *testing.T) {
   396  	outputFlagCompletionTest(t, "upgrade")
   397  }
   398  
   399  func TestUpgradeVersionCompletion(t *testing.T) {
   400  	repoFile := "testdata/helmhome/helm/repositories.yaml"
   401  	repoCache := "testdata/helmhome/helm/repository"
   402  
   403  	repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache)
   404  
   405  	tests := []cmdTestCase{{
   406  		name:   "completion for upgrade version flag",
   407  		cmd:    fmt.Sprintf("%s __complete upgrade releasename testing/alpine --version ''", repoSetup),
   408  		golden: "output/version-comp.txt",
   409  	}, {
   410  		name:   "completion for upgrade version flag, no filter",
   411  		cmd:    fmt.Sprintf("%s __complete upgrade releasename testing/alpine --version 0.3", repoSetup),
   412  		golden: "output/version-comp.txt",
   413  	}, {
   414  		name:   "completion for upgrade version flag too few args",
   415  		cmd:    fmt.Sprintf("%s __complete upgrade releasename --version ''", repoSetup),
   416  		golden: "output/version-invalid-comp.txt",
   417  	}, {
   418  		name:   "completion for upgrade version flag too many args",
   419  		cmd:    fmt.Sprintf("%s __complete upgrade releasename testing/alpine badarg --version ''", repoSetup),
   420  		golden: "output/version-invalid-comp.txt",
   421  	}, {
   422  		name:   "completion for upgrade version flag invalid chart",
   423  		cmd:    fmt.Sprintf("%s __complete upgrade releasename invalid/invalid --version ''", repoSetup),
   424  		golden: "output/version-invalid-comp.txt",
   425  	}}
   426  	runTestCmd(t, tests)
   427  }
   428  
   429  func TestUpgradeFileCompletion(t *testing.T) {
   430  	checkFileCompletion(t, "upgrade", false)
   431  	checkFileCompletion(t, "upgrade myrelease", true)
   432  	checkFileCompletion(t, "upgrade myrelease repo/chart", false)
   433  }