diff --git a/tests/helper/helper.go b/tests/helper/helper.go index bbb3b8124b1..4cee58ca0af 100644 --- a/tests/helper/helper.go +++ b/tests/helper/helper.go @@ -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" ) @@ -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, @@ -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{}) @@ -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{}) @@ -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++ { @@ -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 @@ -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 @@ -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++ { @@ -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 { @@ -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) + } + } +} diff --git a/tests/scalers/aws/aws_cloudwatch_error_null_values/aws_cloudwatch_error_null_values_test.go b/tests/scalers/aws/aws_cloudwatch_error_null_values/aws_cloudwatch_error_null_values_test.go index 9fa7bfa25b7..55ae762867a 100644 --- a/tests/scalers/aws/aws_cloudwatch_error_null_values/aws_cloudwatch_error_null_values_test.go +++ b/tests/scalers/aws/aws_cloudwatch_error_null_values/aws_cloudwatch_error_null_values_test.go @@ -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" ) @@ -121,7 +120,7 @@ spec: dimensionValue: {{.CloudWatchMetricDimensionValue}} metricName: {{.CloudWatchMetricName}} targetMetricValue: "1" - minMetricValue: "0" + minMetricValue: "1" errorWhenNullValues: "true" metricCollectionTime: "120" metricStatPeriod: "60" @@ -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 diff --git a/tests/scalers/aws/aws_cloudwatch_min_value_null_values/aws_cloudwatch_min_value_null_values_test.go b/tests/scalers/aws/aws_cloudwatch_min_value_null_values/aws_cloudwatch_min_value_null_values_test.go index 6a6abccf79e..7729075c4e9 100644 --- a/tests/scalers/aws/aws_cloudwatch_min_value_null_values/aws_cloudwatch_min_value_null_values_test.go +++ b/tests/scalers/aws/aws_cloudwatch_min_value_null_values/aws_cloudwatch_min_value_null_values_test.go @@ -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" @@ -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" ) @@ -139,7 +138,9 @@ var ( cloudwatchMetricNamespace = "DoesNotExist" cloudwatchMetricDimensionName = "dimensionName" cloudwatchMetricDimensionValue = "dimensionValue" - scaledObjectMinValue = 1 + maxReplicaCount = 2 + minReplicaCount = 0 + minMetricValueReplicaCount = 1 ) func TestCloudWatchScalerWithMinValueWhenNullValues(t *testing.T) { @@ -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 {