Skip to content

Commit

Permalink
Merge pull request #204 from weaveworks/separate-tests
Browse files Browse the repository at this point in the history
Separate out promotion tests
  • Loading branch information
squaremo authored Nov 20, 2023
2 parents 1dcfa89 + bd8b6d2 commit e755cd2
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 216 deletions.
5 changes: 4 additions & 1 deletion controllers/leveltriggered/controller_remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ func TestRemoteTargets(t *testing.T) {
// the application hasn't been created, so we expect "not found"
p := getPipeline(ctx, g, client.ObjectKeyFromObject(pipeline))
g.Expect(getTargetStatus(g, p, "test", 0).Ready).NotTo(BeTrue())
g.Expect(getTargetStatus(g, p, "test", 0).Error).To(ContainSubstring("not found"))
// we can see "target cluster client not synced" before "not found"
g.Eventually(func() string {
return getTargetStatus(g, p, "test", 0).Error
}).Should(ContainSubstring("not found"))

targetNs := corev1.Namespace{}
targetNs.Name = ns.Name // newPipeline makes the target namespace the same as the pipeline namespace
Expand Down
215 changes: 0 additions & 215 deletions controllers/leveltriggered/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"github.com/fluxcd/pkg/runtime/conditions"
. "github.com/onsi/gomega"
clusterctrlv1alpha1 "github.com/weaveworks/cluster-controller/api/v1alpha1"
pipelineconditions "github.com/weaveworks/pipeline-controller/pkg/conditions"
"go.uber.org/mock/gomock"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -23,7 +21,6 @@ import (

"github.com/weaveworks/pipeline-controller/api/v1alpha1"
"github.com/weaveworks/pipeline-controller/internal/testingutils"
"github.com/weaveworks/pipeline-controller/server/strategy"
)

const (
Expand Down Expand Up @@ -122,193 +119,6 @@ func TestReconcile(t *testing.T) {
g.Expect(targetStatus.Revision).To(Equal(appRevision))
})

t.Run("promotes revision to all environments", func(t *testing.T) {
g := testingutils.NewGomegaWithT(t)
mockStrategy := setStrategyRegistry(t, pipelineReconciler)
mockStrategy.EXPECT().Handles(gomock.Any()).Return(true).AnyTimes()

name := "pipeline-" + rand.String(5)

managementNs := testingutils.NewNamespace(ctx, g, k8sClient)
devNs := testingutils.NewNamespace(ctx, g, k8sClient)
stagingNs := testingutils.NewNamespace(ctx, g, k8sClient)
prodNs := testingutils.NewNamespace(ctx, g, k8sClient)

pipeline := &v1alpha1.Pipeline{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: managementNs.Name,
},
Spec: v1alpha1.PipelineSpec{
AppRef: v1alpha1.LocalAppReference{
APIVersion: "helm.toolkit.fluxcd.io/v2beta1",
Kind: "HelmRelease",
Name: name,
},
Environments: []v1alpha1.Environment{
{
Name: "dev",
Targets: []v1alpha1.Target{
{Namespace: devNs.Name},
},
},
{
Name: "staging",
Targets: []v1alpha1.Target{
{Namespace: stagingNs.Name},
},
},
{
Name: "prod",
Targets: []v1alpha1.Target{
{Namespace: prodNs.Name},
},
},
},
Promotion: &v1alpha1.Promotion{
Strategy: v1alpha1.Strategy{
Notification: &v1alpha1.NotificationPromotion{},
},
},
},
}

devApp := createApp(ctx, k8sClient, g, name, devNs.Name)
setAppRevisionAndReadyStatus(ctx, g, devApp, "v1.0.0")

stagingApp := createApp(ctx, k8sClient, g, name, stagingNs.Name)
setAppRevisionAndReadyStatus(ctx, g, stagingApp, "v1.0.0")

prodApp := createApp(ctx, k8sClient, g, name, prodNs.Name)
setAppRevisionAndReadyStatus(ctx, g, prodApp, "v1.0.0")

g.Expect(k8sClient.Create(ctx, pipeline)).To(Succeed())
checkCondition(ctx, g, client.ObjectKeyFromObject(pipeline), meta.ReadyCondition, metav1.ConditionTrue, v1alpha1.ReconciliationSucceededReason)

versionToPromote := "v1.0.1"

mockStrategy.EXPECT().
Promote(gomock.Any(), *pipeline.Spec.Promotion, gomock.Any()).
AnyTimes().
Do(func(ctx context.Context, p v1alpha1.Promotion, prom strategy.Promotion) {
switch prom.Environment.Name {
case "staging":
setAppRevision(ctx, g, stagingApp, prom.Version)
case "prod":
setAppRevision(ctx, g, prodApp, prom.Version)
default:
panic("Unexpected environment. Make sure to setup the pipeline properly in the test.")
}
})

// Bumping dev revision to trigger the promotion
setAppRevisionAndReadyStatus(ctx, g, devApp, versionToPromote)

// checks if the revision of all target status is v1.0.1
g.Eventually(func() bool {
p := getPipeline(ctx, g, client.ObjectKeyFromObject(pipeline))

for _, env := range p.Spec.Environments {
if !checkAllTargetsRunRevision(p.Status.Environments[env.Name], versionToPromote) {
return false
}

if !checkAllTargetsAreReady(p.Status.Environments[env.Name]) {
return false
}
}

return true
}, "5s", "0.2s").Should(BeTrue())

t.Run("triggers another promotion if the app is updated again", func(t *testing.T) {
// Bumping dev revision to trigger the promotion
setAppRevisionAndReadyStatus(ctx, g, devApp, "v1.0.2")

// checks if the revision of all target status is v1.0.2
g.Eventually(func() bool {
p := getPipeline(ctx, g, client.ObjectKeyFromObject(pipeline))

for _, env := range p.Spec.Environments {
if !checkAllTargetsRunRevision(p.Status.Environments[env.Name], "v1.0.2") {
return false
}
}

return true
}, "5s", "0.2s").Should(BeTrue())
})
})

