Skip to content

Commit

Permalink
Merge pull request #4 from avi-biton/tests
Browse files Browse the repository at this point in the history
Add integration tests to reconcile
  • Loading branch information
avi-biton authored Jul 14, 2024
2 parents 071a75f + 23f530a commit 53ce083
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 25 deletions.
10 changes: 5 additions & 5 deletions internal/controller/notificationservice_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type NotificationServiceReconciler struct {
// to allow the deletion of this pipelinerun
func (r *NotificationServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {

logger := r.Log.WithValues("pipelinerun", req.NamespacedName)
logger := r.Log.WithName("Notification controller")
pipelineRun := &tektonv1.PipelineRun{}

err := r.Get(ctx, req.NamespacedName, pipelineRun)
Expand All @@ -64,7 +64,7 @@ func (r *NotificationServiceReconciler) Reconcile(ctx context.Context, req ctrl.
!IsFinalizerExistInPipelineRun(pipelineRun, NotificationPipelineRunFinalizer) {
err = AddFinalizerToPipelineRun(ctx, pipelineRun, r, NotificationPipelineRunFinalizer)
if err != nil {
logger.Error(err, "Failed to add finalizer to pipelinerun ", pipelineRun.Name)
logger.Error(err, "Failed to add finalizer", "pipelineRun", pipelineRun.Name)
return ctrl.Result{}, err
}
}
Expand All @@ -73,20 +73,20 @@ func (r *NotificationServiceReconciler) Reconcile(ctx context.Context, req ctrl.
if IsPipelineRunEndedSuccessfully(pipelineRun) && !IsAnnotationExistInPipelineRun(pipelineRun, NotificationPipelineRunAnnotation, NotificationPipelineRunAnnotationValue) {
results, err := GetResultsFromPipelineRun(pipelineRun)
if err != nil {
logger.Error(err, "Failed to get results for pipelineRun ", pipelineRun.Name)
logger.Error(err, "Failed to get results", "pipelineRun", pipelineRun.Name)
return ctrl.Result{}, err
}

fmt.Printf("Results for pipelinerun %s are: %s\n", pipelineRun.Name, results)
err = AddAnnotationToPipelineRun(ctx, pipelineRun, r, NotificationPipelineRunAnnotation, NotificationPipelineRunAnnotationValue)
if err != nil {
logger.Error(err, "Failed to add annotation to pipelinerun ", pipelineRun.Name)
logger.Error(err, "Failed to add annotation", "pipelineRun", pipelineRun.Name)
return ctrl.Result{}, err
}
}
err = RemoveFinalizerFromPipelineRun(ctx, pipelineRun, r, NotificationPipelineRunFinalizer)
if err != nil {
logger.Error(err, "Failed to remove finalizer to pipelinerun ", pipelineRun.Name)
logger.Error(err, "Failed to remove finalizer", "pipelineRun", pipelineRun.Name)
return ctrl.Result{}, err
}
}
Expand Down
275 changes: 271 additions & 4 deletions internal/controller/notificationservice_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,283 @@ limitations under the License.
package controller

import (
"time"

"github.com/konflux-ci/operator-toolkit/metadata"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"knative.dev/pkg/apis"
v1 "knative.dev/pkg/apis/duck/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

var _ = Describe("NotificationService Controller", func() {
Context("When reconciling a resource", func() {
var (
pushPipelineRun, pullRequestPipelineRun *tektonv1.PipelineRun
)
const (
timeout = time.Second * 10
interval = time.Millisecond * 250
pushPipelineRunName = "push-pipelinerun-sample"
pullRequestPipelineRunName = "pull-request-pipelinerun-sample"
namespace = "default"
)

pushPipelineRunLookupKey := types.NamespacedName{Name: pushPipelineRunName, Namespace: namespace}
pullRequestPipelineLookupKey := types.NamespacedName{Name: pullRequestPipelineRunName, Namespace: namespace}
createdPipelineRun := &tektonv1.PipelineRun{}

Describe("Testing successful reconcile push pipelinerun", func() {
BeforeEach(func() {
// Create a push pipelinerun with Unknown status (not ended)
pushPipelineRun = &tektonv1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{
Name: pushPipelineRunName,
Namespace: namespace,
Labels: map[string]string{
PipelineRunTypeLabel: PushPipelineRunTypeValue,
"pipelines.openshift.io/used-by": "build-cloud",
"pipelines.openshift.io/runtime": "nodejs",
"pipelines.openshift.io/strategy": "s2i",
"appstudio.openshift.io/component": "component-sample",
"appstudio.openshift.io/application": "aaa",
},
},
Spec: tektonv1.PipelineRunSpec{
PipelineRef: &tektonv1.PipelineRef{},
},
Status: tektonv1.PipelineRunStatus{
PipelineRunStatusFields: tektonv1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
CompletionTime: &metav1.Time{Time: time.Now().Add(5 * time.Minute)},
},
Status: v1.Status{
Conditions: v1.Conditions{
apis.Condition{
Message: "Tasks Completed: 3 (Failed: 0, Cancelled 0), Incomplete: 10, Skipped:1",
Reason: "Running",
Status: "Unknown",
Type: apis.ConditionSucceeded,
},
},
},
},
}
err := k8sClient.Create(ctx, pushPipelineRun)
Expect(err).NotTo(HaveOccurred(), "failed to create test Pipelinerun resource")

// Wait for the resource to be created
Eventually(func() bool {
err := k8sClient.Get(ctx, pushPipelineRunLookupKey, createdPipelineRun)
return err == nil
}, timeout, interval).Should(BeTrue())
})

Context("when a push pipelinerun is created and end successfully", func() {
It("should reconcile successfully - Add finalizer, Read the results, add annotation and remove the finalizer", func() {
By("Creating a new push pipelinerun and add finalizer")

// The pipelinerun should be reconciled and the notification finalizer has been added successfully
Eventually(func() bool {
err := k8sClient.Get(ctx, pushPipelineRunLookupKey, createdPipelineRun)
Expect(err).ToNot(HaveOccurred())
return controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)
}, timeout, interval).Should(BeTrue())
Expect(controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)).To(BeTrue())

By("Updating status to completed successfully")
createdPipelineRun.Status = tektonv1.PipelineRunStatus{
PipelineRunStatusFields: tektonv1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
CompletionTime: &metav1.Time{Time: time.Now().Add(5 * time.Minute)},
Results: []tektonv1.PipelineRunResult{
{
Name: "IMAGE_DIGEST",
Value: *tektonv1.NewStructuredValues("image_digest_value"),
},
{
Name: "IMAGE_URL",
Value: *tektonv1.NewStructuredValues("image"),
},
{
Name: "CHAINS-GIT_URL",
Value: *tektonv1.NewStructuredValues("git_url_value"),
},
{
Name: "CHAINS-GIT_COMMIT",
Value: *tektonv1.NewStructuredValues("git_commit_value"),
},
},
},
Status: v1.Status{
Conditions: v1.Conditions{
apis.Condition{
Message: "Tasks Completed: 12 (Failed: 0, Cancelled 0), Skipped: 2",
Reason: "Completed",
Status: "True",
Type: apis.ConditionSucceeded,
},
},
},
}
Expect(k8sClient.Status().Update(ctx, createdPipelineRun)).Should(Succeed())

// The pipelinerun should be reconciled:
// Read the results, add the notification annotation, remove the finalizer
Eventually(func() bool {
err := k8sClient.Get(ctx, pushPipelineRunLookupKey, createdPipelineRun)
Expect(err).ToNot(HaveOccurred())
return metadata.HasAnnotationWithValue(createdPipelineRun, NotificationPipelineRunAnnotation, NotificationPipelineRunAnnotationValue)
}, timeout, interval).Should(BeTrue())
Expect(controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)).To(BeFalse())
})
})

It("should successfully reconcile the resource", func() {
Context("when a push pipelinerun is created and end with failure", func() {
It("should reconcile successfully - Add finalizer, Not reading the results, Not adding annotation and remove the finalizer", func() {
By("Creating a new push pipelinerun and add finalizer")

// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
// Example: If you expect a certain status condition after reconciliation, verify it here.
// The pipelinerun should be reconciled and the notification finalizer has been added successfully
Eventually(func() bool {
err := k8sClient.Get(ctx, pushPipelineRunLookupKey, createdPipelineRun)
Expect(err).ToNot(HaveOccurred())
return controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)
}, timeout, interval).Should(BeTrue())
Expect(controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)).To(BeTrue())

By("Updating status to completed with failure")
createdPipelineRun.Status = tektonv1.PipelineRunStatus{
PipelineRunStatusFields: tektonv1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
CompletionTime: &metav1.Time{Time: time.Now().Add(5 * time.Minute)},
},
Status: v1.Status{
Conditions: v1.Conditions{
apis.Condition{
Message: "Tasks Completed: 12 (Failed: 0, Cancelled 0), Skipped: 2",
Reason: "CouldntGetTask",
Status: "False",
Type: apis.ConditionSucceeded,
},
},
},
}
Expect(k8sClient.Status().Update(ctx, createdPipelineRun)).Should(Succeed())

// The pipelinerun should be reconciled:
// Remove the finalizer
Eventually(func() bool {
err := k8sClient.Get(ctx, pushPipelineRunLookupKey, createdPipelineRun)
Expect(err).ToNot(HaveOccurred())
return controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)
}, timeout, interval).Should(BeFalse())
Expect(metadata.HasAnnotationWithValue(createdPipelineRun, NotificationPipelineRunAnnotation, NotificationPipelineRunAnnotationValue)).To(BeFalse())
})
})
})

Describe("Testing No reconcile with non push pipelinerun", func() {
Context("When a non push pipelineRun is created", func() {
It("Reconcile should not run", func() {

// Create a pull_request pipelinerun
pullRequestPipelineRun = &tektonv1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{
Name: pullRequestPipelineRunName,
Namespace: namespace,
Labels: map[string]string{
PipelineRunTypeLabel: "pull_request",
"pipelines.openshift.io/used-by": "build-cloud",
"pipelines.openshift.io/runtime": "nodejs",
"pipelines.openshift.io/strategy": "s2i",
"appstudio.openshift.io/component": "component-sample",
"appstudio.openshift.io/application": "aaa",
},
},
Spec: tektonv1.PipelineRunSpec{
PipelineRef: &tektonv1.PipelineRef{},
},
Status: tektonv1.PipelineRunStatus{
PipelineRunStatusFields: tektonv1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
CompletionTime: &metav1.Time{Time: time.Now().Add(5 * time.Minute)},
},
Status: v1.Status{
Conditions: v1.Conditions{
apis.Condition{
Message: "Tasks Completed: 3 (Failed: 0, Cancelled 0), Incomplete: 10, Skipped:1",
Reason: "Running",
Status: "Unknown",
Type: apis.ConditionSucceeded,
},
},
},
},
}
err := k8sClient.Create(ctx, pullRequestPipelineRun)
Expect(err).NotTo(HaveOccurred(), "failed to create test Pipelinerun resource")

// Wait for the resource to be created
Eventually(func() bool {
err := k8sClient.Get(ctx, pullRequestPipelineLookupKey, createdPipelineRun)
return err == nil
}, timeout, interval).Should(BeTrue())

// No finalizer should be added
Expect(controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)).To(BeFalse())

By("Updating status to completed successfully")
createdPipelineRun.Status = tektonv1.PipelineRunStatus{
PipelineRunStatusFields: tektonv1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
CompletionTime: &metav1.Time{Time: time.Now().Add(5 * time.Minute)},
Results: []tektonv1.PipelineRunResult{
{
Name: "IMAGE_DIGEST",
Value: *tektonv1.NewStructuredValues("image_digest_value"),
},
{
Name: "IMAGE_URL",
Value: *tektonv1.NewStructuredValues("image"),
},
{
Name: "CHAINS-GIT_URL",
Value: *tektonv1.NewStructuredValues("git_url_value"),
},
{
Name: "CHAINS-GIT_COMMIT",
Value: *tektonv1.NewStructuredValues("git_commit_value"),
},
},
},
Status: v1.Status{
Conditions: v1.Conditions{
apis.Condition{
Message: "Tasks Completed: 12 (Failed: 0, Cancelled 0), Skipped: 2",
Reason: "Completed",
Status: "True",
Type: apis.ConditionSucceeded,
},
},
},
}
Expect(k8sClient.Status().Update(ctx, createdPipelineRun)).Should(Succeed())
Eventually(func() bool {
err := k8sClient.Get(ctx, pullRequestPipelineLookupKey, createdPipelineRun)
return err == nil
}, timeout, interval).Should(BeTrue())
// Annotation and finalizer should not be added
Expect(controllerutil.ContainsFinalizer(createdPipelineRun, NotificationPipelineRunFinalizer)).To(BeFalse())
Expect(metadata.HasAnnotationWithValue(createdPipelineRun, NotificationPipelineRunAnnotation, NotificationPipelineRunAnnotationValue)).To(BeFalse())
})
})
})
AfterEach(func() {
err := k8sClient.Delete(ctx, createdPipelineRun)
Expect(err == nil || errors.IsNotFound(err)).To(BeTrue())
})
})
Loading

0 comments on commit 53ce083

Please sign in to comment.