From 17e8b54e83547d8dc37c335c5df1b989f8b5ff3c Mon Sep 17 00:00:00 2001 From: Wojciech Sliwka Date: Mon, 20 Aug 2018 15:45:03 +0200 Subject: Replace sdc client Replace old SDC client to use genericRestClient Change-Id: I9b3b567871ac3f319742fca9457e42b6d4db0a8a Issue-ID: VID-268 Signed-off-by: Wojciech Sliwka --- .../main/java/org/onap/vid/asdc/AsdcClient.java | 5 +- .../org/onap/vid/asdc/rest/RestfulAsdcClient.java | 242 --------------------- .../java/org/onap/vid/asdc/rest/SdcRestClient.java | 123 +++++++++++ .../onap/vid/client/SyncRestClientInterface.java | 12 +- .../java/org/onap/vid/controllers/WebConfig.java | 72 +++--- .../onap/vid/asdc/rest/RestfulAsdcClientTest.java | 69 ------ .../onap/vid/asdc/rest/SdcRestClientITTest.java | 154 +++++++++++++ .../org/onap/vid/asdc/rest/SdcRestClientTest.java | 137 ++++++++++++ .../onap/vid/mso/rest/OutgoingRequestIdTest.java | 35 +-- .../org/onap/vid/testUtils/StubServerUtil.java | 20 +- .../test/resources/WEB-INF/conf/system.properties | 4 +- 11 files changed, 491 insertions(+), 382 deletions(-) delete mode 100644 vid-app-common/src/main/java/org/onap/vid/asdc/rest/RestfulAsdcClient.java create mode 100644 vid-app-common/src/main/java/org/onap/vid/asdc/rest/SdcRestClient.java delete mode 100644 vid-app-common/src/test/java/org/onap/vid/asdc/rest/RestfulAsdcClientTest.java create mode 100644 vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientITTest.java create mode 100644 vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientTest.java diff --git a/vid-app-common/src/main/java/org/onap/vid/asdc/AsdcClient.java b/vid-app-common/src/main/java/org/onap/vid/asdc/AsdcClient.java index 4e0254cd..fdbf2c28 100644 --- a/vid-app-common/src/main/java/org/onap/vid/asdc/AsdcClient.java +++ b/vid-app-common/src/main/java/org/onap/vid/asdc/AsdcClient.java @@ -29,7 +29,10 @@ import java.util.UUID; * The Interface AsdcClient. */ public interface AsdcClient { - + class URIS{ + public static final String METADATA_URL_TEMPLATE = "%s%s/%s/metadata"; + public static final String TOSCA_MODEL_URL_TEMPLATE = "%s%s/%s/toscaModel"; + } /** * Gets the service. * diff --git a/vid-app-common/src/main/java/org/onap/vid/asdc/rest/RestfulAsdcClient.java b/vid-app-common/src/main/java/org/onap/vid/asdc/rest/RestfulAsdcClient.java deleted file mode 100644 index 5dd0f4cc..00000000 --- a/vid-app-common/src/main/java/org/onap/vid/asdc/rest/RestfulAsdcClient.java +++ /dev/null @@ -1,242 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * VID - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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.vid.asdc.rest; - -import com.att.eelf.configuration.EELFLogger; -import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; -import org.onap.portalsdk.core.util.SystemProperties; -import org.onap.vid.asdc.AsdcCatalogException; -import org.onap.vid.asdc.AsdcClient; -import org.onap.vid.asdc.beans.Service; -import org.onap.vid.model.ModelConstants; -import org.onap.vid.properties.VidProperties; -import org.onap.vid.utils.Logging; -import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate; -import org.springframework.http.HttpMethod; - -import javax.ws.rs.ProcessingException; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ResponseProcessingException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.Response; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Collections; -import java.util.UUID; - -import static org.onap.vid.utils.Logging.REQUEST_ID_HEADER_KEY; -/** - * The Class RestfulAsdcClient. - */ -@SuppressWarnings("Duplicates") -public class RestfulAsdcClient implements AsdcClient { - - - /** - * The Class Builder. - */ - public static class Builder { - - /** - * The client. - */ - private final Client client; - - /** - * The uri. - */ - private final URI uri; - - /** - * The auth. - */ - private String auth = null; - - /** - * Instantiates a new builder. - * - * @param client the client - * @param uri the uri - */ - public Builder(Client client, URI uri) { - this.client = client; - this.client.register(JacksonJsonProvider.class); - this.uri = uri; - } - - /** - * Auth. - * - * @param auth the auth - * @return the builder - */ - public Builder auth(String auth) { - this.auth = auth; - return this; - } - - /** - * Builds the. - * - * @return the restful asdc client - */ - public RestfulAsdcClient build() { - return new RestfulAsdcClient(this); - } - } - - /** - * The Constant LOG. - */ - static final EELFLoggerDelegate LOG = EELFLoggerDelegate.getLogger(RestfulAsdcClient.class); - - final private static EELFLogger outgoingRequestsLogger = Logging.getRequestsLogger("asdc"); - - /** - * The client. - */ - private final Client client; - - /** - * The uri. - */ - private final URI uri; - - /** - * The common headers. - */ - private final MultivaluedHashMap commonHeaders; - - /** - * The auth. - */ - private final String auth; - - /** - * Instantiates a new restful asdc client. - * - * @param builder the builder - */ - RestfulAsdcClient(Builder builder) { - client = builder.client; - uri = builder.uri; - auth = builder.auth; - - commonHeaders = new MultivaluedHashMap(); - commonHeaders.put("X-ECOMP-InstanceID", Collections.singletonList((Object) (SystemProperties.getProperty(SystemProperties.APP_DISPLAY_NAME)))); - commonHeaders.put("Authorization", Collections.singletonList((Object) (auth))); - } - - private Path createTmpFile(InputStream csarInputStream) throws AsdcCatalogException { - final Path csarFile; - try { - csarFile = Files.createTempFile("csar", ".zip"); - Files.copy(csarInputStream, csarFile, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw new AsdcCatalogException("Caught IOException while creating CSAR", e); - } - return csarFile; - } - - /** - * Gets the client. - * - * @return the client - */ - private Client getClient() { - return client; - } - - /* (non-Javadoc) - * @see org.onap.vid.asdc.AsdcClient#getService(java.util.UUID) - */ - public Service getService(UUID uuid) throws AsdcCatalogException { - - String path = VidProperties.getPropertyWithDefault( - ModelConstants.ASDC_SVC_API_PATH, - ModelConstants.DEFAULT_ASDC_SVC_API_PATH); - - String url = uri+path + "/" + uuid.toString() + "/metadata"; - Logging.logRequest(outgoingRequestsLogger, HttpMethod.GET, url); - try { - Response response = getClient() - .target(uri) - .path(path + "/" + uuid.toString() + "/metadata") - .request(MediaType.APPLICATION_JSON) - .headers(commonHeaders) - .header(REQUEST_ID_HEADER_KEY, Logging.extractOrGenerateRequestId()) - .get(); - Logging.logResponse(outgoingRequestsLogger, HttpMethod.GET, url, response); - return response.readEntity(Service.class); - } catch (ResponseProcessingException e) { - //Couldn't convert response to Java type - throw new AsdcCatalogException("SDC response could not be processed", e); - } catch (ProcessingException e) { - //IO problems during request - throw new AsdcCatalogException("Failed to get a response from SDC service", e); - } catch (WebApplicationException e) { - //Web service returned data, but the response status wasn't a good one (i.e. non 2xx) - throw new AsdcCatalogException(e); - } - } - - - /* (non-Javadoc) - * @see org.onap.vid.asdc.AsdcClient#getServiceToscaModel(java.util.UUID) - */ - public Path getServiceToscaModel(UUID serviceUuid) throws AsdcCatalogException { - String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, - ModelConstants.DEFAULT_ASDC_SVC_API_PATH); - - String url = uri+path + "/" + serviceUuid + "/toscaModel"; - Logging.logRequest(outgoingRequestsLogger, HttpMethod.GET, url); - try { - final InputStream csarInputStream = getClient() - .target(uri) - .path(path + "/" + serviceUuid + "/toscaModel") - .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) - .headers(commonHeaders) - .header("Content-Type", MediaType.APPLICATION_OCTET_STREAM) - .header(REQUEST_ID_HEADER_KEY, Logging.extractOrGenerateRequestId()) - .get(InputStream.class); - Path toscaFilePath = createTmpFile(csarInputStream); - outgoingRequestsLogger.debug("Received {} {} . Tosca file was saved at: {}", HttpMethod.GET.name(), url, toscaFilePath.toAbsolutePath()); - return toscaFilePath; - } catch (ResponseProcessingException e) { - //Couldn't convert response to Java type - throw new AsdcCatalogException("SDC response could not be processed", e); - } catch (ProcessingException e) { - //IO problems during request - throw new AsdcCatalogException("Failed to get a response from SDC service. Cause: "+e.getMessage(), e); - } catch (WebApplicationException e) { - //Web service returned data, but the response status wasn't a good one (i.e. non 2xx) - throw new AsdcCatalogException(e); - } - } - -} - diff --git a/vid-app-common/src/main/java/org/onap/vid/asdc/rest/SdcRestClient.java b/vid-app-common/src/main/java/org/onap/vid/asdc/rest/SdcRestClient.java new file mode 100644 index 00000000..b4096f9b --- /dev/null +++ b/vid-app-common/src/main/java/org/onap/vid/asdc/rest/SdcRestClient.java @@ -0,0 +1,123 @@ +/*- + * ============LICENSE_START======================================================= + * VID + * ================================================================================ + * Copyright (C) 2018 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * 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.vid.asdc.rest; + +import com.att.eelf.configuration.EELFLogger; +import com.google.common.collect.ImmutableMap; +import io.vavr.control.Try; +import org.onap.portalsdk.core.util.SystemProperties; +import org.onap.vid.asdc.AsdcCatalogException; +import org.onap.vid.asdc.AsdcClient; +import org.onap.vid.asdc.beans.Service; +import org.onap.vid.client.SyncRestClientInterface; +import org.onap.vid.model.ModelConstants; +import org.onap.vid.properties.VidProperties; +import org.onap.vid.utils.Logging; +import org.springframework.http.HttpMethod; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; +import static org.onap.portalsdk.core.util.SystemProperties.APP_DISPLAY_NAME; +import static org.onap.vid.asdc.AsdcClient.URIS.METADATA_URL_TEMPLATE; +import static org.onap.vid.asdc.AsdcClient.URIS.TOSCA_MODEL_URL_TEMPLATE; +import static org.onap.vid.client.SyncRestClientInterface.HEADERS.AUTHORIZATION; +import static org.onap.vid.client.SyncRestClientInterface.HEADERS.CONTENT_TYPE; +import static org.onap.vid.client.SyncRestClientInterface.HEADERS.X_ECOMP_INSTANCE_ID; +import static org.onap.vid.utils.Logging.REQUEST_ID_HEADER_KEY; +import static org.onap.vid.utils.Logging.logRequest; + +public class SdcRestClient implements AsdcClient { + + private String baseUrl; + private String path; + private String auth; + private static final EELFLogger LOGGER = Logging.getRequestsLogger("asdc"); + + private SyncRestClientInterface syncRestClient; + + + public SdcRestClient(String baseUrl, String auth, SyncRestClientInterface client) { + this.syncRestClient = client; + this.auth = auth; + this.baseUrl = baseUrl; + this.path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, ModelConstants.DEFAULT_ASDC_SVC_API_PATH); + } + + + @Override + public Service getService(UUID uuid) throws AsdcCatalogException { + String finalUrl = String.format(METADATA_URL_TEMPLATE, baseUrl, path, uuid); + logRequest(LOGGER, HttpMethod.GET, finalUrl); + + return Try + .of(() -> syncRestClient.get(finalUrl, prepareHeaders(auth, APPLICATION_JSON), Collections.emptyMap(), Service.class)) + .getOrElseThrow(AsdcCatalogException::new) + .getBody(); + + } + + @Override + public Path getServiceToscaModel(UUID uuid) throws AsdcCatalogException { + String finalUrl = String.format(TOSCA_MODEL_URL_TEMPLATE, baseUrl, path, uuid); + logRequest(LOGGER, HttpMethod.GET, finalUrl); + + InputStream inputStream = Try + .of(() -> syncRestClient.getStream(finalUrl, prepareHeaders(auth, APPLICATION_OCTET_STREAM), Collections.emptyMap())) + .getOrElseThrow(AsdcCatalogException::new) + .getBody(); + + return createTmpFile(inputStream); + } + + + private Map prepareHeaders(String auth, String contentType) { + return ImmutableMap.of( + X_ECOMP_INSTANCE_ID, SystemProperties.getProperty(APP_DISPLAY_NAME), + AUTHORIZATION, auth, + REQUEST_ID_HEADER_KEY, Logging.extractOrGenerateRequestId(), + CONTENT_TYPE, contentType + ); + } + + private Path createTmpFile(InputStream csarInputStream) throws AsdcCatalogException { + return Try + .of(() -> tryToCreateTmpFile(csarInputStream)) + .getOrElseThrow(throwable -> new AsdcCatalogException("Caught IOException while creating CSAR", throwable)); + } + + private Path tryToCreateTmpFile(InputStream csarInputStream) throws IOException { + Path csarFile = Files.createTempFile("csar", ".zip"); + Files.copy(csarInputStream, csarFile, StandardCopyOption.REPLACE_EXISTING); + + LOGGER.debug("Tosca file was saved at: {} ", csarFile.toAbsolutePath()); + + return csarFile; + } +} diff --git a/vid-app-common/src/main/java/org/onap/vid/client/SyncRestClientInterface.java b/vid-app-common/src/main/java/org/onap/vid/client/SyncRestClientInterface.java index 80663d65..142adde1 100644 --- a/vid-app-common/src/main/java/org/onap/vid/client/SyncRestClientInterface.java +++ b/vid-app-common/src/main/java/org/onap/vid/client/SyncRestClientInterface.java @@ -2,16 +2,22 @@ package org.onap.vid.client; import io.joshworks.restclient.http.HttpResponse; import io.joshworks.restclient.http.JsonNode; + import java.io.InputStream; import java.util.Map; public interface SyncRestClientInterface { + class HEADERS { + public static final String CONTENT_TYPE = "Content-Type"; + public static final String AUTHORIZATION = "Authorization"; + public static final String X_ECOMP_INSTANCE_ID = "X-ECOMP-InstanceID"; + } HttpResponse post(String url, Map headers, Object body); HttpResponse post(String url, Map headers, Object body, Class aClass); - HttpResponse get(String url, Map headers, Map routeParams); + HttpResponse get(String url, Map headers, Map routeParams); HttpResponse get(String url, Map headers, Map routeParams, Class aClass); @@ -19,9 +25,9 @@ public interface SyncRestClientInterface { HttpResponse put(String url, Map headers, Object body); - HttpResponse put(String url, Map headers, Object body, Class aClass); + HttpResponse put(String url, Map headers, Object body, Class aClass); - HttpResponse delete(String url, Map headers, Class aClass); + HttpResponse delete(String url, Map headers, Class aClass); HttpResponse delete(String url, Map headers); diff --git a/vid-app-common/src/main/java/org/onap/vid/controllers/WebConfig.java b/vid-app-common/src/main/java/org/onap/vid/controllers/WebConfig.java index cf32e92e..0f4b536a 100644 --- a/vid-app-common/src/main/java/org/onap/vid/controllers/WebConfig.java +++ b/vid-app-common/src/main/java/org/onap/vid/controllers/WebConfig.java @@ -22,14 +22,30 @@ package org.onap.vid.controllers; import com.fasterxml.jackson.databind.ObjectMapper; -import org.onap.vid.aai.*; +import org.onap.vid.aai.AaiClient; +import org.onap.vid.aai.AaiClientInterface; +import org.onap.vid.aai.AaiResponseTranslator; +import org.onap.vid.aai.PombaClientImpl; +import org.onap.vid.aai.PombaClientInterface; +import org.onap.vid.aai.PombaRestInterface; import org.onap.vid.aai.model.PortDetailsTranslator; -import org.onap.vid.aai.util.*; +import org.onap.vid.aai.util.AAIRestInterface; +import org.onap.vid.aai.util.HttpsAuthClient; +import org.onap.vid.aai.util.SSLContextProvider; +import org.onap.vid.aai.util.ServletRequestHelper; +import org.onap.vid.aai.util.SystemPropertyHelper; import org.onap.vid.asdc.AsdcClient; import org.onap.vid.asdc.parser.ToscaParserImpl2; -import org.onap.vid.asdc.rest.RestfulAsdcClient; -import org.onap.vid.exceptions.GenericUncheckedException; +import org.onap.vid.asdc.rest.SdcRestClient; +import org.onap.vid.client.SyncRestClient; +import org.onap.vid.client.SyncRestClientInterface; import org.onap.vid.properties.AsdcClientConfiguration; +import org.onap.vid.services.AaiService; +import org.onap.vid.services.AaiServiceImpl; +import org.onap.vid.services.PombaService; +import org.onap.vid.services.PombaServiceImpl; +import org.onap.vid.services.VidService; +import org.onap.vid.services.VidServiceImpl; import org.onap.vid.scheduler.SchedulerRestInterface; import org.onap.vid.scheduler.SchedulerRestInterfaceIfc; import org.onap.vid.services.*; @@ -38,15 +54,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.togglz.core.manager.FeatureManager; -import javax.net.ssl.SSLContext; import javax.servlet.ServletContext; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; @Configuration public class WebConfig { @@ -119,35 +128,18 @@ public class WebConfig { } @Bean - public AsdcClient asdcClient(AsdcClientConfiguration asdcClientConfig) { - - final String protocol = asdcClientConfig.getAsdcClientProtocol(); - final String host = asdcClientConfig.getAsdcClientHost(); - final int port = asdcClientConfig.getAsdcClientPort(); - final String auth = asdcClientConfig.getAsdcClientAuth(); - Client cl = null; - if (protocol.equalsIgnoreCase("https")) { - try { - SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - ctx.init(null, null, null); - cl = ClientBuilder.newBuilder().sslContext(ctx).build(); - } catch (NoSuchAlgorithmException n) { - throw new GenericUncheckedException("SDC Client could not be instantiated due to unsupported protocol TLSv1.2", n); - } catch (KeyManagementException k) { - throw new GenericUncheckedException("SDC Client could not be instantiated due to a key management exception", k); - } - } else { - cl = ClientBuilder.newBuilder().build(); - } - - try { - final URI uri = new URI(protocol + "://" + host + ":" + port + "/"); - return new RestfulAsdcClient.Builder(cl, uri) - .auth(auth) - .build(); - } catch (URISyntaxException e) { - throw new GenericUncheckedException("SDC Client could not be instantiated due to a syntax error in the URI", e); - } + public AsdcClient sdcClient(AsdcClientConfiguration asdcClientConfiguration, SyncRestClientInterface syncRestClient) { + String auth = asdcClientConfiguration.getAsdcClientAuth(); + String host = asdcClientConfiguration.getAsdcClientHost(); + String protocol = asdcClientConfiguration.getAsdcClientProtocol(); + int port = asdcClientConfiguration.getAsdcClientPort(); + + return new SdcRestClient(protocol + "://" + host + ":" + port + "/", auth, syncRestClient); + } + + @Bean + public SyncRestClientInterface syncRestClient() { + return new SyncRestClient(); } @Bean diff --git a/vid-app-common/src/test/java/org/onap/vid/asdc/rest/RestfulAsdcClientTest.java b/vid-app-common/src/test/java/org/onap/vid/asdc/rest/RestfulAsdcClientTest.java deleted file mode 100644 index 75b84b2d..00000000 --- a/vid-app-common/src/test/java/org/onap/vid/asdc/rest/RestfulAsdcClientTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.onap.vid.asdc.rest; - -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.onap.vid.testUtils.TestUtils; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import javax.ws.rs.NotFoundException; -import javax.ws.rs.ProcessingException; -import javax.ws.rs.client.Client; -import java.net.URI; -import java.util.UUID; -import java.util.function.Consumer; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.when; -import static org.testng.AssertJUnit.fail; - -public class RestfulAsdcClientTest { - - @DataProvider - public static Object[][] javaxExceptions() { - - return new Object[][] { - {NotFoundException.class, (Consumer) javaxClientMock -> - when(javaxClientMock.target(any(URI.class))).thenThrow( - new NotFoundException("HTTP 404 Not Found"))}, - {ProcessingException.class, (Consumer) javaxClientMock -> - when(javaxClientMock.target(any(URI.class))).thenThrow( - new ProcessingException("java.net.ConnectException: Connection refused: connect"))}, - }; - } - - - @Test(dataProvider = "javaxExceptions") - public void whenJavaxClientThrowException_thenExceptionRethrown(Class expectedType, Consumer setupMocks) throws Exception { - /* - Call chain is like: - this test -> RestfulAsdcClient -> javax's Client - - In this test, *RestfulAsdcClient* is under test (actual implementation is used), while javax's Client is - mocked to return pseudo-responses or - better - throw exceptions. - */ - - // prepare mocks - TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks(); - Client javaxClientMock = mocks.getFakeClient(); - - // prepare real RestfulAsdcClient (Under test) - RestfulAsdcClient restfulAsdcClient = new RestfulAsdcClient.Builder(javaxClientMock, new URI("")) - .auth("") - .build(); - - /// TEST: - setupMocks.accept(javaxClientMock); - - try { - restfulAsdcClient.getServiceToscaModel(UUID.randomUUID()); - } catch (Exception e) { - assertThat("root cause incorrect for " + ExceptionUtils.getStackTrace(e), ExceptionUtils.getRootCause(e), instanceOf(expectedType)); - return; //OK - } - - fail("exception shall rethrown by getServiceToscaModel once javax client throw exception "); - } - -} diff --git a/vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientITTest.java b/vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientITTest.java new file mode 100644 index 00000000..2ef33742 --- /dev/null +++ b/vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientITTest.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * VID + * ================================================================================ + * Copyright (C) 2018 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * 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.vid.asdc.rest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.xebialabs.restito.semantics.Call; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContextBuilder; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.vid.asdc.AsdcCatalogException; +import org.onap.vid.asdc.beans.Service; +import org.onap.vid.client.SyncRestClient; +import org.onap.vid.testUtils.StubServerUtil; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.Optional; +import java.util.UUID; + +import static com.xebialabs.restito.semantics.Action.ok; +import static com.xebialabs.restito.semantics.Action.stringContent; +import static org.apache.http.client.config.RequestConfig.custom; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.Assert.assertTrue; +import static org.onap.vid.client.SyncRestClientInterface.HEADERS.X_ECOMP_INSTANCE_ID; +import static org.onap.vid.utils.Logging.REQUEST_ID_HEADER_KEY; + + +public class SdcRestClientITTest { + private static final String UUID_REGEX = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + private static final String[] SUPPORTED_SSL_VERSIONS = {"TLSv1", "TLSv1.2"}; + private static StubServerUtil stubServer; + private static SdcRestClient sdcRestClient; + + @BeforeClass + public static void setUpClass() throws GeneralSecurityException { + stubServer = new StubServerUtil(); + stubServer.runSecuredServer(); + SyncRestClient syncRestClient = new SyncRestClient(createNaiveHttpClient()); + String serverUrl = stubServer.constructTargetUrl("https", ""); + sdcRestClient = new SdcRestClient(serverUrl, "", syncRestClient); + } + + @AfterClass + public static void tearDown() { + stubServer.stopServer(); + } + + @Test + public void shouldDownloadToscaArtifactUsingSecuredEndpoint() throws AsdcCatalogException, IOException { + UUID uuid = UUID.randomUUID(); + String expectedEndpoint = String.format("/sdc/v1/catalog/services/%s/toscaModel", uuid); + + stubServer.prepareGetCall( + expectedEndpoint, stringContent("sampleFileContent"), "sampleFileContent", ok(), "application/octet-stream"); + + + Path serviceToscaModel = sdcRestClient.getServiceToscaModel(uuid); + serviceToscaModel.toFile().deleteOnExit(); + + + assertThat(Files.readAllLines(serviceToscaModel), contains("sampleFileContent")); + assertThatRequestHasRequiredHeaders(expectedEndpoint); + } + + @Test + public void shouldGetServiceDetailsUsingSecuredEndpoint() throws AsdcCatalogException, JsonProcessingException { + UUID uuid = UUID.randomUUID(); + String expectedEndpoint = String.format("/sdc/v1/catalog/services/%s/metadata", uuid); + Service expectedService = getExpectedService(uuid.toString()); + + + stubServer.prepareGetCall(expectedEndpoint, expectedService, ok()); + + + Service actualService = sdcRestClient.getService(uuid); + + + assertThat(actualService, is(expectedService)); + assertThatRequestHasRequiredHeaders(expectedEndpoint); + } + + private void assertThatRequestHasRequiredHeaders(String expectedEndpoint) { + Optional first = stubServer + .getServerCalls() + .stream() + .filter(x -> x.getUri().contains(expectedEndpoint)) + .findFirst(); + + assertTrue(first.isPresent()); + + assertThat(first.get().getHeaders().keySet(), hasItems(X_ECOMP_INSTANCE_ID.toLowerCase(), REQUEST_ID_HEADER_KEY.toLowerCase())); + assertThat(first.get().getHeaders().get(REQUEST_ID_HEADER_KEY.toLowerCase()).get(0), matchesPattern(UUID_REGEX)); + } + + private Service getExpectedService(String stringId) { + return new Service(stringId, stringId, + "sampleCategory", "sampleVersion", + "sampleName", "sampleDistStatus", + "sampleToscaUrl", Service.LifecycleState.CERTIFIED, Collections.emptyList(), Collections.emptyList()); + } + + + private static CloseableHttpClient createNaiveHttpClient() throws GeneralSecurityException { + final SSLContext context = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) + .build(); + + final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(context, SUPPORTED_SSL_VERSIONS, + null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + Registry registry = RegistryBuilder.create() + .register("https", socketFactory) + .build(); + + return HttpClientBuilder.create() + .setDefaultRequestConfig(custom().setConnectionRequestTimeout(10000).build()) + .setConnectionManager(new PoolingHttpClientConnectionManager(registry)) + .setSSLSocketFactory(socketFactory).build(); + } +} diff --git a/vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientTest.java b/vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientTest.java new file mode 100644 index 00000000..c1d6ab78 --- /dev/null +++ b/vid-app-common/src/test/java/org/onap/vid/asdc/rest/SdcRestClientTest.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * VID + * ================================================================================ + * Copyright (C) 2018 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * 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.vid.asdc.rest; + +import io.joshworks.restclient.http.HttpResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.vid.asdc.AsdcCatalogException; +import org.onap.vid.asdc.beans.Service; +import org.onap.vid.client.SyncRestClient; + +import java.io.InputStream; +import java.nio.file.Path; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.matches; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class SdcRestClientTest { + + private static final String SAMPLE_SERVICE_NAME = "sampleService"; + private static final String SAMPLE_BASE_URL = "baseUrl"; + private static final String SAMPLE_AUTH = "sampleAuth"; + private static final String METADATA_URL_REGEX = ".*sdc/v1/catalog/services/%s/metadata"; + private static final String MODEL_URL_REGEX = ".*sdc/v1/catalog/services/%s/toscaModel"; + + + @Mock + private SyncRestClient mockedSyncRestClient; + + @Mock + private HttpResponse httpResponse; + + @Mock + private HttpResponse httpStreamResponse; + + @Mock + private InputStream inputStream; + + private UUID randomId; + + private Service sampleService; + + private SdcRestClient restClient; + + + @Before + public void setUp() { + randomId = UUID.randomUUID(); + sampleService = createTestService(); + restClient = new SdcRestClient(SAMPLE_BASE_URL, SAMPLE_AUTH, mockedSyncRestClient); + } + + + @Test + public void shouldReturnServiceForGivenUUID() throws AsdcCatalogException { + String url = String.format(METADATA_URL_REGEX, randomId); + when(mockedSyncRestClient.get(matches(url), anyMapOf(String.class, String.class), anyMapOf(String.class, String.class), any())).thenReturn(httpResponse); + when(httpResponse.getBody()).thenReturn(sampleService); + + Service service = restClient.getService(randomId); + + + assertThat(service, is(sampleService)); + } + + @Test(expected = AsdcCatalogException.class) + public void shouldRaiseAsdcExceptionWhenClientFails() throws AsdcCatalogException { + String url = String.format(METADATA_URL_REGEX, randomId); + when(mockedSyncRestClient.get(matches(url), anyMapOf(String.class, String.class), anyMapOf(String.class, String.class), any())).thenThrow(new RuntimeException()); + + restClient.getService(randomId); + } + + + @Test + public void shouldProperlyDownloadAndCopyToscaArtifact() throws AsdcCatalogException { + String url = String.format(MODEL_URL_REGEX, randomId); + when(mockedSyncRestClient.getStream(matches(url), any(), any())).thenReturn(httpStreamResponse); + when(httpStreamResponse.getBody()).thenReturn(inputStream); + + + Path serviceToscaModel = restClient.getServiceToscaModel(randomId); + + + assertThat(serviceToscaModel, notNullValue()); + assertThat(serviceToscaModel.toFile().isFile(), is(true)); + + serviceToscaModel.toFile().deleteOnExit(); + } + + @Test(expected = AsdcCatalogException.class) + public void shouldRaiseAsdcExceptionWhenDownloadFails() throws AsdcCatalogException { + String url = String.format(MODEL_URL_REGEX, randomId); + when(mockedSyncRestClient.getStream(matches(url), anyMapOf(String.class, String.class), anyMapOf(String.class, String.class))).thenThrow(new RuntimeException()); + + + restClient.getServiceToscaModel(randomId); + } + + + private Service createTestService() { + Service service = new Service(); + service.setInvariantUUID(randomId.toString()); + service.setUuid(randomId.toString()); + service.setName(SAMPLE_SERVICE_NAME); + return service; + } + +} \ No newline at end of file diff --git a/vid-app-common/src/test/java/org/onap/vid/mso/rest/OutgoingRequestIdTest.java b/vid-app-common/src/test/java/org/onap/vid/mso/rest/OutgoingRequestIdTest.java index da2600ea..909975fb 100644 --- a/vid-app-common/src/test/java/org/onap/vid/mso/rest/OutgoingRequestIdTest.java +++ b/vid-app-common/src/test/java/org/onap/vid/mso/rest/OutgoingRequestIdTest.java @@ -2,9 +2,13 @@ package org.onap.vid.mso.rest; import com.google.common.collect.ImmutableList; import org.apache.commons.lang3.reflect.FieldUtils; -import org.mockito.*; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.onap.vid.aai.util.AAIRestInterface; -import org.onap.vid.asdc.rest.RestfulAsdcClient; import org.onap.vid.changeManagement.RequestDetailsWrapper; import org.onap.vid.controller.filter.PromiseEcompRequestIdFilter; import org.onap.vid.mso.RestMsoImplementation; @@ -27,10 +31,13 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.util.UUID.randomUUID; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.mockito.Mockito.mock; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasToString; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.matchesPattern; public class OutgoingRequestIdTest { @@ -42,7 +49,6 @@ public class OutgoingRequestIdTest { @InjectMocks private AAIRestInterface aaiRestInterface; - private RestfulAsdcClient restfulAsdcClient = new RestfulAsdcClient.Builder(mock(Client.class), null).build(); @Captor private ArgumentCaptor> multivaluedMapArgumentCaptor; @@ -57,23 +63,6 @@ public class OutgoingRequestIdTest { RequestContextHolder.setRequestAttributes(new ServletRequestAttributes((HttpServletRequest) PromiseEcompRequestIdFilter.wrapIfNeeded(new MockHttpServletRequest()))); } - @DataProvider - public Object[][] sdcMethods() { - return Stream.>of( - client -> client.getService(randomUUID()), - client -> client.getServiceToscaModel(randomUUID()) - ).map(l -> ImmutableList.of(l).toArray()).collect(Collectors.toList()).toArray(new Object[][]{}); - } - - @Test(dataProvider = "sdcMethods") - public void sdc(Consumer f) throws Exception { - final TestUtils.JavaxRsClientMocks mocks = setAndGetMocksInsideRestImpl(restfulAsdcClient); - - f.accept(restfulAsdcClient); - - verifyRequestIdHeaderWasAdded(mocks.getFakeBuilder()); - } - @DataProvider public Object[][] msoMethods() { return Stream.>of( diff --git a/vid-app-common/src/test/java/org/onap/vid/testUtils/StubServerUtil.java b/vid-app-common/src/test/java/org/onap/vid/testUtils/StubServerUtil.java index e84655f7..f7ffd9a9 100644 --- a/vid-app-common/src/test/java/org/onap/vid/testUtils/StubServerUtil.java +++ b/vid-app-common/src/test/java/org/onap/vid/testUtils/StubServerUtil.java @@ -23,9 +23,12 @@ package org.onap.vid.testUtils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.xebialabs.restito.semantics.Action; +import com.xebialabs.restito.semantics.Call; import com.xebialabs.restito.semantics.Condition; import com.xebialabs.restito.server.StubServer; +import java.util.List; + import static com.xebialabs.restito.builder.stub.StubHttp.whenHttp; import static com.xebialabs.restito.semantics.Action.contentType; import static com.xebialabs.restito.semantics.Action.stringContent; @@ -48,6 +51,10 @@ public class StubServerUtil { stubServer.run(); } + public void runSecuredServer(){ + stubServer.secured().run(); + } + public void stopServer() { stubServer.stop(); } @@ -57,10 +64,15 @@ public class StubServerUtil { return String.format("%s://localhost:%s/%s", protocol, stubServer.getPort(), relativePath); } - public void prepareGetCall(String path, Object returnObj, Action expectedAction) throws JsonProcessingException { + public void prepareGetCall(String path, Action actionToReturn,Object returnObj, Action expectedAction, String contentType) throws JsonProcessingException { whenHttp(stubServer) .match(Condition.get(path)) - .then(expectedAction, jsonContent(returnObj), contentType(APPLICATION_JSON)); + .then(expectedAction, actionToReturn, contentType(contentType)); + } + + + public void prepareGetCall(String path, Object returnObj, Action expectedAction) throws JsonProcessingException { + prepareGetCall(path, jsonContent(returnObj),returnObj, expectedAction, APPLICATION_JSON); } public void prepareDeleteCall(String path, Object returnObj, Action expectedAction) throws JsonProcessingException { @@ -83,6 +95,10 @@ public class StubServerUtil { .then(expectedStatus, jsonContent(returnObj), contentType(APPLICATION_JSON)); } + public List getServerCalls() { + return stubServer.getCalls(); + } + private Action jsonContent(Object returnObj) throws JsonProcessingException { return stringContent(objectMapper.writeValueAsString(returnObj)); } diff --git a/vid-app-common/src/test/resources/WEB-INF/conf/system.properties b/vid-app-common/src/test/resources/WEB-INF/conf/system.properties index a67f5789..8eb70a85 100644 --- a/vid-app-common/src/test/resources/WEB-INF/conf/system.properties +++ b/vid-app-common/src/test/resources/WEB-INF/conf/system.properties @@ -178,8 +178,8 @@ mso.dme2.server.url=http://mso-api-handler-anap-v1.mso.ecomp.att.com/services/ec #mso.dme2.server.url=https://ActiveAndAvailableInventory-CloudNetwork-v1.aai.att.com/aai?version=1&envContext=DEV&routeOffer=devINT1 mso.dme2.enabled=false asdc.model.namespace=org.openecomp. -sdc.svc.api.path=asdc/v1/catalog/services -sdc.resource.api.path=asdc/v1/catalog/resource +sdc.svc.api.path=sdc/v1/catalog/services +sdc.resource.api.path=sdc/v1/catalog/resource # Application base URL has the host and app context only; a proper prefix of the on-boarded URL. # Only required for applications using WebJunction or FE/BE separation. For example: -- cgit 1.2.3-korg