Skip to content

Commit

Permalink
Add tests for status conditions
Browse files Browse the repository at this point in the history
Unit tests and e2e tests have been added to verify the expected behaviour by looking whether the status conditions have been set and what's their value
  • Loading branch information
razo7 committed Aug 1, 2023
1 parent 5954fd2 commit badcfa4
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 4 deletions.
44 changes: 40 additions & 4 deletions controllers/fenceagentsremediation_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ import (
"time"

"github.com/go-logr/logr"
commonConditions "github.com/medik8s/common/pkg/conditions"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -46,6 +48,10 @@ const (
testPodName = "far-pod-test-1"
vaName1 = "va-test-1"
vaName2 = "va-test-2"

// intervals
timeoutDeletion = 10 * time.Second // this timeout is used after all the other steps have finished successfully
pollInterval = 250 * time.Millisecond
)

var (
Expand Down Expand Up @@ -158,6 +164,11 @@ var _ = Describe("FAR Controller", func() {
testVADeletion(vaName1, resourceDeletionWasTriggered)
testVADeletion(vaName2, resourceDeletionWasTriggered)
testPodDeletion(testPodName, resourceDeletionWasTriggered)

By("Having Succeed condition set to true")
verifyExpectedStatusConditionError(underTestFAR, commonConditions.ProcessingType, utils.ConditionSetAndMatchSuccess, metav1.ConditionFalse)
verifyExpectedStatusConditionError(underTestFAR, v1alpha1.FenceAgentActionSucceededType, utils.ConditionSetAndMatchSuccess, metav1.ConditionTrue)
verifyExpectedStatusConditionError(underTestFAR, commonConditions.SucceededType, utils.ConditionSetAndMatchSuccess, metav1.ConditionTrue)
})
})
When("creating invalid FAR CR Name", func() {
Expand Down Expand Up @@ -186,6 +197,11 @@ var _ = Describe("FAR Controller", func() {
testVADeletion(vaName1, resourceDeletionWasTriggered)
testVADeletion(vaName2, resourceDeletionWasTriggered)
testPodDeletion(testPodName, resourceDeletionWasTriggered)

By("Not having any condition set")
verifyExpectedStatusConditionError(underTestFAR, commonConditions.ProcessingType, utils.ConditionNotSetError, metav1.ConditionUnknown)
verifyExpectedStatusConditionError(underTestFAR, v1alpha1.FenceAgentActionSucceededType, utils.ConditionNotSetError, metav1.ConditionUnknown)
verifyExpectedStatusConditionError(underTestFAR, commonConditions.SucceededType, utils.ConditionNotSetError, metav1.ConditionUnknown)
})
})
})
Expand Down Expand Up @@ -294,6 +310,8 @@ func cliCommandsEquality(far *v1alpha1.FenceAgentsRemediation) (bool, error) {
return isEqualStringLists(mocksExecuter.command, expectedCommand), nil
}

// TODO: Think about using Generics for the next two functions

// testVADeletion tests whether the volume attachment no longer exist for successful FAR CR
// and consistently check if the volume attachment exist and was not deleted
func testVADeletion(vaName string, resourceDeletionWasTriggered bool) {
Expand All @@ -307,15 +325,15 @@ func testVADeletion(vaName string, resourceDeletionWasTriggered bool) {
err := k8sClient.Get(context.Background(), vaKey, va)
return apierrors.IsNotFound(err)

}, 5*time.Second, 250*time.Millisecond).Should(BeTrue())
}, timeoutDeletion, pollInterval).Should(BeTrue())
log.Info("Volume attachment is no longer exist", "va", vaName)
} else {
ConsistentlyWithOffset(1, func() bool {
va := &storagev1.VolumeAttachment{}
err := k8sClient.Get(context.Background(), vaKey, va)
return apierrors.IsNotFound(err)

}, 5*time.Second, 250*time.Millisecond).Should(BeFalse())
}, timeoutDeletion, pollInterval).Should(BeFalse())
log.Info("Volume attachment exist", "va", vaName)
}
}
Expand All @@ -333,19 +351,37 @@ func testPodDeletion(podName string, resourceDeletionWasTriggered bool) {
err := k8sClient.Get(context.Background(), podKey, pod)
return apierrors.IsNotFound(err)

}, 5*time.Second, 250*time.Millisecond).Should(BeTrue())
}, timeoutDeletion, pollInterval).Should(BeTrue())
log.Info("Pod is no longer exist", "pod", podName)
} else {
ConsistentlyWithOffset(1, func() bool {
pod := &corev1.Pod{}
err := k8sClient.Get(context.Background(), podKey, pod)
return apierrors.IsNotFound(err)

}, 5*time.Second, 250*time.Millisecond).Should(BeFalse())
}, timeoutDeletion, pollInterval).Should(BeFalse())
log.Info("Pod exist", "pod", podName)
}
}

