Skip to content

Commit 3acd547

Browse files
Add comprehensive test coverage for secondary rate limit handling
Co-authored-by: begonaguereca <[email protected]>
1 parent 820cbea commit 3acd547

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

src/OctoshiftCLI.Tests/Octoshift/Services/GithubClientTests.cs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,96 @@ public async Task PostAsync_Handles_Secondary_Rate_Limit_With_429_Status()
21122112
_mockOctoLogger.Verify(m => m.LogWarning(It.Is<string>(s => s.Contains("Secondary rate limit detected"))), Times.Once);
21132113
}
21142114

2115+
[Fact]
2116+
public async Task GetAsync_Handles_Secondary_Rate_Limit_With_Forbidden_Status()
2117+
{
2118+
// Arrange
2119+
var handlerMock = new Mock<HttpMessageHandler>();
2120+
handlerMock
2121+
.Protected()
2122+
.SetupSequence<Task<HttpResponseMessage>>(
2123+
"SendAsync",
2124+
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Get),
2125+
ItExpr.IsAny<CancellationToken>())
2126+
.ReturnsAsync(CreateHttpResponseFactory(
2127+
statusCode: HttpStatusCode.Forbidden,
2128+
content: "You have triggered an abuse detection mechanism",
2129+
headers: new[] { ("Retry-After", "2") })())
2130+
.ReturnsAsync(CreateHttpResponseFactory(content: "SUCCESS_RESPONSE")());
2131+
2132+
using var httpClient = new HttpClient(handlerMock.Object);
2133+
var githubClient = new GithubClient(_mockOctoLogger.Object, httpClient, null, _retryPolicy, _dateTimeProvider.Object, PERSONAL_ACCESS_TOKEN);
2134+
2135+
// Act
2136+
var result = await githubClient.GetAsync("http://example.com");
2137+
2138+
// Assert
2139+
result.Should().Be("SUCCESS_RESPONSE");
2140+
_mockOctoLogger.Verify(m => m.LogWarning("Secondary rate limit detected (attempt 1/3). Waiting 2 seconds before retrying..."), Times.Once);
2141+
}
2142+
2143+
[Fact]
2144+
public async Task SendAsync_Uses_Exponential_Backoff_When_No_Retry_Headers()
2145+
{
2146+
// Arrange
2147+
var handlerMock = new Mock<HttpMessageHandler>();
2148+
handlerMock
2149+
.Protected()
2150+
.SetupSequence<Task<HttpResponseMessage>>(
2151+
"SendAsync",
2152+
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Patch),
2153+
ItExpr.IsAny<CancellationToken>())
2154+
.ReturnsAsync(CreateHttpResponseFactory(
2155+
statusCode: HttpStatusCode.Forbidden,
2156+
content: "abuse detection mechanism")())
2157+
.ReturnsAsync(CreateHttpResponseFactory(
2158+
statusCode: HttpStatusCode.Forbidden,
2159+
content: "abuse detection mechanism")())
2160+
.ReturnsAsync(CreateHttpResponseFactory(content: "SUCCESS_RESPONSE")());
2161+
2162+
using var httpClient = new HttpClient(handlerMock.Object);
2163+
var githubClient = new GithubClient(_mockOctoLogger.Object, httpClient, null, _retryPolicy, _dateTimeProvider.Object, PERSONAL_ACCESS_TOKEN);
2164+
2165+
// Act
2166+
var result = await githubClient.PatchAsync("http://example.com", _rawRequestBody);
2167+
2168+
// Assert
2169+
result.Should().Be("SUCCESS_RESPONSE");
2170+
_mockOctoLogger.Verify(m => m.LogWarning("Secondary rate limit detected (attempt 1/3). Waiting 60 seconds before retrying..."), Times.Once);
2171+
_mockOctoLogger.Verify(m => m.LogWarning("Secondary rate limit detected (attempt 2/3). Waiting 120 seconds before retrying..."), Times.Once);
2172+
}
2173+
2174+
[Fact]
2175+
public async Task SendAsync_Throws_Exception_After_Max_Secondary_Rate_Limit_Retries()
2176+
{
2177+
// Arrange
2178+
var handlerMock = new Mock<HttpMessageHandler>();
2179+
handlerMock
2180+
.Protected()
2181+
.Setup<Task<HttpResponseMessage>>(
2182+
"SendAsync",
2183+
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Delete),
2184+
ItExpr.IsAny<CancellationToken>())
2185+
.ReturnsAsync(CreateHttpResponseFactory(
2186+
statusCode: HttpStatusCode.TooManyRequests,
2187+
content: "Too many requests")());
2188+
2189+
using var httpClient = new HttpClient(handlerMock.Object);
2190+
var githubClient = new GithubClient(_mockOctoLogger.Object, httpClient, null, _retryPolicy, _dateTimeProvider.Object, PERSONAL_ACCESS_TOKEN);
2191+
2192+
// Act & Assert
2193+
await FluentActions
2194+
.Invoking(async () => await githubClient.DeleteAsync("http://example.com"))
2195+
.Should()
2196+
.ThrowExactlyAsync<OctoshiftCliException>()
2197+
.WithMessage("Secondary rate limit exceeded. Maximum retries (3) reached. Please wait before retrying your request.");
2198+
2199+
// Verify all retry attempts were logged
2200+
_mockOctoLogger.Verify(m => m.LogWarning("Secondary rate limit detected (attempt 1/3). Waiting 60 seconds before retrying..."), Times.Once);
2201+
_mockOctoLogger.Verify(m => m.LogWarning("Secondary rate limit detected (attempt 2/3). Waiting 120 seconds before retrying..."), Times.Once);
2202+
_mockOctoLogger.Verify(m => m.LogWarning("Secondary rate limit detected (attempt 3/3). Waiting 240 seconds before retrying..."), Times.Once);
2203+
}
2204+
21152205
private object CreateRepositoryMigration(string migrationId = null, string state = RepositoryMigrationStatus.Succeeded) => new
21162206
{
21172207
id = migrationId ?? Guid.NewGuid().ToString(),

0 commit comments

Comments
 (0)