Config fetch for VESCollector through DCAE-SDK (CBS Client)
[dcaegen2/collectors/ves.git] / src / test / java / org / onap / dcae / restapi / VesRestControllerTest.java
1 /*
2  * ============LICENSE_START=======================================================
3  * PROJECT
4  * ================================================================================
5  * Copyright (C) 2020 Nokia. All rights reserved.s
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.dcae.restapi;
22
23 import com.fasterxml.jackson.databind.ObjectMapper;
24 import com.google.common.reflect.TypeToken;
25 import com.google.gson.Gson;
26 import com.networknt.schema.JsonSchema;
27 import io.vavr.collection.HashMap;
28 import org.apache.http.HttpStatus;
29 import org.jetbrains.annotations.NotNull;
30 import org.json.JSONObject;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.mockito.ArgumentCaptor;
35 import org.mockito.Mock;
36 import org.mockito.junit.MockitoJUnitRunner;
37 import org.onap.dcae.ApplicationSettings;
38 import org.onap.dcae.JSonSchemasSupplier;
39 import org.onap.dcae.common.EventSender;
40 import org.onap.dcae.common.EventTransformation;
41 import org.onap.dcae.common.HeaderUtils;
42 import org.onap.dcae.common.JsonDataLoader;
43 import org.onap.dcae.common.validator.StndDefinedDataValidator;
44 import org.onap.dcae.common.publishing.DMaaPEventPublisher;
45 import org.slf4j.Logger;
46 import org.springframework.http.ResponseEntity;
47 import org.springframework.mock.web.MockHttpServletRequest;
48 import org.springframework.web.context.request.RequestContextHolder;
49 import org.springframework.web.context.request.ServletRequestAttributes;
50
51 import java.io.FileReader;
52 import java.io.IOException;
53 import java.lang.reflect.Type;
54 import java.util.List;
55 import java.util.Map;
56
57 import static org.assertj.core.api.Assertions.assertThat;
58 import static org.mockito.ArgumentMatchers.any;
59 import static org.mockito.ArgumentMatchers.anyString;
60 import static org.mockito.ArgumentMatchers.eq;
61 import static org.mockito.Mockito.never;
62 import static org.mockito.Mockito.times;
63 import static org.mockito.Mockito.verify;
64 import static org.mockito.Mockito.when;
65
66 @RunWith(MockitoJUnitRunner.class)
67 public class VesRestControllerTest {
68
69     private static final String EVENT_TRANSFORM_FILE_PATH = "/eventTransform.json";
70     private static final String ACCEPTED = "Accepted";
71     private static final String VERSION_V7 = "v7";
72     public static final String VES_FAULT_TOPIC = "ves-fault";
73     public static final String VES_3_GPP_FAULT_SUPERVISION_TOPIC = "ves-3gpp-fault-supervision";
74
75     private VesRestController vesRestController;
76
77     @Mock
78     private ApplicationSettings applicationSettings;
79
80     @Mock
81     private Logger logger;
82
83     @Mock
84     private HeaderUtils headerUtils;
85
86     @Mock
87     private DMaaPEventPublisher eventPublisher;
88
89     @Mock
90     private StndDefinedDataValidator stndDefinedDataValidator;
91
92     @Before
93     public void setUp(){
94         final HashMap<String, String[]> streamIds = HashMap.of(
95                 "fault", new String[]{VES_FAULT_TOPIC},
96                 "3GPP-FaultSupervision", new String[]{VES_3_GPP_FAULT_SUPERVISION_TOPIC}
97         );
98         this.vesRestController = new VesRestController(applicationSettings, logger,
99                 new EventSender(eventPublisher, streamIds), headerUtils, stndDefinedDataValidator);
100     }
101
102     @Test
103     public void shouldReportThatApiVersionIsNotSupported() {
104         // given
105         when(applicationSettings.isVersionSupported("v20")).thenReturn(false);
106         MockHttpServletRequest request = givenMockHttpServletRequest();
107
108         // when
109         final ResponseEntity<String> event = vesRestController.event("", "v20", request);
110
111         // then
112         assertThat(event.getStatusCodeValue()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
113         assertThat(event.getBody()).isEqualTo("API version v20 is not supported");
114         verifyThatEventWasNotSend();
115     }
116
117     @Test
118     public void shouldTransformEventAccordingToEventTransformFile() throws IOException {
119         //given
120         configureEventTransformations();
121         configureHeadersForEventListener();
122
123         MockHttpServletRequest request = givenMockHttpServletRequest();
124
125         String validEvent = JsonDataLoader.loadContent("/ves7_valid_30_1_1_event.json");
126
127         //when
128         final ResponseEntity<String> response = vesRestController.event(validEvent, VERSION_V7, request);
129
130         //then
131         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED);
132         assertThat(response.getBody()).isEqualTo(ACCEPTED);
133         verifyThatTransformedEventWasSend(eventPublisher, validEvent);
134     }
135
136
137     @Test
138     public void shouldSendBatchOfEvents() throws IOException {
139         //given
140         configureEventTransformations();
141         configureHeadersForEventListener();
142
143         MockHttpServletRequest request = givenMockHttpServletRequest();
144
145         String validEvent = JsonDataLoader.loadContent("/ves7_batch_valid.json");
146
147         //when
148         final ResponseEntity<String> response = vesRestController.events(validEvent, VERSION_V7, request);
149
150         //then
151         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED);
152         assertThat(response.getBody()).isEqualTo(ACCEPTED);
153         verify(eventPublisher, times(2)).sendEvent(any(),any());
154     }
155
156     @Test
157     public void shouldSendStndDomainEventIntoDomainStream() throws IOException {
158         //given
159         configureEventTransformations();
160         configureHeadersForEventListener();
161
162         MockHttpServletRequest request = givenMockHttpServletRequest();
163         configureSchemasSupplierForStndDefineEvent();
164
165         String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_valid.json");
166
167         //when
168         final ResponseEntity<String> response = vesRestController.event(validEvent, VERSION_V7, request);
169
170         //then
171         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED);
172         assertThat(response.getBody()).isEqualTo(ACCEPTED);
173         verify(eventPublisher).sendEvent(any(),eq(VES_3_GPP_FAULT_SUPERVISION_TOPIC));
174     }
175
176
177     @Test
178     public void shouldReportThatStndDomainEventHasntGotNamespaceParameter() throws IOException {
179         //given
180         configureEventTransformations();
181         configureHeadersForEventListener();
182
183         MockHttpServletRequest request = givenMockHttpServletRequest();
184         configureSchemasSupplierForStndDefineEvent();
185
186         String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_missing_namespace_invalid.json");
187
188         //when
189         final ResponseEntity<String> response = vesRestController.event(validEvent, VERSION_V7, request);
190
191         //then
192         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
193         verifyErrorResponse(
194                 response,
195                 "SVC2006",
196                 "Mandatory input %1 %2 is missing from request",
197                 List.of("attribute", "event.commonEventHeader.stndDefinedNamespace")
198         );
199         verifyThatEventWasNotSend();
200     }
201
202     @Test
203     public void shouldReportThatStndDomainEventNamespaceParameterIsEmpty() throws IOException {
204         //given
205         configureEventTransformations();
206         configureHeadersForEventListener();
207
208         MockHttpServletRequest request = givenMockHttpServletRequest();
209         configureSchemasSupplierForStndDefineEvent();
210
211         String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_empty_namespace_invalid.json");
212
213         //when
214         final ResponseEntity<String> response = vesRestController.event(validEvent, VERSION_V7, request);
215
216         //then
217         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
218         verifyErrorResponse(
219                 response,
220                 "SVC2006",
221                 "Mandatory input %1 %2 is empty in request",
222                 List.of("attribute", "event.commonEventHeader.stndDefinedNamespace")
223         );
224         verifyThatEventWasNotSend();
225     }
226
227     @Test
228     public void shouldNotSendStndDomainEventWhenTopicCannotBeFoundInConfiguration() throws IOException {
229         //given
230         configureEventTransformations();
231         configureHeadersForEventListener();
232
233         MockHttpServletRequest request = givenMockHttpServletRequest();
234         String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_valid_unknown_topic.json");
235
236         //when
237         final ResponseEntity<String> response = vesRestController.event(validEvent, VERSION_V7, request);
238
239         //then
240         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED);
241         assertThat(response.getBody()).isEqualTo(ACCEPTED);
242         verifyThatEventWasNotSend();
243     }
244
245     @Test
246     public void shouldExecuteStndDefinedValidationWhenFlagIsOnTrue() throws IOException {
247         //given
248         configureEventTransformations();
249         configureHeadersForEventListener();
250
251         MockHttpServletRequest request = givenMockHttpServletRequest();
252         String validEvent = JsonDataLoader.loadContent("/ves7_batch_with_stndDefined_valid.json");
253         when(applicationSettings.getExternalSchemaValidationCheckflag()).thenReturn(true);
254
255         //when
256         final ResponseEntity<String> response = vesRestController.events(validEvent, VERSION_V7, request);
257
258         //then
259         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED);
260         assertThat(response.getBody()).isEqualTo(ACCEPTED);
261         verify(stndDefinedDataValidator, times(2)).validate(any());
262     }
263
264     @Test
265     public void shouldNotExecuteStndDefinedValidationWhenFlagIsOnFalse() throws IOException {
266         //given
267         configureEventTransformations();
268         configureHeadersForEventListener();
269
270         MockHttpServletRequest request = givenMockHttpServletRequest();
271         String validEvent = JsonDataLoader.loadContent("/ves7_batch_with_stndDefined_valid.json");
272         when(applicationSettings.getExternalSchemaValidationCheckflag()).thenReturn(false);
273
274         //when
275         final ResponseEntity<String> response = vesRestController.events(validEvent, VERSION_V7, request);
276
277         //then
278         assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED);
279         assertThat(response.getBody()).isEqualTo(ACCEPTED);
280         verify(stndDefinedDataValidator, times(0)).validate(any());
281     }
282
283     private void verifyThatEventWasNotSend() {
284         verify(eventPublisher, never()).sendEvent(any(), any());
285     }
286
287     private void configureSchemasSupplierForStndDefineEvent() {
288         String collectorSchemaFile = "{\"v7\":\"./etc/CommonEventFormat_30.2_ONAP.json\"}";
289         final io.vavr.collection.Map<String, JsonSchema> loadedJsonSchemas = new JSonSchemasSupplier().loadJsonSchemas(collectorSchemaFile);
290
291         when(applicationSettings.eventSchemaValidationEnabled()).thenReturn(true);
292         when(applicationSettings.jsonSchema(eq(VERSION_V7))).thenReturn(loadedJsonSchemas.get(VERSION_V7).get());
293     }
294
295     private void verifyErrorResponse(ResponseEntity<String> response, String messageId, String messageText, List<String> variables) throws com.fasterxml.jackson.core.JsonProcessingException {
296         final Map<String, ?> errorDetails = fetchErrorDetails(response);
297         assertThat((Map<String, String>)errorDetails).containsEntry("messageId", messageId);
298         assertThat((Map<String, String>)errorDetails).containsEntry("text", messageText);
299         assertThat((Map<String, List<String>>)errorDetails).containsEntry("variables",  variables);
300     }
301
302     private Map<String, ?> fetchErrorDetails(ResponseEntity<String> response) throws com.fasterxml.jackson.core.JsonProcessingException {
303         final String body = response.getBody();
304         ObjectMapper mapper = new ObjectMapper();
305         Map<String, Map<String, Map<String,String>>> map = mapper.readValue(body, Map.class);
306         return map.get("requestError").get("ServiceException");
307     }
308
309     private void configureEventTransformations() throws IOException {
310         final List<EventTransformation> eventTransformations = loadEventTransformations();
311         when(applicationSettings.isVersionSupported(VERSION_V7)).thenReturn(true);
312         when(applicationSettings.eventTransformingEnabled()).thenReturn(true);
313         when(applicationSettings.getEventTransformations()).thenReturn(eventTransformations);
314     }
315
316     private void configureHeadersForEventListener() {
317         when(headerUtils.getRestApiIdentify(anyString())).thenReturn("eventListener");
318         when(headerUtils.getApiVerFilePath(anyString())).thenReturn(
319                 this.getClass().getResource("/api_version_config.json").getPath()
320         );
321     }
322
323     private void verifyThatTransformedEventWasSend(DMaaPEventPublisher eventPublisher, String eventBeforeTransformation) {
324         // event before transformation
325         assertThat(eventBeforeTransformation).contains("\"version\": \"4.0.1\"");
326         assertThat(eventBeforeTransformation).contains("\"faultFieldsVersion\": \"4.0\"");
327
328         ArgumentCaptor<JSONObject> argument = ArgumentCaptor.forClass(JSONObject.class);
329         ArgumentCaptor<String> domain = ArgumentCaptor.forClass(String.class);
330         verify(eventPublisher).sendEvent(argument.capture(), domain.capture());
331
332         final String transformedEvent = argument.getValue().toString();
333         final String eventSentAtTopic = domain.getValue();
334
335         // event after transformation
336         assertThat(transformedEvent).contains("\"priority\":\"High\",\"version\":3,");
337         assertThat(transformedEvent).contains(",\"faultFieldsVersion\":3,\"specificProblem");
338         assertThat(eventSentAtTopic).isEqualTo(VES_FAULT_TOPIC);
339     }
340
341     @NotNull
342     private MockHttpServletRequest givenMockHttpServletRequest() {
343         MockHttpServletRequest request = new MockHttpServletRequest();
344         request.setContentType("application/json");
345
346         RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
347         return request;
348     }
349
350     private List<EventTransformation> loadEventTransformations() throws IOException {
351         Type EVENT_TRANSFORM_LIST_TYPE = new TypeToken<List<EventTransformation>>() {
352         }.getType();
353
354         try (FileReader fr = new FileReader(this.getClass().getResource(EVENT_TRANSFORM_FILE_PATH).getPath())) {
355             return new Gson().fromJson(fr, EVENT_TRANSFORM_LIST_TYPE);
356         }
357     }
358 }