From 3a1f764b762a91e917e9e14a00c4a7ff3c4e0745 Mon Sep 17 00:00:00 2001 From: "mark.j.leonard" Date: Wed, 18 Apr 2018 11:17:11 +0100 Subject: [PATCH] Remove dependency on org.powermock (PowerMockito) Replace use of PowerMockito packages with the standard Mockito. Create a BabelServiceClient Factory class to simplify mocking. Remove duplicated "no mock" test classes that were not in fact free of mocking. Add a dummy sample CSAR file for testing of artifact downloads. Change-Id: Ib86f560e514e1efab0e2f732e494a032d555c7c3 Issue-ID: AAI-1049 Signed-off-by: mark.j.leonard --- pom.xml | 50 ---- .../notification/ArtifactDownloadManager.java | 11 +- .../modelloader/notification/EventCallback.java | 8 +- .../aai/modelloader/restclient/AaiRestClient.java | 6 +- .../restclient/BabelServiceClientFactory.java | 38 +++ .../modelloader/service/ModelLoaderService.java | 5 +- .../catalog/VnfCatalogArtifactHandlerTest.java | 200 +++++++-------- .../VnfCatalogArtifactHandler_noMock_Test.java | 118 --------- .../entity/model/AAIRestClientTest.java | 137 ---------- .../ArtifactDeploymentManagerMockTest.java | 274 -------------------- .../ArtifactDeploymentManagerTest.java | 45 ++-- .../ArtifactDownloadManagerNoMockTest.java | 275 --------------------- .../notification/ArtifactDownloadManagerTest.java | 201 +++++++++++---- .../notification/BabelArtifactConverterTest.java | 7 +- .../notification/EventCallbackNoMockTest.java | 123 --------- .../notification/EventCallbackTest.java | 49 ++-- .../modelloader/restclient/TestAaiRestClient.java | 149 ----------- .../service-VscpaasTest-csar.csar | Bin 0 -> 30511 bytes 18 files changed, 358 insertions(+), 1338 deletions(-) create mode 100644 src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClientFactory.java delete mode 100644 src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler_noMock_Test.java delete mode 100644 src/test/java/org/onap/aai/modelloader/entity/model/AAIRestClientTest.java delete mode 100644 src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerMockTest.java delete mode 100644 src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerNoMockTest.java delete mode 100644 src/test/java/org/onap/aai/modelloader/notification/EventCallbackNoMockTest.java delete mode 100644 src/test/java/org/onap/aai/modelloader/restclient/TestAaiRestClient.java create mode 100644 src/test/resources/compressedArtifacts/service-VscpaasTest-csar.csar diff --git a/pom.xml b/pom.xml index 8829d64..f45e580 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,6 @@ 1.14 2.8.1 1.10.19 - 1.6.2 1.1.1 1.18 2.7 @@ -151,30 +150,6 @@ ${mockito.version} test - - org.powermock - powermock-module-junit4 - ${powermock.version} - test - - - org.powermock - powermock-api-mockito - ${powermock.version} - test - - - org.powermock - powermock-module-junit4-rule-agent - 1.6.2 - test - - - powermock-module-javaagent - org.powermock - - - org.javassist javassist @@ -484,31 +459,6 @@ true - - org.apache.maven.plugins - maven-dependency-plugin - 2.8 - - - copy-agent - process-test-classes - - copy - - - - - org.powermock - powermock-module-javaagent - 1.6.2 - ${project.build.directory}/agents - powermock-javaagent.jar - - - - - - org.apache.maven.plugins maven-surefire-plugin diff --git a/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java index bdd101e..3fa0b40 100644 --- a/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java +++ b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java @@ -26,7 +26,6 @@ import java.util.Base64; import java.util.List; import java.util.Map; import java.util.stream.Collectors; - import org.onap.aai.babel.service.data.BabelArtifact; import org.onap.aai.babel.service.data.BabelArtifact.ArtifactType; import org.onap.aai.cl.api.Logger; @@ -40,6 +39,7 @@ import org.onap.aai.modelloader.entity.model.IModelParser; import org.onap.aai.modelloader.entity.model.NamedQueryArtifactParser; import org.onap.aai.modelloader.extraction.InvalidArchiveException; import org.onap.aai.modelloader.restclient.BabelServiceClient; +import org.onap.aai.modelloader.restclient.BabelServiceClientFactory; import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.openecomp.sdc.api.IDistributionClient; import org.openecomp.sdc.api.notification.IArtifactInfo; @@ -66,10 +66,13 @@ public class ArtifactDownloadManager { private NotificationPublisher notificationPublisher; private BabelArtifactConverter babelArtifactConverter; private ModelLoaderConfig config; + private BabelServiceClientFactory clientFactory; - public ArtifactDownloadManager(IDistributionClient client, ModelLoaderConfig config) { + public ArtifactDownloadManager(IDistributionClient client, ModelLoaderConfig config, + BabelServiceClientFactory clientFactory) { this.client = client; this.config = config; + this.clientFactory = clientFactory; } /** @@ -193,12 +196,12 @@ public class ArtifactDownloadManager { } } - private BabelServiceClient createBabelServiceClient(IArtifactInfo artifact, String serviceVersion) + BabelServiceClient createBabelServiceClient(IArtifactInfo artifact, String serviceVersion) throws ProcessToscaArtifactsException { BabelServiceClient babelClient; try { logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Creating Babel client"); - babelClient = new BabelServiceClient(config); + babelClient = clientFactory.create(config); } catch (Exception e) { logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(), "Error posting artifact " + artifact.getArtifactName() + " " + serviceVersion + " to Babel: " diff --git a/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java b/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java index 827ff81..fe6bf7b 100644 --- a/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java +++ b/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java @@ -28,6 +28,7 @@ import org.onap.aai.cl.mdc.MdcContext; import org.onap.aai.modelloader.config.ModelLoaderConfig; import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.extraction.ArtifactInfoExtractor; +import org.onap.aai.modelloader.restclient.BabelServiceClientFactory; import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.openecomp.sdc.api.IDistributionClient; import org.openecomp.sdc.api.consumer.INotificationCallback; @@ -58,8 +59,8 @@ public class EventCallback implements INotificationCallback { List catalogArtifacts = new ArrayList<>(); List modelArtifacts = new ArrayList<>(); - boolean success = getArtifactDownloadManager() - .downloadArtifacts(data, artifacts, modelArtifacts, catalogArtifacts); + boolean success = + getArtifactDownloadManager().downloadArtifacts(data, artifacts, modelArtifacts, catalogArtifacts); if (success) { success = getArtifactDeploymentManager().deploy(data, artifacts, modelArtifacts, catalogArtifacts); @@ -75,13 +76,12 @@ public class EventCallback implements INotificationCallback { if (artifactDeploymentManager == null) { artifactDeploymentManager = new ArtifactDeploymentManager(client, config); } - return artifactDeploymentManager; } private ArtifactDownloadManager getArtifactDownloadManager() { if (artifactDownloadManager == null) { - artifactDownloadManager = new ArtifactDownloadManager(client, config); + artifactDownloadManager = new ArtifactDownloadManager(client, config, new BabelServiceClientFactory()); } return artifactDownloadManager; diff --git a/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java b/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java index 7d2ab09..28cd671 100644 --- a/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java +++ b/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java @@ -21,7 +21,6 @@ package org.onap.aai.modelloader.restclient; import com.sun.jersey.core.util.MultivaluedMapImpl; // NOSONAR -// import edu.emory.mathcs.backport.java.util.Collections; import java.io.IOException; import java.io.StringReader; import java.net.URI; @@ -91,7 +90,7 @@ public class AaiRestClient { * @return operation result */ public OperationResult putResource(String url, String payload, String transId, MediaType mediaType) { - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload); + logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload); return setupClient().put(url, payload, buildHeaders(transId), mediaType, mediaType); } @@ -106,7 +105,7 @@ public class AaiRestClient { * @return ClientResponse */ public OperationResult postResource(String url, String payload, String transId, MediaType mediaType) { - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload); + logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload); return setupClient().post(url, payload, buildHeaders(transId), mediaType, mediaType); } @@ -180,7 +179,6 @@ public class AaiRestClient { * @param transId * @return map of headers */ - @SuppressWarnings("unchecked") private Map> buildHeaders(String transId) { MultivaluedMap headers = new MultivaluedMapImpl(); headers.put(HEADER_TRANS_ID, Collections.singletonList(transId)); diff --git a/src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClientFactory.java b/src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClientFactory.java new file mode 100644 index 0000000..6ce4a60 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClientFactory.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + */ +package org.onap.aai.modelloader.restclient; + +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import org.onap.aai.modelloader.config.ModelLoaderConfig; + +public class BabelServiceClientFactory { + + public BabelServiceClient create(ModelLoaderConfig config) throws UnrecoverableKeyException, KeyManagementException, + NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { + return new BabelServiceClient(config); + } + +} diff --git a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java index aa3481c..a4cc5d1 100644 --- a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java +++ b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java @@ -39,6 +39,7 @@ import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.notification.ArtifactDeploymentManager; import org.onap.aai.modelloader.notification.ArtifactDownloadManager; import org.onap.aai.modelloader.notification.EventCallback; +import org.onap.aai.modelloader.restclient.BabelServiceClientFactory; import org.openecomp.sdc.api.IDistributionClient; import org.openecomp.sdc.api.notification.IArtifactInfo; import org.openecomp.sdc.api.notification.INotificationData; @@ -196,8 +197,8 @@ public class ModelLoaderService implements ModelLoaderInterface { logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Generating xml models from test artifact"); - new ArtifactDownloadManager(client, config).processToscaArtifacts(modelArtifacts, catalogArtifacts, - csarFile, artifactInfo, "test-transaction-id", modelVersion); + new ArtifactDownloadManager(client, config, new BabelServiceClientFactory()).processToscaArtifacts( + modelArtifacts, catalogArtifacts, csarFile, artifactInfo, "test-transaction-id", modelVersion); List artifacts = new ArrayList<>(); artifacts.add(artifactInfo); diff --git a/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandlerTest.java b/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandlerTest.java index addea78..aa75cd2 100644 --- a/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandlerTest.java +++ b/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandlerTest.java @@ -1,100 +1,100 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.entity.catalog; - -import static org.junit.Assert.fail; - -import com.sun.jersey.api.client.ClientResponse; -import java.io.IOException; -import java.util.Properties; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.restclient.client.OperationResult; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({VnfCatalogArtifactHandler.class, ClientResponse.class, AaiRestClient.class}) -public class VnfCatalogArtifactHandlerTest { - - protected static String CONFIG_FILE = "model-loader.properties"; - - @Test - public void testWithMocks() throws Exception { - - Properties configProperties = new Properties(); - try { - configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); - } catch (IOException e) { - fail(); - } - ModelLoaderConfig config = new ModelLoaderConfig(configProperties, null); - config.setModelVersion("11"); - - AaiRestClient mockRestClient = PowerMockito.mock(AaiRestClient.class); - PowerMockito.whenNew(AaiRestClient.class).withAnyArguments().thenReturn(mockRestClient); - - // GET operation - OperationResult mockGetResp = PowerMockito.mock(OperationResult.class); - - // @formatter:off - PowerMockito.when(mockGetResp.getResultCode()) - .thenReturn(Response.Status.OK.getStatusCode()) - .thenReturn(Response.Status.NOT_FOUND.getStatusCode()) - .thenReturn(Response.Status.NOT_FOUND.getStatusCode()) - .thenReturn(Response.Status.OK.getStatusCode()); - // @formatter:on - PowerMockito.when( - mockRestClient.getResource(Mockito.anyString(), Mockito.anyString(), Mockito.any(MediaType.class))) - .thenReturn(mockGetResp); - - // PUT operation - OperationResult mockPutResp = PowerMockito.mock(OperationResult.class); - - PowerMockito.when(mockPutResp.getResultCode()).thenReturn(Response.Status.CREATED.getStatusCode()); - PowerMockito.when(mockRestClient.putResource(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), - Mockito.any(MediaType.class))).thenReturn(mockPutResp); - - // Example VNF Catalog with - VnfCatalogArtifactHandler vnfCAH = new VnfCatalogArtifactHandler(config); - String examplePath = "src/test/resources/imagedataexample.json"; - /* - * byte[] encoded = Files.readAllBytes(Paths.get(examplePath)); List artifacts = new - * ArrayList(); artifacts.add(new VnfCatalogArtifact(new String(encoded, "utf-8"))); - * - * assertTrue(vnfCAH.pushArtifacts(artifacts, "test", new ArrayList(), mockRestClient)); - * - * // Only two of the VNF images should be pushed ArgumentCaptor argument = - * ArgumentCaptor.forClass(String.class); AaiRestClient r = Mockito.verify(mockRestClient, Mockito.times(2)); - * r.putResource(Mockito.anyString(), argument.capture(), Mockito.anyString(), Mockito.any(MediaType.class)); - * assertTrue(argument.getAllValues().get(0).contains("3.16.9")); - * assertTrue(argument.getAllValues().get(0).contains("VM00")); - * assertTrue(argument.getAllValues().get(1).contains("3.16.1")); - * assertTrue(argument.getAllValues().get(1).contains("VM01")); - */ - } -} +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + */ +package org.onap.aai.modelloader.entity.catalog; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.restclient.AaiRestClient; +import org.onap.aai.restclient.client.OperationResult; + +public class VnfCatalogArtifactHandlerTest { + + protected static String CONFIG_FILE = "model-loader.properties"; + + @Test + public void testWithMocks() throws Exception { + + Properties configProperties = new Properties(); + try { + configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); + } catch (IOException e) { + fail(); + } + ModelLoaderConfig config = new ModelLoaderConfig(configProperties, null); + config.setModelVersion("11"); + + AaiRestClient mockRestClient = mock(AaiRestClient.class); + + // GET operation + OperationResult mockGetResp = mock(OperationResult.class); + + // @formatter:off + when(mockGetResp.getResultCode()) + .thenReturn(Response.Status.OK.getStatusCode()) + .thenReturn(Response.Status.NOT_FOUND.getStatusCode()) + .thenReturn(Response.Status.NOT_FOUND.getStatusCode()) + .thenReturn(Response.Status.OK.getStatusCode()); + // @formatter:on + when(mockRestClient.getResource(Mockito.anyString(), Mockito.anyString(), Mockito.any(MediaType.class))) + .thenReturn(mockGetResp); + + // PUT operation + OperationResult mockPutResp = mock(OperationResult.class); + + when(mockPutResp.getResultCode()).thenReturn(Response.Status.CREATED.getStatusCode()); + when(mockRestClient.putResource(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), + Mockito.any(MediaType.class))).thenReturn(mockPutResp); + + // Example VNF Catalog with + VnfCatalogArtifactHandler vnfCAH = new VnfCatalogArtifactHandler(config); + String examplePath = "src/test/resources/imagedataexample.json"; + byte[] encoded = Files.readAllBytes(Paths.get(examplePath)); + List artifacts = new ArrayList(); + artifacts.add(new VnfCatalogArtifact(new String(encoded, "utf-8"))); + + assertTrue(vnfCAH.pushArtifacts(artifacts, "test", new ArrayList(), mockRestClient)); + + // Only two of the VNF images should be pushed + ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); + AaiRestClient r = Mockito.verify(mockRestClient, Mockito.times(2)); + r.putResource(Mockito.anyString(), argument.capture(), Mockito.anyString(), Mockito.any(MediaType.class)); + assertTrue(argument.getAllValues().get(0).contains("3.16.9")); + assertTrue(argument.getAllValues().get(0).contains("VM00")); + assertTrue(argument.getAllValues().get(1).contains("3.16.1")); + assertTrue(argument.getAllValues().get(1).contains("VM01")); + } +} diff --git a/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler_noMock_Test.java b/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler_noMock_Test.java deleted file mode 100644 index a1ca794..0000000 --- a/src/test/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler_noMock_Test.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.entity.catalog; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.sun.jersey.api.client.ClientResponse; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.Artifact; -import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.restclient.client.OperationResult; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; - - -/** - * No-Mock tests - * - * Because Jacoco (and other coverage tools) can't cope with mocked classes under some circumstances, coverage is/was - * falsely reported as < 50%. Hence these duplicated but non-mock tests to address this, for ONAP reasons. - * - * @author andrewdo - * - */ - -@PrepareForTest({VnfCatalogArtifactHandler.class, ClientResponse.class, AaiRestClient.class}) -public class VnfCatalogArtifactHandler_noMock_Test { - - protected static String CONFIG_FILE = "model-loader.properties"; - - - @Test - public void testWithOutMocks() throws Exception { - - Properties configProperties = new Properties(); - try { - configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); - } catch (IOException e) { - fail(); - } - - ModelLoaderConfig config = new ModelLoaderConfig(configProperties, null); - config.setModelVersion("11"); - - AaiRestClient mockRestClient = PowerMockito.mock(AaiRestClient.class); - PowerMockito.whenNew(AaiRestClient.class).withAnyArguments().thenReturn(mockRestClient); - - // GET operation - OperationResult mockGetResp = PowerMockito.mock(OperationResult.class); - - // @formatter:off - PowerMockito.when(mockGetResp.getResultCode()) - .thenReturn(Response.Status.OK.getStatusCode()) - .thenReturn(Response.Status.NOT_FOUND.getStatusCode()) - .thenReturn(Response.Status.NOT_FOUND.getStatusCode()) - .thenReturn(Response.Status.OK.getStatusCode()); - // @formatter:on - PowerMockito.when( - mockRestClient.getResource(Mockito.anyString(), Mockito.anyString(), Mockito.any(MediaType.class))) - .thenReturn(mockGetResp); - - // PUT operation - OperationResult mockPutResp = PowerMockito.mock(OperationResult.class); - - PowerMockito.when(mockPutResp.getResultCode()).thenReturn(Response.Status.CREATED.getStatusCode()); - PowerMockito.when(mockRestClient.putResource(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), - Mockito.any(MediaType.class))).thenReturn(mockPutResp); - - // Example VNF Catalog with - VnfCatalogArtifactHandler vnfCAH = new VnfCatalogArtifactHandler(config); - String examplePath = "src/test/resources/imagedataexample.json"; - byte[] encoded = Files.readAllBytes(Paths.get(examplePath)); - List artifacts = new ArrayList(); - artifacts.add(new VnfCatalogArtifact(new String(encoded, "utf-8"))); - - assertTrue(vnfCAH.pushArtifacts(artifacts, "test", new ArrayList(), mockRestClient)); - - // Only two of the VNF images should be pushed - ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); - AaiRestClient r = Mockito.verify(mockRestClient, Mockito.times(2)); - r.putResource(Mockito.anyString(), argument.capture(), Mockito.anyString(), Mockito.any(MediaType.class)); - assertTrue(argument.getAllValues().get(0).contains("3.16.9")); - assertTrue(argument.getAllValues().get(0).contains("VM00")); - assertTrue(argument.getAllValues().get(1).contains("3.16.1")); - assertTrue(argument.getAllValues().get(1).contains("VM01")); - } - -} diff --git a/src/test/java/org/onap/aai/modelloader/entity/model/AAIRestClientTest.java b/src/test/java/org/onap/aai/modelloader/entity/model/AAIRestClientTest.java deleted file mode 100644 index ecf37d1..0000000 --- a/src/test/java/org/onap/aai/modelloader/entity/model/AAIRestClientTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.entity.model; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.sun.jersey.api.client.ClientHandlerException; -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.util.Properties; -import javax.ws.rs.core.MediaType; -import org.junit.Before; -import org.junit.Test; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.modelloader.restclient.BabelServiceClient; -import org.onap.aai.modelloader.restclient.BabelServiceClient.BabelServiceException; - -/** - * No-Mock tests - * - * Because Jacoco (and other coverage tools) can't cope with mocked classes under some circumstances, coverage is/was - * falsely reported as < 50%. Hence these duplicated but non-mock tests to address this, for ONAP reasons. - * - * This particular class is to help make up the remaining gaps in test coverage to 50%. - * - * @author andrewdo - * - */ - - -public class AAIRestClientTest { - - private static final String CONFIG_FILE = "model-loader.properties"; - - private ModelLoaderConfig config; - private Properties configProperties; - - @Before - public void setup() throws IOException { - configProperties = new Properties(); - configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); - config = new ModelLoaderConfig(configProperties, null); - } - - @Test - public void testRestClient() { - - AaiRestClient arc = new AaiRestClient(config); - - arc.deleteResource("testurl", "1", "xxx"); - - arc.getAndDeleteResource("testurl", "xxx"); - - arc.getResource("testurl", "xxx", MediaType.APPLICATION_ATOM_XML_TYPE); - - arc.postResource("testurl", "payload", "xxx", MediaType.APPLICATION_ATOM_XML_TYPE); - - arc.putResource("testurl", "payload", "xxx", MediaType.APPLICATION_ATOM_XML_TYPE); - - try { - arc.wait(1); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testBabelClient() { - - ModelLoaderConfig mockedConfig = mock(ModelLoaderConfig.class); - - when(mockedConfig.getBabelKeyStorePath()).thenReturn(null); - - try { - - BabelServiceClient bsc = new BabelServiceClient(mockedConfig); - - byte[] artifactPayload = new byte[11]; - - bsc.postArtifact(artifactPayload, "artifactName", "artifactVersion", "transactionId"); - - - } catch (UnrecoverableKeyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (BabelServiceException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ClientHandlerException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - System.out.println("This is expected!"); - } - - - } -} diff --git a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerMockTest.java b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerMockTest.java deleted file mode 100644 index 396cc03..0000000 --- a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerMockTest.java +++ /dev/null @@ -1,274 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.notification; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithCatalogFile; -import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithOneOfEach; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.onap.aai.babel.service.data.BabelArtifact; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.Artifact; -import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifact; -import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifactHandler; -import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; -import org.onap.aai.modelloader.entity.model.ModelArtifactHandler; -import org.onap.aai.modelloader.extraction.InvalidArchiveException; -import org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder; -import org.onap.aai.modelloader.util.ArtifactTestUtils; -import org.openecomp.sdc.api.IDistributionClient; -import org.openecomp.sdc.api.notification.INotificationData; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.reflect.Whitebox; - -/** - * Tests {@link ArtifactDeploymentManager } - */ -public class ArtifactDeploymentManagerMockTest { - - private static final String CONFIG_FILE = "model-loader.properties"; - private static final String SHOULD_HAVE_RETURNED_FALSE = "This should have returned false"; - - private Properties configProperties; - private ArtifactDeploymentManager manager; - - private IDistributionClient mockDistributionClient; - private ModelArtifactHandler mockModelArtifactHandler; - private NotificationPublisher mockNotificationPublisher; - private VnfCatalogArtifactHandler mockVnfCatalogArtifactHandler; - - @Before - public void setup() throws IOException { - configProperties = new Properties(); - configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); - ModelLoaderConfig config = new ModelLoaderConfig(configProperties, null); - - mockDistributionClient = PowerMockito.mock(IDistributionClient.class); - mockModelArtifactHandler = PowerMockito.mock(ModelArtifactHandler.class); - mockNotificationPublisher = PowerMockito.mock(NotificationPublisher.class); - mockVnfCatalogArtifactHandler = PowerMockito.mock(VnfCatalogArtifactHandler.class); - - manager = new ArtifactDeploymentManager(mockDistributionClient, config); - - Whitebox.setInternalState(manager, mockModelArtifactHandler); - Whitebox.setInternalState(manager, mockNotificationPublisher); - Whitebox.setInternalState(manager, mockVnfCatalogArtifactHandler); - } - - @After - public void tearDown() { - configProperties = null; - mockDistributionClient = null; - mockModelArtifactHandler = null; - mockNotificationPublisher = null; - mockVnfCatalogArtifactHandler = null; - manager = null; - } -/* - @Test - public void deploy_csarDeploymentsFailed() throws IOException, BabelArtifactParsingException { - ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); - INotificationData data = NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile(); - byte[] xml = artifactTestUtils.loadResource("convertedYmls/AAI-SCP-Test-VSP-resource-1.0.xml"); - List toscaArtifacts = setupTest(xml, data); - List modelArtifacts = new BabelArtifactConverter().convertToModel(toscaArtifacts); - - PowerMockito.when( - mockModelArtifactHandler.pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), any())) - .thenReturn(false); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - - assertFalse(SHOULD_HAVE_RETURNED_FALSE, - manager.deploy(data, data.getServiceArtifacts(), modelArtifacts, new ArrayList<>())); - - Mockito.verify(mockModelArtifactHandler).pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), - any()); - Mockito.verify(mockVnfCatalogArtifactHandler, Mockito.never()).pushArtifacts(eq(modelArtifacts), - eq(data.getDistributionID()), any(), any()); - Mockito.verify(mockModelArtifactHandler).rollback(eq(new ArrayList()), eq(data.getDistributionID()), - any()); - Mockito.verify(mockVnfCatalogArtifactHandler, Mockito.never()).rollback(eq(new ArrayList()), - eq(data.getDistributionID()), any()); - Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - } -*/ - private List setupTest(byte[] xml, INotificationData data) throws IOException { - List toscaArtifacts = new ArrayList<>(); - org.openecomp.sdc.api.notification.IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0); - - BabelArtifact xmlArtifact = - new BabelArtifact(artifactInfo.getArtifactName(), BabelArtifact.ArtifactType.MODEL, new String(xml)); - toscaArtifacts.add(xmlArtifact); - - return toscaArtifacts; - } - - @Test - public void deploy_catalogDeploymentsFailed() - throws IOException, BabelArtifactParsingException, InvalidArchiveException { - INotificationData data = getNotificationDataWithCatalogFile(); - - List catalogFiles = new ArrayList<>(); - catalogFiles.add(new VnfCatalogArtifact("Some catalog content")); - - PowerMockito.when(mockModelArtifactHandler.pushArtifacts(any(), any(), any(), any())).thenReturn(true); - PowerMockito.when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any())).thenReturn(false); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - - assertFalse(SHOULD_HAVE_RETURNED_FALSE, - manager.deploy(data, data.getServiceArtifacts(), new ArrayList<>(), catalogFiles)); - - Mockito.verify(mockModelArtifactHandler).pushArtifacts(eq(new ArrayList()), - eq(data.getDistributionID()), any(), any()); - Mockito.verify(mockVnfCatalogArtifactHandler).pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any()); - Mockito.verify(mockModelArtifactHandler).rollback(eq(new ArrayList()), eq(data.getDistributionID()), - any()); - Mockito.verify(mockVnfCatalogArtifactHandler).rollback(eq(new ArrayList()), - eq(data.getDistributionID()), any()); - Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - } - -/* - @Test - public void deploy_bothDeploymentsFailed() - throws IOException, BabelArtifactParsingException, InvalidArchiveException { - doFailedCombinedTests(false, false); - } -*/ -/* - @Test - public void deploy_modelsFailedCatalogsOK() - throws IOException, BabelArtifactParsingException, InvalidArchiveException { - doFailedCombinedTests(false, true); - } -*/ -/* - @Test - public void deploy_catalogsFailedModelsOK() - throws IOException, BabelArtifactParsingException, InvalidArchiveException { - doFailedCombinedTests(true, false); - } -*/ - private void doFailedCombinedTests(boolean modelsOK, boolean catalogsOK) - throws IOException, BabelArtifactParsingException, InvalidArchiveException { - INotificationData data = getNotificationDataWithOneOfEach(); - ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); - byte[] xml = artifactTestUtils.loadResource("convertedYmls/AAI-SCP-Test-VSP-resource-1.0.xml"); - List toscaArtifacts = setupTest(xml, data); - List modelArtifacts = new BabelArtifactConverter().convertToModel(toscaArtifacts); - - List catalogFiles = new ArrayList<>(); - catalogFiles.add(new VnfCatalogArtifact("Some catalog content")); - - PowerMockito.when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any())).thenReturn(catalogsOK); - PowerMockito.when( - mockModelArtifactHandler.pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), any())) - .thenReturn(modelsOK); - - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeploySuccess(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - - assertFalse(SHOULD_HAVE_RETURNED_FALSE, - manager.deploy(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles)); - - // Catalog artifacts are only pushed if models are successful. - Mockito.verify(mockModelArtifactHandler).pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), - any()); - if (modelsOK) { - Mockito.verify(mockVnfCatalogArtifactHandler).pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any()); - } - - if (modelsOK && catalogsOK) { - Mockito.verify(mockNotificationPublisher).publishDeploySuccess(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - Mockito.verify(mockModelArtifactHandler, Mockito.never()).rollback(any(), any(), any()); - Mockito.verify(mockVnfCatalogArtifactHandler, Mockito.never()).rollback(any(), any(), any()); - } else { - Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - if (modelsOK) { - Mockito.verify(mockModelArtifactHandler).rollback(eq(new ArrayList()), - eq(data.getDistributionID()), any()); - Mockito.verify(mockVnfCatalogArtifactHandler).rollback(eq(new ArrayList()), - eq(data.getDistributionID()), any()); - } else { - Mockito.verify(mockModelArtifactHandler).rollback(eq(new ArrayList()), - eq(data.getDistributionID()), any()); - Mockito.verify(mockVnfCatalogArtifactHandler, Mockito.never()).rollback(any(), any(), any()); - } - } - } - -/* - @Test - public void deploy_bothOK() throws IOException, BabelArtifactParsingException, InvalidArchiveException { - INotificationData data = getNotificationDataWithOneOfEach(); - ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); - byte[] xml = artifactTestUtils.loadResource("convertedYmls/AAI-SCP-Test-VSP-resource-1.0.xml"); - List toscaArtifacts = setupTest(xml, data); - List modelArtifacts = new BabelArtifactConverter().convertToModel(toscaArtifacts); - - List catalogFiles = new ArrayList<>(); - catalogFiles.add(new VnfCatalogArtifact("Some catalog content")); - - PowerMockito.when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any())).thenReturn(true); - PowerMockito.when( - mockModelArtifactHandler.pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), any())) - .thenReturn(true); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeploySuccess(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - - assertTrue("This should have returned true", - manager.deploy(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles)); - - Mockito.verify(mockVnfCatalogArtifactHandler).pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any()); - Mockito.verify(mockModelArtifactHandler).pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), - any()); - Mockito.verify(mockNotificationPublisher).publishDeploySuccess(mockDistributionClient, data, - data.getServiceArtifacts().get(0)); - Mockito.verify(mockModelArtifactHandler, Mockito.never()).rollback(any(), any(), any()); - Mockito.verify(mockVnfCatalogArtifactHandler, Mockito.never()).rollback(any(), any(), any()); - } -*/ -} diff --git a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerTest.java b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerTest.java index 9fc0760..0dcff32 100644 --- a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerTest.java +++ b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManagerTest.java @@ -23,6 +23,8 @@ package org.onap.aai.modelloader.notification; import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithCatalogFile; import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithOneOfEach; @@ -33,8 +35,8 @@ import java.util.Properties; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.mockito.internal.util.reflection.Whitebox; import org.onap.aai.babel.service.data.BabelArtifact; import org.onap.aai.modelloader.config.ModelLoaderConfig; import org.onap.aai.modelloader.entity.Artifact; @@ -45,15 +47,12 @@ import org.onap.aai.modelloader.entity.model.ModelArtifactHandler; import org.onap.aai.modelloader.extraction.InvalidArchiveException; import org.onap.aai.modelloader.util.ArtifactTestUtils; import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.notification.IArtifactInfo; import org.openecomp.sdc.api.notification.INotificationData; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.reflect.Whitebox; /** * Tests {@link ArtifactDeploymentManager } */ -@RunWith(PowerMockRunner.class) public class ArtifactDeploymentManagerTest { private static final String CONFIG_FILE = "model-loader.properties"; @@ -73,16 +72,16 @@ public class ArtifactDeploymentManagerTest { configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); ModelLoaderConfig config = new ModelLoaderConfig(configProperties, null); - mockDistributionClient = PowerMockito.mock(IDistributionClient.class); - mockModelArtifactHandler = PowerMockito.mock(ModelArtifactHandler.class); - mockNotificationPublisher = PowerMockito.mock(NotificationPublisher.class); - mockVnfCatalogArtifactHandler = PowerMockito.mock(VnfCatalogArtifactHandler.class); + mockDistributionClient = mock(IDistributionClient.class); + mockModelArtifactHandler = mock(ModelArtifactHandler.class); + mockNotificationPublisher = mock(NotificationPublisher.class); + mockVnfCatalogArtifactHandler = mock(VnfCatalogArtifactHandler.class); manager = new ArtifactDeploymentManager(mockDistributionClient, config); - Whitebox.setInternalState(manager, mockModelArtifactHandler); - Whitebox.setInternalState(manager, mockNotificationPublisher); - Whitebox.setInternalState(manager, mockVnfCatalogArtifactHandler); + Whitebox.setInternalState(manager, "modelArtifactHandler", mockModelArtifactHandler); + Whitebox.setInternalState(manager, "notificationPublisher", mockNotificationPublisher); + Whitebox.setInternalState(manager, "vnfCatalogArtifactHandler", mockVnfCatalogArtifactHandler); } @After @@ -98,7 +97,7 @@ public class ArtifactDeploymentManagerTest { private List setupTest(byte[] xml, INotificationData data) throws IOException { List toscaArtifacts = new ArrayList<>(); - org.openecomp.sdc.api.notification.IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0); + IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0); BabelArtifact xmlArtifact = new BabelArtifact(artifactInfo.getArtifactName(), BabelArtifact.ArtifactType.MODEL, new String(xml)); @@ -115,10 +114,10 @@ public class ArtifactDeploymentManagerTest { List catalogFiles = new ArrayList<>(); catalogFiles.add(new VnfCatalogArtifact("Some catalog content")); - PowerMockito.when(mockModelArtifactHandler.pushArtifacts(any(), any(), any(), any())).thenReturn(true); - PowerMockito.when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any())).thenReturn(false); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, + when(mockModelArtifactHandler.pushArtifacts(any(), any(), any(), any())).thenReturn(true); + when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), any(), any())) + .thenReturn(false); + Mockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, data.getServiceArtifacts().get(0)); assertFalse(SHOULD_HAVE_RETURNED_FALSE, @@ -136,7 +135,6 @@ public class ArtifactDeploymentManagerTest { data.getServiceArtifacts().get(0)); } - private void doFailedCombinedTests(boolean modelsOK, boolean catalogsOK) throws IOException, BabelArtifactParsingException, InvalidArchiveException { INotificationData data = getNotificationDataWithOneOfEach(); @@ -148,15 +146,14 @@ public class ArtifactDeploymentManagerTest { List catalogFiles = new ArrayList<>(); catalogFiles.add(new VnfCatalogArtifact("Some catalog content")); - PowerMockito.when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), - any(), any())).thenReturn(catalogsOK); - PowerMockito.when( - mockModelArtifactHandler.pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), any())) + when(mockVnfCatalogArtifactHandler.pushArtifacts(eq(catalogFiles), eq(data.getDistributionID()), any(), any())) + .thenReturn(catalogsOK); + when(mockModelArtifactHandler.pushArtifacts(eq(modelArtifacts), eq(data.getDistributionID()), any(), any())) .thenReturn(modelsOK); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeploySuccess(mockDistributionClient, data, + Mockito.doNothing().when(mockNotificationPublisher).publishDeploySuccess(mockDistributionClient, data, data.getServiceArtifacts().get(0)); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, + Mockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, data.getServiceArtifacts().get(0)); assertFalse(SHOULD_HAVE_RETURNED_FALSE, diff --git a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerNoMockTest.java b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerNoMockTest.java deleted file mode 100644 index 01f41cf..0000000 --- a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerNoMockTest.java +++ /dev/null @@ -1,275 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.notification; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithInvalidType; -import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithModelQuerySpec; -import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithOneService; -import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Matchers; -import org.mockito.Mockito; -import org.onap.aai.babel.service.data.BabelArtifact; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; -import org.onap.aai.modelloader.restclient.BabelServiceClient; -import org.onap.aai.modelloader.restclient.BabelServiceClient.BabelServiceException; -import org.onap.aai.modelloader.util.ArtifactTestUtils; -import org.openecomp.sdc.api.IDistributionClient; -import org.openecomp.sdc.api.notification.IArtifactInfo; -import org.openecomp.sdc.api.notification.INotificationData; -import org.openecomp.sdc.api.results.IDistributionClientDownloadResult; -import org.openecomp.sdc.impl.DistributionClientDownloadResultImpl; -import org.openecomp.sdc.utils.DistributionActionResultEnum; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.reflect.Whitebox; - -/** - * No-Mock tests - * - * Because Jacoco (and other coverage tools) can't cope with mocked classes under some circumstances, coverage is/was - * falsely reported as < 50%. Hence these duplicated but non-mock tests to address this, for ONAP reasons. - * - * @author andrewdo - * - */ - -/** - * Tests {@link ArtifactDownloadManager} - */ -@PowerMockIgnore({"sun.security.ssl.*", "javax.net.ssl.*"}) -@PrepareForTest({ArtifactDownloadManager.class}) -public class ArtifactDownloadManagerNoMockTest { - - private static final String FALSE_SHOULD_HAVE_BEEN_RETURNED = "A value of 'false' should have been returned"; - private static final String OOPS = "oops"; - private static final String TRUE_SHOULD_HAVE_BEEN_RETURNED = "A value of 'true' should have been returned"; - - private ArtifactDownloadManager downloadManager; - private BabelServiceClient mockBabelClient; - private IDistributionClient mockDistributionClient; - private NotificationPublisher mockNotificationPublisher; - private BabelArtifactConverter mockBabelArtifactConverter; - - @Before - public void setup() throws Exception { - mockBabelClient = PowerMockito.mock(BabelServiceClient.class); - mockDistributionClient = PowerMockito.mock(IDistributionClient.class); - mockNotificationPublisher = PowerMockito.mock(NotificationPublisher.class); - mockBabelArtifactConverter = PowerMockito.mock(BabelArtifactConverter.class); - - Properties configProperties = new Properties(); - configProperties.load(this.getClass().getClassLoader().getResourceAsStream("model-loader.properties")); - downloadManager = - new ArtifactDownloadManager(mockDistributionClient, new ModelLoaderConfig(configProperties, ".")); - - PowerMockito.whenNew(BabelServiceClient.class).withAnyArguments().thenReturn(mockBabelClient); - - Whitebox.setInternalState(downloadManager, mockNotificationPublisher); - Whitebox.setInternalState(downloadManager, mockBabelArtifactConverter); - } - - @After - public void tearDown() { - downloadManager = null; - mockDistributionClient = null; - mockNotificationPublisher = null; - } - - @Test - public void downloadArtifacts_emptyListSupplied() { - List modelFiles = new ArrayList<>(); - List catalogFiles = new ArrayList<>(); - - assertTrue(TRUE_SHOULD_HAVE_BEEN_RETURNED, downloadManager - .downloadArtifacts(getNotificationDataWithOneService(), new ArrayList<>(), modelFiles, catalogFiles)); - - Mockito.verifyZeroInteractions(mockBabelClient, mockDistributionClient, mockNotificationPublisher, - mockBabelArtifactConverter); - } - - @Test - public void downloadArtifacts_artifactDownloadFails() { - INotificationData data = getNotificationDataWithOneService(); - IArtifactInfo artifact = data.getServiceArtifacts().get(0); - PowerMockito.when(mockDistributionClient.download(artifact)) - .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.FAIL, OOPS, null)); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadFailure(mockDistributionClient, data, - artifact, OOPS); - - assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, - downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, null)); - - Mockito.verify(mockDistributionClient).download(artifact); - Mockito.verify(mockNotificationPublisher).publishDownloadFailure(mockDistributionClient, data, artifact, OOPS); - - Mockito.verifyZeroInteractions(mockBabelClient, mockBabelArtifactConverter); - } - - private IDistributionClientDownloadResult createDistributionClientDownloadResult( - DistributionActionResultEnum status, String message, byte[] payload) { - IDistributionClientDownloadResult downloadResult = new DistributionClientDownloadResultImpl(status, message); - - ((DistributionClientDownloadResultImpl) downloadResult).setArtifactPayload(payload); - - return downloadResult; - } - - - /** - * Test disabled as exception handling needs to be reworked - * - * @throws IOException - */ - @SuppressWarnings("unchecked") - @Test - public void downloadArtifacts_invalidToscaCsarFile() throws IOException, BabelServiceException { - INotificationData data = getNotificationDataWithToscaCsarFile(); - IArtifactInfo artifact = data.getServiceArtifacts().get(0); - PowerMockito.when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( - DistributionActionResultEnum.SUCCESS, null, "This is not a valid Tosca CSAR File".getBytes())); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); - PowerMockito.when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), - Matchers.anyString())).thenThrow(BabelServiceException.class); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - artifact); - - assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, - downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, null)); - - Mockito.verify(mockDistributionClient).download(artifact); - Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); - - Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifact); - - Mockito.verifyZeroInteractions(mockBabelArtifactConverter); - - } - - @Test - public void downloadArtifacts_invalidModelQuerySpec() { - INotificationData data = getNotificationDataWithModelQuerySpec(); - IArtifactInfo artifact = data.getServiceArtifacts().get(0); - - List modelArtifacts = new ArrayList<>(); - - PowerMockito.when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( - DistributionActionResultEnum.SUCCESS, null, "This is not a valid Model Query Spec".getBytes())); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); - - assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, - downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, null)); - - Mockito.verify(mockDistributionClient).download(artifact); - Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); - Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifact); - - Mockito.verifyZeroInteractions(mockBabelClient, mockBabelArtifactConverter); - } - - - private void setupValidDownloadCsarMocks(INotificationData data, IArtifactInfo artifactInfo, - ArtifactTestUtils artifactTestUtils) throws IOException, BabelServiceException { - PowerMockito.when(mockDistributionClient.download(artifactInfo)) - .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.SUCCESS, null, - artifactTestUtils.loadResource("compressedArtifacts/service-VscpaasTest-csar.csar"))); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifactInfo); - PowerMockito.when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), - Matchers.anyString())).thenReturn(createBabelArtifacts()); - } - - private List createBabelArtifacts() { - List artifactList = new ArrayList<>(); - artifactList.add(new BabelArtifact("ModelArtifact", BabelArtifact.ArtifactType.MODEL, "Some model payload")); - artifactList.add(new BabelArtifact("VNFCArtifact", BabelArtifact.ArtifactType.VNFCATALOG, "Some VNFC payload")); - return artifactList; - } - - @Test - public void downloadArtifacts_validModelQuerySpec() - throws IOException, BabelServiceException, BabelArtifactParsingException { - ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); - INotificationData data = getNotificationDataWithModelQuerySpec(); - IArtifactInfo artifact = data.getServiceArtifacts().get(0); - setupValidModelQuerySpecMocks(artifactTestUtils, data, artifact); - - List modelFiles = new ArrayList<>(); - List catalogFiles = new ArrayList<>(); - assertTrue(TRUE_SHOULD_HAVE_BEEN_RETURNED, - downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelFiles, catalogFiles)); - - assertTrue("There should have been some model artifacts", !modelFiles.isEmpty()); - assertTrue("There should not have been any catalog artifacts", catalogFiles.isEmpty()); - - Mockito.verify(mockDistributionClient).download(artifact); - Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); - - Mockito.verifyZeroInteractions(mockBabelClient, mockBabelArtifactConverter); - } - - private void setupValidModelQuerySpecMocks(ArtifactTestUtils artifactTestUtils, INotificationData data, - IArtifactInfo artifact) throws IOException { - PowerMockito.when(mockDistributionClient.download(artifact)) - .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.SUCCESS, null, - artifactTestUtils.loadResource("models/named-query-wan-connector.xml"))); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); - } - - - - @Test - public void downloadArtifacts_invalidType() - throws IOException, BabelServiceException, BabelArtifactParsingException { - INotificationData data = getNotificationDataWithInvalidType(); - IArtifactInfo artifact = data.getServiceArtifacts().get(0); - - List catalogArtifacts = new ArrayList<>(); - - PowerMockito.when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( - DistributionActionResultEnum.SUCCESS, null, "This content does not matter.".getBytes())); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); - - assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, - downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, catalogArtifacts)); - - Mockito.verify(mockDistributionClient).download(artifact); - Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); - Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifact); - - Mockito.verifyZeroInteractions(mockBabelClient, mockBabelArtifactConverter); - } -} diff --git a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerTest.java b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerTest.java index c4ba991..71cd8af 100644 --- a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerTest.java +++ b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerTest.java @@ -22,26 +22,36 @@ package org.onap.aai.modelloader.notification; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithInvalidType; import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithModelQuerySpec; +import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithOneOfEach; import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithOneService; import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile; import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mockito; +import org.mockito.internal.util.reflection.Whitebox; import org.onap.aai.babel.service.data.BabelArtifact; import org.onap.aai.modelloader.config.ModelLoaderConfig; import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; import org.onap.aai.modelloader.restclient.BabelServiceClient; import org.onap.aai.modelloader.restclient.BabelServiceClient.BabelServiceException; +import org.onap.aai.modelloader.restclient.BabelServiceClientFactory; import org.onap.aai.modelloader.util.ArtifactTestUtils; import org.openecomp.sdc.api.IDistributionClient; import org.openecomp.sdc.api.notification.IArtifactInfo; @@ -49,18 +59,10 @@ import org.openecomp.sdc.api.notification.INotificationData; import org.openecomp.sdc.api.results.IDistributionClientDownloadResult; import org.openecomp.sdc.impl.DistributionClientDownloadResultImpl; import org.openecomp.sdc.utils.DistributionActionResultEnum; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.reflect.Whitebox; /** * Tests {@link ArtifactDownloadManager} */ -@RunWith(PowerMockRunner.class) -@PowerMockIgnore({"sun.security.ssl.*", "javax.net.ssl.*"}) -@PrepareForTest({ArtifactDownloadManager.class}) public class ArtifactDownloadManagerTest { private static final String FALSE_SHOULD_HAVE_BEEN_RETURNED = "A value of 'false' should have been returned"; @@ -72,23 +74,24 @@ public class ArtifactDownloadManagerTest { private IDistributionClient mockDistributionClient; private NotificationPublisher mockNotificationPublisher; private BabelArtifactConverter mockBabelArtifactConverter; + private BabelServiceClientFactory mockClientFactory; @Before public void setup() throws Exception { - mockBabelClient = PowerMockito.mock(BabelServiceClient.class); - mockDistributionClient = PowerMockito.mock(IDistributionClient.class); - mockNotificationPublisher = PowerMockito.mock(NotificationPublisher.class); - mockBabelArtifactConverter = PowerMockito.mock(BabelArtifactConverter.class); + mockBabelClient = mock(BabelServiceClient.class); + mockDistributionClient = mock(IDistributionClient.class); + mockNotificationPublisher = mock(NotificationPublisher.class); + mockBabelArtifactConverter = mock(BabelArtifactConverter.class); + mockClientFactory = mock(BabelServiceClientFactory.class); + when(mockClientFactory.create(Mockito.any())).thenReturn(mockBabelClient); Properties configProperties = new Properties(); configProperties.load(this.getClass().getClassLoader().getResourceAsStream("model-loader.properties")); - downloadManager = - new ArtifactDownloadManager(mockDistributionClient, new ModelLoaderConfig(configProperties, ".")); + downloadManager = new ArtifactDownloadManager(mockDistributionClient, + new ModelLoaderConfig(configProperties, "."), mockClientFactory); - PowerMockito.whenNew(BabelServiceClient.class).withAnyArguments().thenReturn(mockBabelClient); - - Whitebox.setInternalState(downloadManager, mockNotificationPublisher); - Whitebox.setInternalState(downloadManager, mockBabelArtifactConverter); + Whitebox.setInternalState(downloadManager, "notificationPublisher", mockNotificationPublisher); + Whitebox.setInternalState(downloadManager, "babelArtifactConverter", mockBabelArtifactConverter); } @After @@ -114,10 +117,10 @@ public class ArtifactDownloadManagerTest { public void downloadArtifacts_artifactDownloadFails() { INotificationData data = getNotificationDataWithOneService(); IArtifactInfo artifact = data.getServiceArtifacts().get(0); - PowerMockito.when(mockDistributionClient.download(artifact)) + when(mockDistributionClient.download(artifact)) .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.FAIL, OOPS, null)); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadFailure(mockDistributionClient, data, - artifact, OOPS); + doNothing().when(mockNotificationPublisher).publishDownloadFailure(mockDistributionClient, data, artifact, + OOPS); assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, null)); @@ -137,15 +140,19 @@ public class ArtifactDownloadManagerTest { return downloadResult; } + @Test + public void downloadArtifacts_noSuchAlgorithmExceptionFromCreatingBabelClient() throws Exception { + doCreateBabelClientFailureTest(NoSuchAlgorithmException.class); + } + @SuppressWarnings("unchecked") private void doCreateBabelClientFailureTest(Class exception) throws Exception { - PowerMockito.whenNew(BabelServiceClient.class).withAnyArguments().thenThrow(exception); + when(mockClientFactory.create(Mockito.any())).thenThrow(exception); INotificationData data = getNotificationDataWithToscaCsarFile(); IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0); setupValidDownloadCsarMocks(data, artifactInfo, new ArtifactTestUtils()); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - artifactInfo); + doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifactInfo); assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, null)); @@ -157,9 +164,34 @@ public class ArtifactDownloadManagerTest { Mockito.verifyZeroInteractions(mockBabelArtifactConverter); } + @Test + public void downloadArtifacts_keyStoreExceptionFromCreatingBabelClient() throws Exception { + doCreateBabelClientFailureTest(KeyStoreException.class); + } + + @Test + public void downloadArtifacts_certificateExceptionFromCreatingBabelClient() throws Exception { + doCreateBabelClientFailureTest(CertificateException.class); + } + + @Test + public void downloadArtifacts_iOExceptionFromCreatingBabelClient() throws Exception { + doCreateBabelClientFailureTest(IOException.class); + } + + @Test + public void downloadArtifacts_unrecoverableKeyExceptionFromCreatingBabelClient() throws Exception { + doCreateBabelClientFailureTest(UnrecoverableKeyException.class); + } + + @Test + public void downloadArtifacts_keyManagementExceptionFromCreatingBabelClient() throws Exception { + doCreateBabelClientFailureTest(KeyManagementException.class); + } + /** * Test disabled as exception handling needs to be reworked - * + * * @throws IOException */ @SuppressWarnings("unchecked") @@ -167,14 +199,12 @@ public class ArtifactDownloadManagerTest { public void downloadArtifacts_invalidToscaCsarFile() throws IOException, BabelServiceException { INotificationData data = getNotificationDataWithToscaCsarFile(); IArtifactInfo artifact = data.getServiceArtifacts().get(0); - PowerMockito.when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( + when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( DistributionActionResultEnum.SUCCESS, null, "This is not a valid Tosca CSAR File".getBytes())); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); - PowerMockito.when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), + doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); + when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString())).thenThrow(BabelServiceException.class); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, - artifact); + doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifact); assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, null)); @@ -196,10 +226,9 @@ public class ArtifactDownloadManagerTest { List modelArtifacts = new ArrayList<>(); - PowerMockito.when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( + when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( DistributionActionResultEnum.SUCCESS, null, "This is not a valid Model Query Spec".getBytes())); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); + doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, null)); @@ -211,14 +240,35 @@ public class ArtifactDownloadManagerTest { Mockito.verifyZeroInteractions(mockBabelClient, mockBabelArtifactConverter); } + @Test + public void downloadArtifacts_validToscaCsarFile() + throws IOException, BabelServiceException, BabelArtifactParsingException { + INotificationData data = getNotificationDataWithToscaCsarFile(); + IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0); + + setupValidDownloadCsarMocks(data, artifactInfo, new ArtifactTestUtils()); + + List modelArtifacts = new ArrayList<>(); + List catalogFiles = new ArrayList<>(); + assertTrue(TRUE_SHOULD_HAVE_BEEN_RETURNED, + downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles)); + + assertTrue("There should not have been any catalog files", catalogFiles.size() == 0); + + Mockito.verify(mockDistributionClient).download(artifactInfo); + Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifactInfo); + Mockito.verify(mockBabelClient).postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), + Matchers.anyString()); + Mockito.verify(mockBabelArtifactConverter).convertToModel(Matchers.any()); + Mockito.verify(mockBabelArtifactConverter).convertToCatalog(Matchers.any()); + } + private void setupValidDownloadCsarMocks(INotificationData data, IArtifactInfo artifactInfo, ArtifactTestUtils artifactTestUtils) throws IOException, BabelServiceException { - PowerMockito.when(mockDistributionClient.download(artifactInfo)) + when(mockDistributionClient.download(artifactInfo)) .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.SUCCESS, null, artifactTestUtils.loadResource("compressedArtifacts/service-VscpaasTest-csar.csar"))); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifactInfo); - PowerMockito.when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), + when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString())).thenReturn(createBabelArtifacts()); } @@ -253,14 +303,76 @@ public class ArtifactDownloadManagerTest { private void setupValidModelQuerySpecMocks(ArtifactTestUtils artifactTestUtils, INotificationData data, IArtifactInfo artifact) throws IOException { - PowerMockito.when(mockDistributionClient.download(artifact)) + when(mockDistributionClient.download(artifact)) .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.SUCCESS, null, artifactTestUtils.loadResource("models/named-query-wan-connector.xml"))); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); + doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); } + @Test + public void downloadArtifacts_validCsarAndModelFiles() + throws IOException, BabelServiceException, BabelArtifactParsingException { + ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); + INotificationData data = getNotificationDataWithOneOfEach(); + List artifacts = new ArrayList<>(); + + IArtifactInfo serviceArtifact = data.getServiceArtifacts().get(0); + IArtifactInfo modelSpecArtifact = data.getResources().get(1).getArtifacts().get(0); + + artifacts.add(serviceArtifact); + artifacts.add(modelSpecArtifact); + + setupValidDownloadCsarMocks(data, serviceArtifact, artifactTestUtils); + setupValidModelQuerySpecMocks(artifactTestUtils, data, modelSpecArtifact); + + List modelFiles = new ArrayList<>(); + List catalogFiles = new ArrayList<>(); + assertTrue(TRUE_SHOULD_HAVE_BEEN_RETURNED, + downloadManager.downloadArtifacts(data, artifacts, modelFiles, catalogFiles)); + + Mockito.verify(mockDistributionClient).download(serviceArtifact); + Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, serviceArtifact); + Mockito.verify(mockBabelClient).postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), + Matchers.anyString()); + Mockito.verify(mockBabelArtifactConverter).convertToModel(Matchers.any()); + Mockito.verify(mockBabelArtifactConverter).convertToCatalog(Matchers.any()); + + Mockito.verify(mockDistributionClient).download(modelSpecArtifact); + Mockito.verify(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, + modelSpecArtifact); + + Mockito.verifyNoMoreInteractions(mockBabelClient, mockBabelArtifactConverter); + } + + @Test + @SuppressWarnings("unchecked") + public void activateCallback_toscaToModelConverterHasProcessToscaArtifactsException() throws Exception { + ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); + INotificationData data = getNotificationDataWithToscaCsarFile(); + IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0); + + when(mockDistributionClient.download(artifactInfo)) + .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.SUCCESS, null, + artifactTestUtils.loadResource("compressedArtifacts/service-VscpaasTest-csar.csar"))); + when(mockBabelArtifactConverter.convertToModel(Mockito.anyList())) + .thenThrow(BabelArtifactParsingException.class); + doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifactInfo); + when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), + Matchers.anyString())).thenReturn(createBabelArtifacts()); + + List modelArtifacts = new ArrayList<>(); + List catalogFiles = new ArrayList<>(); + assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, + downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles)); + assertTrue("There should not have been any catalog files", catalogFiles.size() == 0); + + Mockito.verify(mockDistributionClient).download(artifactInfo); + Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifactInfo); + Mockito.verify(mockBabelClient).postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(), + Matchers.anyString()); + Mockito.verify(mockBabelArtifactConverter).convertToModel(Matchers.any()); + } @Test public void downloadArtifacts_invalidType() @@ -270,10 +382,9 @@ public class ArtifactDownloadManagerTest { List catalogArtifacts = new ArrayList<>(); - PowerMockito.when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( + when(mockDistributionClient.download(artifact)).thenReturn(createDistributionClientDownloadResult( DistributionActionResultEnum.SUCCESS, null, "This content does not matter.".getBytes())); - PowerMockito.doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, - artifact); + doNothing().when(mockNotificationPublisher).publishDownloadSuccess(mockDistributionClient, data, artifact); assertFalse(FALSE_SHOULD_HAVE_BEEN_RETURNED, downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), null, catalogArtifacts)); diff --git a/src/test/java/org/onap/aai/modelloader/notification/BabelArtifactConverterTest.java b/src/test/java/org/onap/aai/modelloader/notification/BabelArtifactConverterTest.java index 026c1e3..533a37b 100644 --- a/src/test/java/org/onap/aai/modelloader/notification/BabelArtifactConverterTest.java +++ b/src/test/java/org/onap/aai/modelloader/notification/BabelArtifactConverterTest.java @@ -20,6 +20,7 @@ */ package org.onap.aai.modelloader.notification; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -27,12 +28,13 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.junit.Test; -import org.mockito.Mockito; import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.entity.ArtifactType; import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; import org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder; +import org.onap.aai.modelloader.util.ArtifactTestUtils; import org.openecomp.sdc.api.notification.INotificationData; -import org.powermock.api.mockito.PowerMockito; /** * Tests {@link BabelArtifactConverter} @@ -49,7 +51,6 @@ public class BabelArtifactConverterTest { public void convert_emptyToscaFiles() throws BabelArtifactParsingException { assertTrue("Nothing should have been returned", new BabelArtifactConverter().convertToModel(new ArrayList<>()).isEmpty()); - PowerMockito.verifyStatic(Mockito.times(1)); } @Test(expected = BabelArtifactParsingException.class) diff --git a/src/test/java/org/onap/aai/modelloader/notification/EventCallbackNoMockTest.java b/src/test/java/org/onap/aai/modelloader/notification/EventCallbackNoMockTest.java deleted file mode 100644 index 19110bf..0000000 --- a/src/test/java/org/onap/aai/modelloader/notification/EventCallbackNoMockTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.notification; - -import java.io.IOException; -import java.util.List; -import java.util.Properties; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; -import org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder; -import org.openecomp.sdc.api.IDistributionClient; -import org.openecomp.sdc.api.notification.INotificationData; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.reflect.Whitebox; - -/** - * No-Mock tests - * - * Because Jacoco (and other coverage tools) can't cope with mocked classes under some circumstances, coverage is/was - * falsely reported as < 50%. Hence these duplicated but non-mock tests to address this, for ONAP reasons. - * - * @author andrewdo - * - */ - -/** - * Tests {@link EventCallback} - */ - -public class EventCallbackNoMockTest { - - private static final String CONFIG_FILE = "model-loader.properties"; - - private ModelLoaderConfig config; - private Properties configProperties; - private EventCallback eventCallback; - - private ArtifactDeploymentManager mockArtifactDeploymentManager; - private ArtifactDownloadManager mockArtifactDownloadManager; - private IDistributionClient mockDistributionClient; - - @Before - public void setup() throws IOException { - configProperties = new Properties(); - configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); - config = new ModelLoaderConfig(configProperties, null); - - mockArtifactDeploymentManager = PowerMockito.mock(ArtifactDeploymentManager.class); - mockArtifactDownloadManager = PowerMockito.mock(ArtifactDownloadManager.class); - mockDistributionClient = PowerMockito.mock(IDistributionClient.class); - - eventCallback = new EventCallback(mockDistributionClient, config); - - Whitebox.setInternalState(eventCallback, mockArtifactDeploymentManager); - Whitebox.setInternalState(eventCallback, mockArtifactDownloadManager); - } - - @After - public void tearDown() { - config = null; - configProperties = null; - eventCallback = null; - mockArtifactDeploymentManager = null; - mockArtifactDownloadManager = null; - mockDistributionClient = null; - } - - @Test - @SuppressWarnings("unchecked") - public void activateCallback_downloadFails() { - INotificationData data = NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile(); - - PowerMockito.when(mockArtifactDownloadManager.downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class))).thenReturn(false); - - eventCallback.activateCallback(data); - - Mockito.verify(mockArtifactDownloadManager).downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class)); - Mockito.verifyZeroInteractions(mockArtifactDeploymentManager); - } - - @SuppressWarnings("unchecked") - @Test - public void activateCallback() throws BabelArtifactParsingException { - INotificationData data = NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile(); - - PowerMockito.when(mockArtifactDownloadManager.downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class))).thenReturn(true); - - PowerMockito.when(mockArtifactDeploymentManager.deploy(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class))).thenReturn(true); - - eventCallback.activateCallback(data); - - Mockito.verify(mockArtifactDownloadManager).downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class)); - Mockito.verify(mockArtifactDeploymentManager).deploy(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class)); - } -} diff --git a/src/test/java/org/onap/aai/modelloader/notification/EventCallbackTest.java b/src/test/java/org/onap/aai/modelloader/notification/EventCallbackTest.java index 0cc183d..bc88c85 100644 --- a/src/test/java/org/onap/aai/modelloader/notification/EventCallbackTest.java +++ b/src/test/java/org/onap/aai/modelloader/notification/EventCallbackTest.java @@ -20,27 +20,28 @@ */ package org.onap.aai.modelloader.notification; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.util.List; import java.util.Properties; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.mockito.internal.util.reflection.Whitebox; import org.onap.aai.modelloader.config.ModelLoaderConfig; import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; import org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder; import org.openecomp.sdc.api.IDistributionClient; import org.openecomp.sdc.api.notification.INotificationData; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.reflect.Whitebox; /** * Tests {@link EventCallback} */ -@RunWith(PowerMockRunner.class) public class EventCallbackTest { private static final String CONFIG_FILE = "model-loader.properties"; @@ -59,14 +60,14 @@ public class EventCallbackTest { configProperties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)); config = new ModelLoaderConfig(configProperties, null); - mockArtifactDeploymentManager = PowerMockito.mock(ArtifactDeploymentManager.class); - mockArtifactDownloadManager = PowerMockito.mock(ArtifactDownloadManager.class); - mockDistributionClient = PowerMockito.mock(IDistributionClient.class); + mockArtifactDeploymentManager = mock(ArtifactDeploymentManager.class); + mockArtifactDownloadManager = mock(ArtifactDownloadManager.class); + mockDistributionClient = mock(IDistributionClient.class); eventCallback = new EventCallback(mockDistributionClient, config); - Whitebox.setInternalState(eventCallback, mockArtifactDeploymentManager); - Whitebox.setInternalState(eventCallback, mockArtifactDownloadManager); + Whitebox.setInternalState(eventCallback, "artifactDeploymentManager", mockArtifactDeploymentManager); + Whitebox.setInternalState(eventCallback, "artifactDownloadManager", mockArtifactDownloadManager); } @After @@ -84,14 +85,13 @@ public class EventCallbackTest { public void activateCallback_downloadFails() { INotificationData data = NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile(); - PowerMockito.when(mockArtifactDownloadManager.downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class))) - .thenReturn(false); + when(mockArtifactDownloadManager.downloadArtifacts(any(INotificationData.class), any(List.class), + any(List.class), any(List.class))).thenReturn(false); eventCallback.activateCallback(data); - Mockito.verify(mockArtifactDownloadManager).downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class)); + verify(mockArtifactDownloadManager).downloadArtifacts(any(INotificationData.class), any(List.class), + any(List.class), any(List.class)); Mockito.verifyZeroInteractions(mockArtifactDeploymentManager); } @@ -100,20 +100,17 @@ public class EventCallbackTest { public void activateCallback() throws BabelArtifactParsingException { INotificationData data = NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile(); - PowerMockito.when(mockArtifactDownloadManager.downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class))) - .thenReturn(true); + when(mockArtifactDownloadManager.downloadArtifacts(any(INotificationData.class), any(List.class), + any(List.class), any(List.class))).thenReturn(true); - PowerMockito - .when(mockArtifactDeploymentManager.deploy(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class))) - .thenReturn(true); + when(mockArtifactDeploymentManager.deploy(any(INotificationData.class), any(List.class), any(List.class), + any(List.class))).thenReturn(true); eventCallback.activateCallback(data); - Mockito.verify(mockArtifactDownloadManager).downloadArtifacts(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class)); - Mockito.verify(mockArtifactDeploymentManager).deploy(Mockito.any(INotificationData.class), - Mockito.any(List.class), Mockito.any(List.class), Mockito.any(List.class)); + verify(mockArtifactDownloadManager).downloadArtifacts(any(INotificationData.class), any(List.class), + any(List.class), any(List.class)); + verify(mockArtifactDeploymentManager).deploy(any(INotificationData.class), any(List.class), any(List.class), + any(List.class)); } } diff --git a/src/test/java/org/onap/aai/modelloader/restclient/TestAaiRestClient.java b/src/test/java/org/onap/aai/modelloader/restclient/TestAaiRestClient.java deleted file mode 100644 index d3dab2e..0000000 --- a/src/test/java/org/onap/aai/modelloader/restclient/TestAaiRestClient.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - */ -package org.onap.aai.modelloader.restclient; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Properties; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import org.junit.Ignore; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.model.ModelArtifact; -import org.onap.aai.modelloader.entity.model.ModelArtifactParser; -import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.modelloader.entity.ArtifactType; -import org.onap.aai.restclient.client.OperationResult; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class TestAaiRestClient { - - // This test requires a running A&AI system. To test locally, annotate with org.junit.Test - @Ignore - public void testRestClient() throws Exception { - final String MODEL_FILE = "src/test/resources/models/l3-network-widget.xml"; - - Properties props = new Properties(); - props.setProperty("ml.distribution.ARTIFACT_TYPES", "MODEL_INVENTORY_PROFILE,MODEL_QUERY_SPEC,VNF_CATALOG"); - props.setProperty("ml.aai.BASE_URL", "https://localhost:8443"); - props.setProperty("ml.aai.MODEL_URL", "/aai/v9/service-design-and-creation/models/model/"); - props.setProperty("ml.aai.KEYSTORE_FILE", "aai-client-cert.p12"); - props.setProperty("ml.aai.KEYSTORE_PASSWORD", "OBF:1i9a1u2a1unz1lr61wn51wn11lss1unz1u301i6o"); - - ModelLoaderConfig config = new ModelLoaderConfig(props, "."); - - File xmlFile = new File(MODEL_FILE); - DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); - dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); - Document doc = dBuilder.parse(xmlFile); - - NodeList nodesList = doc.getDocumentElement().getChildNodes(); - - // Get the model IDs - - // @formatter:off - String modelInvariantId = - getNodesStream(nodesList) - .filter(childNode -> childNode.getNodeName().equals(ModelArtifactParser.MODEL_INVARIANT_ID)) - .findFirst() - .map(Node::getTextContent) - .orElse(null); - - String modelId = getNodesStream(nodesList) - .flatMap(n -> getNodesStream(n.getChildNodes())) - .filter(childNode -> childNode.getNodeName().equals(ModelArtifactParser.MODEL_VER)) - .findFirst() - .map(n -> n.getChildNodes().item(1).getTextContent()) - .orElse(null); - // @formatter:on - - try { - // Build the model artifact - ModelArtifact model = new ModelArtifact(); - model.setModelInvariantId(modelInvariantId); - model.setModelVerId(modelId); - model.setPayload(readFile(MODEL_FILE)); - model.setModelNamespace("http://org.openecomp.aai.inventory/v9"); - - AaiRestClient aaiClient = new AaiRestClient(config); - - // GET model - OperationResult opResult = - aaiClient.getResource(getURL(model, config), "example-trans-id-0", MediaType.APPLICATION_XML_TYPE); - assertTrue(opResult.getResultCode() == Response.Status.NOT_FOUND.getStatusCode()); - - // PUT the model - opResult = aaiClient.putResource(getURL(model, config), model.getPayload(), "example-trans-id-1", - MediaType.APPLICATION_XML_TYPE); - assertTrue(opResult.getResultCode() == Response.Status.CREATED.getStatusCode()); - - // DELETE the model - opResult = aaiClient.getAndDeleteResource(getURL(model, config), "example-trans-id-3"); - assertTrue(opResult.getResultCode() == Response.Status.NO_CONTENT.getStatusCode()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private Stream getNodesStream(NodeList nodeList) { - return IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item); - } - - static String readFile(String path) throws IOException { - byte[] encoded = Files.readAllBytes(Paths.get(path)); - return new String(encoded); - } - - private String getURL(ModelArtifact model, ModelLoaderConfig config) { - String baseURL = config.getAaiBaseUrl().trim(); - String subURL = null; - if (model.getType().equals(ArtifactType.MODEL)) { - subURL = config.getAaiModelUrl(model.getModelNamespaceVersion()).trim(); - } else { - subURL = config.getAaiNamedQueryUrl(model.getModelNamespaceVersion()).trim(); - } - - if ((!baseURL.endsWith("/")) && (!subURL.startsWith("/"))) { - baseURL = baseURL + "/"; - } - - if (baseURL.endsWith("/") && subURL.startsWith("/")) { - baseURL = baseURL.substring(0, baseURL.length() - 1); - } - - if (!subURL.endsWith("/")) { - subURL = subURL + "/"; - } - - return baseURL + subURL + model.getModelInvariantId(); - } -} diff --git a/src/test/resources/compressedArtifacts/service-VscpaasTest-csar.csar b/src/test/resources/compressedArtifacts/service-VscpaasTest-csar.csar new file mode 100644 index 0000000000000000000000000000000000000000..d7f505e94c9c969ea31a9f36130b7966f550a6c4 GIT binary patch literal 30511 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 n-ia(h0f7GnRd46J literal 0 HcmV?d00001 -- 2.16.6