@@ -362,10 +362,84 @@ func TestBTPOperatorCleanupStep_NoRuntimeID(t *testing.T) {
362362 assert .Zero (t , backoff )
363363}
364364
365+ func TestBTPOperatorCleanupStep_ErrorCollection (t * testing.T ) {
366+ log := slog .New (slog .NewTextHandler (os .Stdout , & slog.HandlerOptions {
367+ Level : slog .LevelInfo ,
368+ })).With ("step" , "TEST" )
369+
370+ t .Run ("should collect errors from DeleteAllOf" , func (t * testing.T ) {
371+ // given
372+ ms := storage .NewMemoryStorage ()
373+ ns := & corev1.Namespace {ObjectMeta : metav1.ObjectMeta {Name : "kyma-system" }}
374+
375+ scheme := internal .NewSchemeForTests (t )
376+ err := apiextensionsv1 .AddToScheme (scheme )
377+ require .NoError (t , err )
378+ decoder := serializer .NewCodecFactory (scheme ).UniversalDeserializer ()
379+ obj , _ , err := decoder .Decode (siCRD , nil , nil )
380+ require .NoError (t , err )
381+
382+ // fake client that returns error on DeleteAllOf
383+ k8sCli := & fakeK8sClientWrapper {
384+ fake : fake .NewClientBuilder ().WithScheme (scheme ).WithRuntimeObjects (obj , ns ).Build (),
385+ deleteAllOfError : fmt .Errorf ("simulated DeleteAllOf error" ),
386+ }
387+
388+ op := fixture .FixDeprovisioningOperation (fixOperationID , fixInstanceID )
389+ op .Temporary = true
390+ op .ProvisioningParameters .PlanID = broker .TrialPlanID
391+ op .UserAgent = broker .AccountCleanupJob
392+ op .State = operationStateInProgress
393+ step := NewBTPOperatorCleanupStep (ms , kubeconfig .NewFakeK8sClientProvider (k8sCli ))
394+
395+ // when
396+ _ , backoff , err := step .Run (op .Operation , log )
397+
398+ // then
399+ // handleError consumes the error and returns backoff for retry instead
400+ assert .NoError (t , err , "handleError returns nil error, only backoff" )
401+ assert .NotZero (t , backoff , "should return non-zero backoff for retry on temporary errors" )
402+ assert .True (t , k8sCli .cleanupInstances , "DeleteAllOf should have been called for ServiceInstances" )
403+ })
404+
405+ t .Run ("should collect errors from List operation" , func (t * testing.T ) {
406+ // given
407+ ms := storage .NewMemoryStorage ()
408+ ns := & corev1.Namespace {ObjectMeta : metav1.ObjectMeta {Name : "kyma-system" }}
409+
410+ scheme := internal .NewSchemeForTests (t )
411+ err := apiextensionsv1 .AddToScheme (scheme )
412+ require .NoError (t , err )
413+
414+ // fake client that returns error on List
415+ k8sCli := & fakeK8sClientWrapper {
416+ fake : fake .NewClientBuilder ().WithScheme (scheme ).WithRuntimeObjects (ns ).Build (),
417+ listError : fmt .Errorf ("simulated List error" ),
418+ }
419+
420+ op := fixture .FixDeprovisioningOperation (fixOperationID , fixInstanceID )
421+ op .Temporary = true
422+ op .ProvisioningParameters .PlanID = broker .TrialPlanID
423+ op .UserAgent = broker .AccountCleanupJob
424+ op .State = operationStateInProgress
425+ step := NewBTPOperatorCleanupStep (ms , kubeconfig .NewFakeK8sClientProvider (k8sCli ))
426+
427+ // when
428+ _ , backoff , err := step .Run (op .Operation , log )
429+
430+ // then
431+ // handleError consumes the error and returns backoff for retry instead
432+ assert .NoError (t , err , "handleError returns nil error, only backoff" )
433+ assert .NotZero (t , backoff , "should return non-zero backoff for retry on temporary errors" )
434+ })
435+ }
436+
365437type fakeK8sClientWrapper struct {
366438 fake client.Client
367439 cleanupInstances bool
368440 cleanupBindings bool
441+ deleteAllOfError error
442+ listError error
369443}
370444
371445func (f * fakeK8sClientWrapper ) Apply (ctx context.Context , obj runtime.ApplyConfiguration , opts ... client.ApplyOption ) error {
@@ -377,6 +451,9 @@ func (f *fakeK8sClientWrapper) Get(ctx context.Context, key client.ObjectKey, ob
377451}
378452
379453func (f * fakeK8sClientWrapper ) List (ctx context.Context , list client.ObjectList , opts ... client.ListOption ) error {
454+ if f .listError != nil {
455+ return f .listError
456+ }
380457 if u , ok := list .(* unstructured.UnstructuredList ); ok {
381458 switch u .Object ["kind" ] {
382459 case "ServiceBindingList" :
@@ -409,8 +486,16 @@ func (f *fakeK8sClientWrapper) DeleteAllOf(ctx context.Context, obj client.Objec
409486 switch u .Object ["kind" ] {
410487 case "ServiceBinding" :
411488 f .cleanupBindings = true
489+ if f .deleteAllOfError != nil {
490+ return f .deleteAllOfError
491+ }
492+ return nil
412493 case "ServiceInstance" :
413494 f .cleanupInstances = true
495+ if f .deleteAllOfError != nil {
496+ return f .deleteAllOfError
497+ }
498+ return nil
414499 }
415500 }
416501 return f .fake .DeleteAllOf (ctx , obj , opts ... )
0 commit comments