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.model.operations.impl.ModelOperation;
96 import org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper;
97 import org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper;
98 import org.openecomp.sdc.be.servlets.exception.StorageExceptionMapper;
99 import org.openecomp.sdc.be.user.Role;
100 import org.openecomp.sdc.be.user.UserBusinessLogic;
101 import org.openecomp.sdc.common.api.ConfigurationSource;
102 import org.openecomp.sdc.common.api.Constants;
103 import org.openecomp.sdc.common.impl.ExternalConfiguration;
104 import org.openecomp.sdc.common.impl.FSConfigurationSource;
105 import org.openecomp.sdc.exception.ResponseFormat;
106 import org.springframework.context.ApplicationContext;
107 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
108 import org.springframework.context.annotation.Bean;
109 import org.springframework.context.annotation.Configuration;
110 import org.springframework.context.annotation.PropertySource;
111 import org.springframework.http.HttpStatus;
112 import org.springframework.web.context.WebApplicationContext;
114 class ArchiveEndpointTest extends JerseyTest {
116 private static final ServletContext servletContext = mock(ServletContext.class);
117 private static final String CSAR_UUID1 = "123456789abcdefgh";
118 private static final String CSAR_UUID2 = "987654321abcdefgh";
120 public static final WebAppContextWrapper webAppContextWrapper = mock(WebAppContextWrapper.class);
121 private static final WebApplicationContext webApplicationContext = mock(WebApplicationContext.class);
122 private static final ServletUtils servletUtils = mock(ServletUtils.class);
123 private static final UserBusinessLogic userAdmin = mock(UserBusinessLogic.class);
124 private static final ComponentsUtils componentUtils = mock(ComponentsUtils.class);
125 private static final CatalogOperation catalogOperations = mock(CatalogOperation.class);
126 // private static final ToscaOperationFacade toscaOperationFacade = mock(ToscaOperationFacade.class);
127 private static final ToscaOperationFacade toscaOperationFacade = Mockito.spy(new ToscaOperationFacade());
130 private static final ResponseFormat responseFormat = mock(ResponseFormat.class);
131 private static final ResponseFormat notFoundResponseFormat = mock(ResponseFormat.class);
132 private static final ResponseFormat badRequestResponseFormat = mock(ResponseFormat.class);
133 private static final ResponseFormat invalidServiceStateResponseFormat = mock(ResponseFormat.class);
134 private static final AccessValidations accessValidationsMock = mock(AccessValidations.class);
135 private static final ComponentValidations componentValidationsMock = mock(ComponentValidations.class);
136 private static final IGraphLockOperation graphLockOperation = mock(IGraphLockOperation.class);
137 private static final HealingJanusGraphGenericDao
138 janusGraphGenericDao = mock(HealingJanusGraphGenericDao.class);
139 private static final HealingPipelineDao HEALING_PIPELINE_DAO = mock(HealingPipelineDao.class);
140 private static GraphVertex serviceVertex;
141 private static GraphVertex resourceVertex;
142 private static GraphVertex resourceVertexVspArchived;
144 private static HealingJanusGraphDao janusGraphDao;
147 @PropertySource("classpath:dao.properties")
148 static class TestSpringConfig {
150 private ArchiveOperation archiveOperation;
151 private GraphVertex catalogVertex;
154 ArchiveEndpoint archiveEndpoint() {
155 UserBusinessLogic userBusinessLogic = mock(UserBusinessLogic.class);
156 ComponentsUtils componentsUtils = mock(ComponentsUtils.class);
157 return new ArchiveEndpoint(userBusinessLogic, componentsUtils, archiveBusinessLogic());
161 ComponentExceptionMapper componentExceptionMapper() {
162 return new ComponentExceptionMapper(componentUtils);
166 StorageExceptionMapper storageExceptionMapper() {
167 return new StorageExceptionMapper(componentUtils);
171 DefaultExceptionMapper defaultExceptionMapper() {
172 return new DefaultExceptionMapper();
176 ArchiveBusinessLogic archiveBusinessLogic() {
177 return new ArchiveBusinessLogic(janusGraphDao(), accessValidations(), archiveOperation(),
178 toscaOperationFacade(), componentUtils, catalogOperations);
182 ArchiveOperation archiveOperation() {
183 this.archiveOperation = new ArchiveOperation(janusGraphDao(), graphLockOperation());
184 GraphTestUtils.clearGraph(janusGraphDao);
186 return this.archiveOperation;
190 ComponentValidations componentValidations() {
191 return componentValidationsMock;
195 AccessValidations accessValidations() {
196 return accessValidationsMock;
200 ToscaOperationFacade toscaOperationFacade() {
201 return toscaOperationFacade;
205 TopologyTemplateOperation topologyTemplateOperation() {
206 return new TopologyTemplateOperation();
210 NodeTypeOperation nodeTypeOpertaion() {
211 return new NodeTypeOperation(null);
215 NodeTemplateOperation nodeTemplateOperation() {
216 return new NodeTemplateOperation();
220 GroupsOperation groupsOperation() {
221 return new GroupsOperation();
225 HealingJanusGraphDao janusGraphDao() {
226 janusGraphDao = new HealingJanusGraphDao(healingPipelineDao(), janusGraphClient());
227 return janusGraphDao;
231 JanusGraphClient janusGraphClient() {
232 return new JanusGraphClient(janusGraphClientStrategy());
236 JanusGraphClientStrategy janusGraphClientStrategy() {
237 return new DAOJanusGraphStrategy();
241 CategoryOperation categoryOperation() {
242 return new CategoryOperation();
246 IGraphLockOperation graphLockOperation() {
247 return graphLockOperation;
251 JanusGraphGenericDao janusGraphGenericDao() {
252 return janusGraphGenericDao;
256 HealingPipelineDao healingPipelineDao() {
257 return HEALING_PIPELINE_DAO;
261 ContainerInstanceTypesData containerInstanceTypesData() {
262 return new ContainerInstanceTypesData();
266 ModelOperation modelOperation() {
267 return new ModelOperation(null, null, null, null);
270 private void initGraphForTest() {
271 //Create Catalog Root
272 catalogVertex = GraphTestUtils.createRootCatalogVertex(janusGraphDao);
273 //Create Archive Root
274 GraphTestUtils.createRootArchiveVertex(janusGraphDao);
276 createSingleVersionServiceAndResource();
279 private void createSingleVersionServiceAndResource() {
280 //Create Service for Scenario 1 Tests (1 Service)
281 serviceVertex = GraphTestUtils.createServiceVertex(janusGraphDao, propsForHighestVersion());
283 Map<GraphPropertyEnum, Object> props = propsForHighestVersion();
284 props.put(GraphPropertyEnum.IS_VSP_ARCHIVED, false);
285 props.put(GraphPropertyEnum.CSAR_UUID, CSAR_UUID1);
286 resourceVertex = GraphTestUtils.createResourceVertex(janusGraphDao, props, ResourceTypeEnum.VF);
288 props = propsForHighestVersion();
289 props.put(GraphPropertyEnum.IS_VSP_ARCHIVED, true);
290 props.put(GraphPropertyEnum.CSAR_UUID, CSAR_UUID2);
291 resourceVertexVspArchived = GraphTestUtils.createResourceVertex(janusGraphDao, props, ResourceTypeEnum.VF);
293 //Connect Service/Resource to Catalog Root
294 janusGraphDao.createEdge(catalogVertex, serviceVertex, EdgeLabelEnum.CATALOG_ELEMENT, null);
295 janusGraphDao.createEdge(catalogVertex, resourceVertex, EdgeLabelEnum.CATALOG_ELEMENT, null);
298 private Map<GraphPropertyEnum, Object> propsForHighestVersion() {
299 Map<GraphPropertyEnum, Object> props = new HashMap<>();
300 props.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
305 public static final HttpServletRequest request = mock(HttpServletRequest.class);
308 private static final User adminUser = new User("admin", "admin", "admin", "admin@email.com", Role.ADMIN.name(),
309 System.currentTimeMillis());
310 private static final User designerUser = new User("designer", "designer", "designer", "designer@email.com",
311 Role.DESIGNER.name(), System.currentTimeMillis());
312 private static final User otherUser = new User("other", "other", "other", "other@email.com", Role.TESTER.name(),
313 System.currentTimeMillis());
316 public static void setup() {
317 //Needed for User Authorization
318 //========================================================================================================================
319 when(servletContext.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR))
320 .thenReturn(webAppContextWrapper);
321 when(webAppContextWrapper.getWebAppContext(servletContext)).thenReturn(webApplicationContext);
322 when(webApplicationContext.getBean(ServletUtils.class)).thenReturn(servletUtils);
323 when(servletUtils.getUserAdmin()).thenReturn(userAdmin);
324 when(servletUtils.getComponentsUtils()).thenReturn(componentUtils);
325 when(componentUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)).thenReturn(responseFormat);
326 when(componentUtils.getResponseFormat(eq(ActionStatus.INVALID_SERVICE_STATE), any()))
327 .thenReturn(invalidServiceStateResponseFormat);
328 when(responseFormat.getStatus()).thenReturn(HttpStatus.UNAUTHORIZED.value());
330 ComponentException ce = new ByResponseFormatComponentException(responseFormat);
331 doThrow(ce).when(accessValidationsMock).userIsAdminOrDesigner(eq(otherUser.getUserId()), any());
333 //Needed for error configuration
334 when(notFoundResponseFormat.getStatus()).thenReturn(HttpStatus.NOT_FOUND.value());
335 when(invalidServiceStateResponseFormat.getStatus()).thenReturn(HttpStatus.CONFLICT.value());
336 when(badRequestResponseFormat.getStatus()).thenReturn(HttpStatus.BAD_REQUEST.value());
337 when(componentUtils.getResponseFormat(eq(ActionStatus.RESOURCE_NOT_FOUND), (String[]) any()))
338 .thenReturn(notFoundResponseFormat);
339 when(componentUtils.getResponseFormat(eq(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID), (String[]) any()))
340 .thenReturn(badRequestResponseFormat);
342 when(graphLockOperation.lockComponent(anyString(), any(NodeTypeEnum.class)))
343 .thenReturn(StorageOperationStatus.OK);
344 when(userAdmin.getUser(adminUser.getUserId(), false)).thenReturn(adminUser);
345 when(userAdmin.getUser(designerUser.getUserId(), false)).thenReturn(designerUser);
346 when(userAdmin.getUser(otherUser.getUserId(), false)).thenReturn(otherUser);
347 //========================================================================================================================
349 String appConfigDir = "src/test/resources/config/catalog-be";
350 ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(),
352 ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
354 org.openecomp.sdc.be.config.Configuration configuration = new org.openecomp.sdc.be.config.Configuration();
355 configuration.setJanusGraphInMemoryGraph(true);
357 org.openecomp.sdc.be.config.Configuration.HeatDeploymentArtifactTimeout heatDeploymentArtifactTimeout = new org.openecomp.sdc.be.config.Configuration.HeatDeploymentArtifactTimeout();
358 heatDeploymentArtifactTimeout.setDefaultMinutes(30);
360 configuration.setHeatArtifactDeploymentTimeout(heatDeploymentArtifactTimeout);
361 configurationManager.setConfiguration(configuration);
363 configurationManager.setConfiguration(configuration);
364 ExternalConfiguration.setAppName("catalog-be");
368 public void before() throws Exception {
373 public void tearDown() throws Exception {
378 void getArchivedComponents_Empty() {
379 assertOnGetArchivedComponents(null, 0);
383 void archiveAndGetArchivedService_SingleService() {
384 Component serviceComponent = mock(Component.class);
385 final String serviceUniqueId = serviceVertex.getUniqueId();
386 when(toscaOperationFacade.getToscaElement(serviceUniqueId)).thenReturn(Either.left(serviceComponent));
387 when(catalogOperations.updateCatalog(ChangeTypeEnum.ARCHIVE, serviceComponent)).thenReturn(ActionStatus.OK);
388 archiveService(serviceUniqueId, HttpStatus.OK.value());
389 assertOnGetArchivedComponents(ComponentTypeEnum.SERVICE_PARAM_NAME, 1);
390 //restoreService(serviceUniqueId, 200);
394 void archiveAndGetArchivedResource_SingleResource() {
395 Component component = mock(Component.class);
396 final String uniqueId = resourceVertex.getUniqueId();
397 when(toscaOperationFacade.getToscaElement(uniqueId)).thenReturn(Either.left(component));
398 when(catalogOperations.updateCatalog(ChangeTypeEnum.ARCHIVE, component)).thenReturn(ActionStatus.OK);
399 archiveResource(uniqueId, HttpStatus.OK.value());
400 assertOnGetArchivedComponents(ComponentTypeEnum.RESOURCE_PARAM_NAME, 1);
401 //restoreResource(uniqueId, 200);
405 void attemptArchiveCheckedOutService() {
406 checkoutComponent(serviceVertex);
407 archiveService(serviceVertex.getUniqueId(), HttpStatus.CONFLICT.value());
411 void testOnArchivedVsps() {
412 String path = "/v1/catalog/notif/vsp/archived";
413 List<String> csarIds = new LinkedList<>();
414 csarIds.add("123456");
415 csarIds.add(CSAR_UUID2); //An archived CSAR ID
416 Response response = target()
418 .request(MediaType.APPLICATION_JSON)
419 .accept(MediaType.APPLICATION_JSON)
420 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
421 .post(Entity.json(csarIds));
423 assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
424 assertOnVertexProp(resourceVertexVspArchived.getUniqueId(), true);
428 void testOnRestoredVsps() {
429 String path = "/v1/catalog/notif/vsp/restored";
430 List<String> csarIds = new LinkedList<>();
431 csarIds.add("123456");
432 csarIds.add(CSAR_UUID1); //Non archived CSAR_ID
433 Response response = target()
435 .request(MediaType.APPLICATION_JSON)
436 .accept(MediaType.APPLICATION_JSON)
437 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
438 .post(Entity.json(csarIds));
440 assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
441 assertOnVertexProp(resourceVertex.getUniqueId(), false);
448 void archiveWithInvalidUid() {
449 archiveService("fakeUid", HttpStatus.NOT_FOUND.value());
453 void restoreWithInvalidUid() {
454 restoreService("fakeUid", HttpStatus.NOT_FOUND.value());
458 void archiveWithTester() {
459 String path = String.format("/v1/catalog/services/%s/%s", serviceVertex.getUniqueId(), "archive");
460 Response response = target()
463 .accept(MediaType.APPLICATION_JSON)
464 .header(Constants.USER_ID_HEADER, otherUser.getUserId())
467 assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
470 private void checkoutComponent(GraphVertex component) {
471 Either<GraphVertex, JanusGraphOperationStatus> vE = janusGraphDao.getVertexById(component.getUniqueId());
472 GraphVertex v = vE.left().value();
473 v.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
474 v.setJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
475 janusGraphDao.updateVertex(v);
476 janusGraphDao.commit();
479 private void assertOnVertexProp(String componentId, Object expectedValue) {
480 Either<GraphVertex, JanusGraphOperationStatus> vE = janusGraphDao.getVertexById(componentId);
481 GraphVertex v = vE.left().value();
482 assertThat(v.getMetadataProperty(GraphPropertyEnum.IS_VSP_ARCHIVED)).isEqualTo(expectedValue);
485 private void archiveService(String id, int expectedStatus) {
486 archiveOrRestoreService(id, ArchiveOperation.Action.ARCHIVE, expectedStatus);
489 private void restoreService(String id, int expectedStatus) {
490 archiveOrRestoreService(id, ArchiveOperation.Action.RESTORE, expectedStatus);
493 private void archiveResource(String id, int expectedStatus) {
494 archiveOrRestoreResource(id, ArchiveOperation.Action.ARCHIVE, expectedStatus);
497 private void restoreResource(String id, int expectedStatus) {
498 archiveOrRestoreResource(id, ArchiveOperation.Action.RESTORE, expectedStatus);
501 private void archiveOrRestoreService(String compUid, ArchiveOperation.Action action, int expectedStatus) {
502 String path = String.format("/v1/catalog/services/%s/%s", compUid, action.name().toLowerCase());
503 Response response = target()
506 .accept(MediaType.APPLICATION_JSON)
507 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
510 assertThat(response.getStatus()).isEqualTo(expectedStatus);
513 private void archiveOrRestoreResource(String compUid, ArchiveOperation.Action action, int expectedStatus) {
514 String path = String.format("/v1/catalog/resources/%s/%s", compUid, action.name().toLowerCase());
515 Response response = target()
518 .accept(MediaType.APPLICATION_JSON)
519 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
522 assertThat(response.getStatus()).isEqualTo(expectedStatus);
525 private void assertOnGetArchivedComponents(String componentType, int expectedCount) {
526 String path = "/v1/catalog/archive";
528 Response response = target()
531 .accept(MediaType.APPLICATION_JSON)
532 .header(Constants.USER_ID_HEADER, designerUser.getUserId())
535 Map<String, List<CatalogComponent>> archivedComponents = response
536 .readEntity(new GenericType<Map<String, List<CatalogComponent>>>() {
538 assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
540 if (componentType == null) {
541 assertThat(archivedComponents).isEmpty();
543 assertThat(archivedComponents.get(componentType)).hasSize(expectedCount);
549 protected Application configure() {
550 ApplicationContext context = new AnnotationConfigApplicationContext(TestSpringConfig.class);
551 forceSet(TestProperties.CONTAINER_PORT, "0");
552 return new ResourceConfig(ArchiveEndpoint.class)
553 .register(DefaultExceptionMapper.class)
554 .register(ComponentExceptionMapper.class)
555 .register(StorageExceptionMapper.class)
556 .property("contextConfig", context);