/* Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ package helm import ( "errors" "testing" "time" "github.com/edgelesssys/constellation/v2/internal/compatibility" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/semver" "github.com/stretchr/testify/assert" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" ) func TestAppendNewAction(t *testing.T) { assertUpgradeErr := func(assert *assert.Assertions, err error) { var invalidUpgrade *compatibility.InvalidUpgradeError assert.True(errors.As(err, &invalidUpgrade)) } testCases := map[string]struct { lister stubLister release release configTargetVersion semver.Semver force bool allowDestructive bool wantErr bool assertErr func(*assert.Assertions, error) }{ "upgrade release": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), }, "upgrade to same version": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.0.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), wantErr: true, assertErr: assertUpgradeErr, }, "upgrade to older version": { lister: stubLister{version: semver.NewFromInt(1, 1, 0, "")}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.0.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 0, 0, ""), wantErr: true, assertErr: assertUpgradeErr, }, "upgrade to older version can be forced": { lister: stubLister{version: semver.NewFromInt(1, 1, 0, "")}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.0.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 0, 0, ""), force: true, }, "non semver in chart metadata": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "some-version", }, }, }, wantErr: true, }, "listing release fails": { lister: stubLister{err: assert.AnError}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), wantErr: true, }, "release not installed": { lister: stubLister{err: errReleaseNotFound}, release: release{ releaseName: "test", chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), }, "destructive release upgrade requires confirmation": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, releaseName: certManagerInfo.releaseName, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), wantErr: true, assertErr: func(assert *assert.Assertions, err error) { assert.ErrorIs(err, ErrConfirmationMissing) }, }, "destructive release upgrade can be accepted": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, releaseName: certManagerInfo.releaseName, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), allowDestructive: true, }, "config version takes precedence over CLI version": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: constellationServicesInfo.releaseName, chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 0, 0, ""), wantErr: true, assertErr: assertUpgradeErr, }, "error if CLI version does not match config version on upgrade": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: constellationServicesInfo.releaseName, chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.5", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), wantErr: true, assertErr: assertUpgradeErr, }, "config version matches CLI version on upgrade": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: constellationServicesInfo.releaseName, chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.5", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 5, ""), }, "config - CLI version mismatch can be forced through": { lister: stubLister{version: semver.NewFromInt(1, 0, 0, "")}, release: release{ releaseName: constellationServicesInfo.releaseName, chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.5", }, }, }, configTargetVersion: semver.NewFromInt(1, 1, 0, ""), force: true, }, "installing new release requires matching config and CLI version": { lister: stubLister{err: errReleaseNotFound}, release: release{ releaseName: constellationServicesInfo.releaseName, chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 0, 0, ""), wantErr: true, assertErr: assertUpgradeErr, }, "config - CLI version mismatch for new releases can be forced through": { lister: stubLister{err: errReleaseNotFound}, release: release{ releaseName: constellationServicesInfo.releaseName, chart: &chart.Chart{ Metadata: &chart.Metadata{ Version: "1.1.0", }, }, }, configTargetVersion: semver.NewFromInt(1, 0, 0, ""), force: true, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) actions := []applyAction{} actionFactory := newActionFactory(nil, tc.lister, &action.Configuration{}, logger.NewTest(t)) err := actionFactory.appendNewAction(tc.release, tc.configTargetVersion, tc.force, tc.allowDestructive, time.Second, &actions) if tc.wantErr { assert.Error(err) if tc.assertErr != nil { tc.assertErr(assert, err) } return } assert.NoError(err) assert.Len(actions, 1) // no error == actions gets appended }) } } type stubLister struct { err error version semver.Semver } func (s stubLister) currentVersion(_ string) (semver.Semver, error) { return s.version, s.err }