@@ -27,16 +27,19 @@ public class TtsStaticPromptRefreshTaskTests
2727 private IContainer _testWorkerContainer ;
2828 private string _originalServiceBaseUrl ;
2929 private string _originalStaticPromptAdminKey ;
30+ private TimeSpan _originalRetryDelay ;
3031
3132 [ SetUp ]
3233 public void SetUp ( )
3334 {
3435 _originalWorkerContainer = WorkerBootstrapperContainerField . GetValue ( null ) as IContainer ;
3536 _originalServiceBaseUrl = TtsConfig . ServiceBaseUrl ;
3637 _originalStaticPromptAdminKey = TtsConfig . StaticPromptAdminKey ;
38+ _originalRetryDelay = TtsStaticPromptRefreshTask . RetryDelay ;
3739
3840 TtsConfig . ServiceBaseUrl = "https://tts.example.com" ;
3941 TtsConfig . StaticPromptAdminKey = "prompt-admin-key" ;
42+ TtsStaticPromptRefreshTask . RetryDelay = TimeSpan . FromMilliseconds ( 1 ) ;
4043 }
4144
4245 [ TearDown ]
@@ -46,10 +49,11 @@ public void TearDown()
4649 _testWorkerContainer ? . Dispose ( ) ;
4750 TtsConfig . ServiceBaseUrl = _originalServiceBaseUrl ;
4851 TtsConfig . StaticPromptAdminKey = _originalStaticPromptAdminKey ;
52+ TtsStaticPromptRefreshTask . RetryDelay = _originalRetryDelay ;
4953 }
5054
5155 [ Test ]
52- public async Task process_async_should_rethrow_refresh_failures ( )
56+ public async Task process_async_should_throw_after_all_retries_exhausted ( )
5357 {
5458 var failure = new InvalidOperationException ( "refresh failed" ) ;
5559 var ttsAudioService = new Mock < ITtsAudioService > ( MockBehavior . Strict ) ;
@@ -66,6 +70,10 @@ await FluentActions
6670 . Should ( )
6771 . ThrowAsync < InvalidOperationException > ( )
6872 . WithMessage ( "refresh failed" ) ;
73+
74+ ttsAudioService . Verify (
75+ x => x . RegenerateStaticPromptsAsync ( It . IsAny < IEnumerable < string > > ( ) , It . IsAny < CancellationToken > ( ) ) ,
76+ Times . Exactly ( 3 ) ) ;
6977 }
7078
7179 [ Test ]
@@ -85,6 +93,40 @@ await FluentActions
8593 . Awaiting ( ( ) => task . ProcessAsync ( new TtsStaticPromptRefreshCommand ( 1 ) , progress . Object , cancellationTokenSource . Token ) )
8694 . Should ( )
8795 . ThrowAsync < OperationCanceledException > ( ) ;
96+
97+ ttsAudioService . Verify (
98+ x => x . RegenerateStaticPromptsAsync ( It . IsAny < IEnumerable < string > > ( ) , It . IsAny < CancellationToken > ( ) ) ,
99+ Times . Once ) ;
100+ }
101+
102+ [ Test ]
103+ public async Task process_async_should_succeed_on_retry_after_initial_failure ( )
104+ {
105+ var ttsAudioService = new Mock < ITtsAudioService > ( MockBehavior . Strict ) ;
106+ var callCount = 0 ;
107+ ttsAudioService
108+ . Setup ( x => x . RegenerateStaticPromptsAsync ( It . IsAny < IEnumerable < string > > ( ) , It . IsAny < CancellationToken > ( ) ) )
109+ . Returns ( ( ) =>
110+ {
111+ callCount ++ ;
112+ if ( callCount == 1 )
113+ throw new InvalidOperationException ( "transient failure" ) ;
114+
115+ return Task . CompletedTask ;
116+ } ) ;
117+ SetWorkerContainer ( ttsAudioService . Object ) ;
118+
119+ var task = new TtsStaticPromptRefreshTask ( Mock . Of < ILogger > ( ) ) ;
120+ var progress = new Mock < IQuidjiboProgress > ( MockBehavior . Loose ) ;
121+
122+ await FluentActions
123+ . Awaiting ( ( ) => task . ProcessAsync ( new TtsStaticPromptRefreshCommand ( 1 ) , progress . Object , CancellationToken . None ) )
124+ . Should ( )
125+ . NotThrowAsync ( ) ;
126+
127+ ttsAudioService . Verify (
128+ x => x . RegenerateStaticPromptsAsync ( It . IsAny < IEnumerable < string > > ( ) , It . IsAny < CancellationToken > ( ) ) ,
129+ Times . Exactly ( 2 ) ) ;
88130 }
89131
90132 private void SetWorkerContainer ( ITtsAudioService ttsAudioService )
0 commit comments