48cacaf9dcca411072c3dff9eaf216276a251c18
[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,2023 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.servlet.jakarta.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 = "/openapi.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 final 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("openapi");
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         new GsonTestUtils().compareGson(server, HttpServerTest.class);
386         assertThatCode(() -> new GsonTestUtils().compareGson(server, HttpServerTest.class)).doesNotThrowAnyException();
387     }
388
389     @Test
390     public void testSingleServer() throws Exception {
391         logger.info("-- testSingleServer() --");
392
393         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
394                         .build("echo", LOCALHOST, port, "/", false, true);
395         server.addServletPackage("/*", this.getClass().getPackage().getName());
396         server.addFilterClass("/*", TestFilter.class.getName());
397         server.waitedStart(5000);
398
399         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
400         assertFalse(HttpServletServerFactoryInstance.getServerFactory().get(port).isAaf());
401
402         String response = http(portUrl + JUNIT_ECHO_HELLO);
403         assertEquals(HELLO, response);
404
405         assertThatThrownBy(() -> http(portUrl + SWAGGER_JSON)).isInstanceOf(IOException.class);
406
407         response = http(portUrl + "/junit/echo/hello?block=true");
408         assertEquals("FILTERED", response);
409
410         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
411         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
412
413         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
414         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
415     }
416
417     @Test
418     public void testMultipleServers() throws Exception {
419         logger.info("-- testMultipleServers() --");
420
421         HttpServletServer server1 = HttpServletServerFactoryInstance.getServerFactory()
422                         .build("echo-1", false, LOCALHOST, port, false, "/", true, true);
423         server1.addServletPackage("/*", this.getClass().getPackage().getName());
424         server1.waitedStart(5000);
425
426         int port2 = port + 1;
427
428         HttpServletServer server2 = HttpServletServerFactoryInstance.getServerFactory()
429                         .build("echo-2", LOCALHOST, port2, "/", false, true);
430         server2.addServletPackage("/*", this.getClass().getPackage().getName());
431         server2.waitedStart(5000);
432
433         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
434         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port2).isAlive());
435
436         String response = http(portUrl + JUNIT_ECHO_HELLO);
437         assertEquals(HELLO, response);
438
439         response = http(portUrl + SWAGGER_JSON);
440         assertNotNull(response);
441
442         response = http(LOCALHOST_PREFIX + port2 + JUNIT_ECHO_HELLO);
443         assertEquals(HELLO, response);
444
445         assertThatThrownBy(() -> http(LOCALHOST_PREFIX + port2 + SWAGGER_JSON)).isInstanceOf(IOException.class);
446
447         HttpServletServerFactoryInstance.getServerFactory().destroy();
448         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
449     }
450
451     @Test
452     public void testMultiServicePackage() throws Exception {
453         logger.info("-- testMultiServicePackage() --");
454
455         String randomName = UUID.randomUUID().toString();
456
457         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
458                         .build(randomName, LOCALHOST, port, "/", false, true);
459         server.addServletPackage("/*", this.getClass().getPackage().getName());
460         server.waitedStart(5000);
461
462         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
463
464         String response = http(portUrl + JUNIT_ECHO_HELLO);
465         assertEquals(HELLO, response);
466
467         response = http(portUrl + "/junit/endpoints/http/servers");
468         assertTrue(response.contains(randomName));
469
470         HttpServletServerFactoryInstance.getServerFactory().destroy();
471         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
472     }
473
474     @Test
475     public void testServiceClass() throws Exception {
476         logger.info("-- testServiceClass() --");
477         String randomName = UUID.randomUUID().toString();
478
479         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
480                         .build(randomName, LOCALHOST, port, "/", false, true);
481         server.addServletClass("/*", RestEchoService.class.getName());
482         server.waitedStart(5000);
483
484         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
485
486         String response = http(portUrl + JUNIT_ECHO_HELLO);
487         assertEquals(HELLO, response);
488
489         HttpServletServerFactoryInstance.getServerFactory().destroy();
490         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
491     }
492
493     @Test
494     public void testMultiServiceClass() throws Exception {
495         logger.info("-- testMultiServiceClass() --");
496
497         String randomName = UUID.randomUUID().toString();
498
499         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
500                         .build(randomName, LOCALHOST, port, "/", false, true);
501         server.addServletClass("/*", RestEchoService.class.getName());
502         server.addServletClass("/*", RestEndpoints.class.getName());
503         server.waitedStart(5000);
504
505         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
506
507         String response = http(portUrl + JUNIT_ECHO_HELLO);
508         assertEquals(HELLO, response);
509
510         response = http(portUrl + "/junit/endpoints/http/servers");
511         assertTrue(response.contains(randomName));
512
513         HttpServletServerFactoryInstance.getServerFactory().destroy();
514         assertTrue(HttpServletServerFactoryInstance.getServerFactory().inventory().isEmpty());
515     }
516
517     @Test
518     public void testSingleStaticResourceServer() throws Exception {
519         logger.info("-- testSingleStaticResourceServer() --");
520
521         HttpServletServer staticServer = HttpServletServerFactoryInstance.getServerFactory()
522                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, false, "/", true);
523         Throwable thrown = catchThrowable(() -> staticServer.addServletResource("/*", null));
524         assertThat(thrown).isInstanceOf(IllegalArgumentException.class)
525                 .hasMessageContaining("No resourceBase provided");
526
527         staticServer.addServletResource(null,
528                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm());
529
530         thrown = catchThrowable(() -> staticServer.addServletClass("/*", RestEchoService.class.getName()));
531         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
532                 .hasMessageContaining("is not supported on this type of jetty server");
533
534         thrown = catchThrowable(() -> staticServer.addServletPackage("/api/*", this.getClass().getPackage().getName()));
535         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
536                 .hasMessageContaining("is not supported on this type of jetty server");
537
538         thrown = catchThrowable(() -> staticServer.setSerializationProvider(MyGsonProvider.class.getName()));
539         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
540                 .hasMessageContaining("is not supported on this type of jetty server");
541
542         staticServer.waitedStart(5000);
543
544         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
545         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
546
547         String response = http(portUrl);
548         assertThat(response).contains("Test Jetty Static Resources Root");
549
550         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
551         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
552     }
553
554     @Test
555     public void testMultiStaticResourceServer() throws Exception {
556         logger.info("-- testMultiStaticResourceServer() --");
557
558         HttpServletServer staticResourceServer = HttpServletServerFactoryInstance.getServerFactory()
559                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, false, "/", true);
560         staticResourceServer.addServletResource("/root/*",
561                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm());
562         staticResourceServer.addServletResource("/alt-root/*",
563                 HttpServerTest.class.getClassLoader().getResource("webapps/alt-root").toExternalForm());
564         staticResourceServer.waitedStart(5000);
565
566         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
567         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
568
569         String response = http(portUrl + "/root/");
570         assertThat(response).contains("Test Jetty Static Resources Root");
571
572         response = http(portUrl + "/alt-root/");
573         assertThat(response).contains("Test Jetty Static Resources Alt-Root");
574
575         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
576         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
577     }
578
579     @Test
580     public void testMultiTypesServer() throws Exception {
581         logger.info("-- testMultiTypesServer() --");
582
583         HttpServletServer staticResourceServer = HttpServletServerFactoryInstance.getServerFactory()
584                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, false, "/", true);
585         staticResourceServer.addServletResource("/root/*",
586                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm());
587         staticResourceServer.waitedStart(5000);
588
589         int port2 = port + 1;
590         HttpServletServer jerseyServer =
591                 HttpServletServerFactoryInstance.getServerFactory().build("echo", LOCALHOST, port2, "/", false, true);
592         jerseyServer.addServletPackage("/api/*", this.getClass().getPackage().getName());
593
594         Throwable thrown = catchThrowable(() -> jerseyServer.addServletResource("/root/*",
595                 HttpServerTest.class.getClassLoader().getResource("webapps/root").toExternalForm()));
596         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
597                 .hasMessageContaining("is not supported on this type of jetty server");
598
599         jerseyServer.waitedStart(5000);
600
601         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
602         assertEquals(2, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
603
604         String response = http(portUrl + "/root/");
605         assertThat(response).contains("Test Jetty Static Resources Root");
606
607         response = http(LOCALHOST_PREFIX + port2 + "/api" + JUNIT_ECHO_HELLO);
608         assertEquals(HELLO, response);
609
610         HttpServletServerFactoryInstance.getServerFactory().destroy();
611         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
612     }
613
614     /**
615      * performs an http request.
616      *
617      * @throws MalformedURLException make sure URL is good
618      * @throws IOException thrown is IO exception occurs
619      * @throws InterruptedException thrown if thread interrupted occurs
620      */
621     private String http(String urlString)
622             throws IOException, InterruptedException {
623         URL url = new URL(urlString);
624         if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 100)) {
625             throw new IllegalStateException("port never opened: " + url);
626         }
627         return response(url.openConnection());
628     }
629
630     /**
631      * Performs an http request.
632      *
633      * @throws MalformedURLException make sure URL is good
634      * @throws IOException thrown is IO exception occurs
635      * @throws InterruptedException thrown if thread interrupted occurs
636      */
637     private String http(String urlString, String mediaType, String post)
638             throws IOException, InterruptedException {
639         URL url = new URL(urlString);
640         if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 100)) {
641             throw new IllegalStateException("port never opened: " + url);
642         }
643         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
644         conn.setRequestMethod("POST");
645         conn.setDoOutput(true);
646         conn.setRequestProperty("Content-Type", mediaType);
647         conn.setRequestProperty("Accept", mediaType);
648         IOUtils.write(post, conn.getOutputStream(), StandardCharsets.UTF_8);
649         return response(conn);
650     }
651
652     /**
653      * gets http response.
654      *
655      * @param conn connection from which to read
656      *
657      * @throws IOException if an I/O error occurs
658      */
659     private String response(URLConnection conn) throws IOException {
660         try (InputStream inpstr = conn.getInputStream()) {
661             return String.join("", IOUtils.readLines(inpstr, StandardCharsets.UTF_8));
662         }
663     }
664
665 }