View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.testing.classic;
29  
30  import static org.hamcrest.MatcherAssert.assertThat;
31  
32  import java.io.IOException;
33  import java.util.concurrent.CountDownLatch;
34  import java.util.concurrent.ExecutorService;
35  import java.util.concurrent.Executors;
36  import java.util.concurrent.TimeUnit;
37  import java.util.concurrent.atomic.AtomicLong;
38  import java.util.concurrent.atomic.AtomicReference;
39  
40  import org.apache.hc.core5.http.ClassicHttpRequest;
41  import org.apache.hc.core5.http.ClassicHttpResponse;
42  import org.apache.hc.core5.http.ContentType;
43  import org.apache.hc.core5.http.HttpHost;
44  import org.apache.hc.core5.http.HttpStatus;
45  import org.apache.hc.core5.http.Method;
46  import org.apache.hc.core5.http.URIScheme;
47  import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
48  import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
49  import org.apache.hc.core5.http.io.entity.EntityUtils;
50  import org.apache.hc.core5.http.io.entity.StringEntity;
51  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
52  import org.apache.hc.core5.http.protocol.HttpCoreContext;
53  import org.apache.hc.core5.util.Timeout;
54  import org.hamcrest.CoreMatchers;
55  import org.junit.jupiter.api.Assertions;
56  import org.junit.jupiter.api.Test;
57  
58  public abstract class ClassicHttpCoreTransportTest {
59  
60      private static final Timeout TIMEOUT = Timeout.ofMinutes(1);
61  
62      private final URIScheme scheme;
63  
64      public ClassicHttpCoreTransportTest(final URIScheme scheme) {
65          this.scheme = scheme;
66      }
67  
68      abstract HttpServer serverStart() throws IOException;
69  
70      abstract HttpRequester clientStart() throws IOException;
71  
72      @Test
73      public void testSequentialRequests() throws Exception {
74          final HttpServer server = serverStart();
75          final HttpRequester requester = clientStart();
76  
77          final HttpHost target = new HttpHost(scheme.id, "localhost", server.getLocalPort());
78          final HttpCoreContext context = HttpCoreContext.create();
79          final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/stuff");
80          request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
81          try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
82              assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
83              final String body1 = EntityUtils.toString(response1.getEntity());
84              assertThat(body1, CoreMatchers.equalTo("some stuff"));
85          }
86          final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/other-stuff");
87          request2.setEntity(new StringEntity("some other stuff", ContentType.TEXT_PLAIN));
88          try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
89              assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
90              final String body2 = EntityUtils.toString(response2.getEntity());
91              assertThat(body2, CoreMatchers.equalTo("some other stuff"));
92          }
93          final ClassicHttpRequest request3 = new BasicClassicHttpRequest(Method.POST, "/more-stuff");
94          request3.setEntity(new StringEntity("some more stuff", ContentType.TEXT_PLAIN));
95          try (final ClassicHttpResponse response3 = requester.execute(target, request3, TIMEOUT, context)) {
96              assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
97              final String body3 = EntityUtils.toString(response3.getEntity());
98              assertThat(body3, CoreMatchers.equalTo("some more stuff"));
99          }
100     }
101 
102     @Test
103     public void testSequentialRequestsNonPersistentConnection() throws Exception {
104         final HttpServer server = serverStart();
105         final HttpRequester requester = clientStart();
106 
107         final HttpHost target = new HttpHost(scheme.id, "localhost", server.getLocalPort());
108         final HttpCoreContext context = HttpCoreContext.create();
109         final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/stuff");
110         request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
111         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
112             assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
113             final String body1 = EntityUtils.toString(response1.getEntity());
114             assertThat(body1, CoreMatchers.equalTo("some stuff"));
115         }
116         final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/other-stuff");
117         request2.setEntity(new StringEntity("some other stuff", ContentType.TEXT_PLAIN));
118         try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
119             assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
120             final String body2 = EntityUtils.toString(response2.getEntity());
121             assertThat(body2, CoreMatchers.equalTo("some other stuff"));
122         }
123         final ClassicHttpRequest request3 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/more-stuff");
124         request3.setEntity(new StringEntity("some more stuff", ContentType.TEXT_PLAIN));
125         try (final ClassicHttpResponse response3 = requester.execute(target, request3, TIMEOUT, context)) {
126             assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
127             final String body3 = EntityUtils.toString(response3.getEntity());
128             assertThat(body3, CoreMatchers.equalTo("some more stuff"));
129         }
130     }
131 
132     @Test
133     public void testMultiThreadedRequests() throws Exception {
134         final HttpServer server = serverStart();
135         final HttpRequester requester = clientStart();
136 
137         final int c = 10;
138         final CountDownLatch latch = new CountDownLatch(c);
139         final AtomicLong n = new AtomicLong(c + 100);
140         final AtomicReference<AssertionError> exRef = new AtomicReference<>();
141         final ExecutorService executorService = Executors.newFixedThreadPool(c);
142         try {
143             final HttpHost target = new HttpHost(scheme.id, "localhost", server.getLocalPort());
144             for (int i = 0; i < c; i++) {
145                 executorService.execute(() -> {
146                     try {
147                         while (n.decrementAndGet() > 0) {
148                             try {
149                                 final HttpCoreContext context = HttpCoreContext.create();
150                                 final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/stuff");
151                                 request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
152                                 requester.execute(target, request1, TIMEOUT, context, response -> {
153                                     Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
154                                     Assertions.assertEquals("some stuff", EntityUtils.toString(response.getEntity()));
155                                     return null;
156                                 });
157                             } catch (final Exception ex) {
158                                 Assertions.fail(ex);
159                             }
160                         }
161                     } catch (final AssertionError ex) {
162                         exRef.compareAndSet(null, ex);
163                     } finally {
164                         latch.countDown();
165                     }
166                 });
167             }
168             Assertions.assertTrue(latch.await(5, TimeUnit.MINUTES));
169         } finally {
170             executorService.shutdownNow();
171         }
172 
173         final AssertionError assertionError = exRef.get();
174         if (assertionError != null) {
175             throw assertionError;
176         }
177     }
178 
179 }