@@ -138,3 +138,110 @@ func TestConvert2WaitBackoff(t *testing.T) {
138138 Steps : 2 ,
139139 }, * waitBackoff )
140140}
141+
142+ func TestIsResourceConstraintError (t * testing.T ) {
143+ tests := []struct {
144+ name string
145+ err error
146+ expected bool
147+ }{
148+ {
149+ name : "nil error" ,
150+ err : nil ,
151+ expected : false ,
152+ },
153+ {
154+ name : "quota exceeded forbidden error" ,
155+ err : errors .NewForbidden (v1alpha1 .Resource ("workflows" ), "test" , fmt .Errorf ("exceeded quota: workflow-limit" )),
156+ expected : true ,
157+ },
158+ {
159+ name : "regular forbidden error" ,
160+ err : errors .NewForbidden (v1alpha1 .Resource ("sensor" ), "test" , fmt .Errorf ("access denied" )),
161+ expected : false ,
162+ },
163+ {
164+ name : "not found error" ,
165+ err : errors .NewNotFound (v1alpha1 .Resource ("sensor" ), "test" ),
166+ expected : false ,
167+ },
168+ }
169+
170+ for _ , tt := range tests {
171+ t .Run (tt .name , func (t * testing.T ) {
172+ result := IsResourceConstraintError (tt .err )
173+ assert .Equal (t , tt .expected , result )
174+ })
175+ }
176+ }
177+
178+ func TestDoWithResourceAwareRetry (t * testing.T ) {
179+ t .Run ("successful execution" , func (t * testing.T ) {
180+ callCount := 0
181+ err := DoWithResourceAwareRetry (nil , nil , func () error {
182+ callCount ++
183+ return nil
184+ })
185+ assert .NoError (t , err )
186+ assert .Equal (t , 1 , callCount )
187+ })
188+
189+ t .Run ("regular error uses default backoff" , func (t * testing.T ) {
190+ callCount := 0
191+ defaultBackoff := & apicommon.Backoff {Steps : 2 }
192+ err := DoWithResourceAwareRetry (defaultBackoff , nil , func () error {
193+ callCount ++
194+ if callCount < 2 {
195+ return fmt .Errorf ("regular error" )
196+ }
197+ return nil
198+ })
199+ assert .NoError (t , err )
200+ assert .Equal (t , 2 , callCount )
201+ })
202+
203+ t .Run ("resource constraint error uses resource backoff" , func (t * testing.T ) {
204+ callCount := 0
205+ defaultBackoff := & apicommon.Backoff {Steps : 5 }
206+ resourceBackoff := & apicommon.Backoff {Steps : 2 }
207+
208+ err := DoWithResourceAwareRetry (defaultBackoff , resourceBackoff , func () error {
209+ callCount ++
210+ if callCount < 2 {
211+ return errors .NewForbidden (v1alpha1 .Resource ("pods" ), "test" , fmt .Errorf ("exceeded quota" ))
212+ }
213+ return nil
214+ })
215+ assert .NoError (t , err )
216+ assert .Equal (t , 2 , callCount )
217+ })
218+
219+ t .Run ("resource constraint error without resource backoff uses default" , func (t * testing.T ) {
220+ callCount := 0
221+ defaultBackoff := & apicommon.Backoff {Steps : 2 }
222+
223+ err := DoWithResourceAwareRetry (defaultBackoff , nil , func () error {
224+ callCount ++
225+ if callCount < 2 {
226+ return errors .NewForbidden (v1alpha1 .Resource ("pods" ), "test" , fmt .Errorf ("exceeded quota" ))
227+ }
228+ return nil
229+ })
230+ assert .NoError (t , err )
231+ assert .Equal (t , 2 , callCount )
232+ })
233+
234+ t .Run ("all retries exhausted" , func (t * testing.T ) {
235+ callCount := 0
236+ defaultBackoff := & apicommon.Backoff {Steps : 2 }
237+
238+ err := DoWithResourceAwareRetry (defaultBackoff , nil , func () error {
239+ callCount ++
240+ return fmt .Errorf ("persistent error" )
241+ })
242+ assert .Error (t , err )
243+ assert .Contains (t , err .Error (), "failed after retries" )
244+ assert .Contains (t , err .Error (), "persistent error" )
245+ assert .Equal (t , 3 , callCount ) // Initial attempt + 2 retries
246+ })
247+ }
0 commit comments