2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
23 package org.openecomp.sdc.be.servlets;
25 import static org.assertj.core.api.Assertions.assertThat;
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.anyString;
28 import static org.mockito.ArgumentMatchers.eq;
29 import static org.mockito.Mockito.doThrow;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.when;
33 import fj.data.Either;
34 import java.util.HashMap;
35 import java.util.LinkedList;
36 import java.util.List;
38 import javax.servlet.ServletContext;
39 import javax.servlet.http.HttpServletRequest;
40 import javax.ws.rs.client.Entity;
41 import javax.ws.rs.core.Application;
42 import javax.ws.rs.core.GenericType;
43 import javax.ws.rs.core.MediaType;
44 import javax.ws.rs.core.Response;
45 import org.glassfish.jersey.server.ResourceConfig;
46 import org.glassfish.jersey.test.JerseyTest;
47 import org.glassfish.jersey.test.TestProperties;
48 import org.junit.jupiter.api.AfterEach;
49 import org.junit.jupiter.api.BeforeAll;
50 import org.junit.jupiter.api.BeforeEach;
51 import org.junit.jupiter.api.Test;
52 import org.mockito.Mockito;
53 import org.openecomp.sdc.be.catalog.enums.ChangeTypeEnum;
54 import org.openecomp.sdc.be.components.impl.ArchiveBusinessLogic;
55 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
56 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
57 import org.openecomp.sdc.be.components.path.utils.GraphTestUtils;
58 import org.openecomp.sdc.be.components.validation.AccessValidations;
59 import org.openecomp.sdc.be.components.validation.ComponentValidations;
60 import org.openecomp.sdc.be.config.ConfigurationManager;
61 import org.openecomp.sdc.be.dao.DAOJanusGraphStrategy;
62 import org.openecomp.sdc.be.dao.JanusGraphClientStrategy;
63 import org.openecomp.sdc.be.dao.api.ActionStatus;
64 import org.openecomp.sdc.be.dao.impl.HealingPipelineDao;
65 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
66 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphClient;
67 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
68 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
69 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
70 import org.openecomp.sdc.be.dao.jsongraph.HealingJanusGraphDao;
71 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
72 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
73 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
74 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
75 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
76 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
77 import org.openecomp.sdc.be.facade.operations.CatalogOperation;
78 import org.openecomp.sdc.be.impl.ComponentsUtils;
79 import org.openecomp.sdc.be.impl.ServletUtils;
80 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
81 import org.openecomp.sdc.be.model.Component;
82 import org.openecomp.sdc.be.model.LifecycleStateEnum;
83 import org.openecomp.sdc.be.model.User;
84 import org.openecomp.sdc.be.model.catalog.CatalogComponent;
85 import org.openecomp.sdc.be.model.jsonjanusgraph.config.ContainerInstanceTypesData;
86 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArchiveOperation;
87 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.CategoryOperation;
88 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.GroupsOperation;
89 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeTemplateOperation;
90 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeTypeOperation;
91 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOperation;
92 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
93 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
94 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
95 import org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper;
96 import org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper;
97 import org.openecomp.sdc.be.servlets.exception.StorageExceptionMapper;
98 import org.openecomp.sdc.be.user.Role;
99 import org.openecomp.sdc.be.user.UserBusinessLogic;
100 import org.openecomp.sdc.common.api.ConfigurationSource;
101 import org.openecomp.sdc.common.api.Constants;
102 import org.openecomp.sdc.common.impl.ExternalConfiguration;
103 import org.openecomp.sdc.common.impl.FSConfigurationSource;
104 import org.openecomp.sdc.exception.ResponseFormat;
105 import org.springframework.context.ApplicationContext;
106 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
107 import org.springframework.context.annotation.Bean;
108 import org.springframework.context.annotation.Configuration;
109 import org.springframework.context.annotation.PropertySource;
110 import org.springframework.http.HttpStatus;
111 import org.springframework.web.context.WebApplicationContext;
113 class ArchiveEndpointTest extends JerseyTest {
115 private static final ServletContext servletContext = mock(ServletContext.class);
116 private static final String CSAR_UUID1 = "123456789abcdefgh";
117 private static final String CSAR_UUID2 = "987654321abcdefgh";
119 public static final WebAppContextWrapper webAppContextWrapper = mock(WebAppContextWrapper.class);
120 private static final WebApplicationContext webApplicationContext = mock(WebApplicationContext.class);
121 private static final ServletUtils servletUtils = mock(ServletUtils.class);
122 private static final UserBusinessLogic userAdmin = mock(UserBusinessLogic.class);
123 private static final ComponentsUtils componentUtils = mock(ComponentsUtils.class);
124 private static final CatalogOperation catalogOperations = mock(CatalogOperation.class);
125 // private static final ToscaOperationFacade toscaOperationFacade = mock(ToscaOperationFacade.class);
126 private static final ToscaOperationFacade toscaOperationFacade = Mockito.spy(new ToscaOperationFacade());
129 private static final ResponseFormat responseFormat = mock(ResponseFormat.class);
130 private static final ResponseFormat notFoundResponseFormat = mock(ResponseFormat.class);
131 private static final ResponseFormat badRequestResponseFormat = mock(ResponseFormat.class);
132 private static final ResponseFormat invalidServiceStateResponseFormat = mock(ResponseFormat.class);
133 private static final AccessValidations accessValidationsMock = mock(AccessValidations.class);
134 private static final ComponentValidations componentValidationsMock = mock(ComponentValidations.class);
135 private static final IGraphLockOperation graphLockOperation = mock(IGraphLockOperation.class);
136 private static final HealingJanusGraphGenericDao
137 janusGraphGenericDao = mock(HealingJanusGraphGenericDao.class);
138 private static final HealingPipelineDao HEALING_PIPELINE_DAO = mock(HealingPipelineDao.class);
139 private static GraphVertex serviceVertex;
140 private static GraphVertex resourceVertex;
141 private static GraphVertex resourceVertexVspArchived;
143 private static HealingJanusGraphDao janusGraphDao;
146 @PropertySource("classpath:dao.properties")
147 static class TestSpringConfig {
149 private ArchiveOperation archiveOperation;
150 private GraphVertex catalogVertex;
153 ArchiveEndpoint archiveEndpoint() {
154 UserBusinessLogic userBusinessLogic = mock(UserBusinessLogic.class);
155 ComponentsUtils componentsUtils = mock(ComponentsUtils.class);
156 return new ArchiveEndpoint(userBusinessLogic, componentsUtils, archiveBusinessLogic());
160 ComponentExceptionMapper componentExceptionMapper() {
161 return new ComponentExceptionMapper(componentUtils);
165 StorageExceptionMapper storageExceptionMapper() {
166 return new StorageExceptionMapper(componentUtils);
170 DefaultExceptionMapper defaultExceptionMapper() {
171 return new DefaultExceptionMapper();
175 ArchiveBusinessLogic archiveBusinessLogic() {
176 return new ArchiveBusinessLogic(janusGraphDao(), accessValidations(), archiveOperation(),
177 toscaOperationFacade(), componentUtils, catalogOperations);
181 ArchiveOperation archiveOperation() {
182 this.archiveOperation = new ArchiveOperation(janusGraphDao(), graphLockOperation());
183 GraphTestUtils.clearGraph(janusGraphDao);
185 return this.archiveOperation;
189 ComponentValidations componentValidations() {
190 return componentValidationsMock;
194 AccessValidations accessValidations() {
195 return accessValidationsMock;
199 ToscaOperationFacade toscaOperationFacade() {
200 return toscaOperationFacade;
204 TopologyTemplateOperation topologyTemplateOperation() {
205 return new TopologyTemplateOperation();
209 NodeTypeOperation nodeTypeOpertaion() {
210 return new NodeTypeOperation(null);
214 NodeTemplateOperation nodeTemplateOperation() {
215 return new NodeTemplateOperation();
219 GroupsOperation groupsOperation() {
220 return new GroupsOperation();
224 HealingJanusGraphDao janusGraphDao() {
225 janusGraphDao = new HealingJanusGraphDao(healingPipelineDao(), janusGraphClient());
226 return janusGraphDao;
230 JanusGraphClient janusGraphClient() {
231 return new JanusGraphClient(janusGraphClientStrategy());
235 JanusGraphClientStrategy janusGraphClientStrategy() {
236 return new DAOJanusGraphStrategy();
240 CategoryOperation categoryOperation() {
241 return new CategoryOperation();
245 IGraphLockOperation graphLockOperation() {
246 return graphLockOperation;
250 JanusGraphGenericDao janusGraphGenericDao() {
251 return janusGraphGenericDao;
255 HealingPipelineDao healingPipelineDao() {
256 return HEALING_PIPELINE_DAO;
260 ContainerInstanceTypesData containerInstanceTypesData() {
261 return new ContainerInstanceTypesData();
264 private void initGraphForTest() {
265 //Create Catalog Root
266 catalogVertex = GraphTestUtils.createRootCatalogVertex(janusGraphDao);
267 //Create Archive Root
268 GraphTestUtils.createRootArchiveVertex(janusGraphDao);
270 createSingleVersionServiceAndResource();
273 private void createSingleVersionServiceAndResource() {
274 //Create Service for Scenario 1 Tests (1 Service)
275 serviceVertex = GraphTestUtils.createServiceVertex(janusGraphDao, propsForHighestVersion());
277 Map<GraphPropertyEnum, Object> props = propsForHighestVersion();
278 props.put(GraphPropertyEnum.IS_VSP_ARCHIVED, false);
279 props.put(GraphPropertyEnum.CSAR_UUID, CSAR_UUID1);
280 resourceVertex = GraphTestUtils.createResourceVertex(janusGraphDao, props, ResourceTypeEnum.VF);
282 props = propsForHighestVersion();
283 props.put(GraphPropertyEnum.IS_VSP_ARCHIVED, true);
284 props.put(GraphPropertyEnum.CSAR_UUID, CSAR_UUID2);
285 resourceVertexVspArchived = GraphTestUtils.createResourceVertex(janusGraphDao, props, ResourceTypeEnum.VF);
287 //Connect Service/Resource to Catalog Root
288 janusGraphDao.createEdge(catalogVertex, serviceVertex, EdgeLabelEnum.CATALOG_ELEMENT, null);
289 janusGraphDao.createEdge(catalogVertex, resourceVertex, EdgeLabelEnum.CATALOG_ELEMENT, null);
292 private Map<GraphPropertyEnum, Object> propsForHighestVersion() {
293 Map<GraphPropertyEnum, Object> props = new HashMap<>();
294 props.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
299 public static final HttpServletRequest request = mock(HttpServletRequest.class);
302 private static final User adminUser = new User("admin", "admin", "admin", "admin@email.com", Role.ADMIN.name(),
303 System.currentTimeMillis());
304 private static final User designerUser = new User("designer", "designer", "designer", "designer@email.com",
305 Role.DESIGNER.name(), System.currentTimeMillis());
306 private static final User otherUser = new User("other", "other", "other", "other@email.com", Role.TESTER.name(),
307 System.currentTimeMillis());
310 public static void setup() {
311 //Needed for User Authorization
312 //========================================================================================================================
313 when(servletContext.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR))
314 .thenReturn(webAppContextWrapper);
315 when(webAppContextWrapper.getWebAppContext(servletContext)).thenReturn(webApplicationContext);
316 when(webApplicationContext.getBean(ServletUtils.class)).thenReturn(servletUtils);
317 when(servletUtils.getUserAdmin()).thenReturn(userAdmin);
318 when(servletUtils.getComponentsUtils()).thenReturn(componentUtils);
319 when(componentUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)).thenReturn(responseFormat);
320 when(componentUtils.getResponseFormat(eq(ActionStatus.INVALID_SERVICE_STATE), any()))
321 .thenReturn(invalidServiceStateResponseFormat);
322 when(responseFormat.getStatus()).thenReturn(HttpStatus.UNAUTHORIZED.value());
324 ComponentException ce = new ByResponseFormatComponentException(responseFormat);
325 doThrow(ce).when(accessValidationsMock).userIsAdminOrDesigner(eq(otherUser.getUserId()), any());
327 //Needed for error configuration
328 when(notFoundResponseFormat.getStatus()).thenReturn(HttpStatus.NOT_FOUND.value());
329 when(invalidServiceStateResponseFormat.getStatus()).thenReturn(HttpStatus.CONFLICT.value());
330 when(badRequestResponseFormat.getStatus()).thenReturn(HttpStatus.BAD_REQUEST.value());
331 when(componentUtils.getResponseFormat(eq(ActionStatus.RESOURCE_NOT_FOUND), (String[]) any()))
332 .thenReturn(notFoundResponseFormat);
333 when(componentUtils.getResponseFormat(eq(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID), (String[]) any()))
334 .thenReturn(badRequestResponseFormat);
336 when(graphLockOperation.lockComponent(anyString(), any(NodeTypeEnum.class)))
337 .thenReturn(StorageOperationStatus.OK);
338 when(userAdmin.getUser(adminUser.getUserId(), false)).thenReturn(adminUser);
339 when(userAdmin.getUser(designerUser.getUserId(), false)).thenReturn(designerUser);
340 when(userAdmin.getUser(otherUser.getUserId(), false)).thenReturn(otherUser);
341 //========================================================================================================================
343 String appConfigDir = "src/test/resources/config/catalog-be";
344 ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(),
346 ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
348 org.openecomp.sdc.be.config.Configuration configuration = new org.openecomp.sdc.be.config.Configuration();
349 configuration.setJanusGraphInMemoryGraph(true);
351 org.openecomp.sdc.be.config.Configuration.HeatDeploymentArtifactTimeout heatDeploymentArtifactTimeout = new org.openecomp.sdc.be.config.Configuration.HeatDeploymentArtifactTimeout();
352 heatDeploymentArtifactTimeout.setDefaultMinutes(30);
354 configuration.setHeatArtifactDeploymentTimeout(heatDeploymentArtifactTimeout);
355 configurationManager.setConfiguration(configuration);
357 configurationManager.setConfiguration(configuration);
358 ExternalConfiguration.setAppName("catalog-be");
362 public void before() throws Exception {
367 public void tearDown() throws Exception {
372 void getArchivedComponents_Empty() {
373 assertOnGetArchivedComponents(null, 0);
377 void archiveAndGetArchivedService_SingleService() {
378 Component serviceComponent = mock(Component.class);
379 final String serviceUniqueId = serviceVertex.getUniqueId();
380 when(toscaOperationFacade.getToscaElement(serviceUniqueId)).thenReturn(Either.left(serviceComponent));
381 when(catalogOperations.updateCatalog(ChangeTypeEnum.ARCHIVE, serviceComponent)).thenReturn(ActionStatus.OK);
382 archiveService(serviceUniqueId, HttpStatus.OK.value());
383 assertOnGetArchivedComponents(ComponentTypeEnum.SERVICE_PARAM_NAME, 1);
384 //restoreService(serviceUniqueId, 200);
388 void archiveAndGetArchivedResource_SingleResource() {
389 Component component = mock(Component.class);
390 final String uniqueId = resourceVertex.getUniqueId();
391 when(toscaOperationFacade.getToscaElement(uniqueId)).thenReturn(Either.left(component));
392 when(catalogOperations.updateCatalog(ChangeTypeEnum.ARCHIVE, component)).thenReturn(ActionStatus.OK);
393 archiveResource(uniqueId, HttpStatus.OK.value());
394 assertOnGetArchivedComponents(ComponentTypeEnum.RESOURCE_PARAM_NAME, 1);
395 //restoreResource(uniqueId, 200);
399 void attemptArchiveCheckedOutService() {
400 checkoutComponent(serviceVertex);
401 archiveService(serviceVertex.getUniqueId(), HttpStatus.CONFLICT.value());
405 void testOnArchivedVsps() {
406 String path = "/v1/catalog/notif/vsp/archived";
407 List<String> csarIds = new LinkedList<>();
408 csarIds.add("123456");
409 csarIds.add(CSAR_UUID2); //An archived CSAR ID
410 Response response = target()
412 .request(MediaType.APPLICATION_JSON)
413 .accept(MediaType.APPLICATION_JSON)
414 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
415 .post(Entity.json(csarIds));
417 assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
418 assertOnVertexProp(resourceVertexVspArchived.getUniqueId(), true);
422 void testOnRestoredVsps() {
423 String path = "/v1/catalog/notif/vsp/restored";
424 List<String> csarIds = new LinkedList<>();
425 csarIds.add("123456");
426 csarIds.add(CSAR_UUID1); //Non archived CSAR_ID
427 Response response = target()
429 .request(MediaType.APPLICATION_JSON)
430 .accept(MediaType.APPLICATION_JSON)
431 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
432 .post(Entity.json(csarIds));
434 assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
435 assertOnVertexProp(resourceVertex.getUniqueId(), false);
442 void archiveWithInvalidUid() {
443 archiveService("fakeUid", HttpStatus.NOT_FOUND.value());
447 void restoreWithInvalidUid() {
448 restoreService("fakeUid", HttpStatus.NOT_FOUND.value());
452 void archiveWithTester() {
453 String path = String.format("/v1/catalog/services/%s/%s", serviceVertex.getUniqueId(), "archive");
454 Response response = target()
457 .accept(MediaType.APPLICATION_JSON)
458 .header(Constants.USER_ID_HEADER, otherUser.getUserId())
461 assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
464 private void checkoutComponent(GraphVertex component) {
465 Either<GraphVertex, JanusGraphOperationStatus> vE = janusGraphDao.getVertexById(component.getUniqueId());
466 GraphVertex v = vE.left().value();
467 v.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
468 v.setJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
469 janusGraphDao.updateVertex(v);
470 janusGraphDao.commit();
473 private void assertOnVertexProp(String componentId, Object expectedValue) {
474 Either<GraphVertex, JanusGraphOperationStatus> vE = janusGraphDao.getVertexById(componentId);
475 GraphVertex v = vE.left().value();
476 assertThat(v.getMetadataProperty(GraphPropertyEnum.IS_VSP_ARCHIVED)).isEqualTo(expectedValue);
479 private void archiveService(String id, int expectedStatus) {
480 archiveOrRestoreService(id, ArchiveOperation.Action.ARCHIVE, expectedStatus);
483 private void restoreService(String id, int expectedStatus) {
484 archiveOrRestoreService(id, ArchiveOperation.Action.RESTORE, expectedStatus);
487 private void archiveResource(String id, int expectedStatus) {
488 archiveOrRestoreResource(id, ArchiveOperation.Action.ARCHIVE, expectedStatus);
491 private void restoreResource(String id, int expectedStatus) {
492 archiveOrRestoreResource(id, ArchiveOperation.Action.RESTORE, expectedStatus);
495 private void archiveOrRestoreService(String compUid, ArchiveOperation.Action action, int expectedStatus) {
496 String path = String.format("/v1/catalog/services/%s/%s", compUid, action.name().toLowerCase());
497 Response response = target()
500 .accept(MediaType.APPLICATION_JSON)
501 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
504 assertThat(response.getStatus()).isEqualTo(expectedStatus);
507 private void archiveOrRestoreResource(String compUid, ArchiveOperation.Action action, int expectedStatus) {
508 String path = String.format("/v1/catalog/resources/%s/%s", compUid, action.name().toLowerCase());
509 Response response = target()
512 .accept(MediaType.APPLICATION_JSON)
513 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
516 assertThat(response.getStatus()).isEqualTo(expectedStatus);
519 private void assertOnGetArchivedComponents(String componentType, int expectedCount) {
520 String path = "/v1/catalog/archive";
522 Response response = target()
525 .accept(MediaType.APPLICATION_JSON)
526 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
529 Map<String, List<CatalogComponent>> archivedComponents = response
530 .readEntity(new GenericType<Map<String, List<CatalogComponent>>>() {
532 assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
534 if (componentType == null) {
535 assertThat(archivedComponents).isEmpty();
537 assertThat(archivedComponents.get(componentType)).hasSize(expectedCount);
543 protected Application configure() {
544 ApplicationContext context = new AnnotationConfigApplicationContext(TestSpringConfig.class);
545 forceSet(TestProperties.CONTAINER_PORT, "0");
546 return new ResourceConfig(ArchiveEndpoint.class)
547 .register(DefaultExceptionMapper.class)
548 .register(ComponentExceptionMapper.class)
549 .register(StorageExceptionMapper.class)
550 .property("contextConfig", context);