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 package org.apache.hc.client5.http.impl;
28
29 import java.io.IOException;
30 import java.net.ConnectException;
31 import java.net.NoRouteToHostException;
32 import java.net.SocketTimeoutException;
33 import java.net.UnknownHostException;
34 import java.time.Instant;
35 import java.time.temporal.ChronoUnit;
36 import javax.net.ssl.SSLException;
37 import org.apache.hc.client5.http.classic.methods.HttpGet;
38 import org.apache.hc.client5.http.config.RequestConfig;
39 import org.apache.hc.client5.http.protocol.HttpClientContext;
40 import org.apache.hc.client5.http.utils.DateUtils;
41 import org.apache.hc.core5.http.ConnectionClosedException;
42 import org.apache.hc.core5.http.HttpHeaders;
43 import org.apache.hc.core5.http.HttpResponse;
44 import org.apache.hc.core5.http.message.BasicHttpResponse;
45 import org.apache.hc.core5.util.TimeValue;
46 import org.apache.hc.core5.util.Timeout;
47 import org.junit.jupiter.api.Assertions;
48 import org.junit.jupiter.api.BeforeEach;
49 import org.junit.jupiter.api.Test;
50
51 class TestDefaultHttpRequestRetryStrategy {
52
53 private DefaultHttpRequestRetryStrategy retryStrategy;
54
55 @BeforeEach
56 void setup() {
57 this.retryStrategy = new DefaultHttpRequestRetryStrategy(3, TimeValue.ofMilliseconds(1234L));
58 }
59
60 @Test
61 void testBasics() {
62 final HttpResponse response1 = new BasicHttpResponse(503, "Oopsie");
63 Assertions.assertTrue(this.retryStrategy.retryRequest(response1, 1, null));
64 Assertions.assertTrue(this.retryStrategy.retryRequest(response1, 2, null));
65 Assertions.assertTrue(this.retryStrategy.retryRequest(response1, 3, null));
66 Assertions.assertFalse(this.retryStrategy.retryRequest(response1, 4, null));
67 final HttpResponse response2 = new BasicHttpResponse(500, "Big Time Oopsie");
68 Assertions.assertFalse(this.retryStrategy.retryRequest(response2, 1, null));
69 final HttpResponse response3 = new BasicHttpResponse(429, "Oopsie");
70 Assertions.assertTrue(this.retryStrategy.retryRequest(response3, 1, null));
71 Assertions.assertTrue(this.retryStrategy.retryRequest(response3, 2, null));
72 Assertions.assertTrue(this.retryStrategy.retryRequest(response3, 3, null));
73 Assertions.assertFalse(this.retryStrategy.retryRequest(response3, 4, null));
74
75 Assertions.assertEquals(TimeValue.ofMilliseconds(1234L), this.retryStrategy.getRetryInterval(response1, 1, null));
76 }
77
78 @Test
79 void testRetryRequestWithResponseTimeout() {
80 final HttpResponse response = new BasicHttpResponse(503, "Oopsie");
81
82 final HttpClientContext context = HttpClientContext.create();
83 context.setRequestConfig(RequestConfig.custom()
84 .build());
85
86 Assertions.assertTrue(retryStrategy.retryRequest(response, 1, context));
87
88 context.setRequestConfig(RequestConfig.custom()
89 .setResponseTimeout(Timeout.ofMilliseconds(1234L))
90 .build());
91
92 Assertions.assertTrue(retryStrategy.retryRequest(response, 1, context));
93
94 context.setRequestConfig(RequestConfig.custom()
95 .setResponseTimeout(Timeout.ofMilliseconds(1233L))
96 .build());
97
98 Assertions.assertFalse(retryStrategy.retryRequest(response, 1, context));
99 }
100
101 @Test
102 void testRetryAfterHeaderAsLong() {
103 final HttpResponse response = new BasicHttpResponse(503, "Oopsie");
104 response.setHeader(HttpHeaders.RETRY_AFTER, "321");
105
106 Assertions.assertEquals(TimeValue.ofSeconds(321L), this.retryStrategy.getRetryInterval(response, 3, null));
107 }
108
109 @Test
110 void testRetryAfterHeaderAsDate() {
111 this.retryStrategy = new DefaultHttpRequestRetryStrategy(3, TimeValue.ZERO_MILLISECONDS);
112 final HttpResponse response = new BasicHttpResponse(503, "Oopsie");
113 response.setHeader(HttpHeaders.RETRY_AFTER, DateUtils.formatStandardDate(Instant.now().plus(100, ChronoUnit.SECONDS)));
114
115 Assertions.assertTrue(this.retryStrategy.getRetryInterval(response, 3, null).compareTo(TimeValue.ZERO_MILLISECONDS) > 0);
116 }
117
118 @Test
119 void testRetryAfterHeaderAsPastDate() {
120 final HttpResponse response = new BasicHttpResponse(503, "Oopsie");
121 response.setHeader(HttpHeaders.RETRY_AFTER, DateUtils.formatStandardDate(Instant.now().minus(100, ChronoUnit.SECONDS)));
122
123 Assertions.assertEquals(TimeValue.ofMilliseconds(1234L), this.retryStrategy.getRetryInterval(response, 3, null));
124 }
125
126 @Test
127 void testInvalidRetryAfterHeader() {
128 final HttpResponse response = new BasicHttpResponse(503, "Oopsie");
129 response.setHeader(HttpHeaders.RETRY_AFTER, "Stuff");
130
131 Assertions.assertEquals(TimeValue.ofMilliseconds(1234L), retryStrategy.getRetryInterval(response, 3, null));
132 }
133
134 @Test
135 void noRetryOnConnectTimeout() {
136 final HttpGet request = new HttpGet("/");
137
138 Assertions.assertFalse(retryStrategy.retryRequest(request, new SocketTimeoutException(), 1, null));
139 }
140
141 @Test
142 void noRetryOnConnect() {
143 final HttpGet request = new HttpGet("/");
144
145 Assertions.assertFalse(retryStrategy.retryRequest(request, new ConnectException(), 1, null));
146 }
147
148 @Test
149 void noRetryOnConnectionClosed() {
150 final HttpGet request = new HttpGet("/");
151
152 Assertions.assertFalse(retryStrategy.retryRequest(request, new ConnectionClosedException(), 1, null));
153 }
154
155 @Test
156 void noRetryForNoRouteToHostException() {
157 final HttpGet request = new HttpGet("/");
158
159 Assertions.assertFalse(retryStrategy.retryRequest(request, new NoRouteToHostException(), 1, null));
160 }
161
162 @Test
163 void noRetryOnSSLFailure() {
164 final HttpGet request = new HttpGet("/");
165
166 Assertions.assertFalse(retryStrategy.retryRequest(request, new SSLException("encryption failed"), 1, null));
167 }
168
169 @Test
170 void noRetryOnUnknownHost() {
171 final HttpGet request = new HttpGet("/");
172
173 Assertions.assertFalse(retryStrategy.retryRequest(request, new UnknownHostException(), 1, null));
174 }
175
176 @Test
177 void noRetryOnAbortedRequests() {
178 final HttpGet request = new HttpGet("/");
179 request.cancel();
180
181 Assertions.assertFalse(retryStrategy.retryRequest(request, new IOException(), 1, null));
182 }
183
184 @Test
185 void retryOnNonAbortedRequests() {
186 final HttpGet request = new HttpGet("/");
187
188 Assertions.assertTrue(retryStrategy.retryRequest(request, new IOException(), 1, null));
189 }
190
191 }