@@ -16,6 +16,7 @@ import (
1616 "github.com/stretchr/testify/assert"
1717 kerrors "k8s.io/apimachinery/pkg/api/errors"
1818 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
19+ "k8s.io/apimachinery/pkg/runtime/schema"
1920 "k8s.io/utils/ptr"
2021)
2122
@@ -52,6 +53,12 @@ func Test_create(t *testing.T) {
5253 * obj .(* unstructured.Unstructured ) = pod
5354 return nil
5455 },
56+ CreateFn : func (_ context.Context , _ int , _ client.Object , _ ... client.CreateOption ) error {
57+ return kerrors .NewAlreadyExists (
58+ schema.GroupResource {Group : "" , Resource : "pods" },
59+ "test-pod" ,
60+ )
61+ },
5562 },
5663 expect : nil ,
5764 expectedErr : errors .New ("the resource already exists in the cluster" ),
@@ -63,6 +70,12 @@ func Test_create(t *testing.T) {
6370 * obj .(* unstructured.Unstructured ) = pod
6471 return nil
6572 },
73+ CreateFn : func (_ context.Context , _ int , _ client.Object , _ ... client.CreateOption ) error {
74+ return kerrors .NewAlreadyExists (
75+ schema.GroupResource {Group : "" , Resource : "pods" },
76+ "test-pod" ,
77+ )
78+ },
6679 },
6780 expect : nil ,
6881 expectedErr : errors .New ("the resource already exists in the cluster" ),
@@ -99,6 +112,9 @@ func Test_create(t *testing.T) {
99112 GetFn : func (ctx context.Context , _ int , _ client.ObjectKey , _ client.Object , opts ... client.GetOption ) error {
100113 return errors .New ("some arbitrary error" )
101114 },
115+ CreateFn : func (_ context.Context , _ int , _ client.Object , _ ... client.CreateOption ) error {
116+ return errors .New ("unexpected create call" )
117+ },
102118 },
103119 expect : nil ,
104120 expectedErr : errors .New ("some arbitrary error" ),
@@ -238,3 +254,170 @@ func Test_create(t *testing.T) {
238254 })
239255 }
240256}
257+
258+ func Test_retry_logic (t * testing.T ) {
259+ pod := unstructured.Unstructured {
260+ Object : map [string ]any {
261+ "apiVersion" : "v1" ,
262+ "kind" : "Pod" ,
263+ "metadata" : map [string ]any {
264+ "name" : "test-pod" ,
265+ },
266+ "spec" : map [string ]any {
267+ "containers" : []any {
268+ map [string ]any {
269+ "name" : "test-container" ,
270+ "image" : "test-image:v1" ,
271+ },
272+ },
273+ },
274+ },
275+ }
276+
277+ tests := []struct {
278+ name string
279+ object unstructured.Unstructured
280+ client * tclient.FakeClient
281+ cleaner cleaner.Cleaner
282+ expect []v1alpha1.Expectation
283+ expectedErr error
284+ }{
285+ {
286+ name : "conflict error should be retried and eventually succeed" ,
287+ object : pod ,
288+ client : & tclient.FakeClient {
289+ GetFn : func (ctx context.Context , call int , key client.ObjectKey , obj client.Object , _ ... client.GetOption ) error {
290+ return kerrors .NewNotFound (obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().WithResource ("pod" ).GroupResource (), key .Name )
291+ },
292+ CreateFn : func (_ context.Context , call int , _ client.Object , _ ... client.CreateOption ) error {
293+ if call < 2 {
294+ return kerrors .NewConflict (
295+ schema.GroupResource {Group : "" , Resource : "pods" },
296+ "test-pod" ,
297+ errors .New ("conflict error" ),
298+ )
299+ }
300+ return nil
301+ },
302+ },
303+ expect : nil ,
304+ expectedErr : nil ,
305+ },
306+ {
307+ name : "server timeout error should be retried and eventually succeed" ,
308+ object : pod ,
309+ client : & tclient.FakeClient {
310+ GetFn : func (ctx context.Context , call int , key client.ObjectKey , obj client.Object , _ ... client.GetOption ) error {
311+ return kerrors .NewNotFound (obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().WithResource ("pod" ).GroupResource (), key .Name )
312+ },
313+ CreateFn : func (_ context.Context , call int , _ client.Object , _ ... client.CreateOption ) error {
314+ if call < 2 {
315+ return kerrors .NewServerTimeout (
316+ schema.GroupResource {Group : "" , Resource : "pods" },
317+ "create" ,
318+ 10 ,
319+ )
320+ }
321+ return nil
322+ },
323+ },
324+ expect : nil ,
325+ expectedErr : nil ,
326+ },
327+ {
328+ name : "too many requests error should be retried and eventually succeed" ,
329+ object : pod ,
330+ client : & tclient.FakeClient {
331+ GetFn : func (ctx context.Context , call int , key client.ObjectKey , obj client.Object , _ ... client.GetOption ) error {
332+ return kerrors .NewNotFound (obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().WithResource ("pod" ).GroupResource (), key .Name )
333+ },
334+ CreateFn : func (_ context.Context , call int , _ client.Object , _ ... client.CreateOption ) error {
335+ if call < 2 {
336+ return kerrors .NewTooManyRequests (
337+ "too many requests" ,
338+ 10 ,
339+ )
340+ }
341+ return nil
342+ },
343+ },
344+ expect : nil ,
345+ expectedErr : nil ,
346+ },
347+ {
348+ name : "service unavailable error should be retried and eventually succeed" ,
349+ object : pod ,
350+ client : & tclient.FakeClient {
351+ GetFn : func (ctx context.Context , call int , key client.ObjectKey , obj client.Object , _ ... client.GetOption ) error {
352+ return kerrors .NewNotFound (obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().WithResource ("pod" ).GroupResource (), key .Name )
353+ },
354+ CreateFn : func (_ context.Context , call int , _ client.Object , _ ... client.CreateOption ) error {
355+ if call < 2 {
356+ return kerrors .NewServiceUnavailable ("service unavailable" )
357+ }
358+ return nil
359+ },
360+ },
361+ expect : nil ,
362+ expectedErr : nil ,
363+ },
364+ {
365+ name : "already exists error should not be retried" ,
366+ object : pod ,
367+ client : & tclient.FakeClient {
368+ GetFn : func (ctx context.Context , call int , key client.ObjectKey , obj client.Object , _ ... client.GetOption ) error {
369+ return kerrors .NewNotFound (obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().WithResource ("pod" ).GroupResource (), key .Name )
370+ },
371+ CreateFn : func (_ context.Context , call int , _ client.Object , _ ... client.CreateOption ) error {
372+ return kerrors .NewAlreadyExists (
373+ schema.GroupResource {Group : "" , Resource : "pods" },
374+ "test-pod" ,
375+ )
376+ },
377+ },
378+ expect : nil ,
379+ expectedErr : errors .New ("the resource already exists in the cluster" ),
380+ },
381+ {
382+ name : "permanent error should not be retried" ,
383+ object : pod ,
384+ client : & tclient.FakeClient {
385+ GetFn : func (ctx context.Context , call int , key client.ObjectKey , obj client.Object , _ ... client.GetOption ) error {
386+ return kerrors .NewNotFound (obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().WithResource ("pod" ).GroupResource (), key .Name )
387+ },
388+ CreateFn : func (_ context.Context , call int , _ client.Object , _ ... client.CreateOption ) error {
389+ return kerrors .NewBadRequest ("bad request error" )
390+ },
391+ },
392+ expect : nil ,
393+ expectedErr : errors .New ("bad request error" ),
394+ },
395+ }
396+
397+ for _ , tt := range tests {
398+ t .Run (tt .name , func (t * testing.T ) {
399+ logger := & mocks.Logger {}
400+ ctx := logging .WithLogger (context .TODO (), logger )
401+ toCtx , cancel := context .WithTimeout (ctx , 5 * time .Second )
402+ defer cancel ()
403+ ctx = toCtx
404+ operation := New (
405+ apis .DefaultCompilers ,
406+ tt .client ,
407+ tt .object ,
408+ nil ,
409+ nil ,
410+ false ,
411+ tt .expect ,
412+ nil ,
413+ )
414+ outputs , err := operation .Exec (ctx , nil )
415+ assert .Nil (t , outputs )
416+ if tt .expectedErr != nil {
417+ assert .EqualError (t , err , tt .expectedErr .Error ())
418+ } else {
419+ assert .NoError (t , err )
420+ }
421+ })
422+ }
423+ }
0 commit comments