2d4de82b043ebc5c527a261958fd7aef6d012dc9
[policy/common.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2020 Nordix Foundation.
7  * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.common.endpoints.http.server.test;
24
25 import static org.assertj.core.api.Assertions.assertThat;
26 import static org.assertj.core.api.Assertions.assertThatCode;
27 import static org.assertj.core.api.Assertions.assertThatThrownBy;
28 import static org.assertj.core.api.Assertions.catchThrowable;
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertFalse;
31 import static org.junit.Assert.assertNotNull;
32 import static org.junit.Assert.assertTrue;
33
34 import com.google.gson.Gson;
35 import io.prometheus.client.exporter.MetricsServlet;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.net.HttpURLConnection;
39 import java.net.MalformedURLException;
40 import java.net.URL;
41 import java.net.URLConnection;
42 import java.nio.charset.StandardCharsets;
43 import java.util.UUID;
44 import org.apache.commons.io.IOUtils;
45 import org.junit.AfterClass;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
49 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
50 import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler;
51 import org.onap.policy.common.utils.coder.StandardYamlCoder;
52 import org.onap.policy.common.utils.gson.GsonTestUtils;
53 import org.onap.policy.common.utils.network.NetworkUtil;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 /**
58  * HttpServletServer JUNIT tests.
59  */
60 public class HttpServerTest {
61     private static final String JVM_MEMORY_BYTES_USED = "jvm_memory_bytes_used";
62     private static final String METRICS_URI = "/metrics";
63     private static final String PROMETHEUS = "prometheus";
64     private static final String LOCALHOST = "localhost";
65     private static final String JSON_MEDIA = "application/json";
66     private static final String YAML_MEDIA = YamlMessageBodyHandler.APPLICATION_YAML;
67     private static final String SWAGGER_JSON = "/swagger.json";
68     private static final String JUNIT_ECHO_HELLO = "/junit/echo/hello";
69     private static final String JUNIT_ECHO_FULL_REQUEST = "/junit/echo/full/request";
70     private static final String SOME_TEXT = "some text";
71     private static final String HELLO = "hello";
72
73     /**
74      * Logger.
75      */
76     private static Logger logger = LoggerFactory.getLogger(HttpServerTest.class);
77
78     private static final String LOCALHOST_PREFIX = "http://localhost:";
79
80     private static final Gson gson = new Gson();
81
82     /**
83      * Server port.  Incremented by 10 with each test.
84      */
85     private static int port = 5608;
86
87     private String portUrl;
88
89     /**
90      * Increments the port number, clears the servers, and resets the providers.
91      */
92     @Before
93     public void setUp() {
94         incrementPort();
95         portUrl = LOCALHOST_PREFIX + port;
96
97         HttpServletServerFactoryInstance.getServerFactory().destroy();
98
99         MyGsonProvider.resetSome();
100         MyYamlProvider.resetSome();
101     }
102
103     private static void incrementPort() {
104         port += 10;
105     }
106
107     /**
108      * To delete temporary properties cadi_longitude,and cadi_latitude.
109      */
110     @AfterClass
111     public static void tearDownAfterClass() {
112         HttpServletServerFactoryInstance.getServerFactory().destroy();
113         System.clearProperty("cadi_longitude");
114         System.clearProperty("cadi_latitude");
115     }
116
117     @Test
118     public void testDefaultPackageServer() throws Exception {
119         logger.info("-- testDefaultPackageServer() --");
120
121         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
122                         .build("echo", LOCALHOST, port, "/", false, true);
123         server.addServletPackage("/*", this.getClass().getPackage().getName());
124         server.addFilterClass("/*", TestFilter.class.getName());
125         server.waitedStart(5000);
126
127         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
128
129         RestEchoReqResp request = new RestEchoReqResp();
130         request.setRequestId(100);
131         request.setText(SOME_TEXT);
132         String reqText = gson.toJson(request);
133
134         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
135         assertEquals(reqText, response);
136     }
137
138     @Test
139     public void testGsonPackageServer() throws Exception {
140         logger.info("-- testGsonPackageServer() --");
141
142         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
143                         .build("echo", LOCALHOST, port, "/", false, true);
144
145         server.setSerializationProvider(MyGsonProvider.class.getName());
146         server.addServletPackage("/*", this.getClass().getPackage().getName());
147         server.addFilterClass("/*", TestFilter.class.getName());
148         server.waitedStart(5000);
149
150         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
151
152         RestEchoReqResp request = new RestEchoReqResp();
153         request.setRequestId(100);
154         request.setText(SOME_TEXT);
155         String reqText = gson.toJson(request);
156
157         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
158         assertEquals(reqText, response);
159
160         assertTrue(MyGsonProvider.hasReadSome());
161         assertTrue(MyGsonProvider.hasWrittenSome());
162
163         assertFalse(MyYamlProvider.hasReadSome());
164         assertFalse(MyYamlProvider.hasWrittenSome());
165     }
166
167     @Test
168     public void testYamlPackageServer() throws Exception {
169         logger.info("-- testYamlPackageServer() --");
170
171         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
172                         .build("echo", LOCALHOST, port, "/", false, true);
173
174         server.setSerializationProvider(MyYamlProvider.class.getName());
175         server.addServletPackage("/*", this.getClass().getPackage().getName());
176         server.addFilterClass("/*", TestFilter.class.getName());
177         server.waitedStart(5000);
178
179         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
180
181         RestEchoReqResp request = new RestEchoReqResp();
182         request.setRequestId(100);
183         request.setText(SOME_TEXT);
184         String reqText = new StandardYamlCoder().encode(request);
185
186         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, YAML_MEDIA, reqText);
187
188         // response reader strips newlines, so we should, too, before comparing
189         assertEquals(reqText.replace("\n", ""), response);
190
191         assertTrue(MyYamlProvider.hasReadSome());
192         assertTrue(MyYamlProvider.hasWrittenSome());
193
194         assertFalse(MyGsonProvider.hasReadSome());
195         assertFalse(MyGsonProvider.hasWrittenSome());
196     }
197
198     @Test
199     public void testDefaultClassServer() throws Exception {
200         logger.info("-- testDefaultClassServer() --");
201
202         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
203                         .build("echo", LOCALHOST, port, "/", false, true);
204         server.addServletClass("/*", RestEchoService.class.getName());
205         server.addFilterClass("/*", TestFilter.class.getName());
206         server.waitedStart(5000);
207
208         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
209
210         RestEchoReqResp request = new RestEchoReqResp();
211         request.setRequestId(100);
212         request.setText(SOME_TEXT);
213         String reqText = gson.toJson(request);
214
215         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
216         assertEquals(reqText, response);
217     }
218
219     /**
220      * This test checks a server from a plain java servlet (note it uses prometheus as the sample server).
221      */
222     @Test
223     public void testStdServletServer() throws Exception {
224         logger.info("-- testStdServletServer() --");
225
226         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
227             .build(PROMETHEUS, LOCALHOST, port, "/", false, true);
228
229         server.addStdServletClass("/prom-generic-servlet/metrics", MetricsServlet.class.getName());
230         server.waitedStart(5000);
231
232         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
233         assertTrue(server.isPrometheus());
234
235         String response = http(portUrl + "/prom-generic-servlet/metrics");
236         assertThat(response).contains(JVM_MEMORY_BYTES_USED);
237     }
238
239     /**
240      * This test explicitly creates a prometheus server.
241      */
242     @Test
243     public void testExplicitPrometheusServer() throws Exception {
244         logger.info("-- testPrometheusServer() --");
245
246         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
247             .build(PROMETHEUS, LOCALHOST, port, "/", false, true);
248         server.setPrometheus(METRICS_URI);
249         server.waitedStart(5000);
250
251         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
252         assertTrue(server.isPrometheus());
253
254         String response = http(portUrl + METRICS_URI);
255         assertThat(response).contains(JVM_MEMORY_BYTES_USED);
256     }
257
258     /**
259      * This test is an all-in-one for a single server: prometheus, jax-rs, servlet, swagger, and filters.
260      */
261     @Test
262     public void testPrometheusJaxRsFilterSwaggerServer() throws Exception {
263         logger.info("-- testPrometheusServer() --");
264
265         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
266             .build(PROMETHEUS, LOCALHOST, port, "/", true, true);
267
268         server.addServletClass("/*", RestEchoService.class.getName());
269         server.addFilterClass("/*", TestFilter.class.getName());
270         server.setPrometheus(METRICS_URI);
271
272         server.waitedStart(5000);
273
274         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
275         assertTrue(server.isPrometheus());
276
277         String response = http(portUrl + METRICS_URI);
278         assertThat(response).contains(JVM_MEMORY_BYTES_USED);
279
280         RestEchoReqResp request = new RestEchoReqResp();
281         request.setRequestId(100);
282         request.setText(SOME_TEXT);
283         String reqText = gson.toJson(request);
284
285         response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
286         assertEquals(reqText, response);
287
288         response = http(portUrl + SWAGGER_JSON);
289         assertThat(response).contains("Swagger Server");
290     }
291
292     @Test
293     public void testJacksonClassServer() throws Exception {
294         logger.info("-- testJacksonClassServer() --");
295
296         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
297                         .build("echo", LOCALHOST, port, "/", false, true);
298         server.addServletClass("/*", RestEchoService.class.getName());
299         server.addFilterClass("/*", TestFilter.class.getName());
300         server.waitedStart(5000);
301
302         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
303
304         RestEchoReqResp request = new RestEchoReqResp();
305         request.setRequestId(100);
306         request.setText(SOME_TEXT);
307         String reqText = gson.toJson(request);
308
309         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
310         assertEquals(reqText, response);
311
312         assertFalse(MyGsonProvider.hasReadSome());
313         assertFalse(MyGsonProvider.hasWrittenSome());
314
315         assertFalse(MyYamlProvider.hasReadSome());
316         assertFalse(MyYamlProvider.hasWrittenSome());
317     }
318
319     @Test
320     public void testGsonClassServer() throws Exception {
321         logger.info("-- testGsonClassServer() --");
322
323         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
324                         .build("echo", LOCALHOST, port, "/", false, true);
325         server.setSerializationProvider(MyGsonProvider.class.getName());
326         server.addServletClass("/*", RestEchoService.class.getName());
327         server.addFilterClass("/*", TestFilter.class.getName());
328         server.waitedStart(5000);
329
330         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
331
332         RestEchoReqResp request = new RestEchoReqResp();
333         request.setRequestId(100);
334         request.setText(SOME_TEXT);
335         String reqText = gson.toJson(request);
336
337         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
338         assertEquals(reqText, response);
339
340         assertTrue(MyGsonProvider.hasReadSome());
341         assertTrue(MyGsonProvider.hasWrittenSome());
342
343         assertFalse(MyYamlProvider.hasReadSome());
344         assertFalse(MyYamlProvider.hasWrittenSome());
345     }
346
347     @Test
348     public void testYamlClassServer() throws Exception {
349         logger.info("-- testYamlClassServer() --");
350
351         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
352                         .build("echo", LOCALHOST, port, "/", false, true);
353         server.setSerializationProvider(MyYamlProvider.class.getName());
354         server.addServletClass("/*", RestEchoService.class.getName());
355         server.addFilterClass("/*", TestFilter.class.getName());
356         server.waitedStart(5000);
357
358         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
359
360         RestEchoReqResp request = new RestEchoReqResp();
361         request.setRequestId(100);
362         request.setText(SOME_TEXT);
363         String reqText = new StandardYamlCoder().encode(request);
364
365         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, YAML_MEDIA, reqText);
366
367         // response reader strips newlines, so we should, too, before comparing
368         assertEquals(reqText.replace("\n", ""), response);
369
370         assertTrue(MyYamlProvider.hasReadSome());
371         assertTrue(MyYamlProvider.hasWrittenSome());
372
373         assertFalse(MyGsonProvider.hasReadSome());
374         assertFalse(MyGsonProvider.hasWrittenSome());
375     }
376
377     @Test
378     public void testSerialize() {
379         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
380                         .build("echo", LOCALHOST, port, "/", false, true);
381         server.addServletPackage("/*", this.getClass().getPackage().getName());
382         server.addFilterClass("/*", TestFilter.class.getName());
383
384         // ensure we can serialize the server
385         assertThatCode(() -> new GsonTestUtils().compareGson(server, HttpServerTest.class)).doesNotThrowAnyException();
386     }
387
388     @Test
389     public void testSingleServer() throws Exception {
390         logger.info("-- testSingleServer() --");
391
392         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
393                         .build("echo", LOCALHOST, port, "/", false, true);
394         server.addServletPackage("/*", this.getClass().getPackage().getName());
395         server.addFilterClass("/*", TestFilter.class.getName());
396         server.waitedStart(5000);
397
398         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
399         assertFalse(HttpServletServerFactoryInstance.getServerFactory().get(port).isAaf());
400
401         String response = http(portUrl + JUNIT_ECHO_HELLO);
402         assertEquals(HELLO, response);
403
404         assertThatThrownBy(() -> http(portUrl + SWAGGER_JSON)).isInstanceOf(IOException.class);
405
406         response = http(portUrl + "/junit/echo/hello?block=true");
407         assertEquals("FILTERED", response);
408
409         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
410         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
411
412         System.setProperty("cadi_longitude", "0.0");
413         System.setProperty("cadi_latitude", "0.0");
414         server.setAafAuthentication("/*");
415         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAaf());
416
417         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
418         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
419     }
420
421     @Test
422     public void testMultipleServers() throws Exception {
423         logger.info("-- testMultipleServers() --");
424
425         HttpServletServer server1 = HttpServletServerFactoryInstance.getServerFactory()
426                         .build("echo-1", false, LOCALHOST, port, "/", true, true);
427         server1.addServletPackage("/*", this.getClass().getPackage().getName());
428         server1.waitedStart(5000);
429
430         int port2 = port + 1;
431
432         HttpServletServer server2 = HttpServletServerFactoryInstance.getServerFactory()
433                         .build("echo-2", LOCALHOST, port2, "/", false, true);
434         server2.addServletPackage("/*", this.getClass().getPackage().getName());
435         server2.waitedStart(5000);
436
437         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
438         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port2).isAlive());
439
440         String response = http(portUrl + JUNIT_ECHO_HELLO);
441         assertEquals(HELLO, response);
442
443         response = http(portUrl + SWAGGER_JSON);
444         assertNotNull(response);
445
446         response = http(LOCALHOST_PREFIX + port2 + JUNIT_ECHO_HELLO);
447         assertEquals(HELLO, response);
448
449         assertThatThrownBy(() -> http(LOCALHOST_PREFIX + port2 + SWAGGER_JSON)).isInstanceOf(IOException.class);
450
451         HttpServletServerFactoryInstance.getServerFactory().destroy();
452         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
453     }
454
455     @Test
456     public void testMultiServicePackage() throws Exception {
457         logger.info("-- testMultiServicePackage() --");
458
459         String randomName = UUID.randomUUID().toString();
460
461         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
462                         .build(randomName, LOCALHOST, port, "/", false, true);
463         server.addServletPackage("/*", this.getClass().getPackage().getName());
464         server.waitedStart(5000);
465
466         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
467
468         String response = http(portUrl + JUNIT_ECHO_HELLO);
469         assertEquals(HELLO, response);
470
471         response = http(portUrl + "/junit/endpoints/http/servers");
472         assertTrue(response.contains(randomName));
473
474         HttpServletServerFactoryInstance.getServerFactory().destroy();
475         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
476     }
477
478     @Test
479     public void testServiceClass() throws Exception {
480         logger.info("-- testServiceClass() --");
481         String randomName = UUID.randomUUID().toString();
482
483         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
484                         .build(randomName, LOCALHOST, port, "/", false, true);
485         server.addServletClass("/*", RestEchoService.class.getName());
486         server.waitedStart(5000);
487
488         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
489
490         String response = http(portUrl + JUNIT_ECHO_HELLO);
491         assertEquals(HELLO, response);
492
493         HttpServletServerFactoryInstance.getServerFactory().destroy();
494         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
495     }
496
497     @Test
498     public void testMultiServiceClass() throws Exception {
499         logger.info("-- testMultiServiceClass() --");
500
501         String randomName = UUID.randomUUID().toString();
502
503         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
504                         .build(randomName, LOCALHOST, port, "/", false, true);
505         server.addServletClass("/*", RestEchoService.class.getName());
506         server.addServletClass("/*", RestEndpoints.class.getName());
507         server.waitedStart(5000);
508
509         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
510
511         String response = http(portUrl + JUNIT_ECHO_HELLO);
512         assertEquals(HELLO, response);
513
514         response = http(portUrl + "/junit/endpoints/http/servers");
515         assertTrue(response.contains(randomName));
516
517         HttpServletServerFactoryInstance.getServerFactory().destroy();
518         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
519     }
520
521     @Test
522     public void testSingleStaticResourceServer() throws Exception {
523         logger.info("-- testSingleStaticResourceServer() --");
524
525         HttpServletServer staticServer = HttpServletServerFactoryInstance.getServerFactory()
526                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, "/", true);
527         Throwable thrown = catchThrowable(() -> staticServer.addServletResource("/*", null));
528         assertThat(thrown).isInstanceOf(IllegalArgumentException.class)
529                 .hasMessageContaining("No resourceBase provided");
530
531         staticServer.addServletResource(null,
532                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm());
533
534         thrown = catchThrowable(() -> staticServer.addServletClass("/*", RestEchoService.class.getName()));
535         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
536                 .hasMessageContaining("is not supported on this type of jetty server");
537
538         thrown = catchThrowable(() -> staticServer.addServletPackage("/api/*", this.getClass().getPackage().getName()));
539         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
540                 .hasMessageContaining("is not supported on this type of jetty server");
541
542         thrown = catchThrowable(() -> staticServer.setSerializationProvider(MyGsonProvider.class.getName()));
543         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
544                 .hasMessageContaining("is not supported on this type of jetty server");
545
546         staticServer.waitedStart(5000);
547
548         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
549         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
550
551         String response = http(portUrl);
552         assertThat(response).contains("Test Jetty Static Resources Root");
553
554         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
555         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
556     }
557
558     @Test
559     public void testMultiStaticResourceServer() throws Exception {
560         logger.info("-- testMultiStaticResourceServer() --");
561
562         HttpServletServer staticResourceServer = HttpServletServerFactoryInstance.getServerFactory()
563                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, "/", true);
564         staticResourceServer.addServletResource("/root/*",
565                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm());
566         staticResourceServer.addServletResource("/alt-root/*",
567                 HttpServerTest.class.getClassLoader().getResource("webapps/alt-root").toExternalForm());
568         staticResourceServer.waitedStart(5000);
569
570         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
571         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
572
573         String response = http(portUrl + "/root/");
574         assertThat(response).contains("Test Jetty Static Resources Root");
575
576         response = http(portUrl + "/alt-root/");
577         assertThat(response).contains("Test Jetty Static Resources Alt-Root");
578
579         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
580         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
581     }
582
583     @Test
584     public void testMultiTypesServer() throws Exception {
585         logger.info("-- testMultiTypesServer() --");
586
587         HttpServletServer staticResourceServer = HttpServletServerFactoryInstance.getServerFactory()
588                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, "/", true);
589         staticResourceServer.addServletResource("/root/*",
590                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm());
591         staticResourceServer.waitedStart(5000);
592
593         int port2 = port + 1;
594         HttpServletServer jerseyServer =
595                 HttpServletServerFactoryInstance.getServerFactory().build("echo", LOCALHOST, port2, "/", false, true);
596         jerseyServer.addServletPackage("/api/*", this.getClass().getPackage().getName());
597
598         Throwable thrown = catchThrowable(() -> jerseyServer.addServletResource("/root/*",
599                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm()));
600         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
601                 .hasMessageContaining("is not supported on this type of jetty server");
602
603         jerseyServer.waitedStart(5000);
604
605         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
606         assertEquals(2, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
607
608         String response = http(portUrl + "/root/");
609         assertThat(response).contains("Test Jetty Static Resources Root");
610
611         response = http(LOCALHOST_PREFIX + port2 + "/api" + JUNIT_ECHO_HELLO);
612         assertEquals(HELLO, response);
613
614         HttpServletServerFactoryInstance.getServerFactory().destroy();
615         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
616     }
617
618     /**
619      * performs an http request.
620      *
621      * @throws MalformedURLException make sure URL is good
622      * @throws IOException thrown is IO exception occurs
623      * @throws InterruptedException thrown if thread interrupted occurs
624      */
625     private String http(String urlString)
626             throws IOException, InterruptedException {
627         URL url = new URL(urlString);
628         if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 100)) {
629             throw new IllegalStateException("port never opened: " + url);
630         }
631         return response(url.openConnection());
632     }
633
634     /**
635      * Performs an http request.
636      *
637      * @throws MalformedURLException make sure URL is good
638      * @throws IOException thrown is IO exception occurs
639      * @throws InterruptedException thrown if thread interrupted occurs
640      */
641     private String http(String urlString, String mediaType, String post)
642             throws IOException, InterruptedException {
643         URL url = new URL(urlString);
644         if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 100)) {
645             throw new IllegalStateException("port never opened: " + url);
646         }
647         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
648         conn.setRequestMethod("POST");
649         conn.setDoOutput(true);
650         conn.setRequestProperty("Content-Type", mediaType);
651         conn.setRequestProperty("Accept", mediaType);
652         IOUtils.write(post, conn.getOutputStream(), StandardCharsets.UTF_8);
653         return response(conn);
654     }
655
656     /**
657      * gets http response.
658      *
659      * @param conn connection from which to read
660      *
661      * @throws IOException if an I/O error occurs
662      */
663     private String response(URLConnection conn) throws IOException {
664         try (InputStream inpstr = conn.getInputStream()) {
665             return String.join("", IOUtils.readLines(inpstr, StandardCharsets.UTF_8));
666         }
667     }
668
669 }