|
1 | 1 | package com.microsoft.kiota.http.middleware; |
2 | 2 |
|
3 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 4 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
| 5 | +import static org.mockito.Mockito.mock; |
| 6 | +import static org.mockito.Mockito.when; |
| 7 | + |
| 8 | +import com.microsoft.kiota.http.middleware.options.RetryHandlerOption; |
| 9 | + |
| 10 | +import io.opentelemetry.api.trace.Span; |
| 11 | + |
| 12 | +import okhttp3.Request; |
| 13 | +import okhttp3.Response; |
4 | 14 |
|
5 | 15 | import org.junit.jupiter.api.BeforeEach; |
| 16 | +import org.junit.jupiter.api.Test; |
6 | 17 | import org.junit.jupiter.params.ParameterizedTest; |
7 | 18 | import org.junit.jupiter.params.provider.Arguments; |
8 | 19 | import org.junit.jupiter.params.provider.MethodSource; |
@@ -58,4 +69,75 @@ void testTryParseTimeHeader(String headerValue, double expectedDelay) { |
58 | 69 | assertEquals( |
59 | 70 | expectedDelay, result, DELTA, "Failed for header value: '" + headerValue + "'"); |
60 | 71 | } |
| 72 | + |
| 73 | + @Test |
| 74 | + void testGetRetryAfterHandlesNegativeValues() { |
| 75 | + // Create a mock response with a Retry-After header that will fail parsing |
| 76 | + Response mockResponse = mock(Response.class); |
| 77 | + when(mockResponse.header("Retry-After")).thenReturn("invalid"); |
| 78 | + when(mockResponse.code()).thenReturn(429); |
| 79 | + |
| 80 | + // getRetryAfter should return a value between 1-10ms when parsing fails |
| 81 | + long retryAfter = retryHandler.getRetryAfter(mockResponse, 3, 1); |
| 82 | + assertTrue( |
| 83 | + retryAfter >= 1 && retryAfter <= 10, |
| 84 | + "Expected retry interval between 1-10ms, got " + retryAfter); |
| 85 | + } |
| 86 | + |
| 87 | + @Test |
| 88 | + void testRetryRequestHandlesNegativeRetryInterval() { |
| 89 | + // Create mocks |
| 90 | + Response mockResponse = mock(Response.class); |
| 91 | + Request mockRequest = mock(Request.class); |
| 92 | + RetryHandlerOption mockOption = mock(RetryHandlerOption.class); |
| 93 | + Span mockSpan = mock(Span.class); |
| 94 | + |
| 95 | + // Setup mock behaviors |
| 96 | + when(mockResponse.code()).thenReturn(429); |
| 97 | + when(mockResponse.header("Retry-After")).thenReturn("invalid"); |
| 98 | + when(mockRequest.method()).thenReturn("GET"); |
| 99 | + when(mockRequest.body()).thenReturn(null); |
| 100 | + when(mockOption.maxRetries()).thenReturn(3); |
| 101 | + when(mockOption.delay()).thenReturn(3L); |
| 102 | + when(mockOption.shouldRetry()) |
| 103 | + .thenReturn( |
| 104 | + (delay, executionCount, request, response) -> |
| 105 | + true); // Always retry for this test |
| 106 | + |
| 107 | + // Call retryRequest - it should not throw IllegalArgumentException |
| 108 | + // The main goal is to verify no exception is thrown when retry interval is negative |
| 109 | + boolean result = |
| 110 | + retryHandler.retryRequest(mockResponse, 1, mockRequest, mockOption, mockSpan); |
| 111 | + |
| 112 | + // Verify the method returned true (should retry) |
| 113 | + assertTrue(result, "Expected retryRequest to return true"); |
| 114 | + } |
| 115 | + |
| 116 | + @Test |
| 117 | + void testRetryRequestWithNegativeRetryIntervalAppliesRandomDelay() { |
| 118 | + // Create mocks |
| 119 | + Response mockResponse = mock(Response.class); |
| 120 | + Request mockRequest = mock(Request.class); |
| 121 | + RetryHandlerOption mockOption = mock(RetryHandlerOption.class); |
| 122 | + Span mockSpan = mock(Span.class); |
| 123 | + |
| 124 | + // Setup mock behaviors to force negative retry interval |
| 125 | + when(mockResponse.code()).thenReturn(503); |
| 126 | + when(mockResponse.header("Retry-After")).thenReturn("invalid"); |
| 127 | + when(mockRequest.method()).thenReturn("POST"); |
| 128 | + when(mockRequest.body()).thenReturn(null); |
| 129 | + when(mockOption.maxRetries()).thenReturn(5); |
| 130 | + when(mockOption.delay()).thenReturn(1L); |
| 131 | + when(mockOption.shouldRetry()) |
| 132 | + .thenReturn((delay, executionCount, request, response) -> true); |
| 133 | + |
| 134 | + // Test multiple times to verify no exception is thrown |
| 135 | + // This verifies the fix for negative retry intervals |
| 136 | + for (int i = 0; i < 5; i++) { |
| 137 | + boolean result = |
| 138 | + retryHandler.retryRequest(mockResponse, 1, mockRequest, mockOption, mockSpan); |
| 139 | + // Verify each call succeeds without throwing IllegalArgumentException |
| 140 | + assertTrue(result, "Expected retryRequest to return true on iteration " + i); |
| 141 | + } |
| 142 | + } |
61 | 143 | } |
0 commit comments