Skip to content

Commit

Permalink
tidy e2e tests for min value and error when null values
Browse files Browse the repository at this point in the history
Signed-off-by: Rob Pickerill <r.pickerill@gmail.com>
  • Loading branch information
robpickerill committed Apr 4, 2024
1 parent 3088353 commit 53fac56
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 50 deletions.
62 changes: 51 additions & 11 deletions tests/helper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"k8s.io/client-go/tools/remotecommand"
"sigs.k8s.io/controller-runtime/pkg/client/config"

v1alpha1Api "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
"github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/typed/keda/v1alpha1"
)

Expand Down Expand Up @@ -309,17 +310,20 @@ func WaitForNamespaceDeletion(t *testing.T, nsName string) bool {
}

func WaitForScaledJobCount(t *testing.T, kc *kubernetes.Clientset, scaledJobName, namespace string,
target, iterations, intervalSeconds int) bool {
target, iterations, intervalSeconds int,
) bool {
return waitForJobCount(t, kc, fmt.Sprintf("scaledjob.keda.sh/name=%s", scaledJobName), namespace, target, iterations, intervalSeconds)
}

func WaitForJobCount(t *testing.T, kc *kubernetes.Clientset, namespace string,
target, iterations, intervalSeconds int) bool {
target, iterations, intervalSeconds int,
) bool {
return waitForJobCount(t, kc, "", namespace, target, iterations, intervalSeconds)
}

