Skip to content

Commit

Permalink
Add test for upgrade
Browse files Browse the repository at this point in the history
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
  • Loading branch information
matheuscscp committed Dec 13, 2024
1 parent f708e0d commit 0987c72
Showing 1 changed file with 197 additions and 0 deletions.
197 changes: 197 additions & 0 deletions internal/reconcile/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ import (
"time"

. "github.com/onsi/gomega"
"helm.sh/helm/v3/pkg/chart"
helmchart "helm.sh/helm/v3/pkg/chart"
helmchartutil "helm.sh/helm/v3/pkg/chartutil"
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"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"

eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
Expand Down Expand Up @@ -431,6 +434,200 @@ func TestUpgrade_Reconcile(t *testing.T) {
}
}

func TestUpgrade_Reconcile_withSubchartWithCRDs(t *testing.T) {
buildChart := func() *chart.Chart {
subChart := testutil.BuildChart(
testutil.ChartWithName("subchart"),
testutil.ChartWithManifestWithCustomName("sub-chart"),
testutil.ChartWithCRD(),
testutil.ChartWithValues(helmchartutil.Values{
"foo": "bar",
"exports": map[string]any{"data": map[string]any{"myint": 123}},
"default": map[string]any{"data": map[string]any{"myint": 456}},
}))
mainChart := testutil.BuildChart(
testutil.ChartWithManifestWithCustomName("main-chart"),
testutil.ChartWithValues(helmchartutil.Values{
"foo": "baz",
"myimports": map[string]any{"myint": 0},
}),
testutil.ChartWithDependency(&chart.Dependency{
Name: "subchart",
Condition: "subchart.enabled",
ImportValues: []any{
"data",
map[string]any{
"child": "default.data",
"parent": "myimports",
},
},
}, subChart))
return mainChart
}

getValues := func(subchartValues map[string]any) helmchartutil.Values {
return helmchartutil.Values{"subchart": subchartValues}
}

releases := func(namespace string) []*helmrelease.Release {
return []*helmrelease.Release{
testutil.BuildRelease(&helmrelease.MockReleaseOptions{
Name: mockReleaseName,
Namespace: namespace,
Chart: testutil.BuildChart(testutil.ChartWithTestHook()),
Version: 1,
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.TrueCondition(meta.ReadyCondition, v2.UpgradeSucceededReason, "Helm upgrade succeeded"),
*conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "Helm upgrade succeeded"),
}

expectHistory := func(releases []*helmrelease.Release) v2.Snapshots {
return v2.Snapshots{
release.ObservedToSnapshot(release.ObserveRelease(releases[1])),
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
}
}

for _, tt := range []struct {
name string
subchartValues map[string]any
subchartResourcesPresent bool
expectedMainChartValues map[string]any
}{
{
name: "subchart disabled should not deploy resources, including CRDs",
subchartValues: map[string]any{"enabled": false},
subchartResourcesPresent: false,
expectedMainChartValues: map[string]any{
"foo": "baz",
"myimports": map[string]any{"myint": 0},
},
},
{
name: "subchart enabled should deploy resources, including CRDs",
subchartValues: map[string]any{"enabled": true},
subchartResourcesPresent: true,
expectedMainChartValues: map[string]any{
"foo": "baz",
"myint": 123,
"myimports": map[string]any{"myint": 0}, // should be 456: https://github.com/helm/helm/issues/13223
"subchart": map[string]any{
"foo": "bar",
"global": map[string]any{},
"exports": map[string]any{"data": map[string]any{"myint": 123}},
"default": map[string]any{"data": map[string]any{"myint": 456}},
},
},
},
} {
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

releases := releases(releaseNamespace)
helmreleaseutil.SortByRevision(releases)

obj := &v2.HelmRelease{
Spec: v2.HelmReleaseSpec{
ReleaseName: mockReleaseName,
TargetNamespace: releaseNamespace,
StorageNamespace: releaseNamespace,
Timeout: &metav1.Duration{Duration: 100 * time.Millisecond},
},
}
obj.Status = 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())
}

chart := buildChart()
recorder := new(record.FakeRecorder)
got := NewUpgrade(cfg, recorder).Reconcile(context.TODO(), &Request{
Object: obj,
Chart: chart,
Values: getValues(tt.subchartValues),
})
g.Expect(got).ToNot(HaveOccurred())

g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(expectConditions))

releases, _ = store.History(mockReleaseName)
helmreleaseutil.SortByRevision(releases)

g.Expect(obj.Status.History).To(testutil.Equal(expectHistory(releases)))

// Assert main chart configmap is present.
mainChartCM := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm-main-chart",
Namespace: releaseNamespace,
},
}
err = testEnv.Get(context.TODO(), client.ObjectKeyFromObject(mainChartCM), mainChartCM)
g.Expect(err).NotTo(HaveOccurred())

// Assert subchart configmap is absent or present.
subChartCM := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm-sub-chart",
Namespace: releaseNamespace,
},
}
err = testEnv.Get(context.TODO(), client.ObjectKeyFromObject(subChartCM), subChartCM)
if tt.subchartResourcesPresent {
g.Expect(err).NotTo(HaveOccurred())
} else {
g.Expect(err).To(HaveOccurred())
}

// Assert subchart CRD is absent or present.
subChartCRD := &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "crontabs.stable.example.com",
},
}
err = testEnv.Get(context.TODO(), client.ObjectKeyFromObject(subChartCRD), subChartCRD)
if tt.subchartResourcesPresent {
g.Expect(err).NotTo(HaveOccurred())
} else {
g.Expect(err).To(HaveOccurred())
}

// Assert main chart values.
g.Expect(chart.Values).To(testutil.Equal(tt.expectedMainChartValues))
})
}
}

func TestUpgrade_failure(t *testing.T) {
var (
obj = &v2.HelmRelease{
Expand Down

0 comments on commit 0987c72

Please sign in to comment.