|
17 | 17 |
|
18 | 18 | package org.openqa.selenium.remote.http; |
19 | 19 |
|
20 | | -import static java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT; |
21 | 20 | import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; |
22 | 21 | import static java.net.HttpURLConnection.HTTP_OK; |
23 | 22 | import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; |
|
26 | 25 | import static org.openqa.selenium.remote.http.HttpMethod.GET; |
27 | 26 |
|
28 | 27 | import com.google.common.collect.ImmutableMap; |
| 28 | +import java.io.IOException; |
| 29 | +import java.io.UncheckedIOException; |
| 30 | +import java.net.ConnectException; |
29 | 31 | import java.net.MalformedURLException; |
30 | 32 | import java.net.URI; |
31 | 33 | import java.time.Duration; |
|
37 | 39 | import java.util.concurrent.Executors; |
38 | 40 | import java.util.concurrent.Future; |
39 | 41 | import java.util.concurrent.atomic.AtomicInteger; |
| 42 | +import java.util.concurrent.atomic.AtomicReference; |
40 | 43 | import org.junit.jupiter.api.Assertions; |
41 | 44 | import org.junit.jupiter.api.BeforeEach; |
42 | 45 | import org.junit.jupiter.api.Test; |
@@ -73,6 +76,29 @@ void canThrowUnexpectedException() { |
73 | 76 | UnsupportedOperationException.class, () -> handler.execute(new HttpRequest(GET, "/"))); |
74 | 77 | } |
75 | 78 |
|
| 79 | + @Test |
| 80 | + void noUnexpectedRetry() { |
| 81 | + AtomicInteger count = new AtomicInteger(); |
| 82 | + HttpHandler handler = |
| 83 | + new RetryRequest() |
| 84 | + .andFinally( |
| 85 | + (HttpRequest request) -> { |
| 86 | + if (count.getAndIncrement() == 0) { |
| 87 | + throw new StackOverflowError("Testing"); |
| 88 | + } else { |
| 89 | + throw new UncheckedIOException("More testing", new IOException()); |
| 90 | + } |
| 91 | + }); |
| 92 | + |
| 93 | + Assertions.assertThrows( |
| 94 | + StackOverflowError.class, () -> handler.execute(new HttpRequest(GET, "/"))); |
| 95 | + Assertions.assertEquals(1, count.get()); |
| 96 | + |
| 97 | + Assertions.assertThrows( |
| 98 | + UncheckedIOException.class, () -> handler.execute(new HttpRequest(GET, "/"))); |
| 99 | + Assertions.assertEquals(2, count.get()); |
| 100 | + } |
| 101 | + |
76 | 102 | @Test |
77 | 103 | void canReturnAppropriateFallbackResponse() { |
78 | 104 | HttpHandler handler1 = |
@@ -106,17 +132,23 @@ void canReturnAppropriateFallbackResponseWithMultipleThreads() |
106 | 132 | new RetryRequest() |
107 | 133 | .andFinally((HttpRequest request) -> new HttpResponse().setStatus(HTTP_UNAVAILABLE)); |
108 | 134 |
|
109 | | - ExecutorService executorService = Executors.newFixedThreadPool(2); |
| 135 | + ExecutorService executorService = Executors.newFixedThreadPool(3); |
110 | 136 | List<Callable<HttpResponse>> tasks = new ArrayList<>(); |
111 | 137 |
|
112 | | - tasks.add(() -> client.execute(connectionTimeoutRequest)); |
113 | | - tasks.add(() -> handler2.execute(new HttpRequest(GET, "/"))); |
| 138 | + for (int i = 0; i < 1024; i++) { |
| 139 | + tasks.add(() -> client.execute(connectionTimeoutRequest)); |
| 140 | + tasks.add(() -> handler2.execute(new HttpRequest(GET, "/"))); |
| 141 | + } |
114 | 142 |
|
115 | 143 | List<Future<HttpResponse>> results = executorService.invokeAll(tasks); |
116 | 144 |
|
117 | | - Assertions.assertEquals(HTTP_CLIENT_TIMEOUT, results.get(0).get().getStatus()); |
| 145 | + for (int i = 0; i < 1024; i++) { |
| 146 | + int offset = i * 2; |
| 147 | + Assertions.assertThrows(ExecutionException.class, () -> results.get(offset).get()); |
| 148 | + Assertions.assertEquals(HTTP_UNAVAILABLE, results.get(offset + 1).get().getStatus()); |
| 149 | + } |
118 | 150 |
|
119 | | - Assertions.assertEquals(HTTP_UNAVAILABLE, results.get(1).get().getStatus()); |
| 151 | + executorService.shutdown(); |
120 | 152 | } |
121 | 153 |
|
122 | 154 | @Test |
@@ -266,13 +298,59 @@ void shouldGetTheErrorResponseOnServerUnavailableError() { |
266 | 298 |
|
267 | 299 | @Test |
268 | 300 | void shouldBeAbleToRetryARequestOnConnectionFailure() { |
269 | | - AppServer server = new NettyAppServer(req -> new HttpResponse()); |
| 301 | + AtomicInteger count = new AtomicInteger(0); |
| 302 | + HttpHandler handler = |
| 303 | + new RetryRequest() |
| 304 | + .andFinally( |
| 305 | + (HttpRequest request) -> { |
| 306 | + if (count.getAndIncrement() < 2) { |
| 307 | + throw new UncheckedIOException(new ConnectException()); |
| 308 | + } else { |
| 309 | + return new HttpResponse(); |
| 310 | + } |
| 311 | + }); |
270 | 312 |
|
271 | | - URI uri = URI.create(server.whereIs("/")); |
272 | | - HttpRequest request = |
273 | | - new HttpRequest(GET, String.format(REQUEST_PATH, uri.getHost(), uri.getPort())); |
| 313 | + HttpRequest request = new HttpRequest(GET, "/"); |
| 314 | + HttpResponse response = handler.execute(request); |
274 | 315 |
|
275 | | - HttpResponse response = client.execute(request); |
276 | | - assertThat(response).extracting(HttpResponse::getStatus).isEqualTo(HTTP_CLIENT_TIMEOUT); |
| 316 | + assertThat(response).extracting(HttpResponse::getStatus).isEqualTo(HTTP_OK); |
| 317 | + assertThat(count.get()).isEqualTo(3); |
| 318 | + } |
| 319 | + |
| 320 | + @Test |
| 321 | + void shouldRethrowOnConnectFailure() { |
| 322 | + AtomicInteger count = new AtomicInteger(0); |
| 323 | + AtomicReference<UncheckedIOException> lastThrown = new AtomicReference<>(); |
| 324 | + HttpHandler handler = |
| 325 | + new RetryRequest() |
| 326 | + .andFinally( |
| 327 | + (HttpRequest request) -> { |
| 328 | + count.getAndIncrement(); |
| 329 | + lastThrown.set(new UncheckedIOException(new ConnectException())); |
| 330 | + throw lastThrown.get(); |
| 331 | + }); |
| 332 | + |
| 333 | + UncheckedIOException thrown = |
| 334 | + Assertions.assertThrows( |
| 335 | + UncheckedIOException.class, () -> handler.execute(new HttpRequest(GET, "/"))); |
| 336 | + assertThat(thrown).isSameAs(lastThrown.get()); |
| 337 | + assertThat(count.get()).isEqualTo(4); |
| 338 | + } |
| 339 | + |
| 340 | + @Test |
| 341 | + void shouldDeliverUnmodifiedServerErrors() { |
| 342 | + AtomicInteger count = new AtomicInteger(0); |
| 343 | + AtomicReference<HttpResponse> lastResponse = new AtomicReference<>(); |
| 344 | + HttpHandler handler = |
| 345 | + new RetryRequest() |
| 346 | + .andFinally( |
| 347 | + (HttpRequest request) -> { |
| 348 | + count.getAndIncrement(); |
| 349 | + lastResponse.set(new HttpResponse().setStatus(500)); |
| 350 | + return lastResponse.get(); |
| 351 | + }); |
| 352 | + |
| 353 | + assertThat(handler.execute(new HttpRequest(GET, "/"))).isSameAs(lastResponse.get()); |
| 354 | + assertThat(count.get()).isEqualTo(3); |
277 | 355 | } |
278 | 356 | } |
0 commit comments