716 lines
19 KiB
Go
716 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 (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/go-logr/logr"
|
|
. "github.com/onsi/gomega"
|
|
"helm.sh/helm/v3/pkg/chart"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"github.com/fluxcd/pkg/apis/kustomize"
|
|
"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"
|
|
)
|
|
|
|
const (
|
|
mockReleaseName = "mock-release"
|
|
mockReleaseNamespace = "mock-ns"
|
|
)
|
|
|
|
var (
|
|
postRenderers = []v2.PostRenderer{
|
|
{
|
|
Kustomize: &v2.Kustomize{
|
|
Patches: []kustomize.Patch{
|
|
{
|
|
Target: &kustomize.Selector{
|
|
Kind: "Deployment",
|
|
Name: "test",
|
|
},
|
|
Patch: `
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
replicas: 2
|
|
`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
postRenderers2 = []v2.PostRenderer{
|
|
{
|
|
Kustomize: &v2.Kustomize{
|
|
Patches: []kustomize.Patch{
|
|
{
|
|
Target: &kustomize.Selector{
|
|
Kind: "Deployment",
|
|
Name: "test",
|
|
},
|
|
Patch: `
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
replicas: 3
|
|
`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
func Test_summarize(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
generation int64
|
|
spec *v2.HelmReleaseSpec
|
|
status v2.HelmReleaseStatus
|
|
expectedStatus *v2.HelmReleaseStatus
|
|
}{
|
|
{
|
|
name: "summarize conditions",
|
|
generation: 1,
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with tests enabled",
|
|
generation: 1,
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.TestSucceededReason,
|
|
Message: "test hook(s) succeeded",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
spec: &v2.HelmReleaseSpec{
|
|
Test: &v2.Test{
|
|
Enable: true,
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.TestSucceededReason,
|
|
Message: "test hook(s) succeeded",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.TestSucceededReason,
|
|
Message: "test hook(s) succeeded",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with tests enabled and failure tests",
|
|
generation: 1,
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
spec: &v2.HelmReleaseSpec{
|
|
Test: &v2.Test{
|
|
Enable: true,
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with test hooks enabled and pending tests",
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionUnknown,
|
|
Reason: "AwaitingTests",
|
|
Message: "Release is awaiting tests",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
spec: &v2.HelmReleaseSpec{
|
|
Test: &v2.Test{
|
|
Enable: true,
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionUnknown,
|
|
Reason: "AwaitingTests",
|
|
Message: "Release is awaiting tests",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionUnknown,
|
|
Reason: "AwaitingTests",
|
|
Message: "Release is awaiting tests",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with remediation failure",
|
|
generation: 1,
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.RemediatedCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.UninstallFailedReason,
|
|
Message: "Uninstall failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
spec: &v2.HelmReleaseSpec{
|
|
Test: &v2.Test{
|
|
Enable: true,
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.UninstallFailedReason,
|
|
Message: "Uninstall failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.InstallSucceededReason,
|
|
Message: "Install complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.RemediatedCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.UninstallFailedReason,
|
|
Message: "Uninstall failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with remediation success",
|
|
generation: 1,
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.UpgradeFailedReason,
|
|
Message: "Upgrade failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.RemediatedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.RollbackSucceededReason,
|
|
Message: "Uninstall complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.RollbackSucceededReason,
|
|
Message: "Uninstall complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.UpgradeFailedReason,
|
|
Message: "Upgrade failure",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.RemediatedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.RollbackSucceededReason,
|
|
Message: "Uninstall complete",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with stale ready",
|
|
generation: 1,
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: "ChartNotFound",
|
|
Message: "chart not found",
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.UpgradeSucceededReason,
|
|
Message: "Upgrade finished",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.UpgradeSucceededReason,
|
|
Message: "Upgrade finished",
|
|
ObservedGeneration: 1,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.UpgradeSucceededReason,
|
|
Message: "Upgrade finished",
|
|
ObservedGeneration: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with stale observed generation",
|
|
generation: 5,
|
|
spec: &v2.HelmReleaseSpec{
|
|
Test: &v2.Test{
|
|
Enable: true,
|
|
},
|
|
},
|
|
status: v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.UpgradeSucceededReason,
|
|
Message: "Upgrade finished",
|
|
ObservedGeneration: 4,
|
|
},
|
|
{
|
|
Type: v2.RemediatedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.RollbackSucceededReason,
|
|
Message: "Rollback finished",
|
|
ObservedGeneration: 3,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 2,
|
|
},
|
|
},
|
|
},
|
|
expectedStatus: &v2.HelmReleaseStatus{
|
|
Conditions: []metav1.Condition{
|
|
{
|
|
Type: meta.ReadyCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.UpgradeSucceededReason,
|
|
Message: "Upgrade finished",
|
|
ObservedGeneration: 5,
|
|
},
|
|
{
|
|
Type: v2.ReleasedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.UpgradeSucceededReason,
|
|
Message: "Upgrade finished",
|
|
ObservedGeneration: 4,
|
|
},
|
|
{
|
|
Type: v2.RemediatedCondition,
|
|
Status: metav1.ConditionTrue,
|
|
Reason: v2.RollbackSucceededReason,
|
|
Message: "Rollback finished",
|
|
ObservedGeneration: 3,
|
|
},
|
|
{
|
|
Type: v2.TestSuccessCondition,
|
|
Status: metav1.ConditionFalse,
|
|
Reason: v2.TestFailedReason,
|
|
Message: "test hook(s) failure",
|
|
ObservedGeneration: 2,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
obj := &v2.HelmRelease{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Generation: tt.generation,
|
|
},
|
|
Status: tt.status,
|
|
}
|
|
if tt.spec != nil {
|
|
obj.Spec = *tt.spec.DeepCopy()
|
|
}
|
|
summarize(&Request{Object: obj})
|
|
|
|
g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectedStatus.Conditions))
|
|
g.Expect(obj.Status.ObservedPostRenderersDigest).To(Equal(tt.expectedStatus.ObservedPostRenderersDigest))
|
|
})
|
|
}
|
|
}
|
|
|
|
func mockLogBuffer(size int, lines int) *action.LogBuffer {
|
|
log := action.NewLogBuffer(action.NewDebugLog(logr.Discard()), size)
|
|
for i := 0; i < lines; i++ {
|
|
log.Log("line %d", i+1)
|
|
}
|
|
return log
|
|
}
|
|
|
|
func Test_RecordOnObject(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
obj *v2.HelmRelease
|
|
r observedReleases
|
|
mutate bool
|
|
testFunc func(*v2.HelmRelease) error
|
|
}{
|
|
{
|
|
name: "record observed releases",
|
|
obj: &v2.HelmRelease{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
},
|
|
},
|
|
r: observedReleases{
|
|
1: {
|
|
Name: mockReleaseName,
|
|
Version: 1,
|
|
ChartMetadata: chart.Metadata{
|
|
Name: mockReleaseName,
|
|
Version: "1.0.0",
|
|
},
|
|
},
|
|
},
|
|
testFunc: func(obj *v2.HelmRelease) error {
|
|
if len(obj.Status.History) != 1 {
|
|
return fmt.Errorf("history length is not 1")
|
|
}
|
|
if obj.Status.History[0].Name != mockReleaseName {
|
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
name: "record observed releases with multiple versions",
|
|
obj: &v2.HelmRelease{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
},
|
|
},
|
|
r: observedReleases{
|
|
1: {
|
|
Name: mockReleaseName,
|
|
Version: 1,
|
|
ChartMetadata: chart.Metadata{
|
|
Name: mockReleaseName,
|
|
Version: "1.0.0",
|
|
},
|
|
},
|
|
2: {
|
|
Name: mockReleaseName,
|
|
Version: 2,
|
|
ChartMetadata: chart.Metadata{
|
|
Name: mockReleaseName,
|
|
Version: "2.0.0",
|
|
},
|
|
},
|
|
},
|
|
testFunc: func(obj *v2.HelmRelease) error {
|
|
if len(obj.Status.History) != 1 {
|
|
return fmt.Errorf("want history length 1, got %d", len(obj.Status.History))
|
|
}
|
|
if obj.Status.History[0].Name != mockReleaseName {
|
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
|
}
|
|
if obj.Status.History[0].ChartVersion != "2.0.0" {
|
|
return fmt.Errorf("want chart version %s, got %s", "2.0.0", obj.Status.History[0].ChartVersion)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
name: "record observed releases with status digest",
|
|
obj: &v2.HelmRelease{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
},
|
|
Status: v2.HelmReleaseStatus{
|
|
LastAttemptedRevisionDigest: "sha256:123456",
|
|
},
|
|
},
|
|
r: observedReleases{
|
|
1: {
|
|
Name: mockReleaseName,
|
|
Version: 1,
|
|
ChartMetadata: chart.Metadata{
|
|
Name: mockReleaseName,
|
|
Version: "1.0.0",
|
|
},
|
|
},
|
|
},
|
|
mutate: true,
|
|
testFunc: func(obj *v2.HelmRelease) error {
|
|
h := obj.Status.History.Latest()
|
|
if h.Name != mockReleaseName {
|
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
|
}
|
|
if h.ChartVersion != "1.0.0" {
|
|
return fmt.Errorf("want chart version %s, got %s", "1.0.0", h.ChartVersion)
|
|
}
|
|
if h.OCIDigest != obj.Status.LastAttemptedRevisionDigest {
|
|
return fmt.Errorf("want digest %s, got %s", obj.Status.LastAttemptedRevisionDigest, h.OCIDigest)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
name: "record observed releases with multiple versions and status digest",
|
|
obj: &v2.HelmRelease{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: mockReleaseName,
|
|
Namespace: mockReleaseNamespace,
|
|
},
|
|
Status: v2.HelmReleaseStatus{
|
|
LastAttemptedRevisionDigest: "sha256:123456",
|
|
},
|
|
},
|
|
r: observedReleases{
|
|
1: {
|
|
Name: mockReleaseName,
|
|
Version: 1,
|
|
ChartMetadata: chart.Metadata{
|
|
Name: mockReleaseName,
|
|
Version: "1.0.0",
|
|
},
|
|
},
|
|
2: {
|
|
Name: mockReleaseName,
|
|
Version: 2,
|
|
ChartMetadata: chart.Metadata{
|
|
Name: mockReleaseName,
|
|
Version: "2.0.0",
|
|
},
|
|
},
|
|
},
|
|
mutate: true,
|
|
testFunc: func(obj *v2.HelmRelease) error {
|
|
if len(obj.Status.History) != 1 {
|
|
return fmt.Errorf("want history length 1, got %d", len(obj.Status.History))
|
|
}
|
|
h := obj.Status.History.Latest()
|
|
if h.Name != mockReleaseName {
|
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
|
}
|
|
if h.ChartVersion != "2.0.0" {
|
|
return fmt.Errorf("want chart version %s, got %s", "2.0.0", h.ChartVersion)
|
|
}
|
|
if h.OCIDigest != obj.Status.LastAttemptedRevisionDigest {
|
|
return fmt.Errorf("want digest %s, got %s", obj.Status.LastAttemptedRevisionDigest, h.OCIDigest)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
g := NewWithT(t)
|
|
|
|
if tt.mutate {
|
|
tt.r.recordOnObject(tt.obj, mutateOCIDigest)
|
|
} else {
|
|
tt.r.recordOnObject(tt.obj)
|
|
}
|
|
err := tt.testFunc(tt.obj)
|
|
g.Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
}
|
|
|
|
}
|