2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.common.endpoints.http.server.test;
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
34 import java.io.IOException;
35 import java.io.PrintWriter;
36 import java.net.HttpURLConnection;
38 import java.nio.charset.StandardCharsets;
39 import java.util.Arrays;
40 import java.util.Base64;
41 import java.util.Properties;
42 import javax.servlet.http.HttpServletRequest;
43 import javax.ws.rs.Consumes;
44 import javax.ws.rs.POST;
45 import javax.ws.rs.Path;
46 import javax.ws.rs.Produces;
47 import javax.ws.rs.core.MediaType;
48 import javax.ws.rs.core.Response;
50 import org.apache.commons.io.IOUtils;
51 import org.junit.AfterClass;
52 import org.junit.Before;
53 import org.junit.BeforeClass;
54 import org.junit.Test;
55 import org.mockito.ArgumentCaptor;
56 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
57 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactory;
58 import org.onap.policy.common.endpoints.http.server.JsonExceptionMapper;
59 import org.onap.policy.common.endpoints.http.server.RestServer;
60 import org.onap.policy.common.endpoints.http.server.RestServer.Factory;
61 import org.onap.policy.common.endpoints.http.server.YamlExceptionMapper;
62 import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler;
63 import org.onap.policy.common.endpoints.http.server.aaf.AafAuthFilter;
64 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
65 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
66 import org.onap.policy.common.gson.GsonMessageBodyHandler;
67 import org.onap.policy.common.utils.coder.StandardCoder;
68 import org.onap.policy.common.utils.network.NetworkUtil;
69 import org.powermock.reflect.Whitebox;
71 public class RestServerTest {
72 private static final String SERVER1 = "my-server-A";
73 private static final String SERVER2 = "my-server-B";
74 private static final String FACTORY_FIELD = "factory";
75 private static final String HOST = "my-host";
76 private static final String PARAM_NAME = "my-param";
77 private static final String PASS = "my-pass";
78 private static final Integer PORT = 9876;
79 private static final String USER = "my-user";
81 private static Factory saveFactory;
82 private static RestServer realRest;
83 private static int realPort;
84 private static RestServerParameters params;
86 private RestServer rest;
87 private HttpServletServer server1;
88 private HttpServletServer server2;
89 private Factory factory;
90 private HttpServletServerFactory serverFactory;
91 private String errorMsg;
94 * Starts the REST server.
95 * @throws Exception if an error occurs
98 public static void setUpBeforeClass() throws Exception {
99 saveFactory = Whitebox.getInternalState(RestServer.class, FACTORY_FIELD);
101 realPort = NetworkUtil.allocPort();
105 realRest = new RestServer(params, null, RealProvider.class) {
107 protected Properties getServerProperties(RestServerParameters restServerParameters, String names) {
108 Properties props = super.getServerProperties(restServerParameters, names);
110 String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "."
111 + restServerParameters.getName();
112 props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, "false");
119 assertTrue(NetworkUtil.isTcpPortOpen(params.getHost(), params.getPort(), 100, 100));
123 * Restores the factory and stops the REST server.
126 public static void tearDownAfterClass() {
127 Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, saveFactory);
136 public void setUp() {
137 server1 = mock(HttpServletServer.class);
138 server2 = mock(HttpServletServer.class);
139 factory = mock(Factory.class);
140 serverFactory = mock(HttpServletServerFactory.class);
144 when(factory.getServerFactory()).thenReturn(serverFactory);
145 when(serverFactory.build(any())).thenReturn(Arrays.asList(server1, server2));
147 when(server1.getName()).thenReturn(SERVER1);
148 when(server2.getName()).thenReturn(SERVER2);
150 Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, factory);
154 public void testRestServer() {
155 rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
158 verify(server1).start();
159 verify(server2).start();
162 verify(server1).stop();
163 verify(server2).stop();
167 public void testRestServer_NoAaf() {
168 rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
169 verify(server1, never()).addFilterClass(any(), any());
170 verify(server2, never()).addFilterClass(any(), any());
174 public void testRestServer_OnlyOneAaf() {
175 when(server2.isAaf()).thenReturn(true);
177 rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
179 verify(server1, never()).addFilterClass(any(), any());
180 verify(server2).addFilterClass(null, Filter.class.getName());
184 public void testRestServer_BothAaf() {
185 when(server1.isAaf()).thenReturn(true);
186 when(server2.isAaf()).thenReturn(true);
188 rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
190 verify(server1).addFilterClass(null, Filter.class.getName());
191 verify(server2).addFilterClass(null, Filter.class.getName());
195 public void testRestServer_BothAaf_NoFilter() {
196 when(server1.isAaf()).thenReturn(true);
197 when(server2.isAaf()).thenReturn(true);
199 rest = new RestServer(params, null, Provider1.class, Provider2.class);
201 verify(server1, never()).addFilterClass(any(), any());
202 verify(server2, never()).addFilterClass(any(), any());
206 public void testRestServer_MissingProviders() {
207 assertThatIllegalArgumentException().isThrownBy(() -> new RestServer(params, Filter.class));
211 public void testGetServerProperties_testGetProviderNames() {
212 rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
214 ArgumentCaptor<Properties> cap = ArgumentCaptor.forClass(Properties.class);
215 verify(serverFactory).build(cap.capture());
217 Properties props = cap.getValue();
218 String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + PARAM_NAME;
220 assertEquals(HOST, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX));
221 assertEquals(String.valueOf(PORT),
222 props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX));
223 assertEquals(Provider1.class.getName() + "," + Provider2.class.getName(),
224 props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_REST_CLASSES_SUFFIX));
225 assertEquals("false", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX));
226 assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX));
227 assertEquals(USER, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_USERNAME_SUFFIX));
228 assertEquals(PASS, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_PASSWORD_SUFFIX));
229 assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX));
230 assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_AAF_SUFFIX));
231 assertEquals(String.join(",", GsonMessageBodyHandler.class.getName(), YamlMessageBodyHandler.class.getName(),
232 JsonExceptionMapper.class.getName(), YamlExceptionMapper.class.getName()),
233 props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER));
237 public void testInvalidJson() throws Exception {
240 assertEquals(200, roundTrip(new StandardCoder().encode(new MyRequest())));
241 assertEquals(400, roundTrip("{'bogus-json'"));
242 assertThat(errorMsg).contains("Invalid request");
246 public void testInvalidYaml() throws Exception {
249 assertEquals(200, roundTrip(new StandardCoder().encode(new MyRequest()),
250 YamlMessageBodyHandler.APPLICATION_YAML));
251 assertEquals(400, roundTrip("<bogus yaml", YamlMessageBodyHandler.APPLICATION_YAML));
252 assertThat(errorMsg).contains("Invalid request");
255 private int roundTrip(String request) throws IOException {
256 return roundTrip(request, MediaType.APPLICATION_JSON);
259 private int roundTrip(String request, String mediaType) throws IOException {
260 URL url = new URL("http://" + params.getHost() + ":" + params.getPort() + "/request");
261 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
262 conn.setDoInput(true);
263 conn.setDoOutput(true);
264 conn.setRequestMethod("POST");
265 String auth = params.getUserName() + ":" + params.getPassword();
266 conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(auth.getBytes()));
267 conn.setRequestProperty("Content-type", mediaType);
268 conn.setRequestProperty("Accept", mediaType);
271 try (PrintWriter wtr = new PrintWriter(conn.getOutputStream())) {
275 int code = conn.getResponseCode();
280 errorMsg = IOUtils.toString(conn.getErrorStream(), StandardCharsets.UTF_8);
287 public void testToString() {
288 rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
289 assertNotNull(rest.toString());
293 public void testFactory() {
294 assertNotNull(saveFactory);
295 assertNotNull(saveFactory.getServerFactory());
298 private static void initRealParams() {
301 when(params.getHost()).thenReturn("localhost");
302 when(params.getPort()).thenReturn(realPort);
303 when(params.isHttps()).thenReturn(false);
304 when(params.isAaf()).thenReturn(false);
307 private static void initParams() {
308 params = mock(RestServerParameters.class);
310 when(params.getHost()).thenReturn(HOST);
311 when(params.getName()).thenReturn(PARAM_NAME);
312 when(params.getPassword()).thenReturn(PASS);
313 when(params.getPort()).thenReturn(PORT);
314 when(params.getUserName()).thenReturn(USER);
315 when(params.isAaf()).thenReturn(true);
316 when(params.isHttps()).thenReturn(true);
319 private static class Filter extends AafAuthFilter {
321 protected String getPermissionType(HttpServletRequest request) {
326 protected String getPermissionInstance(HttpServletRequest request) {
331 private static class Provider1 {
332 private Provider1() {
337 private static class Provider2 {
338 private Provider2() {
344 @Produces({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML})
345 @Consumes({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML})
346 public static class RealProvider {
349 public Response decision(MyRequest body) {
350 return Response.status(Response.Status.OK).entity(new MyResponse()).build();
355 public static class MyRequest {
360 public static class MyResponse {
361 private String text = "hello";