From 9534f7bc2274140f1e92ac1e16fa108468ce8a97 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Fri, 3 May 2024 14:04:20 +0200 Subject: [PATCH] tests added to kuadrant_controller --- ...adrant-operator.clusterserviceversion.yaml | 2 +- bundle/manifests/kuadrant.io_kuadrants.yaml | 12 +- config/crd/bases/kuadrant.io_kuadrants.yaml | 12 +- controllers/kuadrant_controller.go | 31 +++- controllers/suite_test.go | 86 ----------- go.mod | 4 +- go.sum | 8 +- make/integration-tests.mk | 2 +- pkg/kuadranttools/limitador_mutators.go | 133 ++++++++++++++++++ ...ols_test.go => limitador_mutators_test.go} | 22 ++- pkg/kuadranttools/limitador_tools.go | 71 ---------- .../kuadrant/kuadrant_controller_test.go | 107 ++++++++++++-- tests/commons.go | 28 +++- 13 files changed, 315 insertions(+), 203 deletions(-) delete mode 100644 controllers/suite_test.go create mode 100644 pkg/kuadranttools/limitador_mutators.go rename pkg/kuadranttools/{limitador_tools_test.go => limitador_mutators_test.go} (71%) delete mode 100644 pkg/kuadranttools/limitador_tools.go diff --git a/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml b/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml index 250689658..7ec101439 100644 --- a/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml +++ b/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml @@ -106,7 +106,7 @@ metadata: capabilities: Basic Install categories: Integration & Delivery containerImage: quay.io/kuadrant/kuadrant-operator:latest - createdAt: "2024-07-05T16:23:56Z" + createdAt: "2024-07-10T15:04:27Z" operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/Kuadrant/kuadrant-operator diff --git a/bundle/manifests/kuadrant.io_kuadrants.yaml b/bundle/manifests/kuadrant.io_kuadrants.yaml index cdb4baa58..e5fae6bb4 100644 --- a/bundle/manifests/kuadrant.io_kuadrants.yaml +++ b/bundle/manifests/kuadrant.io_kuadrants.yaml @@ -983,6 +983,10 @@ spec: x-kubernetes-map-type: atomic options: properties: + batch-size: + description: 'BatchSize defines the size of entries + to flush in as single flush [default: 100]' + type: integer flush-period: description: 'FlushPeriod for counters in milliseconds [default: 1000]' @@ -991,18 +995,10 @@ spec: description: 'MaxCached refers to the maximum amount of counters cached [default: 10000]' type: integer - ratio: - description: 'Ratio to apply to the TTL from Redis - on cached counters [default: 10]' - type: integer response-timeout: description: 'ResponseTimeout defines the timeout for Redis commands in milliseconds [default: 350]' type: integer - ttl: - description: 'TTL for cached counters in milliseconds - [default: 5000]' - type: integer type: object type: object type: object diff --git a/config/crd/bases/kuadrant.io_kuadrants.yaml b/config/crd/bases/kuadrant.io_kuadrants.yaml index 9152ea8f6..44c899c15 100644 --- a/config/crd/bases/kuadrant.io_kuadrants.yaml +++ b/config/crd/bases/kuadrant.io_kuadrants.yaml @@ -981,6 +981,10 @@ spec: x-kubernetes-map-type: atomic options: properties: + batch-size: + description: 'BatchSize defines the size of entries + to flush in as single flush [default: 100]' + type: integer flush-period: description: 'FlushPeriod for counters in milliseconds [default: 1000]' @@ -989,18 +993,10 @@ spec: description: 'MaxCached refers to the maximum amount of counters cached [default: 10000]' type: integer - ratio: - description: 'Ratio to apply to the TTL from Redis - on cached counters [default: 10]' - type: integer response-timeout: description: 'ResponseTimeout defines the timeout for Redis commands in milliseconds [default: 350]' type: integer - ttl: - description: 'TTL for cached counters in milliseconds - [default: 5000]' - type: integer type: object type: object type: object diff --git a/controllers/kuadrant_controller.go b/controllers/kuadrant_controller.go index 284a0b0c9..a4e771628 100644 --- a/controllers/kuadrant_controller.go +++ b/controllers/kuadrant_controller.go @@ -436,7 +436,36 @@ func (r *KuadrantReconciler) reconcileLimitador(ctx context.Context, kObj *kuadr return err } - return r.ReconcileResource(ctx, &limitadorv1alpha1.Limitador{}, limitador, kuadranttools.LimitadorMutator) + limitadorMutators := make([]kuadranttools.LimitadorMutateFn, 0) + + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorOwnerRefsMutator) + + if kObj.Spec.Limitador.Affinity != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorAffinityMutator) + } + if kObj.Spec.Limitador.Replicas != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorReplicasMutator) + } + if kObj.Spec.Limitador.Storage != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorStorageMutator) + } + if kObj.Spec.Limitador.RateLimitHeaders != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorRateLimitHeadersMutator) + } + if kObj.Spec.Limitador.Telemetry != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorTelemetryMutator) + } + if kObj.Spec.Limitador.PodDisruptionBudget != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorPodDisruptionBudgetMutator) + } + if kObj.Spec.Limitador.ResourceRequirements != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorResourceRequirementsMutator) + } + if kObj.Spec.Limitador.Verbosity != nil { + limitadorMutators = append(limitadorMutators, kuadranttools.LimitadorVerbosityMutator) + } + + return r.ReconcileResource(ctx, &limitadorv1alpha1.Limitador{}, limitador, kuadranttools.LimitadorMutator(limitadorMutators...)) } func (r *KuadrantReconciler) reconcileAuthorino(ctx context.Context, kObj *kuadrantv1beta1.Kuadrant) error { diff --git a/controllers/suite_test.go b/controllers/suite_test.go deleted file mode 100644 index df2591098..000000000 --- a/controllers/suite_test.go +++ /dev/null @@ -1,86 +0,0 @@ -//go:build integration - -/* -Copyright 2021. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllers - -import ( - "os" - "testing" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/kuadrant/kuadrant-operator/pkg/log" -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -// This test suite will be run on k8s with GatewayAPI CRDS and at least one GatewayAPI provider installed - -var k8sClient client.Client -var testEnv *envtest.Environment - -func testClient() client.Client { return k8sClient } - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Controller Suite") -} - -var _ = BeforeSuite(func(ctx SpecContext) { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - UseExistingCluster: &[]bool{true}[0], - } - - cfg, err := testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - SetupKuadrantOperatorForTest(scheme.Scheme, cfg) - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) -}) - -var _ = AfterSuite(func(ctx SpecContext) { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}, NodeTimeout(3*time.Minute)) - -func TestMain(m *testing.M) { - logger := log.NewLogger( - log.SetLevel(log.DebugLevel), - log.SetMode(log.ModeDev), - log.WriteTo(GinkgoWriter), - ).WithName("controller_test") - log.SetLogger(logger) - os.Exit(m.Run()) -} diff --git a/go.mod b/go.mod index 1be70e148..0080f5cff 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/kuadrant/authorino v0.17.2 github.com/kuadrant/authorino-operator v0.11.1 github.com/kuadrant/dns-operator v0.0.0-20240627145308-8a571eaae927 - github.com/kuadrant/limitador-operator v0.8.0 + github.com/kuadrant/limitador-operator v0.9.0 github.com/martinlindhe/base36 v1.1.1 github.com/onsi/ginkgo/v2 v2.13.2 github.com/onsi/gomega v1.30.0 @@ -28,7 +28,7 @@ require ( k8s.io/apimachinery v0.28.4 k8s.io/client-go v0.28.4 k8s.io/klog/v2 v2.110.1 - k8s.io/utils v0.0.0-20231127182322-b307cd553661 + k8s.io/utils v0.0.0-20240310230437-4693a0247e57 maistra.io/istio-operator v0.0.0-20231214211859-76e404c8df41 sigs.k8s.io/controller-runtime v0.16.3 sigs.k8s.io/external-dns v0.14.0 diff --git a/go.sum b/go.sum index 9e384b43e..2309883d3 100644 --- a/go.sum +++ b/go.sum @@ -252,8 +252,8 @@ github.com/kuadrant/authorino-operator v0.11.1 h1:jndTZhiHMU+2Dk0NU+KP2+MUSfvclr github.com/kuadrant/authorino-operator v0.11.1/go.mod h1:TeFFdX477vUTMushCojaHpvwPLga4DpErGI2oQbqFIs= github.com/kuadrant/dns-operator v0.0.0-20240627145308-8a571eaae927 h1:T/pEIu+l13ecaJhCKNBlVu8YELcye4qM6m8b0u9rTbA= github.com/kuadrant/dns-operator v0.0.0-20240627145308-8a571eaae927/go.mod h1:XquyzShT4VAew+2Kfg7zuQ1SrhbohyGgXIFZh2udTa0= -github.com/kuadrant/limitador-operator v0.7.0 h1:pLIpM6vUxAY/Jn6ny61IGpqS7Oti786duBzJ67DJOuA= -github.com/kuadrant/limitador-operator v0.7.0/go.mod h1:tg+G+3eTzUUfvUmdbiqH3FnScEPSWZ3DmorD1ZAx1bo= +github.com/kuadrant/limitador-operator v0.9.0 h1:hTQ6CFPayf/sL7cIzwWjCoU8uTn6fzWdsJgKbDlnFts= +github.com/kuadrant/limitador-operator v0.9.0/go.mod h1:DQOlg9qFOcnWPrwO529JRCMLLOEXJQxkmOes952S/Hw= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= @@ -469,8 +469,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= diff --git a/make/integration-tests.mk b/make/integration-tests.mk index 24437244f..ef8c48f22 100644 --- a/make/integration-tests.mk +++ b/make/integration-tests.mk @@ -75,4 +75,4 @@ test-integration: clean-cov generate fmt vet ginkgo ## Requires kubernetes clust --fail-on-pending \ --keep-going \ --trace \ - $(INTEGRATION_TESTS_EXTRA_ARGS) tests/common/... + $(INTEGRATION_TESTS_EXTRA_ARGS) tests/common/kuadrant/... diff --git a/pkg/kuadranttools/limitador_mutators.go b/pkg/kuadranttools/limitador_mutators.go new file mode 100644 index 000000000..959d95e07 --- /dev/null +++ b/pkg/kuadranttools/limitador_mutators.go @@ -0,0 +1,133 @@ +package kuadranttools + +import ( + "fmt" + "reflect" + + "sigs.k8s.io/controller-runtime/pkg/client" + + limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + + "github.com/kuadrant/kuadrant-operator/pkg/library/reconcilers" +) + +// DeploymentMutateFn is a function which mutates the existing Deployment into it's desired state. +type LimitadorMutateFn func(desired, existing *limitadorv1alpha1.Limitador) bool + +func LimitadorMutator(opts ...LimitadorMutateFn) reconcilers.MutateFn { + return func(existingObj, desiredObj client.Object) (bool, error) { + existing, ok := existingObj.(*limitadorv1alpha1.Limitador) + if !ok { + return false, fmt.Errorf("existingObj %T is not a *limitadorv1alpha1.Limitador", existingObj) + } + desired, ok := desiredObj.(*limitadorv1alpha1.Limitador) + if !ok { + return false, fmt.Errorf("desiredObj %T is not a *limitadorv1alpha1.Limitador", desiredObj) + } + + update := false + + // Loop through each option + for _, opt := range opts { + tmpUpdate := opt(desired, existing) + update = update || tmpUpdate + } + + return update, nil + } +} + +func LimitadorAffinityMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.Affinity, desired.Spec.Affinity) { + existing.Spec.Affinity = desired.Spec.Affinity + update = true + } + return update +} + +func LimitadorReplicasMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + + var existingReplicas = 1 + + if existing.Spec.Replicas != nil { + existingReplicas = *existing.Spec.Replicas + } + + var desiredReplicas = 1 + + if desired.Spec.Replicas != nil { + desiredReplicas = *desired.Spec.Replicas + } + + if desiredReplicas != existingReplicas { + existing.Spec.Replicas = &desiredReplicas + update = true + } + + return update +} + +func LimitadorStorageMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.Storage, desired.Spec.Storage) { + existing.Spec.Storage = desired.Spec.Storage + update = true + } + return update +} + +func LimitadorOwnerRefsMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.OwnerReferences, desired.OwnerReferences) { + existing.OwnerReferences = desired.OwnerReferences + update = true + } + return update +} + +func LimitadorRateLimitHeadersMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.RateLimitHeaders, desired.Spec.RateLimitHeaders) { + existing.Spec.RateLimitHeaders = desired.Spec.RateLimitHeaders + update = true + } + return update +} + +func LimitadorTelemetryMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.Telemetry, desired.Spec.Telemetry) { + existing.Spec.Telemetry = desired.Spec.Telemetry + update = true + } + return update +} + +func LimitadorPodDisruptionBudgetMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.PodDisruptionBudget, desired.Spec.PodDisruptionBudget) { + existing.Spec.PodDisruptionBudget = desired.Spec.PodDisruptionBudget + update = true + } + return update +} + +func LimitadorResourceRequirementsMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.ResourceRequirements, desired.Spec.ResourceRequirements) { + existing.Spec.ResourceRequirements = desired.Spec.ResourceRequirements + update = true + } + return update +} + +func LimitadorVerbosityMutator(desired, existing *limitadorv1alpha1.Limitador) bool { + update := false + if !reflect.DeepEqual(existing.Spec.Verbosity, desired.Spec.Verbosity) { + existing.Spec.Verbosity = desired.Spec.Verbosity + update = true + } + return update +} diff --git a/pkg/kuadranttools/limitador_tools_test.go b/pkg/kuadranttools/limitador_mutators_test.go similarity index 71% rename from pkg/kuadranttools/limitador_tools_test.go rename to pkg/kuadranttools/limitador_mutators_test.go index 94fd53897..b5290c7f8 100644 --- a/pkg/kuadranttools/limitador_tools_test.go +++ b/pkg/kuadranttools/limitador_mutators_test.go @@ -13,6 +13,18 @@ import ( ) func TestLimitadorMutator(t *testing.T) { + limitadorMutator := LimitadorMutator( + LimitadorOwnerRefsMutator, + LimitadorAffinityMutator, + LimitadorReplicasMutator, + LimitadorStorageMutator, + LimitadorRateLimitHeadersMutator, + LimitadorTelemetryMutator, + LimitadorPodDisruptionBudgetMutator, + LimitadorResourceRequirementsMutator, + LimitadorVerbosityMutator, + ) + type args struct { existingObj client.Object desiredObj client.Object @@ -35,7 +47,7 @@ func TestLimitadorMutator(t *testing.T) { existingObj: &limitadorv1alpha1.Limitador{}, }, wantErr: true, - errorContains: "desireObj", + errorContains: "desiredObj", }, { name: "No update required", @@ -64,19 +76,19 @@ func TestLimitadorMutator(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := LimitadorMutator(tt.args.existingObj, tt.args.desiredObj) + got, err := limitadorMutator(tt.args.existingObj, tt.args.desiredObj) if (err != nil) != tt.wantErr { - t.Errorf("LimitadorMutator() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("limitadorMutator() error = %v, wantErr %v", err, tt.wantErr) return } if err != nil && tt.wantErr { if !strings.Contains(err.Error(), tt.errorContains) { - t.Errorf("LimitadorMutator() error = %v, should contain %v", err, tt.errorContains) + t.Errorf("limitadorMutator() error = %v, should contain %v", err, tt.errorContains) } } if got != tt.want { - t.Errorf("LimitadorMutator() got = %v, want %v", got, tt.want) + t.Errorf("limitadorMutator() got = %v, want %v", got, tt.want) } }) } diff --git a/pkg/kuadranttools/limitador_tools.go b/pkg/kuadranttools/limitador_tools.go deleted file mode 100644 index 66948ab2e..000000000 --- a/pkg/kuadranttools/limitador_tools.go +++ /dev/null @@ -1,71 +0,0 @@ -package kuadranttools - -import ( - "fmt" - "reflect" - - "sigs.k8s.io/controller-runtime/pkg/client" - - limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" - - "github.com/kuadrant/kuadrant-operator/api/v1beta1" -) - -func LimitadorMutator(existingObj, desiredObj client.Object) (bool, error) { - update := false - existing, ok := existingObj.(*limitadorv1alpha1.Limitador) - if !ok { - return false, fmt.Errorf("existingObj %T is not a *limitadorv1alpha1.Limitador", existingObj) - } - desired, ok := desiredObj.(*limitadorv1alpha1.Limitador) - if !ok { - return false, fmt.Errorf("desireObj %T is not a *limitadorv1alpha1.Limitador", desiredObj) - } - - if !reflect.DeepEqual(existing.OwnerReferences, desired.OwnerReferences) { - update = true - existing.OwnerReferences = desired.OwnerReferences - } - - if !reflect.DeepEqual(existing.Spec.Affinity, desired.Spec.Affinity) { - update = true - existing.Spec.Affinity = desired.Spec.Affinity - } - - if !reflect.DeepEqual(existing.Spec.Replicas, desired.Spec.Replicas) { - update = true - existing.Spec.Replicas = desired.Spec.Replicas - } - - if !reflect.DeepEqual(existing.Spec.Storage, desired.Spec.Storage) { - update = true - existing.Spec.Storage = desired.Spec.Storage - } - - if !reflect.DeepEqual(existing.Spec.RateLimitHeaders, desired.Spec.RateLimitHeaders) { - update = true - existing.Spec.RateLimitHeaders = desired.Spec.RateLimitHeaders - } - - if !reflect.DeepEqual(existing.Spec.Telemetry, desired.Spec.Telemetry) { - update = true - existing.Spec.Telemetry = desired.Spec.Telemetry - } - - if !reflect.DeepEqual(existing.Spec.PodDisruptionBudget, desired.Spec.PodDisruptionBudget) { - update = true - existing.Spec.PodDisruptionBudget = desired.Spec.PodDisruptionBudget - } - - if !reflect.DeepEqual(existing.Spec.ResourceRequirements, desired.Spec.ResourceRequirements) { - update = true - existing.Spec.ResourceRequirements = desired.Spec.ResourceRequirements - } - - if !reflect.DeepEqual(existing.Spec.Verbosity, desired.Spec.Verbosity) { - update = true - existing.Spec.Verbosity = desired.Spec.Verbosity - } - - return update, nil -} diff --git a/tests/common/kuadrant/kuadrant_controller_test.go b/tests/common/kuadrant/kuadrant_controller_test.go index e7d4214ee..30229fa25 100644 --- a/tests/common/kuadrant/kuadrant_controller_test.go +++ b/tests/common/kuadrant/kuadrant_controller_test.go @@ -6,44 +6,53 @@ import ( "reflect" "time" - "github.com/kuadrant/limitador-operator/api/v1alpha1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" + limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + kuadrantv1beta1 "github.com/kuadrant/kuadrant-operator/api/v1beta1" "github.com/kuadrant/kuadrant-operator/pkg/common" "github.com/kuadrant/kuadrant-operator/tests" ) -var _ = Describe("Kuadrant controller", func() { +var _ = Describe("Kuadrant controller", Serial, func() { var ( testNamespace string ) const ( - testTimeOut = SpecTimeout(2 * time.Minute) - afterEachTimeOut = NodeTimeout(3 * time.Minute) - kuadrant = "kuadrant-sample" + testTimeOut = SpecTimeout(2 * time.Minute) + afterEachTimeOut = NodeTimeout(3 * time.Minute) + beforeEachTimeOut = NodeTimeout(2 * time.Minute) + kuadrant = "kuadrant-sample" ) + + BeforeEach(func(ctx SpecContext) { + testNamespace = tests.CreateNamespace(ctx, testClient()) + }, beforeEachTimeOut) + + AfterEach(func(ctx SpecContext) { + tests.DeleteNamespace(ctx, testClient(), testNamespace) + }, afterEachTimeOut) + Context("Reconcile limitador resources", func() { BeforeEach(func(ctx SpecContext) { - testNamespace = tests.CreateNamespace(ctx, testClient()) tests.ApplyKuadrantCRWithName(ctx, testClient(), testNamespace, kuadrant) - }) + }, beforeEachTimeOut) - AfterEach(func(ctx SpecContext) { - tests.DeleteNamespace(ctx, testClient(), testNamespace) - }, afterEachTimeOut) It("Copy configuration from Kuadrant CR to Limitador CR", func(ctx SpecContext) { - lObj := &v1alpha1.Limitador{} + lObj := &limitadorv1alpha1.Limitador{} Eventually(func() bool { err := k8sClient.Get(ctx, client.ObjectKey{Name: common.LimitadorName, Namespace: testNamespace}, lObj) return err == nil }).WithContext(ctx).Should(BeTrue()) - var tmp *int - Expect(lObj.Spec.Replicas).Should(Equal(tmp)) + Expect(lObj.Spec.Replicas).Should(BeNil()) Eventually(func() bool { kObj := &kuadrantv1beta1.Kuadrant{} @@ -67,7 +76,7 @@ var _ = Describe("Kuadrant controller", func() { }, testTimeOut) It("Kuadrant CR configuration overrides Limitador CR configuration", func(ctx SpecContext) { - lObj := &v1alpha1.Limitador{} + lObj := &limitadorv1alpha1.Limitador{} Eventually(func() bool { err := k8sClient.Get(ctx, client.ObjectKey{Name: common.LimitadorName, Namespace: testNamespace}, lObj) @@ -100,4 +109,74 @@ var _ = Describe("Kuadrant controller", func() { }).WithContext(ctx).Should(BeTrue()) }, testTimeOut) }) + + Context("deploy limitador resources", func() { + It("creates basic Limitador CR", func(ctx SpecContext) { + tests.ApplyKuadrantCRWithName(ctx, testClient(), testNamespace, kuadrant, func(kCR *kuadrantv1beta1.Kuadrant) { + kCR.Spec.Limitador = nil + }) + + kuadrantKey := client.ObjectKey{Name: kuadrant, Namespace: testNamespace} + + Eventually(tests.KuadrantIsReady(ctx, testClient(), kuadrantKey)).WithContext(ctx).Should(Succeed()) + + limitadorKey := client.ObjectKey{Name: common.LimitadorName, Namespace: testNamespace} + + Eventually(tests.LimitadorIsReady(ctx, testClient(), limitadorKey)).WithContext(ctx).Should(Succeed()) + }, testTimeOut) + + It("Limitador CR has the same fields set", func(ctx SpecContext) { + var ( + affinity *corev1.Affinity = &corev1.Affinity{ + PodAffinity: &corev1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ + { + Weight: 100, + PodAffinityTerm: corev1.PodAffinityTerm{ + TopologyKey: "limitador", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "limitador", + }, + }, + }, + }, + }, + }, + } + + podDisruptionBudget *limitadorv1alpha1.PodDisruptionBudgetType = &limitadorv1alpha1.PodDisruptionBudgetType{ + MinAvailable: &intstr.IntOrString{ + IntVal: 1, + }, + } + + storage *limitadorv1alpha1.Storage = &limitadorv1alpha1.Storage{ + Disk: &limitadorv1alpha1.DiskSpec{}, + } + ) + tests.ApplyKuadrantCRWithName(ctx, testClient(), testNamespace, kuadrant, func(kCR *kuadrantv1beta1.Kuadrant) { + kCR.Spec.Limitador = &kuadrantv1beta1.LimitadorSpec{} + kCR.Spec.Limitador.Affinity = affinity + kCR.Spec.Limitador.PodDisruptionBudget = podDisruptionBudget + kCR.Spec.Limitador.Storage = storage + }) + + kuadrantKey := client.ObjectKey{Name: kuadrant, Namespace: testNamespace} + + Eventually(tests.KuadrantIsReady(ctx, testClient(), kuadrantKey)).WithContext(ctx).Should(Succeed()) + + limitadorKey := client.ObjectKey{Name: common.LimitadorName, Namespace: testNamespace} + + Eventually(tests.LimitadorIsReady(ctx, testClient(), limitadorKey)).WithContext(ctx).Should(Succeed()) + + limitador := &limitadorv1alpha1.Limitador{} + err := k8sClient.Get(ctx, limitadorKey, limitador) + // must exist + Expect(err).ToNot(HaveOccurred()) + Expect(limitador.Spec.Affinity).To(Equal(affinity)) + Expect(limitador.Spec.PodDisruptionBudget).To(Equal(podDisruptionBudget)) + Expect(limitador.Spec.Storage).To(Equal(storage)) + }, testTimeOut) + }) }) diff --git a/tests/commons.go b/tests/commons.go index 3610f885e..990dcb348 100644 --- a/tests/commons.go +++ b/tests/commons.go @@ -14,7 +14,6 @@ import ( certmanv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" certmanmetav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" - kuadrantdnsv1alpha1 "github.com/kuadrant/dns-operator/api/v1alpha1" istioclientgoextensionv1alpha1 "istio.io/client-go/pkg/apis/extensions/v1alpha1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -26,6 +25,9 @@ import ( gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + kuadrantdnsv1alpha1 "github.com/kuadrant/dns-operator/api/v1alpha1" + limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + kuadrantv1beta1 "github.com/kuadrant/kuadrant-operator/api/v1beta1" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" @@ -118,7 +120,7 @@ func ApplyKuadrantCR(ctx context.Context, cl client.Client, namespace string) { ApplyKuadrantCRWithName(ctx, cl, namespace, "kuadrant-sample") } -func ApplyKuadrantCRWithName(ctx context.Context, cl client.Client, namespace, name string) { +func ApplyKuadrantCRWithName(ctx context.Context, cl client.Client, namespace, name string, mutateFns ...func(*kuadrantv1beta1.Kuadrant)) { kuadrantCR := &kuadrantv1beta1.Kuadrant{ TypeMeta: metav1.TypeMeta{ Kind: "Kuadrant", @@ -129,6 +131,11 @@ func ApplyKuadrantCRWithName(ctx context.Context, cl client.Client, namespace, n Namespace: namespace, }, } + + for _, mutateFn := range mutateFns { + mutateFn(kuadrantCR) + } + err := cl.Create(ctx, kuadrantCR) Expect(err).ToNot(HaveOccurred()) } @@ -630,3 +637,20 @@ func createSelfSignedIssuerSpec() certmanv1.IssuerSpec { }, } } + +func LimitadorIsReady(ctx context.Context, cl client.Client, lKey client.ObjectKey) func(g Gomega) { + return func(g Gomega) { + existing := &limitadorv1alpha1.Limitador{} + g.Expect(cl.Get(ctx, lKey, existing)).To(Succeed()) + g.Expect(meta.IsStatusConditionTrue(existing.Status.Conditions, limitadorv1alpha1.StatusConditionReady)).To(BeTrue()) + } +} + +func KuadrantIsReady(ctx context.Context, cl client.Client, key client.ObjectKey) func(g Gomega) { + return func(g Gomega) { + kuadrantCR := &kuadrantv1beta1.Kuadrant{} + err := cl.Get(ctx, key, kuadrantCR) + g.Expect(err).To(Succeed()) + g.Expect(meta.IsStatusConditionTrue(kuadrantCR.Status.Conditions, "Ready")).To(BeTrue()) + } +}