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 }