@@ -252,6 +252,7 @@ func TestReconcileLBHealthMonitor(t *testing.T) {
252252 }
253253
254254 clusterScope := newLBClusterScope (
255+ testutils .WithControlPlaneInitialized (true ),
255256 testutils .WithHMService (healthMonitorService ),
256257 testutils .WithHealthMonitorParams (tc .delayS , tc .timeoutS , tc .upThreshold , tc .downThresh ),
257258 )
@@ -333,7 +334,7 @@ func TestReconcileLoadBalancer_ErrorStatusProceedsWithMemberReconciliation(t *te
333334 result , err := r .reconcileLoadBalancer (context .Background (), clusterScope )
334335
335336 g .Expect (err ).ToNot (HaveOccurred ())
336- g .Expect (result .RequeueAfter ).To (BeZero ( ), "error status should not block member reconciliation" )
337+ g .Expect (result .RequeueAfter ).To (Equal ( 10 * time . Second ), "error status should requeue to re-check the LB after member reconciliation" )
337338
338339 // LoadBalancerReadyCondition should be False because LB is not running
339340 cond := conditions .Get (clusterScope .CloudscaleCluster , infrastructurev1beta2 .LoadBalancerReadyCondition )
@@ -371,7 +372,7 @@ func TestReconcileLoadBalancer_DegradedStatusProceedsWithMemberReconciliation(t
371372 result , err := r .reconcileLoadBalancer (context .Background (), clusterScope )
372373
373374 g .Expect (err ).ToNot (HaveOccurred ())
374- g .Expect (result .RequeueAfter ).To (BeZero ( ), "degraded status should not block member reconciliation" )
375+ g .Expect (result .RequeueAfter ).To (Equal ( 10 * time . Second ), "degraded status should requeue to re-check the LB after member reconciliation" )
375376
376377 // Stale member should have been removed
377378 g .Expect (deletedMemberUUID ).To (Equal ("stale-uuid" ))
@@ -433,17 +434,80 @@ func TestReconcileLoadBalancer_SetsControlPlaneEndpoint(t *testing.T) {
433434 clusterScope .CloudscaleCluster .Status .LoadBalancerID = testLBUUID
434435 clusterScope .CloudscaleCluster .Status .LoadBalancerPoolID = testPoolUUID
435436 clusterScope .CloudscaleCluster .Status .LoadBalancerListenerID = testListenerUUID
436- clusterScope .CloudscaleCluster .Status .LoadBalancerHealthMonitorID = testHMUUID
437437
438438 r := newTestReconciler ()
439439
440- _ , err := r .reconcileLoadBalancer (context .Background (), clusterScope )
440+ result , err := r .reconcileLoadBalancer (context .Background (), clusterScope )
441441
442442 g .Expect (err ).ToNot (HaveOccurred ())
443+ g .Expect (result .IsZero ()).To (BeTrue (), "reconcileLoadBalancer must not requeue for the health monitor" )
443444 g .Expect (clusterScope .CloudscaleCluster .Spec .ControlPlaneEndpoint .Host ).To (Equal ("203.0.113.10" ))
444445 g .Expect (clusterScope .CloudscaleCluster .Spec .ControlPlaneEndpoint .Port ).To (Equal (int32 (6443 )))
445446}
446447
448+ // hmServiceWithCreate returns a health-monitor mock whose List is empty and
449+ // whose Create flips *created and returns a fixed UUID.
450+ func hmServiceWithCreate (created * bool ) * testutils.MockLoadBalancerHealthMonitorService {
451+ return & testutils.MockLoadBalancerHealthMonitorService {
452+ ListFn : func (ctx context.Context , modifiers ... cloudscalesdk.ListRequestModifier ) ([]cloudscalesdk.LoadBalancerHealthMonitor , error ) {
453+ return nil , nil
454+ },
455+ CreateFn : func (ctx context.Context , req * cloudscalesdk.LoadBalancerHealthMonitorRequest ) (* cloudscalesdk.LoadBalancerHealthMonitor , error ) {
456+ * created = true
457+ return & cloudscalesdk.LoadBalancerHealthMonitor {UUID : "hm-uuid" }, nil
458+ },
459+ }
460+ }
461+
462+ func TestReconcileLBHealthMonitor_RequeuesUntilControlPlaneInitialized (t * testing.T ) {
463+ g := NewWithT (t )
464+
465+ var created bool
466+ clusterScope := newLBClusterScope (testutils .WithHMService (hmServiceWithCreate (& created )))
467+ clusterScope .CloudscaleCluster .Status .LoadBalancerPoolID = testPoolUUID
468+
469+ result , err := newTestReconciler ().reconcileLBHealthMonitor (context .Background (), clusterScope )
470+
471+ g .Expect (err ).ToNot (HaveOccurred ())
472+ g .Expect (result .RequeueAfter ).To (Equal (10 * time .Second ), "must poll until the control plane is initialized" )
473+ g .Expect (created ).To (BeFalse (), "health monitor must not be created before the control plane is initialized" )
474+ g .Expect (clusterScope .CloudscaleCluster .Status .LoadBalancerHealthMonitorID ).To (BeEmpty ())
475+ }
476+
477+ func TestReconcileLBHealthMonitor_CreatesWhenControlPlaneInitialized (t * testing.T ) {
478+ g := NewWithT (t )
479+
480+ var created bool
481+ clusterScope := newLBClusterScope (
482+ testutils .WithControlPlaneInitialized (true ),
483+ testutils .WithHMService (hmServiceWithCreate (& created )),
484+ )
485+ clusterScope .CloudscaleCluster .Status .LoadBalancerPoolID = testPoolUUID
486+
487+ result , err := newTestReconciler ().reconcileLBHealthMonitor (context .Background (), clusterScope )
488+
489+ g .Expect (err ).ToNot (HaveOccurred ())
490+ g .Expect (result .IsZero ()).To (BeTrue ())
491+ g .Expect (created ).To (BeTrue (), "health monitor must be created once the control plane is initialized" )
492+ g .Expect (clusterScope .CloudscaleCluster .Status .LoadBalancerHealthMonitorID ).To (Equal ("hm-uuid" ))
493+ }
494+
495+ func TestReconcileLBHealthMonitor_SkipsWhenLBDisabled (t * testing.T ) {
496+ g := NewWithT (t )
497+
498+ var created bool
499+ clusterScope := newLBClusterScope (
500+ testutils .WithLBEnabled (false ),
501+ testutils .WithHMService (hmServiceWithCreate (& created )),
502+ )
503+
504+ result , err := newTestReconciler ().reconcileLBHealthMonitor (context .Background (), clusterScope )
505+
506+ g .Expect (err ).ToNot (HaveOccurred ())
507+ g .Expect (result .IsZero ()).To (BeTrue ())
508+ g .Expect (created ).To (BeFalse (), "external control plane has no health monitor" )
509+ }
510+
447511// ============================================================================
448512// Tests for deleteLoadBalancer
449513// ============================================================================
0 commit comments