-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathRetryHttpClientHandlerUTest.cs
160 lines (136 loc) · 5.49 KB
/
RetryHttpClientHandlerUTest.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// --------------------------------------------------------------------------------------------------------------------
// SPDX-FileCopyrightText: 2025 Siemens AG
//
// SPDX-License-Identifier: MIT
// --------------------------------------------------------------------------------------------------------------------
using log4net;
using Moq.Protected;
using Moq;
using System.Net;
namespace LCT.APICommunications.UTest
{
public class RetryHttpClientHandlerUTest
{
private Mock<ILog> _mockLogger;
[SetUp]
public void SetUp()
{
// Mock the logger
_mockLogger = new Mock<ILog>();
}
[Test]
public async Task SendAsync_ShouldRetry_OnTransientErrors()
{
// Arrange
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
.SetupSequence<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ThrowsAsync(new HttpRequestException())
.ThrowsAsync(new TaskCanceledException())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
var retryHandler = new RetryHttpClientHandler
{
InnerHandler = handlerMock.Object
};
var httpClient = new HttpClient(retryHandler);
// Act
var response = await httpClient.GetAsync("http://test.com");
// Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(3), // 2 retries + 1 initial call
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>());
}
[Test]
public async Task SendAsync_ShouldNotRetry_OnNonTransientErrors()
{
// Arrange
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.BadRequest));
var retryHandler = new RetryHttpClientHandler
{
InnerHandler = handlerMock.Object
};
var httpClient = new HttpClient(retryHandler);
// Act
var response = await httpClient.GetAsync("http://test.com");
// Assert
Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
handlerMock.Protected().Verify(
"SendAsync",
Times.Once(), // No retries
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>());
}
[Test]
public async Task SendAsync_ShouldLogRetryAttempts()
{
// Arrange
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
.SetupSequence<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ThrowsAsync(new HttpRequestException())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
var retryHandler = new RetryHttpClientHandler()
{
InnerHandler = handlerMock.Object
};
var httpClient = new HttpClient(retryHandler);
// Act
var response = await httpClient.GetAsync("http://test.com");
// Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
[Test]
public async Task ExecuteWithRetryAsync_ShouldCompleteSuccessfully_WhenActionSucceedsAfterRetry()
{
// Arrange
var attempts = 0;
var action = new Func<Task>(() =>
{
attempts++;
if (attempts < ApiConstant.APIRetryIntervals.Count)
{
throw new WebException("Temporary error", WebExceptionStatus.Timeout);
}
return Task.CompletedTask; // Successfully completes after retries
});
// Act
await RetryHttpClientHandler.ExecuteWithRetryAsync(action);
// Assert
Assert.AreEqual(ApiConstant.APIRetryIntervals.Count, attempts, "Action should have been attempted the expected number of times.");
}
[Test]
public async Task ExecuteWithRetryAsync_ShouldNotRetry_WhenNoWebExceptionIsThrown()
{
// Arrange
var actionExecuted = false;
var action = new Func<Task>(() =>
{
actionExecuted = true;
return Task.CompletedTask;
});
// Act
await RetryHttpClientHandler.ExecuteWithRetryAsync(action);
// Assert
Assert.IsTrue(actionExecuted, "Action should have been executed.");
_mockLogger.Verify(logger => logger.Debug(It.IsAny<string>()), Times.Never, "Retry should not occur if there is no exception.");
}
}
}