628 lines
19 KiB
Go
628 lines
19 KiB
Go
/*
|
|
Copyright 2022 The Flux authors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package reconcile
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
. "github.com/onsi/gomega"
|
|
helmrelease "helm.sh/helm/v3/pkg/release"
|
|
helmreleaseutil "helm.sh/helm/v3/pkg/releaseutil"
|
|
helmstorage "helm.sh/helm/v3/pkg/storage"
|
|
helmdriver "helm.sh/helm/v3/pkg/storage/driver"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/tools/record"
|
|
|
|
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
|
"github.com/fluxcd/pkg/apis/meta"
|
|
"github.com/fluxcd/pkg/runtime/conditions"
|
|
|
|
v2 "github.com/fluxcd/helm-controller/api/v2"
|
|
"github.com/fluxcd/helm-controller/internal/action"
|
|
"github.com/fluxcd/helm-controller/internal/digest"
|
|
"github.com/fluxcd/helm-controller/internal/release"
|
|
"github.com/fluxcd/helm-controller/internal/testutil"
|
|
"github.com/fluxcd/pkg/chartutil"
|
|
)
|
|
|
|
// testHookFixtures is a list of release.Hook in every possible LastRun state.
|
|
var testHookFixtures = []*helmrelease.Hook{
|
|
{
|
|
Name: "never-run-test",
|
|
Events: []helmrelease.HookEvent{helmrelease.HookTest},
|
|
},
|
|
{
|
|
Name: "passing-test",
|
|
Events: []helmrelease.HookEvent{helmrelease.HookTest},
|
|
LastRun: helmrelease.HookExecution{
|
|
StartedAt: testutil.MustParseHelmTime("2006-01-02T15:04:05Z"),
|
|
CompletedAt: testutil.MustParseHelmTime("2006-01-02T15:04:07Z"),
|
|
Phase: helmrelease.HookPhaseSucceeded,
|
|
},
|
|
},
|
|
{
|
|
Name: "failing-test",
|
|
Events: []helmrelease.HookEvent{helmrelease.HookTest},
|
|
LastRun: helmrelease.HookExecution{
|
|
StartedAt: testutil.MustParseHelmTime("2006-01-02T15:10:05Z"),
|
|
CompletedAt: testutil.MustParseHelmTime("2006-01-02T15:10:07Z"),
|
|
Phase: helmrelease.HookPhaseFailed,
|
|
},
|
|
},
|
|
{
|
|
Name: "passing-pre-install",
|
|
Events: []helmrelease.HookEvent{helmrelease.HookPreInstall},
|
|
LastRun: helmrelease.HookExecution{
|
|
StartedAt: testutil.MustParseHelmTime("2006-01-02T15:00:05Z"),
|
|
CompletedAt: testutil.MustParseHelmTime("2006-01-02T15:00:07Z"),
|
|
Phase: helmrelease.HookPhaseSucceeded,
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestTest_Reconcile(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
// driver allows for modifying the Helm storage driver.
|
|
driver func(driver helmdriver.Driver) helmdriver.Driver
|
|
// releases is the list of releases that are stored in the driver
|
|
// before test.
|
|
releases func(namespace string) []*helmrelease.Release
|
|
// spec modifies the HelmRelease Object spec before test.
|
|
spec func(spec *v2.HelmReleaseSpec)
|
|
// status to configure on the HelmRelease Object before test.
|
|
status func(releases []*helmrelease.Release) v2.HelmReleaseStatus
|
|
// wantErr is the error that is expected to be returned.
|
|
wantErr error
|
|
// expectedConditions are the conditions that are expected to be set on
|
|
// the HelmRelease after running test.
|
|
expectConditions []metav1.Condition
|
|
// expectHistory is the expected History on the HelmRelease after
|
|
// running test.
|
|
expectHistory func(releases []*helmrelease.Release) v2.Snapshots
|
|
// expectFailures is the expected Failures count of the HelmRelease.
|
|
expectFailures int64
|
|
// expectInstallFailures is the expected InstallFailures count of the
|
|
// HelmRelease.
|
|
expectInstallFailures int64
|
|
// expectUpgradeFailures is the expected UpgradeFailures count of the
|
|
// HelmRelease.
|
|
expectUpgradeFailures int64
|
|
}{
|
|
{
|
|
name: "test success",
|
|
releases: func(namespace string) []*helmrelease.Release {
|
|
return []*helmrelease.Release{
|
|
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: namespace,
|
|
Version: 1,
|
|
Chart: testutil.BuildChart(testutil.ChartWithTestHook()),
|
|
Status: helmrelease.StatusDeployed,
|
|
}, testutil.ReleaseWithTestHook()),
|
|
}
|
|
},
|
|
status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus {
|
|
return v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
|
|
},
|
|
}
|
|
},
|
|
expectConditions: []metav1.Condition{
|
|
*conditions.TrueCondition(meta.ReadyCondition, v2.TestSucceededReason,
|
|
"1 test hook completed successfully"),
|
|
*conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason,
|
|
"1 test hook completed successfully"),
|
|
},
|
|
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
|
|
withTests := release.ObservedToSnapshot(release.ObserveRelease(releases[0]))
|
|
withTests.SetTestHooks(release.TestHooksFromRelease(releases[0]))
|
|
return v2.Snapshots{withTests}
|
|
},
|
|
},
|
|
{
|
|
name: "test without hooks",
|
|
releases: func(namespace string) []*helmrelease.Release {
|
|
return []*helmrelease.Release{
|
|
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: namespace,
|
|
Version: 1,
|
|
Status: helmrelease.StatusDeployed,
|
|
Chart: testutil.BuildChart(),
|
|
}),
|
|
}
|
|
},
|
|
status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus {
|
|
return v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
|
|
},
|
|
}
|
|
},
|
|
expectConditions: []metav1.Condition{
|
|
*conditions.TrueCondition(meta.ReadyCondition, v2.TestSucceededReason,
|
|
"no test hooks"),
|
|
*conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason,
|
|
"no test hooks"),
|
|
},
|
|
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
|
|
withTests := release.ObservedToSnapshot(release.ObserveRelease(releases[0]))
|
|
withTests.SetTestHooks(release.TestHooksFromRelease(releases[0]))
|
|
return v2.Snapshots{withTests}
|
|
},
|
|
},
|
|
{
|
|
name: "test install failure",
|
|
releases: func(namespace string) []*helmrelease.Release {
|
|
return []*helmrelease.Release{
|
|
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: namespace,
|
|
Version: 1,
|
|
Status: helmrelease.StatusDeployed,
|
|
Chart: testutil.BuildChart(testutil.ChartWithFailingTestHook()),
|
|
}, testutil.ReleaseWithFailingTestHook()),
|
|
}
|
|
},
|
|
status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus {
|
|
return v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
|
|
},
|
|
LastAttemptedReleaseAction: v2.ReleaseActionInstall,
|
|
InstallFailures: 0,
|
|
}
|
|
},
|
|
expectConditions: []metav1.Condition{
|
|
*conditions.FalseCondition(meta.ReadyCondition, v2.TestFailedReason,
|
|
"timed out waiting for the condition"),
|
|
*conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason,
|
|
"timed out waiting for the condition"),
|
|
},
|
|
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
|
|
withTests := release.ObservedToSnapshot(release.ObserveRelease(releases[0]))
|
|
withTests.SetTestHooks(release.TestHooksFromRelease(releases[0]))
|
|
return v2.Snapshots{withTests}
|
|
},
|
|
expectFailures: 1,
|
|
expectInstallFailures: 1,
|
|
},
|
|
{
|
|
name: "test without current",
|
|
releases: func(namespace string) []*helmrelease.Release {
|
|
return []*helmrelease.Release{
|
|
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: namespace,
|
|
Version: 1,
|
|
Chart: testutil.BuildChart(testutil.ChartWithTestHook()),
|
|
Status: helmrelease.StatusDeployed,
|
|
}, testutil.ReleaseWithTestHook()),
|
|
}
|
|
},
|
|
expectConditions: []metav1.Condition{},
|
|
wantErr: ErrNoLatest,
|
|
},
|
|
{
|
|
name: "test with stale current",
|
|
releases: func(namespace string) []*helmrelease.Release {
|
|
return []*helmrelease.Release{
|
|
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: namespace,
|
|
Version: 1,
|
|
Chart: testutil.BuildChart(testutil.ChartWithTestHook()),
|
|
Status: helmrelease.StatusSuperseded,
|
|
}, testutil.ReleaseWithTestHook()),
|
|
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: namespace,
|
|
Version: 2,
|
|
Chart: testutil.BuildChart(),
|
|
Status: helmrelease.StatusDeployed,
|
|
}),
|
|
}
|
|
},
|
|
status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus {
|
|
return v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
|
|
},
|
|
}
|
|
},
|
|
expectConditions: []metav1.Condition{
|
|
*conditions.FalseCondition(meta.ReadyCondition, v2.TestFailedReason,
|
|
ErrReleaseMismatch.Error()),
|
|
*conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason,
|
|
ErrReleaseMismatch.Error()),
|
|
},
|
|
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
|
|
return v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
|
|
}
|
|
},
|
|
expectFailures: 1,
|
|
wantErr: ErrReleaseMismatch,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
namedNS, err := testEnv.CreateNamespace(context.TODO(), mockReleaseNamespace)
|
|
g.Expect(err).NotTo(HaveOccurred())
|
|
t.Cleanup(func() {
|
|
_ = testEnv.Delete(context.TODO(), namedNS)
|
|
})
|
|
releaseNamespace := namedNS.Name
|
|
|
|
var releases []*helmrelease.Release
|
|
if tt.releases != nil {
|
|
releases = tt.releases(releaseNamespace)
|
|
helmreleaseutil.SortByRevision(releases)
|
|
}
|
|
|
|
obj := &v2.HelmRelease{
|
|
Spec: v2.HelmReleaseSpec{
|
|
ReleaseName: mockReleaseName,
|
|
TargetNamespace: releaseNamespace,
|
|
StorageNamespace: releaseNamespace,
|
|
Timeout: &metav1.Duration{Duration: 100 * time.Millisecond},
|
|
Test: &v2.Test{
|
|
Enable: true,
|
|
},
|
|
},
|
|
}
|
|
if tt.spec != nil {
|
|
tt.spec(&obj.Spec)
|
|
}
|
|
if tt.status != nil {
|
|
obj.Status = tt.status(releases)
|
|
}
|
|
|
|
getter, err := RESTClientGetterFromManager(testEnv.Manager, obj.GetReleaseNamespace())
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
|
|
cfg, err := action.NewConfigFactory(getter,
|
|
action.WithStorage(action.DefaultStorageDriver, obj.GetStorageNamespace()),
|
|
)
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
|
|
store := helmstorage.Init(cfg.Driver)
|
|
for _, r := range releases {
|
|
g.Expect(store.Create(r)).To(Succeed())
|
|
}
|
|
|
|
if tt.driver != nil {
|
|
cfg.Driver = tt.driver(cfg.Driver)
|
|
}
|
|
|
|
recorder := new(record.FakeRecorder)
|
|
got := (NewTest(cfg, recorder)).Reconcile(context.TODO(), &Request{
|
|
Object: obj,
|
|
})
|
|
if tt.wantErr != nil {
|
|
g.Expect(errors.Is(got, tt.wantErr)).To(BeTrue())
|
|
} else {
|
|
g.Expect(got).ToNot(HaveOccurred())
|
|
}
|
|
|
|
g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions))
|
|
|
|
releases, _ = store.History(mockReleaseName)
|
|
helmreleaseutil.SortByRevision(releases)
|
|
|
|
if tt.expectHistory != nil {
|
|
g.Expect(obj.Status.History).To(testutil.Equal(tt.expectHistory(releases)))
|
|
} else {
|
|
g.Expect(obj.Status.History).To(BeEmpty(), "expected history to be empty")
|
|
}
|
|
|
|
g.Expect(obj.Status.Failures).To(Equal(tt.expectFailures))
|
|
g.Expect(obj.Status.InstallFailures).To(Equal(tt.expectInstallFailures))
|
|
g.Expect(obj.Status.UpgradeFailures).To(Equal(tt.expectUpgradeFailures))
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_observeTest(t *testing.T) {
|
|
t.Run("test with current", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
obj := &v2.HelmRelease{
|
|
Status: v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
&v2.Snapshot{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 1,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 1,
|
|
}, testutil.ReleaseWithHooks(testHookFixtures))
|
|
|
|
expect := release.ObservedToSnapshot(release.ObserveRelease(rls))
|
|
expect.SetTestHooks(release.TestHooksFromRelease(rls))
|
|
|
|
observeTest(obj)(rls)
|
|
g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{
|
|
expect,
|
|
}))
|
|
})
|
|
|
|
t.Run("test with current OCI Digest", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
obj := &v2.HelmRelease{
|
|
Status: v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
&v2.Snapshot{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 1,
|
|
OCIDigest: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 1,
|
|
}, testutil.ReleaseWithHooks(testHookFixtures))
|
|
|
|
obs := release.ObserveRelease(rls)
|
|
obs.OCIDigest = "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6"
|
|
expect := release.ObservedToSnapshot(obs)
|
|
expect.SetTestHooks(release.TestHooksFromRelease(rls))
|
|
|
|
observeTest(obj)(rls)
|
|
g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{
|
|
expect,
|
|
}))
|
|
})
|
|
|
|
t.Run("test targeting different version than latest", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
current := &v2.Snapshot{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 2,
|
|
}
|
|
previous := &v2.Snapshot{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 1,
|
|
}
|
|
obj := &v2.HelmRelease{
|
|
Status: v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
current,
|
|
previous,
|
|
},
|
|
},
|
|
}
|
|
rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: previous.Version,
|
|
}, testutil.ReleaseWithHooks(testHookFixtures))
|
|
|
|
observeTest(obj)(rls)
|
|
g.Expect(obj.Status.History).To(testutil.Equal(v2.Snapshots{
|
|
current,
|
|
previous,
|
|
}))
|
|
})
|
|
|
|
t.Run("test without current", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
obj := &v2.HelmRelease{}
|
|
|
|
rls := testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Version: 2,
|
|
}, testutil.ReleaseWithHooks(testHookFixtures))
|
|
|
|
observeTest(obj)(rls)
|
|
g.Expect(obj.Status.History).To(BeEmpty())
|
|
})
|
|
}
|
|
|
|
func TestTest_failure(t *testing.T) {
|
|
var (
|
|
cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Chart: testutil.BuildChart(),
|
|
Version: 4,
|
|
})
|
|
obj = &v2.HelmRelease{
|
|
Status: v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(cur)),
|
|
},
|
|
},
|
|
}
|
|
err = errors.New("test error")
|
|
)
|
|
|
|
t.Run("records failure", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
recorder := testutil.NewFakeRecorder(10, false)
|
|
r := &Test{
|
|
eventRecorder: recorder,
|
|
}
|
|
|
|
req := &Request{Object: obj.DeepCopy()}
|
|
r.failure(req, err)
|
|
|
|
expectMsg := fmt.Sprintf(fmtTestFailure,
|
|
fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version),
|
|
fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version),
|
|
err.Error())
|
|
|
|
g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{
|
|
*conditions.FalseCondition(v2.TestSuccessCondition, v2.TestFailedReason, expectMsg),
|
|
}))
|
|
g.Expect(req.Object.Status.Failures).To(Equal(int64(1)))
|
|
g.Expect(req.Object.Status.InstallFailures).To(BeZero())
|
|
g.Expect(req.Object.Status.UpgradeFailures).To(BeZero())
|
|
g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{
|
|
{
|
|
Type: corev1.EventTypeWarning,
|
|
Reason: v2.TestFailedReason,
|
|
Message: expectMsg,
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Annotations: map[string]string{
|
|
eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version,
|
|
eventMetaGroupKey(metaAppVersionKey): cur.Chart.Metadata.AppVersion,
|
|
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(),
|
|
},
|
|
},
|
|
},
|
|
}))
|
|
})
|
|
|
|
t.Run("increases remediation failure count", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
recorder := testutil.NewFakeRecorder(10, false)
|
|
r := &Test{
|
|
eventRecorder: recorder,
|
|
}
|
|
|
|
obj := obj.DeepCopy()
|
|
obj.Status.LastAttemptedReleaseAction = v2.ReleaseActionInstall
|
|
obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{})
|
|
req := &Request{Object: obj}
|
|
r.failure(req, err)
|
|
|
|
g.Expect(req.Object.Status.InstallFailures).To(Equal(int64(1)))
|
|
})
|
|
|
|
t.Run("follows ignore failure instructions", func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
recorder := testutil.NewFakeRecorder(10, false)
|
|
r := &Test{
|
|
eventRecorder: recorder,
|
|
}
|
|
|
|
obj := obj.DeepCopy()
|
|
obj.Spec.Test = &v2.Test{IgnoreFailures: true}
|
|
obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{})
|
|
req := &Request{Object: obj}
|
|
r.failure(req, err)
|
|
|
|
g.Expect(req.Object.Status.InstallFailures).To(BeZero())
|
|
})
|
|
}
|
|
|
|
func TestTest_success(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
var (
|
|
cur = testutil.BuildRelease(&helmrelease.MockReleaseOptions{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
Chart: testutil.BuildChart(),
|
|
Version: 4,
|
|
})
|
|
obj = &v2.HelmRelease{
|
|
Status: v2.HelmReleaseStatus{
|
|
History: v2.Snapshots{
|
|
release.ObservedToSnapshot(release.ObserveRelease(cur)),
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
t.Run("records success", func(t *testing.T) {
|
|
recorder := testutil.NewFakeRecorder(10, false)
|
|
r := &Test{
|
|
eventRecorder: recorder,
|
|
}
|
|
|
|
obj := obj.DeepCopy()
|
|
obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{
|
|
"test": {
|
|
Phase: helmrelease.HookPhaseSucceeded.String(),
|
|
},
|
|
"test-2": {
|
|
Phase: helmrelease.HookPhaseSucceeded.String(),
|
|
},
|
|
})
|
|
req := &Request{Object: obj}
|
|
r.success(req)
|
|
|
|
expectMsg := fmt.Sprintf(fmtTestSuccess,
|
|
fmt.Sprintf("%s/%s.v%d", cur.Namespace, cur.Name, cur.Version),
|
|
fmt.Sprintf("%s@%s", cur.Chart.Name(), cur.Chart.Metadata.Version),
|
|
"2 test hooks completed successfully")
|
|
|
|
g.Expect(req.Object.Status.Conditions).To(conditions.MatchConditions([]metav1.Condition{
|
|
*conditions.TrueCondition(v2.TestSuccessCondition, v2.TestSucceededReason, expectMsg),
|
|
}))
|
|
g.Expect(req.Object.Status.Failures).To(Equal(int64(0)))
|
|
g.Expect(recorder.GetEvents()).To(ConsistOf([]corev1.Event{
|
|
{
|
|
Type: corev1.EventTypeNormal,
|
|
Reason: v2.TestSucceededReason,
|
|
Message: expectMsg,
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Annotations: map[string]string{
|
|
eventMetaGroupKey(eventv1.MetaRevisionKey): cur.Chart.Metadata.Version,
|
|
eventMetaGroupKey(metaAppVersionKey): cur.Chart.Metadata.AppVersion,
|
|
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, cur.Config).String(),
|
|
},
|
|
},
|
|
},
|
|
}))
|
|
})
|
|
|
|
t.Run("records success without hooks", func(t *testing.T) {
|
|
r := &Test{
|
|
eventRecorder: new(testutil.FakeRecorder),
|
|
}
|
|
|
|
obj := obj.DeepCopy()
|
|
obj.Status.History.Latest().SetTestHooks(map[string]*v2.TestHookStatus{})
|
|
req := &Request{Object: obj}
|
|
r.success(req)
|
|
|
|
g.Expect(conditions.IsTrue(req.Object, v2.TestSuccessCondition)).To(BeTrue())
|
|
g.Expect(req.Object.Status.Conditions[0].Message).To(ContainSubstring("no test hooks"))
|
|
})
|
|
}
|