@@ -5,13 +5,17 @@ import (
55 "testing"
66
77 appsv1alpha1 "github.com/3scale/3scale-operator/apis/apps/v1alpha1"
8+ "github.com/3scale/3scale-operator/pkg/3scale/amp/component"
89 "github.com/3scale/3scale-operator/pkg/reconcilers"
910
1011 grafanav1alpha1 "github.com/grafana-operator/grafana-operator/v4/api/integreatly/v1alpha1"
1112 monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
13+ hpav2 "k8s.io/api/autoscaling/v2"
1214 v1 "k8s.io/api/core/v1"
15+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
1316 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1417 "k8s.io/apimachinery/pkg/runtime"
18+ "k8s.io/apimachinery/pkg/types"
1519 fakeclientset "k8s.io/client-go/kubernetes/fake"
1620 "k8s.io/client-go/kubernetes/scheme"
1721 "k8s.io/client-go/tools/record"
@@ -400,6 +404,216 @@ func TestBaseAPIManagerLogicReconcilerHasPodMonitors(t *testing.T) {
400404 }
401405}
402406
407+ func newTestReconciler (t * testing.T , apimanager * appsv1alpha1.APIManager , existingObjs ... runtime.Object ) (* BaseAPIManagerLogicReconciler , client.Client ) {
408+ t .Helper ()
409+ s := scheme .Scheme
410+ if err := appsv1alpha1 .AddToScheme (s ); err != nil {
411+ t .Fatal (err )
412+ }
413+
414+ objs := append ([]runtime.Object {apimanager }, existingObjs ... )
415+ cl := fake .NewClientBuilder ().WithScheme (s ).WithRuntimeObjects (objs ... ).Build ()
416+ clientAPIReader := fake .NewClientBuilder ().WithScheme (s ).WithRuntimeObjects (objs ... ).Build ()
417+ clientset := fakeclientset .NewSimpleClientset ()
418+ recorder := record .NewFakeRecorder (10000 )
419+ log := logf .Log .WithName ("operator_test" )
420+
421+ baseReconciler := reconcilers .NewBaseReconciler (context .Background (), cl , s , clientAPIReader , log , clientset .Discovery (), recorder )
422+ return NewBaseAPIManagerLogicReconciler (baseReconciler , apimanager ), cl
423+ }
424+
425+ func TestReconcileHpa (t * testing.T ) {
426+ baseAM := func (annotations map [string ]string ) * appsv1alpha1.APIManager {
427+ am := & appsv1alpha1.APIManager {
428+ ObjectMeta : metav1.ObjectMeta {
429+ Name : apimanagerName ,
430+ Namespace : namespace ,
431+ Annotations : annotations ,
432+ },
433+ Spec : appsv1alpha1.APIManagerSpec {
434+ APIManagerCommonSpec : appsv1alpha1.APIManagerCommonSpec {
435+ WildcardDomain : wildcardDomain ,
436+ },
437+ },
438+ }
439+ if _ , err := am .SetDefaults (); err != nil {
440+ panic (err )
441+ }
442+ return am
443+ }
444+
445+ hpaExists := func (t * testing.T , cl client.Client , name string ) bool {
446+ t .Helper ()
447+ obj := & hpav2.HorizontalPodAutoscaler {}
448+ err := cl .Get (context .Background (), types.NamespacedName {Name : name , Namespace : namespace }, obj )
449+ if k8serrors .IsNotFound (err ) {
450+ return false
451+ }
452+ if err != nil {
453+ t .Fatalf ("unexpected error checking HPA %s: %v" , name , err )
454+ }
455+ return true
456+ }
457+
458+ tests := []struct {
459+ name string
460+ apimanager * appsv1alpha1.APIManager
461+ existingHPA * hpav2.HorizontalPodAutoscaler
462+ desired * hpav2.HorizontalPodAutoscaler
463+ assert func (t * testing.T , cl client.Client )
464+ }{
465+ // Backend listener
466+ {
467+ name : "backend listener - HPA does not exist in cluster, disabled in config - no-op" ,
468+ apimanager : baseAM (nil ),
469+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
470+ assert : func (t * testing.T , cl client.Client ) {
471+ if hpaExists (t , cl , component .BackendListenerName ) {
472+ t .Error ("HPA should not exist when disabled and was not pre-existing" )
473+ }
474+ },
475+ },
476+ {
477+ name : "backend listener - HPA exists in cluster, disabled in config - deletes HPA" ,
478+ apimanager : baseAM (nil ),
479+ existingHPA : component .DefaultHpa (component .BackendListenerName , namespace ),
480+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
481+ assert : func (t * testing.T , cl client.Client ) {
482+ if hpaExists (t , cl , component .BackendListenerName ) {
483+ t .Error ("HPA should have been deleted when disabled" )
484+ }
485+ },
486+ },
487+ {
488+ name : "backend listener - HPA does not exist in cluster, enabled in config - creates HPA" ,
489+ apimanager : func () * appsv1alpha1.APIManager {
490+ am := baseAM (nil )
491+ am .Spec .Backend .ListenerSpec .Hpa = true
492+ return am
493+ }(),
494+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
495+ assert : func (t * testing.T , cl client.Client ) {
496+ if ! hpaExists (t , cl , component .BackendListenerName ) {
497+ t .Error ("HPA should have been created when enabled" )
498+ }
499+ },
500+ },
501+ {
502+ name : "backend listener - HPA exists in cluster, enabled but with async-disable annotation - deletes HPA" ,
503+ apimanager : func () * appsv1alpha1.APIManager {
504+ am := baseAM (map [string ]string {appsv1alpha1 .DisableAsyncAnnotation : "true" })
505+ am .Spec .Backend .ListenerSpec .Hpa = true
506+ return am
507+ }(),
508+ existingHPA : component .DefaultHpa (component .BackendListenerName , namespace ),
509+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
510+ assert : func (t * testing.T , cl client.Client ) {
511+ if hpaExists (t , cl , component .BackendListenerName ) {
512+ t .Error ("HPA should have been deleted when async is disabled regardless of HPA flag" )
513+ }
514+ },
515+ },
516+ // Backend worker
517+ {
518+ name : "backend worker - HPA exists in cluster, disabled in config - deletes HPA" ,
519+ apimanager : baseAM (nil ),
520+ existingHPA : component .DefaultHpa (component .BackendWorkerName , namespace ),
521+ desired : component .DefaultHpa (component .BackendWorkerName , namespace ),
522+ assert : func (t * testing.T , cl client.Client ) {
523+ if hpaExists (t , cl , component .BackendWorkerName ) {
524+ t .Error ("backend worker HPA should have been deleted when disabled" )
525+ }
526+ },
527+ },
528+ {
529+ name : "backend worker - HPA does not exist in cluster, enabled in config - creates HPA" ,
530+ apimanager : func () * appsv1alpha1.APIManager {
531+ am := baseAM (nil )
532+ am .Spec .Backend .WorkerSpec .Hpa = true
533+ return am
534+ }(),
535+ desired : component .DefaultHpa (component .BackendWorkerName , namespace ),
536+ assert : func (t * testing.T , cl client.Client ) {
537+ if ! hpaExists (t , cl , component .BackendWorkerName ) {
538+ t .Error ("HPA should have been created when enabled" )
539+ }
540+ },
541+ },
542+ {
543+ name : "backend worker - HPA exists in cluster, enabled in config but with async-disable annotation - deletes HPA" ,
544+ apimanager : func () * appsv1alpha1.APIManager {
545+ am := baseAM (map [string ]string {appsv1alpha1 .DisableAsyncAnnotation : "true" })
546+ am .Spec .Backend .WorkerSpec .Hpa = true
547+ return am
548+ }(),
549+ existingHPA : component .DefaultHpa (component .BackendWorkerName , namespace ),
550+ desired : component .DefaultHpa (component .BackendWorkerName , namespace ),
551+ assert : func (t * testing.T , cl client.Client ) {
552+ if hpaExists (t , cl , component .BackendWorkerName ) {
553+ t .Error ("backend worker HPA should have been deleted when async is disabled" )
554+ }
555+ },
556+ },
557+ // Apicast
558+ {
559+ name : "apicast - HPA exists in cluster, disabled in config - deletes HPA" ,
560+ apimanager : baseAM (nil ),
561+ existingHPA : component .DefaultHpa (component .ApicastProductionName , namespace ),
562+ desired : component .DefaultHpa (component .ApicastProductionName , namespace ),
563+ assert : func (t * testing.T , cl client.Client ) {
564+ if hpaExists (t , cl , component .ApicastProductionName ) {
565+ t .Error ("Apicast HPA should have been deleted when disabled" )
566+ }
567+ },
568+ },
569+ {
570+ name : "apicast - HPA does not exist in cluster, enabled in config - creates HPA" ,
571+ apimanager : func () * appsv1alpha1.APIManager {
572+ am := baseAM (nil )
573+ am .Spec .Apicast .ProductionSpec .Hpa = true
574+ return am
575+ }(),
576+ desired : component .DefaultHpa (component .ApicastProductionName , namespace ),
577+ assert : func (t * testing.T , cl client.Client ) {
578+ if ! hpaExists (t , cl , component .ApicastProductionName ) {
579+ t .Error ("Apicast HPA should have been created when enabled" )
580+ }
581+ },
582+ },
583+ {
584+ name : "apicast - HPA does not exist in cluster, enabled in config with async-disable annotation - creates HPA (annotation has no effect)" ,
585+ apimanager : func () * appsv1alpha1.APIManager {
586+ am := baseAM (map [string ]string {appsv1alpha1 .DisableAsyncAnnotation : "true" })
587+ am .Spec .Apicast .ProductionSpec .Hpa = true
588+ return am
589+ }(),
590+ desired : component .DefaultHpa (component .ApicastProductionName , namespace ),
591+ assert : func (t * testing.T , cl client.Client ) {
592+ if ! hpaExists (t , cl , component .ApicastProductionName ) {
593+ t .Error ("Apicast HPA should be created regardless of async-disable annotation" )
594+ }
595+ },
596+ },
597+ }
598+
599+ for _ , tt := range tests {
600+ t .Run (tt .name , func (t * testing.T ) {
601+ var existingObjs []runtime.Object
602+ if tt .existingHPA != nil {
603+ existingObjs = append (existingObjs , tt .existingHPA )
604+ }
605+
606+ r , cl := newTestReconciler (t , tt .apimanager , existingObjs ... )
607+
608+ if err := r .ReconcileHpa (tt .desired , reconcilers .CreateOnlyMutator ); err != nil {
609+ t .Fatalf ("unexpected error: %v" , err )
610+ }
611+
612+ tt .assert (t , cl )
613+ })
614+ }
615+ }
616+
403617func TestBaseAPIManagerLogicReconcilerHasServiceMonitors (t * testing.T ) {
404618 var (
405619 apimanagerName = "example-apimanager"
0 commit comments