Fix 'Import use case fails when interfaces in template do not exist in system'-bug...
[sdc.git] / catalog-be / src / test / java / org / openecomp / sdc / be / servlets / ResourceUploadServletTest.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19 package org.openecomp.sdc.be.servlets;
20
21 import static org.assertj.core.api.Assertions.assertThat;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyBoolean;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29
30 import java.io.File;
31 import java.io.FileReader;
32 import java.io.IOException;
33 import java.net.URISyntaxException;
34 import java.net.URL;
35 import java.nio.file.Path;
36 import java.util.Optional;
37 import javax.servlet.ServletContext;
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpSession;
40 import javax.ws.rs.client.Entity;
41 import javax.ws.rs.core.MediaType;
42 import javax.ws.rs.core.Response;
43 import org.apache.commons.lang3.tuple.ImmutablePair;
44 import org.eclipse.jetty.http.HttpStatus;
45 import org.glassfish.hk2.utilities.binding.AbstractBinder;
46 import org.glassfish.jersey.client.ClientConfig;
47 import org.glassfish.jersey.media.multipart.FormDataMultiPart;
48 import org.glassfish.jersey.media.multipart.MultiPartFeature;
49 import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
50 import org.glassfish.jersey.server.ResourceConfig;
51 import org.glassfish.jersey.test.JerseyTest;
52 import org.glassfish.jersey.test.TestProperties;
53 import org.json.simple.JSONObject;
54 import org.json.simple.parser.JSONParser;
55 import org.json.simple.parser.ParseException;
56 import org.junit.jupiter.api.AfterEach;
57 import org.junit.jupiter.api.BeforeEach;
58 import org.junit.jupiter.api.Test;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
62 import org.openecomp.sdc.be.components.impl.ModelBusinessLogic;
63 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
64 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
65 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
66 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
67 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
68 import org.openecomp.sdc.be.config.ConfigurationManager;
69 import org.openecomp.sdc.be.config.SpringConfig;
70 import org.openecomp.sdc.be.dao.api.ActionStatus;
71 import org.openecomp.sdc.be.impl.ComponentsUtils;
72 import org.openecomp.sdc.be.impl.ServletUtils;
73 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
74 import org.openecomp.sdc.be.model.Model;
75 import org.openecomp.sdc.be.model.Resource;
76 import org.openecomp.sdc.be.model.User;
77 import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder;
78 import org.openecomp.sdc.be.servlets.exception.OperationExceptionMapper;
79 import org.openecomp.sdc.be.user.Role;
80 import org.openecomp.sdc.be.user.UserBusinessLogic;
81 import org.openecomp.sdc.common.api.ConfigurationSource;
82 import org.openecomp.sdc.common.api.Constants;
83 import org.openecomp.sdc.common.impl.ExternalConfiguration;
84 import org.openecomp.sdc.common.impl.FSConfigurationSource;
85 import org.openecomp.sdc.exception.ResponseFormat;
86 import org.springframework.context.ApplicationContext;
87 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
88 import org.springframework.web.context.WebApplicationContext;
89
90 class ResourceUploadServletTest extends JerseyTest {
91     private static final String USER_ID = "cs0008";
92     private static final User USER = new User(USER_ID);
93
94     @Mock
95     private HttpServletRequest request;
96     @Mock
97     private HttpSession session;
98     @Mock
99     private ServletContext servletContext;
100     @Mock
101     private WebAppContextWrapper webAppContextWrapper;
102     @Mock
103     private WebApplicationContext webApplicationContext;
104     @Mock
105     private UserBusinessLogic userBusinessLogic;
106     @Mock
107     private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
108     @Mock
109     private ComponentsUtils componentsUtils;
110     @Mock
111     private ServletUtils servletUtils;
112     @Mock
113     private ResourceImportManager resourceImportManager;
114     @Mock
115     private ResourceBusinessLogic resourceBusinessLogic;
116     @Mock
117     private ResponseFormat responseFormat;
118     @Mock
119     private ModelBusinessLogic modelBusinessLogic;
120     @Mock
121     private ResponseFormatManager responseFormatManager;
122     private final String modelName = "ETSI-SOL001-331";
123
124     private final Path rootPath = Path.of("/v1/catalog/upload");
125     private final Path bulkImportPath = rootPath.resolve("resource/import");
126     private final String multipartPath = "/v1/catalog/upload/multipart";
127     private User user;
128
129     @BeforeEach
130     void resetMock() throws Exception {
131         super.setUp();
132         initMocks();
133         initConfig();
134         initTestData();
135     }
136
137     @AfterEach
138     void after() throws Exception {
139         super.tearDown();
140     }
141
142     @Override
143     protected ResourceConfig configure() {
144         MockitoAnnotations.openMocks(this);
145         forceSet(TestProperties.CONTAINER_PORT, "0");
146         final ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
147         return new ResourceConfig(ResourceUploadServlet.class)
148             .register(new AbstractBinder() {
149                 @Override
150                 protected void configure() {
151                     bind(request).to(HttpServletRequest.class);
152                     bind(userBusinessLogic).to(UserBusinessLogic.class);
153                     bind(componentInstanceBusinessLogic).to(ComponentInstanceBusinessLogic.class);
154                     bind(componentsUtils).to(ComponentsUtils.class);
155                     bind(servletUtils).to(ServletUtils.class);
156                     bind(resourceImportManager).to(ResourceImportManager.class);
157                     bind(resourceBusinessLogic).to(ResourceBusinessLogic.class);
158                     bind(modelBusinessLogic).to(ModelBusinessLogic.class);
159                 }
160             })
161             .register(new OperationExceptionMapper(new ServletResponseBuilder(), responseFormatManager))
162             .register(MultiPartFeature.class)
163             .property("contextConfig", context);
164     }
165
166     @Override
167     protected void configureClient(final ClientConfig config) {
168         config.register(MultiPartFeature.class);
169     }
170
171     void initMocks() {
172         when(request.getSession()).thenReturn(session);
173         when(session.getServletContext()).thenReturn(servletContext);
174         when(servletContext.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR))
175             .thenReturn(webAppContextWrapper);
176         when(webAppContextWrapper.getWebAppContext(servletContext)).thenReturn(webApplicationContext);
177         when(webApplicationContext.getBean(ModelBusinessLogic.class)).thenReturn(modelBusinessLogic);
178         when(webApplicationContext.getBean(UserBusinessLogic.class)).thenReturn(userBusinessLogic);
179         when(userBusinessLogic.getUser(USER_ID, false)).thenReturn(USER);
180         when(request.getHeader(Constants.USER_ID_HEADER)).thenReturn(USER_ID);
181         when(webApplicationContext.getBean(ServletUtils.class)).thenReturn(servletUtils);
182         when(servletUtils.getComponentsUtils()).thenReturn(componentsUtils);
183     }
184
185     void initConfig() {
186         final String appConfigDir = "src/test/resources/config/catalog-be";
187         final ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), appConfigDir);
188         final ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
189         final org.openecomp.sdc.be.config.Configuration configuration = new org.openecomp.sdc.be.config.Configuration();
190         configuration.setJanusGraphInMemoryGraph(true);
191         configurationManager.setConfiguration(configuration);
192         ExternalConfiguration.setAppName("catalog-be");
193     }
194
195     private void initTestData() {
196         user = new User();
197         user.setUserId(USER_ID);
198         user.setRole(Role.ADMIN.name());
199         when(userBusinessLogic.getUser(USER_ID)).thenReturn(user);
200     }
201
202     @Test
203     void uploadMultipartWithModelSuccessTest() throws IOException, ParseException, URISyntaxException {
204         when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
205         when(componentsUtils.getResponseFormat(ActionStatus.CREATED)).thenReturn(responseFormat);
206         when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
207         when(userBusinessLogic.getUser(anyString())).thenReturn(user);
208         when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
209         when(resourceImportManager.importNormativeResource(anyString(), any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean()))
210             .thenReturn(new ImmutablePair<>(new Resource(), ActionStatus.CREATED));
211         when(modelBusinessLogic.findModel(modelName)).thenReturn(Optional.of(new Model(modelName)));
212         final var response = target().path(multipartPath).request(MediaType.APPLICATION_JSON)
213             .header(Constants.USER_ID_HEADER, USER_ID)
214             .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType001.zip",
215                 "src/test/resources/node-types/nodeTypeWithModelsField.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
216         assertThat(response.getStatus()).isEqualTo(HttpStatus.OK_200);
217     }
218
219     @Test
220     void uploadMultipartWithoutModelsFieldSuccessTest() throws IOException, ParseException, URISyntaxException {
221         when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
222         when(componentsUtils.getResponseFormat(ActionStatus.CREATED)).thenReturn(responseFormat);
223         when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
224         when(userBusinessLogic.getUser(anyString())).thenReturn(user);
225         when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
226         when(resourceImportManager.importNormativeResource(anyString(), any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean()))
227             .thenReturn(new ImmutablePair<>(new Resource(), ActionStatus.CREATED));
228         final var response = target().path(multipartPath).request(MediaType.APPLICATION_JSON)
229             .header(Constants.USER_ID_HEADER, USER_ID)
230             .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType002.zip",
231                 "src/test/resources/node-types/nodeTypeWithoutModelsField.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
232         assertThat(response.getStatus()).isEqualTo(HttpStatus.OK_200);
233     }
234
235     @Test
236     void uploadMultipartFailWithEmptyModelsTest() throws IOException, ParseException, URISyntaxException {
237         when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
238         when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
239         when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
240         when(userBusinessLogic.getUser(anyString())).thenReturn(user);
241         when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
242         when(modelBusinessLogic.findModel("")).thenReturn(Optional.empty());
243         final Response response = target().path(multipartPath).request(MediaType.APPLICATION_JSON)
244             .header(Constants.USER_ID_HEADER, USER_ID)
245             .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType002.zip",
246                 "src/test/resources/node-types/nodeTypeWithEmptyModels.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
247         assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
248     }
249
250     @Test
251     void uploadMultipartFailWithModelNotFoundTest() throws IOException, ParseException, URISyntaxException {
252         when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
253         when(userBusinessLogic.getUser(anyString())).thenReturn(user);
254         when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
255         when(modelBusinessLogic.findModel(modelName)).thenReturn(Optional.empty());
256         final var response = target().path(multipartPath).request(MediaType.APPLICATION_JSON)
257             .header(Constants.USER_ID_HEADER, USER_ID)
258             .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType001.zip",
259                 "src/test/resources/node-types/nodeTypeWithModelsField.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
260         assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
261     }
262
263     @Test
264     void uploadMultipartThrowsBusinessExceptionTest() throws IOException, ParseException, URISyntaxException {
265         when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
266         when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
267         when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
268         when(userBusinessLogic.getUser(anyString())).thenReturn(user);
269         when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
270         final var response = target().path(multipartPath).request(MediaType.APPLICATION_JSON)
271             .header(Constants.USER_ID_HEADER, USER_ID)
272             .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType001.zip",
273                 "src/test/resources/node-types/invalid.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
274         assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
275     }
276
277     @Test
278     void bulkImportSuccessTest() throws IOException, ParseException {
279         when(responseFormat.getStatus()).thenReturn(HttpStatus.CREATED_201);
280         when(componentsUtils.getResponseFormat(ActionStatus.CREATED)).thenReturn(responseFormat);
281
282         final Response response = doValidCallToBulkImport(USER_ID);
283
284         verify(resourceImportManager).importAllNormativeResource(anyString(), any(), eq(USER), eq(false), eq(false));
285         assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED_201);
286     }
287
288     @Test
289     void bulkImportFailTest_businessException() throws IOException, ParseException {
290         doThrow(new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR))
291             .when(resourceImportManager)
292             .importAllNormativeResource(anyString(), any(), eq(USER), eq(false), eq(false));
293
294         final Response response = doValidCallToBulkImport(USER_ID);
295
296         assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
297     }
298
299     @Test
300     void bulkImportFailTest_unexpectedException() throws IOException, ParseException {
301         when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
302         when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
303
304         doThrow(RuntimeException.class)
305             .when(resourceImportManager)
306             .importAllNormativeResource(anyString(), any(), eq(USER), eq(false), eq(false));
307
308         final Response response = doValidCallToBulkImport(USER_ID);
309
310         assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
311     }
312
313     @Test
314     void bulkImportFailTest_invalidUser() throws IOException, ParseException {
315         var userId = "userId";
316         when(userBusinessLogic.getUser(userId, false)).thenThrow(ComponentException.class);
317         when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
318         when(componentsUtils.getResponseFormat(any(ComponentException.class))).thenReturn(responseFormat);
319
320         final Response response = doValidCallToBulkImport(userId);
321
322         assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
323     }
324
325     private Response doValidCallToBulkImport(final String userId) throws IOException, ParseException {
326         final Path nodeTypesYamlPath = Path.of("src/test/resources/node-types/nodeTypes.yaml");
327         final Path nodeTypeMetadataJsonPath = Path.of("src/test/resources/node-types/payload.json");
328         return target().path(bulkImportPath.toString()).request(MediaType.APPLICATION_JSON)
329             .header(Constants.USER_ID_HEADER, userId)
330             .post(
331                 Entity.entity(buildBulkImportMultiPartData(nodeTypesYamlPath, nodeTypeMetadataJsonPath), MediaType.MULTIPART_FORM_DATA),
332                 Response.class
333             );
334     }
335
336     private String parseFileToJsonString(final Path jsonFilePath) throws IOException, ParseException {
337         final JSONObject inputData = (JSONObject) new JSONParser().parse(
338             new FileReader(jsonFilePath.toString()));
339         return inputData.toJSONString();
340     }
341
342     private File getFile(final String fileName) throws URISyntaxException {
343         final URL resource = this.getClass().getClassLoader().getResource(fileName);
344         if (resource == null) {
345             throw new IllegalArgumentException("file not found! " + fileName);
346         }
347         return new File(resource.toURI());
348     }
349
350     private FormDataMultiPart buildFormDataMultiPart(final String zipFilePath, final String inputJsonData)
351         throws IOException, ParseException, URISyntaxException {
352         final FileDataBodyPart filePart = new FileDataBodyPart("resourceZip", getFile(zipFilePath));
353         final FormDataMultiPart multipartEntity = new FormDataMultiPart();
354         multipartEntity.bodyPart(filePart);
355         multipartEntity.field("resourceMetadata", parseFileToJsonString(Path.of(inputJsonData)));
356         return  multipartEntity;
357     }
358
359     private FormDataMultiPart buildBulkImportMultiPartData(final Path nodeTypesYamlPath, final Path payloadJsonPath)
360         throws IOException, ParseException {
361         final FileDataBodyPart formDataBodyPart = new FileDataBodyPart("nodeTypesYaml", nodeTypesYamlPath.toFile());
362         final FormDataMultiPart multipartEntity = new FormDataMultiPart();
363         multipartEntity.bodyPart(formDataBodyPart);
364         multipartEntity.field("nodeTypeMetadataJson", parseFileToJsonString(payloadJsonPath), MediaType.APPLICATION_JSON_TYPE);
365         multipartEntity.field("createNewVersion", String.valueOf(false), MediaType.TEXT_PLAIN_TYPE);
366         return multipartEntity;
367     }
368 }