Merge "Verify audit logs format `audit2019`"
[vid.git] / vid-app-common / src / test / java / org / onap / vid / mso / rest / OutgoingRequestHeadersTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 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.vid.mso.rest;
22
23 import static org.apache.commons.io.IOUtils.toInputStream;
24 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
25 import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
26 import static org.hamcrest.CoreMatchers.is;
27 import static org.hamcrest.CoreMatchers.startsWith;
28 import static org.hamcrest.MatcherAssert.assertThat;
29 import static org.hamcrest.Matchers.allOf;
30 import static org.hamcrest.Matchers.hasItem;
31 import static org.hamcrest.Matchers.hasToString;
32 import static org.hamcrest.Matchers.instanceOf;
33 import static org.hamcrest.Matchers.matchesPattern;
34 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertNotEquals;
36 import static org.mockito.ArgumentMatchers.any;
37 import static org.mockito.ArgumentMatchers.anyMap;
38 import static org.mockito.ArgumentMatchers.anyString;
39 import static org.mockito.ArgumentMatchers.eq;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.reset;
42 import static org.mockito.Mockito.when;
43
44 import com.google.common.collect.ImmutableList;
45 import io.joshworks.restclient.http.HttpResponse;
46 import java.nio.charset.StandardCharsets;
47 import java.util.Map;
48 import java.util.Optional;
49 import java.util.Set;
50 import java.util.UUID;
51 import java.util.function.Consumer;
52 import java.util.stream.Collectors;
53 import java.util.stream.Stream;
54 import javax.servlet.http.HttpServletRequest;
55 import javax.ws.rs.client.Client;
56 import javax.ws.rs.client.Invocation;
57 import javax.ws.rs.core.MultivaluedMap;
58 import org.apache.commons.lang3.reflect.FieldUtils;
59 import org.mockito.ArgumentCaptor;
60 import org.mockito.Captor;
61 import org.mockito.InjectMocks;
62 import org.mockito.Matchers;
63 import org.mockito.Mock;
64 import org.mockito.Mockito;
65 import org.mockito.MockitoAnnotations;
66 import org.onap.portalsdk.core.util.SystemProperties;
67 import org.onap.vid.aai.util.AAIRestInterface;
68 import org.onap.vid.aai.util.HttpsAuthClient;
69 import org.onap.vid.aai.util.ServletRequestHelper;
70 import org.onap.vid.aai.util.SystemPropertyHelper;
71 import org.onap.vid.client.SyncRestClient;
72 import org.onap.vid.controller.filter.PromiseRequestIdFilter;
73 import org.onap.vid.logging.Headers;
74 import org.onap.vid.mso.MsoProperties;
75 import org.onap.vid.mso.RestMsoImplementation;
76 import org.onap.vid.testUtils.TestUtils;
77 import org.onap.vid.utils.Logging;
78 import org.onap.vid.utils.SystemPropertiesWrapper;
79 import org.onap.vid.utils.Unchecked;
80 import org.springframework.http.HttpMethod;
81 import org.springframework.mock.web.MockHttpServletRequest;
82 import org.springframework.web.context.request.RequestContextHolder;
83 import org.springframework.web.context.request.ServletRequestAttributes;
84 import org.testng.annotations.BeforeClass;
85 import org.testng.annotations.BeforeMethod;
86 import org.testng.annotations.DataProvider;
87 import org.testng.annotations.Test;
88
89
90 public class OutgoingRequestHeadersTest {
91
92     private static final PromiseRequestIdFilter promiseRequestIdFilter = new PromiseRequestIdFilter();
93
94     @InjectMocks
95     private RestMsoImplementation restMsoImplementation;
96
97     private MsoRestClientNew msoRestClientNew;
98
99     @Mock
100     private SystemPropertyHelper systemPropertyHelper;
101
102     @Mock
103     private SystemPropertiesWrapper  systemPropertiesWrapper;
104
105     @Mock
106     private HttpsAuthClient httpsAuthClient;
107
108     @Mock
109     private ServletRequestHelper servletRequestHelper;
110
111     @Mock
112     private Logging loggingService;
113
114     @Mock
115     SyncRestClient syncRestClient;
116
117     @InjectMocks
118     private AAIRestInterface aaiRestInterface;
119
120     @Captor
121     private ArgumentCaptor<MultivaluedMap<String, Object>> multivaluedMapArgumentCaptor;
122
123     @BeforeClass
124     public void initMocks() {
125         MockitoAnnotations.initMocks(this);
126         when(servletRequestHelper.extractOrGenerateRequestId()).thenAnswer(invocation -> UUID.randomUUID().toString());
127         when(systemPropertiesWrapper.getProperty(MsoProperties.MSO_PASSWORD)).thenReturn("OBF:1vub1ua51uh81ugi1u9d1vuz");
128         when(systemPropertiesWrapper.getProperty(SystemProperties.APP_DISPLAY_NAME)).thenReturn("vid");
129         //the ctor of MsoRestClientNew require the above lines as preconditions
130         msoRestClientNew = new MsoRestClientNew(syncRestClient, "baseUrl",systemPropertiesWrapper);
131     }
132
133     @BeforeMethod
134     private void setup() {
135         putRequestInSpringContext();
136     }
137
138     public static void putRequestInSpringContext() {
139         RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(
140             (HttpServletRequest) promiseRequestIdFilter.wrapIfNeeded(new MockHttpServletRequest())));
141     }
142
143     @DataProvider
144     public Object[][] msoMethods() {
145         return Stream.<ThrowingConsumer<RestMsoImplementation>>of(
146                 client -> client.GetForObject("/any path", Object.class),
147                 client -> client.restCall(HttpMethod.DELETE, Object.class, "some payload", "/any path", Optional.of("userId")),
148                 client -> client.PostForObject("some payload", "/any path", Object.class)
149         ).map(l -> ImmutableList.of(l).toArray()).collect(Collectors.toList()).toArray(new Object[][]{});
150     }
151
152     @Test(dataProvider = "msoMethods")
153     public void mso(Consumer<RestMsoImplementation> f) throws Exception {
154         final TestUtils.JavaxRsClientMocks mocks = setAndGetMocksInsideRestImpl(restMsoImplementation);
155
156         f.accept(restMsoImplementation);
157
158         Invocation.Builder fakeBuilder = mocks.getFakeBuilder();
159         String requestIdValue = verifyXEcompRequestIdHeaderWasAdded(fakeBuilder);
160         assertEquals(requestIdValue, captureHeaderKeyAndReturnItsValue(fakeBuilder, "X-ONAP-RequestID"));
161         String invocationId1 = assertRequestHeaderIsUUID(fakeBuilder, "X-InvocationID");
162         assertThat((String) captureHeaderKeyAndReturnItsValue(fakeBuilder, "Authorization"), startsWith("Basic "));
163         verifyXOnapPartnerNameHeaderWasAdded(fakeBuilder);
164
165         //validate requestId is same in next call but invocationId is different
166
167         //given
168         final TestUtils.JavaxRsClientMocks mocks2 = setAndGetMocksInsideRestImpl(restMsoImplementation);
169
170         //when
171         f.accept(restMsoImplementation);
172         Invocation.Builder fakeBuilder2 = mocks2.getFakeBuilder();
173
174         //then
175         String requestIdValue2 = verifyXEcompRequestIdHeaderWasAdded(fakeBuilder2);
176         assertEquals(requestIdValue, requestIdValue2);
177
178         Object invocationId2 = assertRequestHeaderIsUUID(fakeBuilder2, "X-InvocationID");
179         assertNotEquals(invocationId1, invocationId2);
180     }
181
182     @Test
183     public void whenProvideMsoRestCallUserId_builderHasXRequestorIDHeader() throws Exception {
184
185         final TestUtils.JavaxRsClientMocks mocks = setAndGetMocksInsideRestImpl(restMsoImplementation);
186         String randomUserName = randomAlphabetic(10);
187
188         restMsoImplementation.restCall(HttpMethod.DELETE, String.class, null, "abc", Optional.of(randomUserName));
189         assertEquals(randomUserName, captureHeaderKeyAndReturnItsValue(mocks.getFakeBuilder(), "X-RequestorID"));
190     }
191
192     @DataProvider
193     public Object[][] msoRestClientNewMethods() {
194         return Stream.<ThrowingConsumer<MsoRestClientNew>>of(
195             client -> client.createInstance(new Object(), "/any path")
196         ).map(l -> ImmutableList.of(l).toArray()).collect(Collectors.toList()).toArray(new Object[][]{});
197     }
198
199     @Test(dataProvider = "msoRestClientNewMethods")
200     public void msoRestClientNewHeadersTest(Consumer<MsoRestClientNew> f) throws Exception {
201         Map[] captor = setMocksForMsoRestClientNew();
202
203         f.accept(msoRestClientNew);
204         Map headers = captor[0];
205
206         String ecompRequestId = assertRequestHeaderIsUUID(headers, "X-ECOMP-RequestID");
207         String onapRequestID = assertRequestHeaderIsUUID(headers, "X-ONAP-RequestID");
208         assertEquals(ecompRequestId, onapRequestID);
209
210
211         String invocationId1 = assertRequestHeaderIsUUID(headers, "X-InvocationID");
212         assertThat((String) headers.get("Authorization"), startsWith("Basic "));
213         assertThat(headers.get("X-ONAP-PartnerName"), is("VID.VID"));
214
215         //validate requestId is same in next call but invocationId is different
216
217         //given
218         captor = setMocksForMsoRestClientNew();
219
220         //when
221         f.accept(msoRestClientNew);
222         headers = captor[0];
223
224         //then
225         assertEquals(headers.get("X-ONAP-RequestID"), onapRequestID);
226         String invocationId2 = assertRequestHeaderIsUUID(headers, "X-InvocationID");
227         assertNotEquals(invocationId1, invocationId2);
228
229     }
230
231     private Map[] setMocksForMsoRestClientNew() {
232         reset(syncRestClient);
233         HttpResponse<String> httpResponse = mock(HttpResponse.class);
234         String expectedResponse = "myResponse";
235         when(httpResponse.getStatus()).thenReturn(202);
236         when(httpResponse.getBody()).thenReturn(expectedResponse);
237         when(httpResponse.getRawBody()).thenReturn(toInputStream(expectedResponse, StandardCharsets.UTF_8));
238         final Map[] headersCapture = new Map[1];
239         when(syncRestClient.post(anyString(), anyMap(), any(), eq(String.class))).thenAnswer(
240             invocation -> {
241                 headersCapture[0] = (Map)invocation.getArguments()[1];
242                 return httpResponse;
243             });
244
245         return headersCapture;
246     }
247
248     @DataProvider
249     public Object[][] aaiMethods() {
250         return Stream.<ThrowingConsumer<AAIRestInterface>>of(
251
252                 client -> client.RestGet("from app id", "some transId", Unchecked.toURI("/any path"), false),
253                 client -> client.Delete("whatever source id", "some transId", "/any path"),
254                 client -> client.RestPost("from app id", "/any path", "some payload", false),
255                 client -> client.RestPut("from app id", "/any path", "some payload", false, false)
256
257         ).map(l -> ImmutableList.of(l).toArray()).collect(Collectors.toList()).toArray(new Object[][]{});
258     }
259
260     @Test(dataProvider = "aaiMethods")
261     public void aai(Consumer<AAIRestInterface> f) throws Exception {
262         final TestUtils.JavaxRsClientMocks mocks = setAndGetMocksInsideRestImpl(aaiRestInterface);
263
264         f.accept(aaiRestInterface);
265
266         verifyXEcompRequestIdHeaderWasAdded(mocks.getFakeBuilder());
267         verifyXOnapPartnerNameHeaderWasAdded(mocks.getFakeBuilder());
268     }
269
270 //    @Test(dataProvider = "schedulerMethods")
271 //    public void scheduler(Consumer<AAIRestInterface> f) throws Exception {
272 //
273 //        This test os not feasible in the wat acheduler is implemented today,
274 //        as Scheduler's client is rewritten in every call.
275 //
276 //        :-(
277 //
278 //    }
279
280     private String verifyXEcompRequestIdHeaderWasAdded(Invocation.Builder fakeBuilder) {
281         final String requestIdHeader = "x-ecomp-requestid";
282         return assertRequestHeaderIsUUID(fakeBuilder, requestIdHeader);
283     }
284
285     private String assertRequestHeaderIsUUID(Invocation.Builder fakeBuilder, String headerName) {
286         Object headerValue = captureHeaderKeyAndReturnItsValue(fakeBuilder, headerName);
287         return assertRequestHeaderIsUUID(headerName, headerValue);
288     }
289
290     private String assertRequestHeaderIsUUID(Map headers, String headerName) {
291         return assertRequestHeaderIsUUID(headerName, headers.get(headerName));
292     }
293
294     private String assertRequestHeaderIsUUID(String headerName, Object headerValue) {
295         final String uuidRegex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
296         assertThat("header '" + headerName + "' should be a uuid", headerValue,
297                 allOf(instanceOf(String.class), hasToString(matchesPattern(uuidRegex))));
298         return (String)headerValue;
299     }
300
301     private void verifyXOnapPartnerNameHeaderWasAdded(Invocation.Builder fakeBuilder) {
302         assertThat(
303             captureHeaderKeyAndReturnItsValue(fakeBuilder, Headers.PARTNER_NAME.getHeaderName()),
304             is("VID.VID")
305         );
306     }
307
308     private Object captureHeaderKeyAndReturnItsValue(Invocation.Builder fakeBuilder, String headerName) {
309         // Checks that the builder was called with either one of header("x-ecomp-requestid", uuid)
310         // or the plural brother: headers(Map.of("x-ecomp-requestid", Set.of(uuid))
311
312         Object requestId;
313         // The 'verify()' will capture the request id. If no match -- AssertionError will
314         // catch for a second chance -- another 'verify()'.
315         try {
316             try {
317                 ArgumentCaptor<Object> argumentCaptor = ArgumentCaptor.forClass(Object.class);
318                 Mockito.verify(fakeBuilder)
319                     .header(
320                         Matchers.argThat(s -> equalsIgnoreCase(s, headerName)),
321                         argumentCaptor.capture()
322                     );
323                 requestId = argumentCaptor.getValue();
324
325             } catch (AssertionError e) {
326                 Mockito.verify(fakeBuilder).headers(multivaluedMapArgumentCaptor.capture());
327
328                 final MultivaluedMap<String, Object> headersMap = multivaluedMapArgumentCaptor.getValue();
329                 final String thisRequestIdHeader = getFromSetCaseInsensitive(headersMap.keySet(), headerName);
330
331                 assertThat(headersMap.keySet(), hasItem(thisRequestIdHeader));
332                 requestId = headersMap.getFirst(thisRequestIdHeader);
333             }
334         } catch (AssertionError e) {
335             throw new AssertionError("header not captured: " + headerName, e);
336         }
337         return requestId;
338     }
339
340     private String getFromSetCaseInsensitive(Set<String> set, String key) {
341         return set.stream()
342                 .filter(anotherString -> anotherString.equalsIgnoreCase(key))
343                 .findFirst()
344                 .orElse(key);
345     }
346
347     private TestUtils.JavaxRsClientMocks setAndGetMocksInsideRestImpl(Class<?> clazz) throws IllegalAccessException {
348         TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks();
349         Client fakeClient = mocks.getFakeClient();
350
351         FieldUtils.writeStaticField(clazz, "client", fakeClient, true);
352
353         return mocks;
354     }
355
356     private TestUtils.JavaxRsClientMocks setAndGetMocksInsideRestImpl(Object instance) throws IllegalAccessException {
357         TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks();
358         Client fakeClient = mocks.getFakeClient();
359
360         FieldUtils.writeField(instance, "client", fakeClient, true);
361
362         return mocks;
363     }
364
365     @FunctionalInterface
366     public interface ThrowingConsumer<T> extends Consumer<T> {
367         @Override
368         default void accept(T t) {
369             try {
370                 acceptThrows(t);
371             } catch (Exception e) {
372                 throw new RuntimeException(e);
373             }
374         }
375
376         void acceptThrows(T t) throws Exception;
377     }
378
379 }