Skip to content

Commit 8cad80f

Browse files
Goutham-Annemclaude
andcommitted
test(controller): cover double-error path when both traffic routing and status sync fail
Adds TestProgressDeadlineSyncStatusErrorWithTrafficRoutingError to exercise the branch where reconcileTrafficRouting() and syncRolloutStatusCanary() both return errors, verifying that the sync error (not the traffic routing error) is surfaced so the controller requeues. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fd6aa45 commit 8cad80f

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

rollout/trafficrouting_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"testing"
1010
"time"
1111

12+
core "k8s.io/client-go/testing"
13+
1214
log "github.com/sirupsen/logrus"
1315
corev1 "k8s.io/api/core/v1"
1416
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -186,6 +188,65 @@ func TestProgressDeadlineAbortWithTrafficRoutingError(t *testing.T) {
186188
f.verifyPatchedRolloutAborted(patchIndex, rs2.Name)
187189
}
188190

191+
// TestProgressDeadlineSyncStatusErrorWithTrafficRoutingError verifies that when both
192+
// reconcileTrafficRouting() and syncRolloutStatusCanary() return errors, the sync error is
193+
// surfaced (not silently dropped), so the controller requeues the reconcile.
194+
func TestProgressDeadlineSyncStatusErrorWithTrafficRoutingError(t *testing.T) {
195+
f := newFixture(t)
196+
defer f.Close()
197+
198+
steps := []v1alpha1.CanaryStep{
199+
{SetWeight: ptr.To[int32](50)},
200+
}
201+
r1 := newCanaryRollout("foo", 10, nil, steps, ptr.To[int32](0), intstr.FromInt(1), intstr.FromInt(0))
202+
progressDeadlineSeconds := int32(1)
203+
r1.Spec.ProgressDeadlineSeconds = &progressDeadlineSeconds
204+
r1.Spec.ProgressDeadlineAbort = true
205+
r2 := bumpVersion(r1)
206+
r2.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{}
207+
r2.Spec.Strategy.Canary.CanaryService = "canary"
208+
r2.Spec.Strategy.Canary.StableService = "stable"
209+
210+
rs1 := newReplicaSetWithStatus(r1, 10, 10)
211+
rs2 := newReplicaSetWithStatus(r2, 3, 3)
212+
213+
rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]
214+
rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]
215+
canarySelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}
216+
stableSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}
217+
canarySvc := newService("canary", 80, canarySelector, r2)
218+
stableSvc := newService("stable", 80, stableSelector, r2)
219+
220+
f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc)
221+
f.replicaSetLister = append(f.replicaSetLister, rs1, rs2)
222+
223+
r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 13, 3, 13, false)
224+
r2.Status.CurrentPodHash = rs2PodHash
225+
226+
msg := fmt.Sprintf("ReplicaSet %q has timed out progressing.", rs2.Name)
227+
timedOutCond := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionFalse, conditions.TimedOutReason, msg)
228+
conditions.SetRolloutCondition(&r2.Status, *timedOutCond)
229+
230+
f.rolloutLister = append(f.rolloutLister, r2)
231+
f.objects = append(f.objects, r2)
232+
233+
f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler()
234+
f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(
235+
fmt.Errorf("delaying destination rule switch: ReplicaSet %s not fully available", rs2.Name),
236+
)
237+
238+
// Initialize the controller first (creates f.client), then inject a reactor that makes
239+
// the rollout status patch fail. This causes syncRolloutStatusCanary() to return an error,
240+
// exercising the double-error branch: trafficErr != nil AND syncErr != nil → return syncErr.
241+
c, i, k8sI := f.newController(noResyncPeriodFunc)
242+
f.client.PrependReactor("patch", "rollouts", func(action core.Action) (bool, runtime.Object, error) {
243+
return true, nil, fmt.Errorf("injected patch failure")
244+
})
245+
246+
f.expectPatchRolloutAction(r2)
247+
f.runController(getKey(r2, t), true, true, c, i, k8sI)
248+
}
249+
189250
// verify error is not returned when VerifyWeight returns error (so that we can continue reconciling)
190251
func TestReconcileTrafficRoutingVerifyWeightErr(t *testing.T) {
191252
f, ro := newTrafficWeightFixture(t)

0 commit comments

Comments
 (0)