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.testing.async;
28
29 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
30 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
31 import org.apache.hc.client5.http.config.RequestConfig;
32 import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
33 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
34 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
35 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
36 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
37 import org.apache.hc.core5.function.Decorator;
38 import org.apache.hc.core5.function.Resolver;
39 import org.apache.hc.core5.http.HttpHost;
40 import org.apache.hc.core5.http.HttpRequest;
41 import org.apache.hc.core5.http.HttpStatus;
42 import org.apache.hc.core5.http.HttpVersion;
43 import org.apache.hc.core5.http.URIScheme;
44 import org.apache.hc.core5.http.config.Http1Config;
45 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
46 import org.apache.hc.core5.http2.HttpVersionPolicy;
47 import org.apache.hc.core5.http2.config.H2Config;
48 import org.apache.hc.core5.util.TimeValue;
49 import org.hamcrest.CoreMatchers;
50 import org.junit.Assert;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.rules.ExternalResource;
54 import org.junit.runner.RunWith;
55 import org.junit.runners.Parameterized;
56
57 import java.util.Arrays;
58 import java.util.Collection;
59 import java.util.concurrent.Future;
60 import java.util.concurrent.atomic.AtomicInteger;
61
62 @RunWith(Parameterized.class)
63 public class TestHttp1RequestReExecution extends AbstractIntegrationTestBase<CloseableHttpAsyncClient> {
64
65 @Parameterized.Parameters(name = "{0}")
66 public static Collection<Object[]> protocolVersions() {
67 return Arrays.asList(new Object[][]{
68 { HttpVersion.HTTP_1_1 },
69 { HttpVersion.HTTP_2 }
70 });
71 }
72
73 private final HttpVersion version;
74
75 public TestHttp1RequestReExecution(final HttpVersion version) {
76 super(URIScheme.HTTP);
77 this.version = version;
78 }
79
80 HttpAsyncClientBuilder clientBuilder;
81 PoolingAsyncClientConnectionManager connManager;
82
83 @Rule
84 public ExternalResource connManagerResource = new ExternalResource() {
85
86 @Override
87 protected void before() throws Throwable {
88 connManager = PoolingAsyncClientConnectionManagerBuilder.create()
89 .build();
90 }
91
92 @Override
93 protected void after() {
94 if (connManager != null) {
95 connManager.close();
96 connManager = null;
97 }
98 }
99
100 };
101
102 @Rule
103 public ExternalResource clientBuilderResource = new ExternalResource() {
104
105 @Override
106 protected void before() throws Throwable {
107 clientBuilder = HttpAsyncClientBuilder.create()
108 .setDefaultRequestConfig(RequestConfig.custom()
109 .setConnectionRequestTimeout(TIMEOUT)
110 .setConnectTimeout(TIMEOUT)
111 .build())
112 .setConnectionManager(connManager)
113 .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2) ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1);
114 }
115
116 };
117
118 @Override
119 public final HttpHost start() throws Exception {
120
121 final Resolver<HttpRequest, TimeValue> serviceAvailabilityResolver = new Resolver<HttpRequest, TimeValue>() {
122
123 private final AtomicInteger count = new AtomicInteger(0);
124
125 @Override
126 public TimeValue resolve(final HttpRequest request) {
127 final int n = count.incrementAndGet();
128 return n <= 3 ? TimeValue.ofSeconds(1) : null;
129 }
130
131 };
132
133 if (version.greaterEquals(HttpVersion.HTTP_2)) {
134 return super.start(null, new Decorator<AsyncServerExchangeHandler>() {
135
136 @Override
137 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler handler) {
138 return new ServiceUnavailableAsyncDecorator(handler, serviceAvailabilityResolver);
139 }
140
141 }, H2Config.DEFAULT);
142 } else {
143 return super.start(null, new Decorator<AsyncServerExchangeHandler>() {
144
145 @Override
146 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler handler) {
147 return new ServiceUnavailableAsyncDecorator(handler, serviceAvailabilityResolver);
148 }
149
150 }, Http1Config.DEFAULT);
151 }
152 }
153
154 @Override
155 protected CloseableHttpAsyncClient createClient() throws Exception {
156 return clientBuilder.build();
157 }
158
159 @Test
160 public void testGiveUpAfterOneRetry() throws Exception {
161 clientBuilder.setRetryStrategy(new DefaultHttpRequestRetryStrategy(1, TimeValue.ofSeconds(1)));
162 final HttpHost target = start();
163 final Future<SimpleHttpResponse> future = httpclient.execute(
164 SimpleRequestBuilder.get()
165 .setHttpHost(target)
166 .setPath("/random/2048")
167 .build(), null);
168 final SimpleHttpResponse response = future.get();
169 Assert.assertThat(response, CoreMatchers.notNullValue());
170 Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_SERVICE_UNAVAILABLE));
171 }
172
173 @Test
174 public void testDoNotGiveUpEasily() throws Exception {
175 clientBuilder.setRetryStrategy(new DefaultHttpRequestRetryStrategy(5, TimeValue.ofSeconds(1)));
176 final HttpHost target = start();
177 final Future<SimpleHttpResponse> future = httpclient.execute(
178 SimpleRequestBuilder.get()
179 .setHttpHost(target)
180 .setPath("/random/2048")
181 .build(), null);
182 final SimpleHttpResponse response = future.get();
183 Assert.assertThat(response, CoreMatchers.notNullValue());
184 Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
185 }
186
187 }