@@ -14,6 +14,7 @@ import (
1414 "sigs.k8s.io/controller-runtime/pkg/client"
1515 "sigs.k8s.io/controller-runtime/pkg/client/fake"
1616 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
17+ "sigs.k8s.io/controller-runtime/pkg/event"
1718 "sigs.k8s.io/controller-runtime/pkg/handler"
1819 "sigs.k8s.io/controller-runtime/pkg/predicate"
1920 "sigs.k8s.io/controller-runtime/pkg/source"
@@ -235,3 +236,186 @@ func (m *mockTrackingCacheInternal) Watch(ctx context.Context, user client.Objec
235236func (m * mockTrackingCacheInternal ) Source (h handler.EventHandler , predicates ... predicate.Predicate ) source.Source {
236237 return nil
237238}
239+
240+ func Test_skipProgressDeadlineExceededUpdateFunc (t * testing.T ) {
241+ for _ , tc := range []struct {
242+ name string
243+ oldRev * ocv1.ClusterObjectSet
244+ newRev * ocv1.ClusterObjectSet
245+ expected bool
246+ }{
247+ {
248+ name : "allow deletion" ,
249+ oldRev : & ocv1.ClusterObjectSet {
250+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
251+ Status : ocv1.ClusterObjectSetStatus {
252+ Conditions : []metav1.Condition {
253+ {
254+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
255+ Status : metav1 .ConditionFalse ,
256+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
257+ },
258+ },
259+ },
260+ },
261+ newRev : & ocv1.ClusterObjectSet {
262+ ObjectMeta : metav1.ObjectMeta {
263+ Generation : 1 ,
264+ DeletionTimestamp : & metav1.Time {Time : time .Now ()},
265+ },
266+ Status : ocv1.ClusterObjectSetStatus {
267+ Conditions : []metav1.Condition {
268+ {
269+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
270+ Status : metav1 .ConditionFalse ,
271+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
272+ },
273+ },
274+ },
275+ },
276+ expected : true ,
277+ },
278+ {
279+ name : "allow when ProgressDeadlineExceeded condition not present" ,
280+ oldRev : & ocv1.ClusterObjectSet {
281+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
282+ },
283+ newRev : & ocv1.ClusterObjectSet {
284+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
285+ },
286+ expected : true ,
287+ },
288+ {
289+ name : "allow when Progressing condition is true" ,
290+ oldRev : & ocv1.ClusterObjectSet {
291+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
292+ Status : ocv1.ClusterObjectSetStatus {
293+ Conditions : []metav1.Condition {
294+ {
295+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
296+ Status : metav1 .ConditionTrue ,
297+ Reason : ocv1 .ReasonRollingOut ,
298+ },
299+ },
300+ },
301+ },
302+ newRev : & ocv1.ClusterObjectSet {
303+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
304+ Status : ocv1.ClusterObjectSetStatus {
305+ Conditions : []metav1.Condition {
306+ {
307+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
308+ Status : metav1 .ConditionTrue ,
309+ Reason : ocv1 .ReasonRollingOut ,
310+ },
311+ },
312+ },
313+ },
314+ expected : true ,
315+ },
316+ {
317+ name : "allow generation change when ProgressDeadlineExceeded" ,
318+ oldRev : & ocv1.ClusterObjectSet {
319+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
320+ Status : ocv1.ClusterObjectSetStatus {
321+ Conditions : []metav1.Condition {
322+ {
323+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
324+ Status : metav1 .ConditionFalse ,
325+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
326+ },
327+ },
328+ },
329+ },
330+ newRev : & ocv1.ClusterObjectSet {
331+ ObjectMeta : metav1.ObjectMeta {Generation : 2 }, // Generation changed
332+ Status : ocv1.ClusterObjectSetStatus {
333+ Conditions : []metav1.Condition {
334+ {
335+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
336+ Status : metav1 .ConditionFalse ,
337+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
338+ },
339+ },
340+ },
341+ },
342+ expected : true ,
343+ },
344+ {
345+ name : "suppress status-only update when ProgressDeadlineExceeded" ,
346+ oldRev : & ocv1.ClusterObjectSet {
347+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
348+ Status : ocv1.ClusterObjectSetStatus {
349+ Conditions : []metav1.Condition {
350+ {
351+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
352+ Status : metav1 .ConditionFalse ,
353+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
354+ },
355+ },
356+ },
357+ },
358+ newRev : & ocv1.ClusterObjectSet {
359+ ObjectMeta : metav1.ObjectMeta {Generation : 1 }, // Same generation
360+ Status : ocv1.ClusterObjectSetStatus {
361+ Conditions : []metav1.Condition {
362+ {
363+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
364+ Status : metav1 .ConditionFalse ,
365+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
366+ },
367+ {
368+ Type : ocv1 .ClusterObjectSetTypeAvailable ,
369+ Status : metav1 .ConditionFalse ,
370+ Reason : "SomeReason" ,
371+ },
372+ },
373+ },
374+ },
375+ expected : false ,
376+ },
377+ {
378+ name : "allow spec change via generation bump when ProgressDeadlineExceeded (lifecycleState transition)" ,
379+ oldRev : & ocv1.ClusterObjectSet {
380+ ObjectMeta : metav1.ObjectMeta {Generation : 1 },
381+ Spec : ocv1.ClusterObjectSetSpec {
382+ LifecycleState : ocv1 .ClusterObjectSetLifecycleStateActive ,
383+ },
384+ Status : ocv1.ClusterObjectSetStatus {
385+ Conditions : []metav1.Condition {
386+ {
387+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
388+ Status : metav1 .ConditionFalse ,
389+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
390+ },
391+ },
392+ },
393+ },
394+ newRev : & ocv1.ClusterObjectSet {
395+ ObjectMeta : metav1.ObjectMeta {Generation : 2 }, // Generation bumped due to spec change
396+ Spec : ocv1.ClusterObjectSetSpec {
397+ LifecycleState : ocv1 .ClusterObjectSetLifecycleStateArchived ,
398+ },
399+ Status : ocv1.ClusterObjectSetStatus {
400+ Conditions : []metav1.Condition {
401+ {
402+ Type : ocv1 .ClusterObjectSetTypeProgressing ,
403+ Status : metav1 .ConditionFalse ,
404+ Reason : ocv1 .ReasonProgressDeadlineExceeded ,
405+ },
406+ },
407+ },
408+ },
409+ expected : true ,
410+ },
411+ } {
412+ t .Run (tc .name , func (t * testing.T ) {
413+ e := event.UpdateEvent {
414+ ObjectOld : tc .oldRev ,
415+ ObjectNew : tc .newRev ,
416+ }
417+ result := skipProgressDeadlineExceededUpdateFunc (e )
418+ require .Equal (t , tc .expected , result )
419+ })
420+ }
421+ }
0 commit comments