55using System . Threading ;
66using System . Threading . Tasks ;
77using Microsoft . Extensions . DependencyInjection ;
8+ using Microsoft . Extensions . Logging ;
89using Moq ;
910using Moq . Protected ;
1011using Prometheus ;
1112using Xunit ;
12- using Cognite . Extractor . Logging ;
1313using Cognite . Extractor . Metrics ;
1414using Cognite . Extractor . Utils ;
1515using System . Reflection ;
@@ -245,6 +245,65 @@ public async Task TestMultipeGatewaysAsync()
245245 File . Delete ( path ) ;
246246 }
247247
248+ [ Fact ]
249+ public async Task TestRetryPolicyRetriesOnTransientErrorAsync ( )
250+ {
251+ Metrics . SuppressDefaultMetrics ( ) ;
252+ var callCount = 0 ;
253+ var ( provider , logger ) = BuildRetryTestServices ( ( request , token ) =>
254+ {
255+ var status = callCount ++ == 0 ? HttpStatusCode . ServiceUnavailable : HttpStatusCode . OK ;
256+ return Task . FromResult ( new HttpResponseMessage ( status ) ) ;
257+ } ) ;
258+
259+ using ( provider )
260+ await provider . GetRequiredService < IHttpClientFactory > ( )
261+ . CreateClient ( "prometheus-httpclient" ) . GetAsync ( "http://example.com/test" ) ;
262+
263+ Assert . Equal ( 2 , callCount ) ;
264+ Assert . Contains ( logger . Entries , e => e . Level == LogLevel . Warning && e . Message . Contains ( "failed with status code" ) ) ;
265+ }
266+
267+ [ Fact ]
268+ public async Task TestRetryPolicyRetriesOnExceptionAsync ( )
269+ {
270+ Metrics . SuppressDefaultMetrics ( ) ;
271+ var callCount = 0 ;
272+ var ( provider , logger ) = BuildRetryTestServices ( ( request , token ) =>
273+ {
274+ if ( callCount ++ == 0 )
275+ throw new HttpRequestException ( "connection failed" , new Exception ( "inner failure" ) ) ;
276+ return Task . FromResult ( new HttpResponseMessage ( HttpStatusCode . OK ) ) ;
277+ } ) ;
278+
279+ using ( provider )
280+ await provider . GetRequiredService < IHttpClientFactory > ( )
281+ . CreateClient ( "prometheus-httpclient" ) . GetAsync ( "http://example.com/test" ) ;
282+
283+ Assert . Equal ( 2 , callCount ) ;
284+ Assert . Contains ( logger . Entries , e => e . Level == LogLevel . Warning && e . Message . Contains ( "connection failed" ) ) ;
285+ Assert . Contains ( logger . Entries , e => e . Level == LogLevel . Debug && e . Message . Contains ( "inner failure" ) ) ;
286+ }
287+
288+ private ( ServiceProvider provider , FakeLogger < MetricServer > logger ) BuildRetryTestServices (
289+ Func < HttpRequestMessage , CancellationToken , Task < HttpResponseMessage > > handler )
290+ {
291+ var fakeLogger = new FakeLogger < MetricServer > ( ) ;
292+ var services = new ServiceCollection ( ) ;
293+ services . AddTestLogging ( _output ) ;
294+ services . AddSingleton < ILogger < MetricServer > > ( fakeLogger ) ;
295+ services . AddCogniteMetrics ( ) ;
296+ services . AddHttpClient ( "prometheus-httpclient" )
297+ . ConfigurePrimaryHttpMessageHandler ( ( ) => new TestHttpHandler ( handler ) ) ;
298+ return ( services . BuildServiceProvider ( ) , fakeLogger ) ;
299+ }
300+
301+ private sealed class TestHttpHandler ( Func < HttpRequestMessage , CancellationToken , Task < HttpResponseMessage > > handler ) : HttpMessageHandler
302+ {
303+ protected override Task < HttpResponseMessage > SendAsync ( HttpRequestMessage request , CancellationToken cancellationToken )
304+ => handler ( request , cancellationToken ) ;
305+ }
306+
248307 [ Fact ]
249308 public void TestVersion ( )
250309 {
@@ -257,5 +316,6 @@ public void TestVersion()
257316 // Assert.False(string.IsNullOrWhiteSpace(desc));
258317 // Assert.NotEqual(version.Trim(), desc.Trim());
259318 }
319+
260320 }
261321}
0 commit comments