From 8a5d0d18fec375b53e4ba8c6e4db1dc218fcc9d7 Mon Sep 17 00:00:00 2001 From: Tushar-Khandelwal-2004 Date: Tue, 30 Jun 2026 17:52:11 +0530 Subject: [PATCH] Let KEDA functions scale to zero --- pkg/keda/deployer.go | 2 +- pkg/keda/deployer_test.go | 77 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 pkg/keda/deployer_test.go diff --git a/pkg/keda/deployer.go b/pkg/keda/deployer.go index 72ac31cd01..8338b0c433 100644 --- a/pkg/keda/deployer.go +++ b/pkg/keda/deployer.go @@ -147,7 +147,7 @@ func (d *Deployer) httpScaledObject(f fn.Function, namespace string, deployment annotations := deployer.GenerateCommonAnnotations(f, d.decorator, false /*we don't care about dapr for the HttpScaledObject*/, KedaDeployerName) - minScale := int32(1) + minScale := int32(0) maxScale := int32(10) if scaleOptions := f.Deploy.Options.Scale; scaleOptions != nil { if scaleOptions.Min != nil { diff --git a/pkg/keda/deployer_test.go b/pkg/keda/deployer_test.go new file mode 100644 index 0000000000..f30cadeec8 --- /dev/null +++ b/pkg/keda/deployer_test.go @@ -0,0 +1,77 @@ +package keda + +import ( + "testing" + + httpv1alpha1 "github.com/kedacore/http-add-on/operator/apis/http/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + fn "knative.dev/func/pkg/functions" +) + +func TestHTTPScaledObjectDefaultsMinReplicasToZero(t *testing.T) { + httpScaledObject := newTestHTTPScaledObject(t, fn.Function{}) + + if httpScaledObject.Spec.Replicas == nil || httpScaledObject.Spec.Replicas.Min == nil { + t.Fatal("expected replicas.min to be set") + } + + if got := *httpScaledObject.Spec.Replicas.Min; got != 0 { + t.Fatalf("expected replicas.min to default to 0, got %d", got) + } +} + +func TestHTTPScaledObjectUsesConfiguredMinReplicas(t *testing.T) { + minScale := int64(1) + httpScaledObject := newTestHTTPScaledObject(t, fn.Function{ + Deploy: fn.DeploySpec{ + Options: fn.Options{ + Scale: &fn.ScaleOptions{ + Min: &minScale, + }, + }, + }, + }) + + if httpScaledObject.Spec.Replicas == nil || httpScaledObject.Spec.Replicas.Min == nil { + t.Fatal("expected replicas.min to be set") + } + + if got := *httpScaledObject.Spec.Replicas.Min; got != int32(minScale) { + t.Fatalf("expected replicas.min to use configured value %d, got %d", minScale, got) + } +} + +func newTestHTTPScaledObject(t *testing.T, f fn.Function) *httpv1alpha1.HTTPScaledObject { + t.Helper() + + f.Name = "test-function" + f.Runtime = "go" + + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-function", + UID: types.UID("test-uid"), + }, + } + service := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-function", + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + {Port: 8080}, + }, + }, + } + + httpScaledObject, err := NewDeployer().httpScaledObject(f, "default", deployment, service, []string{"test-function.default.svc"}) + if err != nil { + t.Fatalf("httpScaledObject() error = %v", err) + } + + return httpScaledObject +}