func waitForJobCount(t *testing.T, kc *kubernetes.Clientset, selector, namespace string,
target, iterations, intervalSeconds int) bool {
target, iterations, intervalSeconds int,
) bool {
for i := 0; i < iterations; i++ {
jobList, _ := kc.BatchV1().Jobs(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: selector,
Expand All @@ -340,8 +344,9 @@ func waitForJobCount(t *testing.T, kc *kubernetes.Clientset, selector, namespace
}

func WaitForJobCountUntilIteration(t *testing.T, kc *kubernetes.Clientset, namespace string,
target, iterations, intervalSeconds int) bool {
var isTargetAchieved = false
target, iterations, intervalSeconds int,
) bool {
isTargetAchieved := false

for i := 0; i < iterations; i++ {
jobList, _ := kc.BatchV1().Jobs(namespace).List(context.Background(), metav1.ListOptions{})
Expand All @@ -364,7 +369,8 @@ func WaitForJobCountUntilIteration(t *testing.T, kc *kubernetes.Clientset, names

// Waits until deployment count hits target or number of iterations are done.
func WaitForPodCountInNamespace(t *testing.T, kc *kubernetes.Clientset, namespace string,
target, iterations, intervalSeconds int) bool {
target, iterations, intervalSeconds int,
) bool {
for i := 0; i < iterations; i++ {
pods, _ := kc.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{})

Expand Down Expand Up @@ -410,7 +416,8 @@ func WaitForAllPodRunningInNamespace(t *testing.T, kc *kubernetes.Clientset, nam
// Waits until the Horizontal Pod Autoscaler for the scaledObject reports that it has metrics available
// to calculate, or until the number of iterations are done, whichever happens first.
func WaitForHPAMetricsToPopulate(t *testing.T, kc *kubernetes.Clientset, name, namespace string,
iterations, intervalSeconds int) bool {
iterations, intervalSeconds int,
) bool {
totalWaitDuration := time.Duration(iterations) * time.Duration(intervalSeconds) * time.Second
startedWaiting := time.Now()
for i := 0; i < iterations; i++ {
Expand All @@ -436,7 +443,8 @@ func WaitForHPAMetricsToPopulate(t *testing.T, kc *kubernetes.Clientset, name, n

// Waits until deployment ready replica count hits target or number of iterations are done.
func WaitForDeploymentReplicaReadyCount(t *testing.T, kc *kubernetes.Clientset, name, namespace string,
target, iterations, intervalSeconds int) bool {
target, iterations, intervalSeconds int,
) bool {
for i := 0; i < iterations; i++ {
deployment, _ := kc.AppsV1().Deployments(namespace).Get(context.Background(), name, metav1.GetOptions{})
replicas := deployment.Status.ReadyReplicas
Expand All @@ -456,7 +464,8 @@ func WaitForDeploymentReplicaReadyCount(t *testing.T, kc *kubernetes.Clientset,

// Waits until statefulset count hits target or number of iterations are done.
func WaitForStatefulsetReplicaReadyCount(t *testing.T, kc *kubernetes.Clientset, name, namespace string,
target, iterations, intervalSeconds int) bool {
target, iterations, intervalSeconds int,
) bool {
for i := 0; i < iterations; i++ {
statefulset, _ := kc.AppsV1().StatefulSets(namespace).Get(context.Background(), name, metav1.GetOptions{})
replicas := statefulset.Status.ReadyReplicas
Expand Down Expand Up @@ -518,7 +527,8 @@ func AssertReplicaCountNotChangeDuringTimePeriod(t *testing.T, kc *kubernetes.Cl
}

func WaitForHpaCreation(t *testing.T, kc *kubernetes.Clientset, name, namespace string,
iterations, intervalSeconds int) (*autoscalingv2.HorizontalPodAutoscaler, error) {
iterations, intervalSeconds int,
) (*autoscalingv2.HorizontalPodAutoscaler, error) {
hpa := &autoscalingv2.HorizontalPodAutoscaler{}
var err error
for i := 0; i < iterations; i++ {
Expand Down Expand Up @@ -754,7 +764,8 @@ func DeletePodsInNamespaceBySelector(t *testing.T, kc *kubernetes.Clientset, sel

// Wait for Pods identified by selector to complete termination
func WaitForPodsTerminated(t *testing.T, kc *kubernetes.Clientset, selector, namespace string,
iterations, intervalSeconds int) bool {
iterations, intervalSeconds int,
) bool {
for i := 0; i < iterations; i++ {
pods, err := kc.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: selector})
if (err != nil && errors.IsNotFound(err)) || len(pods.Items) == 0 {
Expand Down Expand Up @@ -910,3 +921,32 @@ func CheckKubectlGetResult(t *testing.T, kind string, name string, namespace str
unqoutedOutput := strings.ReplaceAll(string(output), "\"", "")
assert.Equal(t, expected, unqoutedOutput)
}

// FailIfScaledObjectStatusNotReachedWithTimeout waits for the scaledobject to reach the desired state, within the timeout
// or fails the test if the timeout is reached.
func FailIfScaledObjectStatusNotReachedWithTimeout(t *testing.T, kedaClient *v1alpha1.KedaV1alpha1Client, namespace, scaledObjectName string, timeout time.Duration, desiredState v1alpha1Api.ConditionType) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

for {
select {
case <-ctx.Done():
t.Fatalf("timeout waiting for scaledobject to be in %s state", desiredState)
default:
scaledObject, err := kedaClient.ScaledObjects(namespace).Get(context.Background(), scaledObjectName, metav1.GetOptions{})
if err != nil {
t.Fatalf("error getting scaledobject: %s", err)
}

conditions := scaledObject.Status.Conditions

t.Logf("scaledobject status: %+v", conditions)

if len(conditions) > 0 && conditions[len(conditions)-1].Type == desiredState {
return
}

time.Sleep(10 * time.Second)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import (
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/joho/godotenv"
v1alpha1Api "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/typed/keda/v1alpha1"
. "github.com/kedacore/keda/v2/tests/helper"
)

Expand Down Expand Up @@ -121,7 +120,7 @@ spec:
dimensionValue: {{.CloudWatchMetricDimensionValue}}
metricName: {{.CloudWatchMetricName}}
targetMetricValue: "1"
minMetricValue: "0"
minMetricValue: "1"
errorWhenNullValues: "true"
metricCollectionTime: "120"
metricStatPeriod: "60"
Expand Down Expand Up @@ -162,21 +161,14 @@ func TestCloudWatchScalerWithErrorWhenNullValues(t *testing.T) {
assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 1),
"replica count should be %d after 1 minute", minReplicaCount)

time.Sleep(1 * time.Minute)
// check that the scaledobject is in paused state
FailIfScaledObjectStatusNotReachedWithTimeout(t, kedaClient, testNamespace, scaledObjectName, 2*time.Minute, v1alpha1Api.ConditionPaused)

// Fail the test if the HPA is actively autoscaling the deployment
failIfScaledObjectIsNotInPausedState(t, kedaClient, testNamespace, scaledObjectName)
}

func failIfScaledObjectIsNotInPausedState(t *testing.T, kedaClient *v1alpha1.KedaV1alpha1Client, namespace, scaledObjectName string) {
scaledObject, err := kedaClient.ScaledObjects(namespace).Get(context.Background(), scaledObjectName, metav1.GetOptions{})
if err != nil {
t.Fatalf("error getting scaledobject: %s", err)
}

if scaledObject.Status.Conditions[len(scaledObject.Status.Conditions)-1].Type != "Paused" {
t.Fatalf("expected scaledobject to be in paused state, but got: %s", scaledObject.Status.Conditions[len(scaledObject.Status.Conditions)-1].Type)
}
// check that the deployment did not scale, as the metric query is returning
// null values and the scaledobject is receiving errors, the deployment
// should not scale.
assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 1),
"replica count should be %d after 1 minute", minReplicaCount)
}

// checkCloudWatchCustomMetric will evaluate the custom metric for any metric values, if any
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//go:build e2e
// +build e2e

package aws_cloudwatch_min_value_null_metric_values_test
package aws_cloudwatch_min_value_null_values_test

import (
"context"
Expand All @@ -17,10 +17,9 @@ import (
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/joho/godotenv"
v1alpha1Api "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/typed/keda/v1alpha1"
. "github.com/kedacore/keda/v2/tests/helper"
)

Expand Down Expand Up @@ -139,7 +138,9 @@ var (
cloudwatchMetricNamespace = "DoesNotExist"
cloudwatchMetricDimensionName = "dimensionName"
cloudwatchMetricDimensionValue = "dimensionValue"
scaledObjectMinValue = 1
maxReplicaCount = 2
minReplicaCount = 0
minMetricValueReplicaCount = 1
)

func TestCloudWatchScalerWithMinValueWhenNullValues(t *testing.T) {
Expand All @@ -155,28 +156,17 @@ func TestCloudWatchScalerWithMinValueWhenNullValues(t *testing.T) {
kedaClient := GetKedaKubernetesClient(t)
data, templates := getTemplateData()
CreateKubernetesResources(t, kc, testNamespace, data, templates)

// always cleanup
defer DeleteKubernetesResources(t, testNamespace, data, templates)

assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, scaledObjectMinValue, 60, 1),
"replica count should be %d after 1 minute", scaledObjectMinValue)

time.Sleep(1 * time.Minute)
assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 1),
"replica count should be %d after 1 minute", minReplicaCount)

// check that the scaledobject is in active state
failIfScaledObjectIsNotInActiveState(t, kedaClient, testNamespace, scaledObjectName)
}
// check that the scaledobject is in paused state
FailIfScaledObjectStatusNotReachedWithTimeout(t, kedaClient, testNamespace, scaledObjectName, 2*time.Minute, v1alpha1Api.ConditionPaused)

func failIfScaledObjectIsNotInActiveState(t *testing.T, kedaClient *v1alpha1.KedaV1alpha1Client, namespace, scaledObjectName string) {
scaledObject, err := kedaClient.ScaledObjects(namespace).Get(context.Background(), scaledObjectName, metav1.GetOptions{})
if err != nil {
t.Fatalf("error getting scaledobject: %s", err)
}

if scaledObject.Status.Conditions[len(scaledObject.Status.Conditions)-1].Type != "Active" {
t.Fatalf("expected scaledobject to be in paused state, but got: %s", scaledObject.Status.Conditions[len(scaledObject.Status.Conditions)-1].Type)
}
// check that the deployment scaled up to the minMetricValueReplicaCount
assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minMetricValueReplicaCount, 60, 1),
"replica count should be %d after 1 minute", minMetricValueReplicaCount)
}

func createCloudWatchClient() *cloudwatch.Client {
Expand Down

0 comments on commit 53fac56

Please sign in to comment.