ee28b96d78c7e3697686550e332baff93e508af8
[policy/common.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019 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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.common.endpoints.http.server.test;
22
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.Matchers.any;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32
33 import java.io.IOException;
34 import java.io.PrintWriter;
35 import java.net.HttpURLConnection;
36 import java.net.URL;
37 import java.util.Arrays;
38 import java.util.Base64;
39 import java.util.Properties;
40 import javax.servlet.http.HttpServletRequest;
41 import javax.ws.rs.Consumes;
42 import javax.ws.rs.POST;
43 import javax.ws.rs.Path;
44 import javax.ws.rs.Produces;
45 import javax.ws.rs.core.MediaType;
46 import javax.ws.rs.core.Response;
47 import lombok.Getter;
48 import org.junit.After;
49 import org.junit.AfterClass;
50 import org.junit.Before;
51 import org.junit.BeforeClass;
52 import org.junit.Test;
53 import org.mockito.ArgumentCaptor;
54 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
55 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactory;
56 import org.onap.policy.common.endpoints.http.server.JsonExceptionMapper;
57 import org.onap.policy.common.endpoints.http.server.RestServer;
58 import org.onap.policy.common.endpoints.http.server.RestServer.Factory;
59 import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler;
60 import org.onap.policy.common.endpoints.http.server.aaf.AafAuthFilter;
61 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
62 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
63 import org.onap.policy.common.gson.GsonMessageBodyHandler;
64 import org.onap.policy.common.utils.coder.StandardCoder;
65 import org.onap.policy.common.utils.network.NetworkUtil;
66 import org.powermock.reflect.Whitebox;
67
68 public class RestServerTest {
69     private static final String SERVER1 = "my-server-A";
70     private static final String SERVER2 = "my-server-B";
71     private static final String FACTORY_FIELD = "factory";
72     private static final String HOST = "my-host";
73     private static final String PARAM_NAME = "my-param";
74     private static final String PASS = "my-pass";
75     private static final Integer PORT = 9876;
76     private static final String USER = "my-user";
77     private static Factory saveFactory;
78
79     private RestServer realRest;
80     private RestServer rest;
81     private HttpServletServer server1;
82     private HttpServletServer server2;
83     private Factory factory;
84     private HttpServletServerFactory serverFactory;
85     private RestServerParameters params;
86
87     @BeforeClass
88     public static void setUpBeforeClass() {
89         saveFactory = Whitebox.getInternalState(RestServer.class, FACTORY_FIELD);
90     }
91
92     @AfterClass
93     public static void tearDownAfterClass() {
94         Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, saveFactory);
95     }
96
97     /**
98      * Initializes mocks.
99      */
100     @Before
101     public void setUp() {
102         server1 = mock(HttpServletServer.class);
103         server2 = mock(HttpServletServer.class);
104         factory = mock(Factory.class);
105         serverFactory = mock(HttpServletServerFactory.class);
106         params = mock(RestServerParameters.class);
107
108         when(factory.getServerFactory()).thenReturn(serverFactory);
109         when(serverFactory.build(any())).thenReturn(Arrays.asList(server1, server2));
110
111         when(server1.getName()).thenReturn(SERVER1);
112         when(server2.getName()).thenReturn(SERVER2);
113
114         when(params.getHost()).thenReturn(HOST);
115         when(params.getName()).thenReturn(PARAM_NAME);
116         when(params.getPassword()).thenReturn(PASS);
117         when(params.getPort()).thenReturn(PORT);
118         when(params.getUserName()).thenReturn(USER);
119         when(params.isAaf()).thenReturn(true);
120         when(params.isHttps()).thenReturn(true);
121
122         Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, factory);
123
124         realRest = null;
125     }
126
127     /**
128      * Stops the rest server.
129      */
130     @After
131     public void tearDown() {
132         if (realRest != null) {
133             realRest.stop();
134         }
135     }
136
137     @Test
138     public void testRestServer() {
139         rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
140
141         rest.start();
142         verify(server1).start();
143         verify(server2).start();
144
145         rest.stop();
146         verify(server1).stop();
147         verify(server2).stop();
148     }
149
150     @Test
151     public void testRestServer_NoAaf() {
152         rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
153         verify(server1, never()).addFilterClass(any(), any());
154         verify(server2, never()).addFilterClass(any(), any());
155     }
156
157     @Test
158     public void testRestServer_OnlyOneAaf() {
159         when(server2.isAaf()).thenReturn(true);
160
161         rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
162
163         verify(server1, never()).addFilterClass(any(), any());
164         verify(server2).addFilterClass(null, Filter.class.getName());
165     }
166
167     @Test
168     public void testRestServer_BothAaf() {
169         when(server1.isAaf()).thenReturn(true);
170         when(server2.isAaf()).thenReturn(true);
171
172         rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
173
174         verify(server1).addFilterClass(null, Filter.class.getName());
175         verify(server2).addFilterClass(null, Filter.class.getName());
176     }
177
178     @Test
179     public void testRestServer_BothAaf_NoFilter() {
180         when(server1.isAaf()).thenReturn(true);
181         when(server2.isAaf()).thenReturn(true);
182
183         rest = new RestServer(params, null, Provider1.class, Provider2.class);
184
185         verify(server1, never()).addFilterClass(any(), any());
186         verify(server2, never()).addFilterClass(any(), any());
187     }
188
189     @Test
190     public void testRestServer_MissingProviders() {
191         assertThatIllegalArgumentException().isThrownBy(() -> new RestServer(params, Filter.class));
192     }
193
194     @Test
195     public void testGetServerProperties_testGetProviderNames() {
196         rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
197
198         ArgumentCaptor<Properties> cap = ArgumentCaptor.forClass(Properties.class);
199         verify(serverFactory).build(cap.capture());
200
201         Properties props = cap.getValue();
202         String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + PARAM_NAME;
203
204         assertEquals(HOST, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX));
205         assertEquals(String.valueOf(PORT),
206                         props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX));
207         assertEquals(Provider1.class.getName() + "," + Provider2.class.getName(),
208                         props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_REST_CLASSES_SUFFIX));
209         assertEquals("false", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX));
210         assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX));
211         assertEquals(USER, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_USERNAME_SUFFIX));
212         assertEquals(PASS, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_PASSWORD_SUFFIX));
213         assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX));
214         assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_AAF_SUFFIX));
215         assertEquals(String.join(",", GsonMessageBodyHandler.class.getName(), YamlMessageBodyHandler.class.getName(),
216                         JsonExceptionMapper.class.getName()),
217                         props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER));
218     }
219
220     @Test
221     public void testInvalidJson() throws Exception {
222         when(params.getHost()).thenReturn("localhost");
223         when(params.getPort()).thenReturn(NetworkUtil.allocPort());
224         when(params.isHttps()).thenReturn(false);
225         when(params.isAaf()).thenReturn(false);
226
227         // use real factory
228         Whitebox.setInternalState(RestServer.class, FACTORY_FIELD, saveFactory);
229
230         realRest = new RestServer(params, null, RealProvider.class) {
231             @Override
232             protected Properties getServerProperties(RestServerParameters restServerParameters, String names) {
233                 Properties props = super.getServerProperties(restServerParameters, names);
234
235                 String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "."
236                                 + restServerParameters.getName();
237                 props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, "false");
238
239                 return props;
240             }
241         };
242
243         realRest.start();
244         assertTrue(NetworkUtil.isTcpPortOpen(params.getHost(), params.getPort(), 100, 100));
245
246         assertEquals(200, roundTrip(new StandardCoder().encode(new MyRequest())));
247         assertEquals(400, roundTrip("{'bogus-json'"));
248     }
249
250     private int roundTrip(String request) throws IOException {
251         URL url = new URL("http://" + params.getHost() + ":" + params.getPort() + "/request");
252         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
253         conn.setDoInput(true);
254         conn.setDoOutput(true);
255         conn.setRequestMethod("POST");
256         String auth = params.getUserName() + ":" + params.getPassword();
257         conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(auth.getBytes()));
258         conn.setRequestProperty("Content-type", MediaType.APPLICATION_JSON);
259         conn.connect();
260
261         try (PrintWriter wtr = new PrintWriter(conn.getOutputStream())) {
262             wtr.write(request);
263         }
264
265         return conn.getResponseCode();
266     }
267
268     @Test
269     public void testToString() {
270         rest = new RestServer(params, Filter.class, Provider1.class, Provider2.class);
271         assertNotNull(rest.toString());
272     }
273
274     @Test
275     public void testFactory() {
276         assertNotNull(saveFactory);
277         assertNotNull(saveFactory.getServerFactory());
278     }
279
280     private static class Filter extends AafAuthFilter {
281         @Override
282         protected String getPermissionType(HttpServletRequest request) {
283             return "";
284         }
285
286         @Override
287         protected String getPermissionInstance(HttpServletRequest request) {
288             return "";
289         }
290     }
291
292     private static class Provider1 {
293         private Provider1() {
294             // do nothing
295         }
296     }
297
298     private static class Provider2 {
299         private Provider2() {
300             // do nothing
301         }
302     }
303
304     @Path("/")
305     @Produces(MediaType.APPLICATION_JSON)
306     @Consumes(MediaType.APPLICATION_JSON)
307     public static class RealProvider {
308         @POST
309         @Path("/request")
310         public Response decision(MyRequest body) {
311             return Response.status(Response.Status.OK).entity(new MyResponse()).build();
312         }
313     }
314
315     @Getter
316     public static class MyRequest {
317         private String data;
318     }
319
320     @Getter
321     public static class MyResponse {
322         private String text = "hello";
323     }
324 }