t.Run("sets PipelinePending condition", func(t *testing.T) {
g := testingutils.NewGomegaWithT(t)
mockStrategy := setStrategyRegistry(t, pipelineReconciler)
mockStrategy.EXPECT().Handles(gomock.Any()).Return(true).AnyTimes()

name := "pipeline-" + rand.String(5)

managementNs := testingutils.NewNamespace(ctx, g, k8sClient)
devNs := testingutils.NewNamespace(ctx, g, k8sClient)
devNs2 := testingutils.NewNamespace(ctx, g, k8sClient)
stagingNs := testingutils.NewNamespace(ctx, g, k8sClient)

pipeline := &v1alpha1.Pipeline{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: managementNs.Name,
},
Spec: v1alpha1.PipelineSpec{
AppRef: v1alpha1.LocalAppReference{
APIVersion: "helm.toolkit.fluxcd.io/v2beta1",
Kind: "HelmRelease",
Name: name,
},
Environments: []v1alpha1.Environment{
{
Name: "dev",
Targets: []v1alpha1.Target{
{Namespace: devNs.Name},
{Namespace: devNs2.Name},
},
},
{
Name: "staging",
Targets: []v1alpha1.Target{
{Namespace: stagingNs.Name},
},
},
},
Promotion: &v1alpha1.Promotion{
Strategy: v1alpha1.Strategy{
Notification: &v1alpha1.NotificationPromotion{},
},
},
},
}

devApp := createApp(ctx, k8sClient, g, name, devNs.Name)
setAppRevisionAndReadyStatus(ctx, g, devApp, "v1.0.0")

devApp2 := createApp(ctx, k8sClient, g, name, devNs2.Name)

stagingApp := createApp(ctx, k8sClient, g, name, stagingNs.Name)
setAppRevisionAndReadyStatus(ctx, g, stagingApp, "v1.0.0")

g.Expect(k8sClient.Create(ctx, pipeline)).To(Succeed())
checkCondition(ctx, g, client.ObjectKeyFromObject(pipeline), meta.ReadyCondition, metav1.ConditionTrue, v1alpha1.ReconciliationSucceededReason)
checkCondition(ctx, g, client.ObjectKeyFromObject(pipeline), pipelineconditions.PromotionPendingCondition, metav1.ConditionTrue, v1alpha1.EnvironmentNotReadyReason)

setAppRevision(ctx, g, devApp2, "v1.0.0")
checkCondition(ctx, g, client.ObjectKeyFromObject(pipeline), pipelineconditions.PromotionPendingCondition, metav1.ConditionTrue, v1alpha1.EnvironmentNotReadyReason)

setAppStatusReadyCondition(ctx, g, devApp2)

g.Eventually(func() bool {
p := getPipeline(ctx, g, client.ObjectKeyFromObject(pipeline))
return apimeta.FindStatusCondition(p.Status.Conditions, pipelineconditions.PromotionPendingCondition) == nil
}).Should(BeTrue())
})

t.Run("works with a Kustomization", func(t *testing.T) {
g := testingutils.NewGomegaWithT(t)
ctx := context.TODO()
Expand Down Expand Up @@ -365,31 +175,6 @@ func TestReconcile(t *testing.T) {

// TODO possibly: check the events too, as it used to.
})

}

func setAppRevisionAndReadyStatus(ctx context.Context, g Gomega, hr *helmv2.HelmRelease, revision string) {
setAppRevision(ctx, g, hr, revision)
setAppStatusReadyCondition(ctx, g, hr)
}

func setAppRevision(ctx context.Context, g Gomega, hr *helmv2.HelmRelease, revision string) {
hr.Status.LastAppliedRevision = revision
g.Expect(k8sClient.Status().Update(ctx, hr)).To(Succeed())
}

func setAppStatusReadyCondition(ctx context.Context, g Gomega, hr *helmv2.HelmRelease) {
apimeta.SetStatusCondition(&hr.Status.Conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "test"})
g.Expect(k8sClient.Status().Update(ctx, hr)).To(Succeed())
}

func setStrategyRegistry(t *testing.T, r *PipelineReconciler) *strategy.MockStrategy {
mockCtrl := gomock.NewController(t)
mockStrategy := strategy.NewMockStrategy(mockCtrl)

r.stratReg.Register(mockStrategy)

return mockStrategy
}

func getPipeline(ctx context.Context, g Gomega, key client.ObjectKey) *v1alpha1.Pipeline {
Expand Down
Loading

0 comments on commit e755cd2

Please sign in to comment.