@@ -181,3 +181,381 @@ func TestGetActiveDeadlineSecondsForNever(t *testing.T) {
181181 })
182182 }
183183}
184+
185+ func TestGetTTLSecondsForAlways (t * testing.T ) {
186+ cases := []struct {
187+ name string
188+ getImageJob func () * appsv1alpha1.ImagePullJob
189+ checkFunc func (result * int32 ) bool
190+ }{
191+ {
192+ name : "with TTLSecondsAfterFinished" ,
193+ getImageJob : func () * appsv1alpha1.ImagePullJob {
194+ return & appsv1alpha1.ImagePullJob {
195+ Spec : appsv1alpha1.ImagePullJobSpec {
196+ CompletionPolicy : appsv1alpha1.CompletionPolicy {
197+ TTLSecondsAfterFinished : ptr .To (int32 (3600 )),
198+ },
199+ },
200+ }
201+ },
202+ checkFunc : func (result * int32 ) bool {
203+ return * result >= 3600 && * result <= 3600 + 600
204+ },
205+ },
206+ {
207+ name : "with ActiveDeadlineSeconds" ,
208+ getImageJob : func () * appsv1alpha1.ImagePullJob {
209+ return & appsv1alpha1.ImagePullJob {
210+ Spec : appsv1alpha1.ImagePullJobSpec {
211+ CompletionPolicy : appsv1alpha1.CompletionPolicy {
212+ ActiveDeadlineSeconds : ptr .To (int64 (7200 )),
213+ },
214+ },
215+ }
216+ },
217+ checkFunc : func (result * int32 ) bool {
218+ return * result >= 7200 && * result <= 7200 + 600
219+ },
220+ },
221+ {
222+ name : "with PullPolicy" ,
223+ getImageJob : func () * appsv1alpha1.ImagePullJob {
224+ return & appsv1alpha1.ImagePullJob {
225+ Spec : appsv1alpha1.ImagePullJobSpec {
226+ ImagePullJobTemplate : appsv1alpha1.ImagePullJobTemplate {
227+ PullPolicy : & appsv1alpha1.PullPolicy {
228+ TimeoutSeconds : ptr .To (int32 (300 )),
229+ BackoffLimit : ptr .To (int32 (5 )),
230+ },
231+ },
232+ },
233+ }
234+ },
235+ checkFunc : func (result * int32 ) bool {
236+ expectedBase := int32 (300 * 5 )
237+ return * result >= expectedBase && * result <= expectedBase + 600
238+ },
239+ },
240+ }
241+
242+ for _ , cs := range cases {
243+ t .Run (cs .name , func (t * testing.T ) {
244+ ret := getTTLSecondsForAlways (cs .getImageJob ())
245+ if ! cs .checkFunc (ret ) {
246+ t .Fatalf ("result %d is not in expected range" , * ret )
247+ }
248+ })
249+ }
250+ }
251+
252+ func TestGetTTLSecondsForNever (t * testing.T ) {
253+ result := getTTLSecondsForNever ()
254+ if * result < defaultTTLSecondsForNever - 600 || * result > defaultTTLSecondsForNever + 600 {
255+ t .Fatalf ("expected result to be in range [%d, %d], but got %d" ,
256+ defaultTTLSecondsForNever - 600 , defaultTTLSecondsForNever + 600 , * result )
257+ }
258+ }
259+
260+ func TestGetSecrets (t * testing.T ) {
261+ cases := []struct {
262+ name string
263+ getImageJob func () * appsv1alpha1.ImagePullJob
264+ expected []appsv1alpha1.ReferenceObject
265+ }{
266+ {
267+ name : "no secrets" ,
268+ getImageJob : func () * appsv1alpha1.ImagePullJob {
269+ return & appsv1alpha1.ImagePullJob {
270+ ObjectMeta : metav1.ObjectMeta {
271+ Namespace : "default" ,
272+ },
273+ Spec : appsv1alpha1.ImagePullJobSpec {
274+ ImagePullJobTemplate : appsv1alpha1.ImagePullJobTemplate {
275+ PullSecrets : []string {},
276+ },
277+ },
278+ }
279+ },
280+ expected : []appsv1alpha1.ReferenceObject {},
281+ },
282+ {
283+ name : "with secrets" ,
284+ getImageJob : func () * appsv1alpha1.ImagePullJob {
285+ return & appsv1alpha1.ImagePullJob {
286+ ObjectMeta : metav1.ObjectMeta {
287+ Namespace : "default" ,
288+ },
289+ Spec : appsv1alpha1.ImagePullJobSpec {
290+ ImagePullJobTemplate : appsv1alpha1.ImagePullJobTemplate {
291+ PullSecrets : []string {"secret1" , "secret2" },
292+ },
293+ },
294+ }
295+ },
296+ expected : []appsv1alpha1.ReferenceObject {
297+ {Namespace : "default" , Name : "secret1" },
298+ {Namespace : "default" , Name : "secret2" },
299+ },
300+ },
301+ }
302+
303+ for _ , cs := range cases {
304+ t .Run (cs .name , func (t * testing.T ) {
305+ result := getSecrets (cs .getImageJob ())
306+ if ! reflect .DeepEqual (result , cs .expected ) {
307+ t .Fatalf ("expected %v, but got %v" , cs .expected , result )
308+ }
309+ })
310+ }
311+ }
312+
313+ func TestContainsObject (t * testing.T ) {
314+ slice := []appsv1alpha1.ReferenceObject {
315+ {Namespace : "ns1" , Name : "name1" },
316+ {Namespace : "ns2" , Name : "name2" },
317+ }
318+
319+ cases := []struct {
320+ name string
321+ obj appsv1alpha1.ReferenceObject
322+ expected bool
323+ }{
324+ {
325+ name : "contains object" ,
326+ obj : appsv1alpha1.ReferenceObject {Namespace : "ns1" , Name : "name1" },
327+ expected : true ,
328+ },
329+ {
330+ name : "does not contain object" ,
331+ obj : appsv1alpha1.ReferenceObject {Namespace : "ns3" , Name : "name3" },
332+ expected : false ,
333+ },
334+ {
335+ name : "same name different namespace" ,
336+ obj : appsv1alpha1.ReferenceObject {Namespace : "ns3" , Name : "name1" },
337+ expected : false ,
338+ },
339+ }
340+
341+ for _ , cs := range cases {
342+ t .Run (cs .name , func (t * testing.T ) {
343+ result := containsObject (slice , cs .obj )
344+ if result != cs .expected {
345+ t .Fatalf ("expected %v, but got %v" , cs .expected , result )
346+ }
347+ })
348+ }
349+ }
350+
351+ func TestFormatStatusMessage (t * testing.T ) {
352+ cases := []struct {
353+ name string
354+ status * appsv1alpha1.ImagePullJobStatus
355+ expected string
356+ }{
357+ {
358+ name : "completed job" ,
359+ status : & appsv1alpha1.ImagePullJobStatus {
360+ CompletionTime : & metav1.Time {},
361+ },
362+ expected : "job has completed" ,
363+ },
364+ {
365+ name : "no progress" ,
366+ status : & appsv1alpha1.ImagePullJobStatus {
367+ Desired : 0 ,
368+ },
369+ expected : "job is running, no progress" ,
370+ },
371+ {
372+ name : "partial progress" ,
373+ status : & appsv1alpha1.ImagePullJobStatus {
374+ Desired : 10 ,
375+ Succeeded : 3 ,
376+ Failed : 2 ,
377+ },
378+ expected : "job is running, progress 50.0%" ,
379+ },
380+ }
381+
382+ for _ , cs := range cases {
383+ t .Run (cs .name , func (t * testing.T ) {
384+ result := formatStatusMessage (cs .status )
385+ if result != cs .expected {
386+ t .Fatalf ("expected %s, but got %s" , cs .expected , result )
387+ }
388+ })
389+ }
390+ }
391+
392+ func TestKeyFromRef (t * testing.T ) {
393+ ref := appsv1alpha1.ReferenceObject {
394+ Namespace : "test-ns" ,
395+ Name : "test-name" ,
396+ }
397+
398+ result := keyFromRef (ref )
399+ expected := types.NamespacedName {
400+ Namespace : "test-ns" ,
401+ Name : "test-name" ,
402+ }
403+
404+ if result != expected {
405+ t .Fatalf ("expected %v, but got %v" , expected , result )
406+ }
407+ }
408+
409+ func TestKeyFromObject (t * testing.T ) {
410+ obj := & v1.Secret {
411+ ObjectMeta : metav1.ObjectMeta {
412+ Namespace : "test-ns" ,
413+ Name : "test-name" ,
414+ },
415+ }
416+
417+ result := keyFromObject (obj )
418+ expected := types.NamespacedName {
419+ Namespace : "test-ns" ,
420+ Name : "test-name" ,
421+ }
422+
423+ if result != expected {
424+ t .Fatalf ("expected %v, but got %v" , expected , result )
425+ }
426+ }
427+
428+ func TestReferenceSet (t * testing.T ) {
429+ set := makeReferenceSet ()
430+
431+ // Test Insert
432+ key1 := types.NamespacedName {Namespace : "ns1" , Name : "name1" }
433+ key2 := types.NamespacedName {Namespace : "ns2" , Name : "name2" }
434+
435+ set .Insert (key1 )
436+ set .Insert (key2 )
437+
438+ // Test Contains
439+ if ! set .Contains (key1 ) {
440+ t .Fatalf ("expected set to contain %v" , key1 )
441+ }
442+ if ! set .Contains (key2 ) {
443+ t .Fatalf ("expected set to contain %v" , key2 )
444+ }
445+
446+ // Test String
447+ str := set .String ()
448+ if ! reflect .DeepEqual (str , "ns1/name1,ns2/name2" ) && ! reflect .DeepEqual (str , "ns2/name2,ns1/name1" ) {
449+ t .Fatalf ("unexpected string representation: %s" , str )
450+ }
451+
452+ // Test Delete
453+ set .Delete (key1 )
454+ if set .Contains (key1 ) {
455+ t .Fatalf ("expected set to not contain %v after deletion" , key1 )
456+ }
457+
458+ // Test IsEmpty
459+ if set .IsEmpty () {
460+ t .Fatalf ("expected set to not be empty" )
461+ }
462+
463+ set .Delete (key2 )
464+ if ! set .IsEmpty () {
465+ t .Fatalf ("expected set to be empty" )
466+ }
467+ }
468+
469+ func TestComputeTargetSyncAction (t * testing.T ) {
470+ source := & v1.Secret {
471+ ObjectMeta : metav1.ObjectMeta {
472+ Namespace : "source-ns" ,
473+ Name : "source-name" ,
474+ },
475+ Data : map [string ][]byte {
476+ "key" : []byte ("value" ),
477+ },
478+ }
479+
480+ job := & appsv1alpha1.ImagePullJob {
481+ ObjectMeta : metav1.ObjectMeta {
482+ Namespace : "job-ns" ,
483+ Name : "job-name" ,
484+ },
485+ }
486+
487+ cases := []struct {
488+ name string
489+ target * v1.Secret
490+ expected syncAction
491+ }{
492+ {
493+ name : "no target" ,
494+ target : nil ,
495+ expected : create ,
496+ },
497+ {
498+ name : "target with empty UID" ,
499+ target : & v1.Secret {
500+ ObjectMeta : metav1.ObjectMeta {
501+ UID : "" ,
502+ },
503+ },
504+ expected : create ,
505+ },
506+ {
507+ name : "target needs update - different data" ,
508+ target : & v1.Secret {
509+ ObjectMeta : metav1.ObjectMeta {
510+ UID : "test-uid" ,
511+ Annotations : map [string ]string {
512+ TargetOwnerReferencesAnno : "job-ns/job-name" ,
513+ },
514+ },
515+ Data : map [string ][]byte {
516+ "key" : []byte ("different-value" ),
517+ },
518+ },
519+ expected : update ,
520+ },
521+ {
522+ name : "target needs update - missing job reference" ,
523+ target : & v1.Secret {
524+ ObjectMeta : metav1.ObjectMeta {
525+ UID : "test-uid" ,
526+ Annotations : map [string ]string {
527+ TargetOwnerReferencesAnno : "other-ns/other-name" ,
528+ },
529+ },
530+ Data : map [string ][]byte {
531+ "key" : []byte ("value" ),
532+ },
533+ },
534+ expected : update ,
535+ },
536+ {
537+ name : "no action needed" ,
538+ target : & v1.Secret {
539+ ObjectMeta : metav1.ObjectMeta {
540+ UID : "test-uid" ,
541+ Annotations : map [string ]string {
542+ TargetOwnerReferencesAnno : "job-ns/job-name" ,
543+ },
544+ },
545+ Data : map [string ][]byte {
546+ "key" : []byte ("value" ),
547+ },
548+ },
549+ expected : noAction ,
550+ },
551+ }
552+
553+ for _ , cs := range cases {
554+ t .Run (cs .name , func (t * testing.T ) {
555+ result := computeTargetSyncAction (source , cs .target , job )
556+ if result != cs .expected {
557+ t .Fatalf ("expected %v, but got %v" , cs .expected , result )
558+ }
559+ })
560+ }
561+ }
0 commit comments