@@ -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,162 @@ 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+ {
466+ name : "disabled with no existing HPA is a no-op" ,
467+ apimanager : baseAM (nil ),
468+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
469+ assert : func (t * testing.T , cl client.Client ) {
470+ if hpaExists (t , cl , component .BackendListenerName ) {
471+ t .Error ("HPA should not exist when disabled and was not pre-existing" )
472+ }
473+ },
474+ },
475+ {
476+ name : "disabled with existing HPA deletes it" ,
477+ apimanager : baseAM (nil ),
478+ existingHPA : component .DefaultHpa (component .BackendListenerName , namespace ),
479+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
480+ assert : func (t * testing.T , cl client.Client ) {
481+ if hpaExists (t , cl , component .BackendListenerName ) {
482+ t .Error ("HPA should have been deleted when disabled" )
483+ }
484+ },
485+ },
486+ {
487+ name : "backend listener HPA enabled creates HPA" ,
488+ apimanager : func () * appsv1alpha1.APIManager {
489+ am := baseAM (nil )
490+ am .Spec .Backend .ListenerSpec .Hpa = true
491+ return am
492+ }(),
493+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
494+ assert : func (t * testing.T , cl client.Client ) {
495+ if ! hpaExists (t , cl , component .BackendListenerName ) {
496+ t .Error ("HPA should have been created when enabled" )
497+ }
498+ },
499+ },
500+ {
501+ name : "backend listener HPA enabled with async-disable annotation deletes HPA" ,
502+ apimanager : func () * appsv1alpha1.APIManager {
503+ am := baseAM (map [string ]string {appsv1alpha1 .DisableAsyncAnnotation : "true" })
504+ am .Spec .Backend .ListenerSpec .Hpa = true
505+ return am
506+ }(),
507+ existingHPA : component .DefaultHpa (component .BackendListenerName , namespace ),
508+ desired : component .DefaultHpa (component .BackendListenerName , namespace ),
509+ assert : func (t * testing.T , cl client.Client ) {
510+ if hpaExists (t , cl , component .BackendListenerName ) {
511+ t .Error ("HPA should have been deleted when async is disabled regardless of HPA flag" )
512+ }
513+ },
514+ },
515+ {
516+ name : "backend worker HPA enabled creates HPA" ,
517+ apimanager : func () * appsv1alpha1.APIManager {
518+ am := baseAM (nil )
519+ am .Spec .Backend .WorkerSpec .Hpa = true
520+ return am
521+ }(),
522+ desired : component .DefaultHpa (component .BackendWorkerName , namespace ),
523+ assert : func (t * testing.T , cl client.Client ) {
524+ if ! hpaExists (t , cl , component .BackendWorkerName ) {
525+ t .Error ("HPA should have been created when enabled" )
526+ }
527+ },
528+ },
529+ {
530+ name : "apicast HPA enabled with async-disable annotation creates HPA" ,
531+ apimanager : func () * appsv1alpha1.APIManager {
532+ am := baseAM (map [string ]string {appsv1alpha1 .DisableAsyncAnnotation : "true" })
533+ am .Spec .Apicast .ProductionSpec .Hpa = true
534+ return am
535+ }(),
536+ desired : component .DefaultHpa (component .ApicastProductionName , namespace ),
537+ assert : func (t * testing.T , cl client.Client ) {
538+ if ! hpaExists (t , cl , component .ApicastProductionName ) {
539+ t .Error ("Apicast HPA should be created regardless of async-disable annotation" )
540+ }
541+ },
542+ },
543+ }
544+
545+ for _ , tt := range tests {
546+ t .Run (tt .name , func (t * testing.T ) {
547+ var existingObjs []runtime.Object
548+ if tt .existingHPA != nil {
549+ existingObjs = append (existingObjs , tt .existingHPA )
550+ }
551+
552+ r , cl := newTestReconciler (t , tt .apimanager , existingObjs ... )
553+
554+ if err := r .ReconcileHpa (tt .desired , reconcilers .CreateOnlyMutator ); err != nil {
555+ t .Fatalf ("unexpected error: %v" , err )
556+ }
557+
558+ tt .assert (t , cl )
559+ })
560+ }
561+ }
562+
403563func TestBaseAPIManagerLogicReconcilerHasServiceMonitors (t * testing.T ) {
404564 var (
405565 apimanagerName = "example-apimanager"
0 commit comments