// verifyExpectedStatusConditionState checks whether the status condition state matches the expectedResult
func verifyExpectedStatusConditionError(testFAR *v1alpha1.FenceAgentsRemediation, conditionType, expectedError string, conditionStatus metav1.ConditionStatus) {
far := &v1alpha1.FenceAgentsRemediation{}
Eventually(func() string {
if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(testFAR), far); err != nil {
return utils.NoFenceAgentsRemediationCRFound
}
if gotCondition := meta.FindStatusCondition(far.Status.Conditions, conditionType); gotCondition == nil {
return utils.ConditionNotSetError
}
if meta.IsStatusConditionPresentAndEqual(far.Status.Conditions, conditionType, conditionStatus) {
return utils.ConditionSetAndMatchSuccess
}
return utils.ConditionSetButNoMatchError

}, timeoutDeletion, pollInterval).Should(Equal(expectedError), "'%v' status condition was expected to be %v", conditionType, conditionStatus)
}

// Implements Execute function to mock/test Execute of FenceAgentsRemediationReconciler
type mockExecuter struct {
command []string
Expand Down
9 changes: 9 additions & 0 deletions pkg/utils/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package utils

const (
// condition status error messages
NoFenceAgentsRemediationCRFound = "noFenceAgentsRemediationCRFound"
ConditionNotSetError = "ConditionNotSet"
ConditionSetButNoMatchError = "ConditionSetButNoMatch"
ConditionSetAndMatchSuccess = "ConditionSetAndMatchSuccess"
)
27 changes: 27 additions & 0 deletions test/e2e/far_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import (
"math/rand"
"time"

commonConditions "github.com/medik8s/common/pkg/conditions"
medik8sLabels "github.com/medik8s/common/pkg/labels"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
Expand Down Expand Up @@ -407,6 +409,25 @@ func checkPodDeleted(pod *corev1.Pod) {
log.Info("Pod has already been deleted", "pod name", pod.Name)
}

// verifyExpectedStatusConditionState checks whether the status condition state matches the expectedResult
func verifyExpectedStatusConditionError(nodeName, conditionType, expectedError string, conditionStatus metav1.ConditionStatus) {
far := &v1alpha1.FenceAgentsRemediation{}
farNamespacedName := client.ObjectKey{Name: nodeName, Namespace: operatorNsName}
Eventually(func() string {
if err := k8sClient.Get(context.Background(), farNamespacedName, far); err != nil {
return utils.NoFenceAgentsRemediationCRFound
}
if gotCondition := meta.FindStatusCondition(far.Status.Conditions, conditionType); gotCondition == nil {
return utils.ConditionNotSetError
}
if meta.IsStatusConditionPresentAndEqual(far.Status.Conditions, conditionType, conditionStatus) {
return utils.ConditionSetAndMatchSuccess
}
return utils.ConditionSetButNoMatchError

}, timeoutDeletion, pollInterval).Should(Equal(expectedError), "'%v' status condition was expected to be %v", conditionType, conditionStatus)
}

// checkRemediation verify whether the node was remediated
func checkRemediation(nodeName string, nodeBootTimeBefore time.Time, oldPodCreationTime time.Time, va *storagev1.VolumeAttachment, pod *corev1.Pod) {
By("Check if FAR NoExecute taint was added")
Expand All @@ -426,4 +447,10 @@ func checkRemediation(nodeName string, nodeBootTimeBefore time.Time, oldPodCreat

By("checking if old pod has been deleted")
checkPodDeleted(pod)

By("checking if the status conditions match a successful remediation")
verifyExpectedStatusConditionError(nodeName, commonConditions.ProcessingType, utils.ConditionSetAndMatchSuccess, metav1.ConditionFalse)
verifyExpectedStatusConditionError(nodeName, v1alpha1.FenceAgentActionSucceededType, utils.ConditionSetAndMatchSuccess, metav1.ConditionTrue)
verifyExpectedStatusConditionError(nodeName, commonConditions.SucceededType, utils.ConditionSetAndMatchSuccess, metav1.ConditionTrue)

}

0 comments on commit badcfa4

Please sign in to comment.