399754a65d70caff01ab2dc51fde37f45894bf3e
[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-2024 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.jupiter.api.Assertions.assertEquals;
30 import static org.junit.jupiter.api.Assertions.assertFalse;
31 import static org.junit.jupiter.api.Assertions.assertNotNull;
32 import static org.junit.jupiter.api.Assertions.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.Objects;
44 import java.util.UUID;
45 import org.apache.commons.io.IOUtils;
46 import org.junit.jupiter.api.AfterAll;
47 import org.junit.jupiter.api.BeforeEach;
48 import org.junit.jupiter.api.Test;
49 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
50 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
51 import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler;
52 import org.onap.policy.common.utils.coder.StandardYamlCoder;
53 import org.onap.policy.common.utils.gson.GsonTestUtils;
54 import org.onap.policy.common.utils.network.NetworkUtil;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 /**
59  * HttpServletServer JUNIT tests.
60  */
61 class HttpServerTest {
62     private static final String JVM_MEMORY_BYTES_USED = "jvm_memory_bytes_used";
63     private static final String METRICS_URI = "/metrics";
64     private static final String PROMETHEUS = "prometheus";
65     private static final String LOCALHOST = "localhost";
66     private static final String JSON_MEDIA = "application/json";
67     private static final String YAML_MEDIA = YamlMessageBodyHandler.APPLICATION_YAML;
68     private static final String SWAGGER_JSON = "/openapi.json";
69     private static final String JUNIT_ECHO_HELLO = "/junit/echo/hello";
70     private static final String JUNIT_ECHO_FULL_REQUEST = "/junit/echo/full/request";
71     private static final String SOME_TEXT = "some text";
72     private static final String HELLO = "hello";
73
74     /**
75      * Logger.
76      */
77     private static final Logger logger = LoggerFactory.getLogger(HttpServerTest.class);
78
79     private static final String LOCALHOST_PREFIX = "http://localhost:";
80
81     private static final Gson gson = new Gson();
82
83     /**
84      * Server port.  Incremented by 10 with each test.
85      */
86     private static int port = 5608;
87
88     private String portUrl;
89
90     /**
91      * Increments the port number, clears the servers, and resets the providers.
92      */
93     @BeforeEach
94     public void setUp() {
95         incrementPort();
96         portUrl = LOCALHOST_PREFIX + port;
97
98         HttpServletServerFactoryInstance.getServerFactory().destroy();
99
100         MyGsonProvider.resetSome();
101         MyYamlProvider.resetSome();
102     }
103
104     private static void incrementPort() {
105         port += 10;
106     }
107
108     /**
109      * To delete temporary properties cadi_longitude,and cadi_latitude.
110      */
111     @AfterAll
112     public static void tearDownAfterClass() {
113         HttpServletServerFactoryInstance.getServerFactory().destroy();
114         System.clearProperty("cadi_longitude");
115         System.clearProperty("cadi_latitude");
116     }
117
118     @Test
119     void testDefaultPackageServer() throws Exception {
120         logger.info("-- testDefaultPackageServer() --");
121
122         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
123                         .build("echo", LOCALHOST, port, "/", false, true);
124         server.addServletPackage("/*", this.getClass().getPackage().getName());
125         server.addFilterClass("/*", TestFilter.class.getName());
126         server.waitedStart(5000);
127
128         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
129
130         RestEchoReqResp request = new RestEchoReqResp();
131         request.setRequestId(100);
132         request.setText(SOME_TEXT);
133         String reqText = gson.toJson(request);
134
135         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
136         assertEquals(reqText, response);
137     }
138
139     @Test
140     void testGsonPackageServer() throws Exception {
141         logger.info("-- testGsonPackageServer() --");
142
143         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
144                         .build("echo", LOCALHOST, port, "/", false, true);
145
146         server.setSerializationProvider(MyGsonProvider.class.getName());
147         server.addServletPackage("/*", this.getClass().getPackage().getName());
148         server.addFilterClass("/*", TestFilter.class.getName());
149         server.waitedStart(5000);
150
151         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
152
153         RestEchoReqResp request = new RestEchoReqResp();
154         request.setRequestId(100);
155         request.setText(SOME_TEXT);
156         String reqText = gson.toJson(request);
157
158         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
159         assertEquals(reqText, response);
160
161         assertTrue(MyGsonProvider.hasReadSome());
162         assertTrue(MyGsonProvider.hasWrittenSome());
163
164         assertFalse(MyYamlProvider.hasReadSome());
165         assertFalse(MyYamlProvider.hasWrittenSome());
166     }
167
168     @Test
169     void testYamlPackageServer() throws Exception {
170         logger.info("-- testYamlPackageServer() --");
171
172         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
173                         .build("echo", LOCALHOST, port, "/", false, true);
174
175         server.setSerializationProvider(MyYamlProvider.class.getName());
176         server.addServletPackage("/*", this.getClass().getPackage().getName());
177         server.addFilterClass("/*", TestFilter.class.getName());
178         server.waitedStart(5000);
179
180         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
181
182         RestEchoReqResp request = new RestEchoReqResp();
183         request.setRequestId(100);
184         request.setText(SOME_TEXT);
185         String reqText = new StandardYamlCoder().encode(request);
186
187         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, YAML_MEDIA, reqText);
188
189         // response reader strips newlines, so we should, too, before comparing
190         assertEquals(reqText.replace("\n", ""), response);
191
192         assertTrue(MyYamlProvider.hasReadSome());
193         assertTrue(MyYamlProvider.hasWrittenSome());
194
195         assertFalse(MyGsonProvider.hasReadSome());
196         assertFalse(MyGsonProvider.hasWrittenSome());
197     }
198
199     @Test
200     void testDefaultClassServer() throws Exception {
201         logger.info("-- testDefaultClassServer() --");
202
203         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
204                         .build("echo", LOCALHOST, port, "/", false, true);
205         server.addServletClass("/*", RestEchoService.class.getName());
206         server.addFilterClass("/*", TestFilter.class.getName());
207         server.waitedStart(5000);
208
209         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
210
211         RestEchoReqResp request = new RestEchoReqResp();
212         request.setRequestId(100);
213         request.setText(SOME_TEXT);
214         String reqText = gson.toJson(request);
215
216         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
217         assertEquals(reqText, response);
218     }
219
220     /**
221      * This test checks a server from a plain java servlet (note it uses prometheus as the sample server).
222      */
223     @Test
224     void testStdServletServer() throws Exception {
225         logger.info("-- testStdServletServer() --");
226
227         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
228             .build(PROMETHEUS, LOCALHOST, port, "/", false, true);
229
230         server.addStdServletClass("/prom-generic-servlet/metrics", MetricsServlet.class.getName());
231         server.waitedStart(5000);
232
233         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
234         assertTrue(server.isPrometheus());
235
236         String response = http(portUrl + "/prom-generic-servlet/metrics");
237         assertThat(response).contains(JVM_MEMORY_BYTES_USED);
238     }
239
240     /**
241      * This test explicitly creates a prometheus server.
242      */
243     @Test
244     void testExplicitPrometheusServer() throws Exception {
245         logger.info("-- testExplicitPrometheusServer() --");
246
247         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
248             .build(PROMETHEUS, LOCALHOST, port, "/", false, true);
249         server.setPrometheus(METRICS_URI);
250         server.waitedStart(5000);
251
252         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
253         assertTrue(server.isPrometheus());
254
255         String response = http(portUrl + METRICS_URI);
256         assertThat(response).contains(JVM_MEMORY_BYTES_USED);
257     }
258
259     /**
260      * This test is an all-in-one for a single server: prometheus, jax-rs, servlet, swagger, and filters.
261      */
262     @Test
263     void testPrometheusJaxRsFilterSwaggerServer() throws Exception {
264         logger.info("-- testPrometheusJaxRsFilterSwaggerServer() --");
265
266         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
267             .build(PROMETHEUS, LOCALHOST, port, "/", true, true);
268
269         server.addServletClass("/*", RestEchoService.class.getName());
270         server.addFilterClass("/*", TestFilter.class.getName());
271         server.setPrometheus(METRICS_URI);
272
273         server.waitedStart(5000);
274
275         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
276         assertTrue(server.isPrometheus());
277
278         String response = http(portUrl + METRICS_URI);
279         assertThat(response).contains(JVM_MEMORY_BYTES_USED);
280
281         RestEchoReqResp request = new RestEchoReqResp();
282         request.setRequestId(100);
283         request.setText(SOME_TEXT);
284         String reqText = gson.toJson(request);
285
286         response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
287         assertEquals(reqText, response);
288
289         response = http(portUrl + SWAGGER_JSON);
290         assertThat(response).contains("openapi");
291     }
292
293     @Test
294     void testJacksonClassServer() throws Exception {
295         logger.info("-- testJacksonClassServer() --");
296
297         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
298                         .build("echo", LOCALHOST, port, "/", false, true);
299         server.addServletClass("/*", RestEchoService.class.getName());
300         server.addFilterClass("/*", TestFilter.class.getName());
301         server.waitedStart(5000);
302
303         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
304
305         RestEchoReqResp request = new RestEchoReqResp();
306         request.setRequestId(100);
307         request.setText(SOME_TEXT);
308         String reqText = gson.toJson(request);
309
310         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
311         assertEquals(reqText, response);
312
313         assertFalse(MyGsonProvider.hasReadSome());
314         assertFalse(MyGsonProvider.hasWrittenSome());
315
316         assertFalse(MyYamlProvider.hasReadSome());
317         assertFalse(MyYamlProvider.hasWrittenSome());
318     }
319
320     @Test
321     void testGsonClassServer() throws Exception {
322         logger.info("-- testGsonClassServer() --");
323
324         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
325                         .build("echo", LOCALHOST, port, "/", false, true);
326         server.setSerializationProvider(MyGsonProvider.class.getName());
327         server.addServletClass("/*", RestEchoService.class.getName());
328         server.addFilterClass("/*", TestFilter.class.getName());
329         server.waitedStart(5000);
330
331         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
332
333         RestEchoReqResp request = new RestEchoReqResp();
334         request.setRequestId(100);
335         request.setText(SOME_TEXT);
336         String reqText = gson.toJson(request);
337
338         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText);
339         assertEquals(reqText, response);
340
341         assertTrue(MyGsonProvider.hasReadSome());
342         assertTrue(MyGsonProvider.hasWrittenSome());
343
344         assertFalse(MyYamlProvider.hasReadSome());
345         assertFalse(MyYamlProvider.hasWrittenSome());
346     }
347
348     @Test
349     void testYamlClassServer() throws Exception {
350         logger.info("-- testYamlClassServer() --");
351
352         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
353                         .build("echo", LOCALHOST, port, "/", false, true);
354         server.setSerializationProvider(MyYamlProvider.class.getName());
355         server.addServletClass("/*", RestEchoService.class.getName());
356         server.addFilterClass("/*", TestFilter.class.getName());
357         server.waitedStart(5000);
358
359         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
360
361         RestEchoReqResp request = new RestEchoReqResp();
362         request.setRequestId(100);
363         request.setText(SOME_TEXT);
364         String reqText = new StandardYamlCoder().encode(request);
365
366         String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, YAML_MEDIA, reqText);
367
368         // response reader strips newlines, so we should, too, before comparing
369         assertEquals(reqText.replace("\n", ""), response);
370
371         assertTrue(MyYamlProvider.hasReadSome());
372         assertTrue(MyYamlProvider.hasWrittenSome());
373
374         assertFalse(MyGsonProvider.hasReadSome());
375         assertFalse(MyGsonProvider.hasWrittenSome());
376     }
377
378     @Test
379     void testSerialize() {
380         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
381                         .build("echo", LOCALHOST, port, "/", false, true);
382         server.addServletPackage("/*", this.getClass().getPackage().getName());
383         server.addFilterClass("/*", TestFilter.class.getName());
384
385         // ensure we can serialize the server
386         new GsonTestUtils().compareGson(server, HttpServerTest.class);
387         assertThatCode(() -> new GsonTestUtils().compareGson(server, HttpServerTest.class)).doesNotThrowAnyException();
388     }
389
390     @Test
391     void testSingleServer() throws Exception {
392         logger.info("-- testSingleServer() --");
393
394         HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory()
395                         .build("echo", LOCALHOST, port, "/", false, true);
396         server.addServletPackage("/*", this.getClass().getPackage().getName());
397         server.addFilterClass("/*", TestFilter.class.getName());
398         server.waitedStart(5000);
399
400         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
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     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     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     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     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     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                 Objects.requireNonNull(HttpServerTest.class.getClassLoader().getResource("webapps/root"))
529                     .toExternalForm());
530
531         thrown = catchThrowable(() -> staticServer.addServletClass("/*", RestEchoService.class.getName()));
532         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
533                 .hasMessageContaining("is not supported on this type of jetty server");
534
535         thrown = catchThrowable(() -> staticServer.addServletPackage("/api/*", this.getClass().getPackage().getName()));
536         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
537                 .hasMessageContaining("is not supported on this type of jetty server");
538
539         thrown = catchThrowable(() -> staticServer.setSerializationProvider(MyGsonProvider.class.getName()));
540         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
541                 .hasMessageContaining("is not supported on this type of jetty server");
542
543         staticServer.waitedStart(5000);
544
545         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
546         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
547
548         String response = http(portUrl);
549         assertThat(response).contains("Test Jetty Static Resources Root");
550
551         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
552         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
553     }
554
555     @Test
556     void testMultiStaticResourceServer() throws Exception {
557         logger.info("-- testMultiStaticResourceServer() --");
558
559         HttpServletServer staticResourceServer = HttpServletServerFactoryInstance.getServerFactory()
560                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, false, "/", true);
561         staticResourceServer.addServletResource("/root/*",
562                 Objects.requireNonNull(HttpServerTest.class.getClassLoader().getResource("webapps/root"))
563                     .toExternalForm());
564         staticResourceServer.addServletResource("/alt-root/*",
565                 Objects.requireNonNull(HttpServerTest.class.getClassLoader().getResource("webapps/alt-root"))
566                     .toExternalForm());
567         staticResourceServer.waitedStart(5000);
568
569         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
570         assertEquals(1, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
571
572         String response = http(portUrl + "/root/");
573         assertThat(response).contains("Test Jetty Static Resources Root");
574
575         response = http(portUrl + "/alt-root/");
576         assertThat(response).contains("Test Jetty Static Resources Alt-Root");
577
578         HttpServletServerFactoryInstance.getServerFactory().destroy(port);
579         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
580     }
581
582     @Test
583     void testMultiTypesServer() throws Exception {
584         logger.info("-- testMultiTypesServer() --");
585
586         HttpServletServer staticResourceServer = HttpServletServerFactoryInstance.getServerFactory()
587                 .buildStaticResourceServer("Static Resources Server", false, LOCALHOST, port, false, "/", true);
588         staticResourceServer.addServletResource("/root/*",
589                 Objects.requireNonNull(HttpServerTest.class.getClassLoader().getResource("webapps/root"))
590                     .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                 Objects.requireNonNull(HttpServerTest.class.getClassLoader().getResource("webapps/root"))
600                     .toExternalForm()));
601         assertThat(thrown).isInstanceOf(UnsupportedOperationException.class)
602                 .hasMessageContaining("is not supported on this type of jetty server");
603
604         jerseyServer.waitedStart(5000);
605
606         assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive());
607         assertEquals(2, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
608
609         String response = http(portUrl + "/root/");
610         assertThat(response).contains("Test Jetty Static Resources Root");
611
612         response = http(LOCALHOST_PREFIX + port2 + "/api" + JUNIT_ECHO_HELLO);
613         assertEquals(HELLO, response);
614
615         HttpServletServerFactoryInstance.getServerFactory().destroy();
616         assertEquals(0, HttpServletServerFactoryInstance.getServerFactory().inventory().size());
617     }
618
619     /**
620      * performs an http request.
621      *
622      * @throws MalformedURLException make sure URL is good
623      * @throws IOException thrown is IO exception occurs
624      * @throws InterruptedException thrown if thread interrupted occurs
625      */
626     private String http(String urlString)
627             throws IOException, InterruptedException {
628         URL url = new URL(urlString);
629         if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 100)) {
630             throw new IllegalStateException("port never opened: " + url);
631         }
632         return response(url.openConnection());
633     }
634
635     /**
636      * Performs a http request.
637      *
638      * @throws MalformedURLException make sure URL is good
639      * @throws IOException thrown is IO exception occurs
640      * @throws InterruptedException thrown if thread interrupted occurs
641      */
642     private String http(String urlString, String mediaType, String post)
643             throws IOException, InterruptedException {
644         URL url = new URL(urlString);
645         if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 100)) {
646             throw new IllegalStateException("port never opened: " + url);
647         }
648         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
649         conn.setRequestMethod("POST");
650         conn.setDoOutput(true);
651         conn.setRequestProperty("Content-Type", mediaType);
652         conn.setRequestProperty("Accept", mediaType);
653         IOUtils.write(post, conn.getOutputStream(), StandardCharsets.UTF_8);
654         return response(conn);
655     }
656
657     /**
658      * gets http response.
659      *
660      * @param conn connection from which to read
661      *
662      * @throws IOException if an I/O error occurs
663      */
664     private String response(URLConnection conn) throws IOException {
665         try (InputStream inpstr = conn.getInputStream()) {
666             return String.join("", IOUtils.readLines(inpstr, StandardCharsets.UTF_8));
667         }
668     }
669
670 }