@@ -405,28 +405,42 @@ func TestSyncQueue_AddHonorsPerCallContextCancel(t *testing.T) {
405405 }
406406}
407407
408- func TestSyncQueue_AddPerCallTimeoutPropagates (t * testing.T ) {
408+ func TestSyncQueue_AddDetachesPerCallTimeoutAfterEnqueue (t * testing.T ) {
409+ handlerStarted := make (chan struct {}, 1 )
409410 handlerDone := make (chan error , 1 )
411+ release := make (chan struct {})
410412 handler := func (ctx context.Context , repoFullName , cloneURL , branch string ) error {
411- <- ctx .Done ()
413+ handlerStarted <- struct {}{}
414+ <- release
412415 handlerDone <- ctx .Err ()
413- return ctx . Err ()
416+ return nil
414417 }
415418
416419 q := NewSyncQueue (1 , handler )
417420 defer q .Shutdown ()
418421
419422 ctx , cancel := context .WithTimeout (context .Background (), 50 * time .Millisecond )
420423 defer cancel ()
421- q .Add (ctx , "org/svc" , "url" , "main" )
424+ if err := q .Add (ctx , "org/svc" , "url" , "main" ); err != nil {
425+ t .Fatalf ("Add returned error: %v" , err )
426+ }
427+
428+ select {
429+ case <- handlerStarted :
430+ case <- time .After (2 * time .Second ):
431+ t .Fatal ("timed out waiting for handler start" )
432+ }
433+
434+ time .Sleep (100 * time .Millisecond )
435+ close (release )
422436
423437 select {
424438 case err := <- handlerDone :
425- if ! errors . Is ( err , context . DeadlineExceeded ) {
426- t .Fatalf ("expected deadline exceeded , got %v" , err )
439+ if err != nil {
440+ t .Fatalf ("expected detached handler context , got %v" , err )
427441 }
428442 case <- time .After (2 * time .Second ):
429- t .Fatal ("timed out waiting for handler" )
443+ t .Fatal ("timed out waiting for handler completion " )
430444 }
431445}
432446
@@ -546,6 +560,54 @@ func TestSyncQueue_AddAllowsExistingRepoUpdateWhenAtCapacity(t *testing.T) {
546560 }
547561}
548562
563+ func TestSyncQueue_AddRejectsAfterShutdownStarts (t * testing.T ) {
564+ q := NewSyncQueueWithConfig (context .Background (), 0 , func (context.Context , string , string , string ) error {
565+ return nil
566+ }, QueueConfig {
567+ RetryConfig : RetryConfig {MaxAttempts : 1 , BaseDelay : time .Millisecond , MaxDelay : time .Millisecond },
568+ ShutdownTimeout : time .Second ,
569+ MaxTrackedRepos : 1 ,
570+ })
571+ defer q .Shutdown ()
572+
573+ q .Shutdown ()
574+
575+ err := q .Add (context .Background (), "org/svc" , "url" , "main" )
576+ if ! errors .Is (err , ErrSyncQueueShuttingDown ) {
577+ t .Fatalf ("Add error = %v, want %v" , err , ErrSyncQueueShuttingDown )
578+ }
579+ }
580+
581+ func TestSyncQueue_ShutdownUsesConfiguredTimeout (t * testing.T ) {
582+ release := make (chan struct {})
583+ q := NewSyncQueueWithConfig (context .Background (), 1 , func (context.Context , string , string , string ) error {
584+ <- release
585+ return nil
586+ }, QueueConfig {
587+ RetryConfig : RetryConfig {MaxAttempts : 1 , BaseDelay : time .Millisecond , MaxDelay : time .Millisecond },
588+ ShutdownTimeout : 30 * time .Millisecond ,
589+ MaxTrackedRepos : 1 ,
590+ })
591+
592+ if err := q .Add (context .Background (), "org/svc" , "url" , "main" ); err != nil {
593+ t .Fatalf ("Add returned error: %v" , err )
594+ }
595+ time .Sleep (10 * time .Millisecond )
596+
597+ start := time .Now ()
598+ q .Shutdown ()
599+ elapsed := time .Since (start )
600+ close (release )
601+
602+ if elapsed > 250 * time .Millisecond {
603+ t .Fatalf ("Shutdown took %s, want close to configured timeout" , elapsed )
604+ }
605+ stats := q .Stats ()
606+ if stats .FailureTotal == 0 {
607+ t .Fatalf ("expected shutdown timeout failure to be recorded, got %+v" , stats )
608+ }
609+ }
610+
549611func TestSyncQueueStats_ReportsQueueFull (t * testing.T ) {
550612 q := NewSyncQueueWithConfig (context .Background (), 0 , func (context.Context , string , string , string ) error {
551613 return nil
@@ -899,8 +961,9 @@ func TestSyncQueueStats_RecentRepos_IncludesQueuedAndProcessingBeforeFirstOutcom
899961func TestSyncQueueStats_ReportsAgesAndLastSuccess (t * testing.T ) {
900962 release := make (chan struct {})
901963 started := make (chan struct {})
964+ var once sync.Once
902965 q := NewSyncQueueWithConfig (context .Background (), 1 , func (context.Context , string , string , string ) error {
903- close (started )
966+ once . Do ( func () { close (started ) } )
904967 <- release
905968 return nil
906969 }, QueueConfig {
0 commit comments