Release version 6.0.0
[vid.git] / vid-app-common / src / test / java / org / onap / vid / controller / PromiseRequestIdFilterTest.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.controller;
22
23 import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
24 import static org.hamcrest.CoreMatchers.is;
25 import static org.hamcrest.MatcherAssert.assertThat;
26 import static org.hamcrest.Matchers.containsInAnyOrder;
27 import static org.hamcrest.Matchers.emptyOrNullString;
28 import static org.hamcrest.Matchers.equalToIgnoringCase;
29 import static org.hamcrest.Matchers.not;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.argThat;
32 import static org.onap.portalsdk.core.util.SystemProperties.ECOMP_REQUEST_ID;
33
34 import com.google.common.collect.ImmutableMap;
35 import java.io.IOException;
36 import java.util.Arrays;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.Enumeration;
40 import java.util.Map;
41 import java.util.function.Function;
42 import javax.servlet.FilterChain;
43 import javax.servlet.ServletException;
44 import javax.servlet.ServletRequest;
45 import javax.servlet.ServletResponse;
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletResponse;
48 import org.mockito.ArgumentCaptor;
49 import org.mockito.Mockito;
50 import org.mockito.stubbing.Answer;
51 import org.onap.portalsdk.core.web.support.UserUtils;
52 import org.onap.vid.controller.filter.PromiseRequestIdFilter;
53 import org.springframework.mock.web.MockHttpServletResponse;
54 import org.testng.annotations.Test;
55
56 @Test
57 public class PromiseRequestIdFilterTest {
58
59     private final String anotherHeader = "ANDREI_RUBLEV";
60     private final String anotherValue = "foo value";
61     private final String mixedCaseHeader = "x-ecomp-REQUESTID";
62
63     @Test
64     public void givenRequestIdHeader_headerValueNotChanged() throws IOException, ServletException {
65
66         final String someTxId = "863850e2-8545-4efd-94b8-afba5f52b3d5";
67
68         final ImmutableMap<String, String> incomingRequestHeaders = ImmutableMap.of(
69                 anotherHeader, anotherValue,
70                 ECOMP_REQUEST_ID, someTxId
71         );
72
73         buildRequestThenRunThroughFilterAndAssertResultRequestHeaders(incomingRequestHeaders, specificTxId(someTxId));
74     }
75
76
77     @Test
78     public void givenRequestIdHeaderThatIsNotAUUID_headerValueChanged() throws IOException, ServletException {
79
80         final String someTxId = "863850e28544efd94b8afba5f52b3d5";
81
82         final ImmutableMap<String, String> incomingRequestHeaders = ImmutableMap.of(
83                 anotherHeader, anotherValue,
84                 ECOMP_REQUEST_ID, someTxId
85         );
86
87         buildRequestThenRunThroughFilterAndAssertResultRequestHeaders(incomingRequestHeaders, UserUtils::getRequestId);
88     }
89
90
91     @Test
92     public void givenMixedCaseRequestIdHeader_headerValueNotChanged() throws IOException, ServletException {
93
94         final String someTxId = "729bbd8d-b0c2-4809-a794-dcccd9cda2c0";
95
96         final ImmutableMap<String, String> incomingRequestHeaders = ImmutableMap.of(
97                 mixedCaseHeader, someTxId,
98                 anotherHeader, anotherValue
99         );
100
101         buildRequestThenRunThroughFilterAndAssertResultRequestHeaders(incomingRequestHeaders, specificTxId(someTxId));
102     }
103
104     @Test
105     public void givenNoRequestIdHeader_headerValueWasGenerated() throws IOException, ServletException {
106
107         final ImmutableMap<String, String> incomingRequestHeaders = ImmutableMap.of(
108                 anotherHeader, anotherValue
109         );
110
111         buildRequestThenRunThroughFilterAndAssertResultRequestHeaders(incomingRequestHeaders, UserUtils::getRequestId);
112     }
113
114     
115     private void buildRequestThenRunThroughFilterAndAssertResultRequestHeaders(
116             ImmutableMap<String, String> originalRequestHeaders,
117             Function<HttpServletRequest, String> txIdExtractor
118     ) throws IOException, ServletException {
119         HttpServletRequest servletRequest = createMockedHttpServletRequest(originalRequestHeaders);
120         HttpServletResponse servletResponse = createMockedHttpServletResponse();
121
122         final FilterChain capturingFilterChain = Mockito.mock(FilterChain.class);
123
124         //////////////////
125         //
126         // doFilter() is the function under test
127         //
128         new PromiseRequestIdFilter().doFilter(servletRequest, servletResponse, capturingFilterChain);
129         //
130         //////////////////
131
132         final ServletRequest capturedServletRequest = extractCapturedServletRequest(capturingFilterChain);
133         final ServletResponse capturedServletResponse = extractCapturedServletResponse(capturingFilterChain);
134         final String expectedTxId = txIdExtractor.apply((HttpServletRequest) capturedServletRequest);
135
136         assertRequestObjectHeaders(capturedServletRequest, expectedTxId);
137         assertResponseObjectHeaders(capturedServletResponse, expectedTxId);
138     }
139
140
141     private void assertRequestObjectHeaders(ServletRequest request, String expectedTxId) {
142         /*
143         Assert that:
144         - Two headers are in place
145         - Direct value extraction is as expected
146         - UserUtils.getRequestId() returns correct and valid value
147          */
148         final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
149
150         assertThat(Collections.list(httpServletRequest.getHeaderNames()),
151                 containsInAnyOrder(equalToIgnoringCase(ECOMP_REQUEST_ID), equalToIgnoringCase(anotherHeader)));
152
153         assertThat(httpServletRequest.getHeader(anotherHeader), is(anotherValue));
154
155         assertThat(httpServletRequest.getHeader(ECOMP_REQUEST_ID), is(expectedTxId));
156         assertThat(httpServletRequest.getHeader(mixedCaseHeader), is(expectedTxId));
157
158         assertThat(UserUtils.getRequestId(httpServletRequest), is(expectedTxId));
159         assertThat(UserUtils.getRequestId(httpServletRequest), is(not(emptyOrNullString())));
160     }
161
162     private void assertResponseObjectHeaders(ServletResponse response, String txId) {
163         final String REQUEST_ID_HEADER_NAME_IN_RESPONSE = mixedCaseHeader + "-echo";
164         final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
165
166         assertThat("header " + REQUEST_ID_HEADER_NAME_IN_RESPONSE.toLowerCase() + " in response must be provided",
167                 httpServletResponse.getHeader(REQUEST_ID_HEADER_NAME_IN_RESPONSE), is(txId));
168     }
169
170
171
172     private HttpServletRequest createMockedHttpServletRequest(Map<String, String> requestHeaders) {
173         HttpServletRequest servletRequest = Mockito.mock(HttpServletRequest.class);
174         requestHeaders.forEach((k, v) -> {
175             Mockito.when(servletRequest.getHeader(argThat(s -> equalsIgnoreCase(s, k)))).thenReturn(v);
176             Mockito.when(servletRequest.getHeaders(argThat(s -> equalsIgnoreCase(s, k)))).then(returnEnumerationAnswer(v));
177         });
178         Mockito.when(servletRequest.getHeaderNames()).then(returnEnumerationAnswer(requestHeaders.keySet()));
179         return servletRequest;
180     }
181
182     private HttpServletResponse createMockedHttpServletResponse() {
183         return new MockHttpServletResponse();
184     }
185
186     private static Answer<Enumeration<String>> returnEnumerationAnswer(String ... items) {
187         return returnEnumerationAnswer(Arrays.asList(items));
188     }
189
190     private static Answer<Enumeration<String>> returnEnumerationAnswer(Collection<String> items) {
191         return invocation -> Collections.enumeration(items);
192     }
193
194     private Function<HttpServletRequest, String> specificTxId(String someTxId) {
195         return r -> someTxId;
196     }
197
198     private ServletRequest extractCapturedServletRequest(FilterChain capturingFilterChain) throws IOException, ServletException {
199         ArgumentCaptor<ServletRequest> captor = ArgumentCaptor.forClass(ServletRequest.class);
200         Mockito.verify(capturingFilterChain).doFilter(captor.capture(), any());
201         return captor.getValue();
202     }
203
204     private ServletResponse extractCapturedServletResponse(FilterChain capturingFilterChain) throws IOException, ServletException {
205         ArgumentCaptor<ServletResponse> captor = ArgumentCaptor.forClass(ServletResponse.class);
206         Mockito.verify(capturingFilterChain).doFilter(any(), captor.capture());
207         return captor.getValue();
208     }
209
210 }