From 7c4a9aa88269dbdb21c5c54bc47508463548bc1e Mon Sep 17 00:00:00 2001 From: tragait Date: Mon, 19 Jul 2021 13:46:37 +0100 Subject: implement dmi get modules using sdnc client Issue-ID: CPS-483 Change-Id: Ib9b730cabeba308f11db31ef1b45bbd92e3a6ed5 Signed-off-by: tragait --- docs/openapi/openapi.yml | 48 +++++++++++--- pom.xml | 7 +- .../onap/cps/ncmp/dmi/config/CpsConfiguration.java | 55 ---------------- .../onap/cps/ncmp/dmi/config/DmiConfiguration.java | 69 ++++++++++++++++++++ .../onap/cps/ncmp/dmi/exception/DmiException.java | 59 +++++++++++++++++ .../ncmp/dmi/exception/DmiExceptionHandler.java | 74 +++++++++++++++++++++ .../dmi/exception/ModulesNotFoundException.java | 38 +++++++++++ .../dmi/rest/controller/DmiRestController.java | 16 +++-- .../org/onap/cps/ncmp/dmi/service/DmiService.java | 12 +++- .../onap/cps/ncmp/dmi/service/DmiServiceImpl.java | 28 +++++++- .../ncmp/dmi/service/client/NcmpRestClient.java | 2 +- .../dmi/service/client/SdncRestconfClient.java | 57 ++++++++++++++++ .../ncmp/dmi/service/operation/SdncOperations.java | 75 ++++++++++++++++++++++ src/main/resources/application.yml | 9 ++- .../rest/controller/DmiRestControllerSpec.groovy | 58 +++++++++++------ .../cps/ncmp/dmi/service/DmiServiceImplSpec.groovy | 47 ++++++++++++-- .../dmi/service/client/NcmpRestClientSpec.groovy | 8 +-- .../service/client/SdncRestconfClientSpec.groovy | 52 +++++++++++++++ .../service/operation/SdncOperationsSpec.groovy | 44 +++++++++++++ 19 files changed, 652 insertions(+), 106 deletions(-) delete mode 100644 src/main/java/org/onap/cps/ncmp/dmi/config/CpsConfiguration.java create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/config/DmiConfiguration.java create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/exception/DmiException.java create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/exception/ModulesNotFoundException.java create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java create mode 100644 src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy create mode 100644 src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml index 36e3d12e..7d0569d4 100644 --- a/docs/openapi/openapi.yml +++ b/docs/openapi/openapi.yml @@ -24,22 +24,52 @@ info: servers: - url: //localhost:8088/ tags: - - name: dmi-rest - description: DMI Rest + - name: dmi-plugin-internal + description: DMI plugin internal rest apis + - name: dmi-plugin + description: DMI plugin rest apis + + paths: - /v1/helloworld: - get: - description: Hello World + /v1/ch/{cmHandle}/modules : + post: tags: - dmi-plugin - summary: Hello World - operationId: helloWorld + summary: Get all modules for cm handle + description: Get all modules for given cm handle + operationId: getModulesForCmHandle + parameters: + - name: cmHandle + in: path + description: The cm handle to fetch all the modules + required: true + schema: + type: string responses: '200': - $ref: 'components.yml#/components/responses/Ok' + description: OK + content: + application/json: + schema: + type: string + example: { + 'schemas': { + 'schema': [ + { + 'identifier': 'example-identifier', + 'version': 'example-version', + 'format': 'example-format', + 'namespace': 'example:namespace', + 'location': [ + 'example-location' + ] + } + ] + } + } '400': $ref: 'components.yml#/components/responses/BadRequest' '401': $ref: 'components.yml#/components/responses/Unauthorized' '403': - $ref: 'components.yml#/components/responses/Forbidden' + $ref: 'components.yml#/components/responses/Forbidden' \ No newline at end of file diff --git a/pom.xml b/pom.xml index a6815aef..fd1f1894 100644 --- a/pom.xml +++ b/pom.xml @@ -159,8 +159,8 @@ ${project.basedir}/docs/openapi/openapi.yml spring false - org.onap.cps.ncmp.rest.api - org.onap.cps.ncmp.rest.model + org.onap.cps.ncmp.dmi.rest.api + org.onap.cps.ncmp.dmi.model src/gen/java java11 @@ -320,7 +320,8 @@ 0.8.5 - org/onap/cps/ncmp/rest/model/* + org/onap/cps/ncmp/dmi/model/* + org/onap/cps/ncmp/dmi/config/* diff --git a/src/main/java/org/onap/cps/ncmp/dmi/config/CpsConfiguration.java b/src/main/java/org/onap/cps/ncmp/dmi/config/CpsConfiguration.java deleted file mode 100644 index a9970da8..00000000 --- a/src/main/java/org/onap/cps/ncmp/dmi/config/CpsConfiguration.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation - * ================================================================================ - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.dmi.config; - -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -/** - * Provides access to cps base url and cps authentication. - */ -@Configuration -public class CpsConfiguration { - - @Getter - @Component - public static class CpsProperties { - - @Value("${cps-core.baseUrl}") - private String baseUrl; - @Value("${cps-core.dmiRegistrationUrl}") - private String dmiRegistrationUrl; - @Value("${cps-core.auth.username}") - private String authUsername; - @Value("${cps-core.auth.password}") - private String authPassword; - } - - @Bean - public RestTemplate restTemplate(final RestTemplateBuilder restTemplateBuilder) { - return restTemplateBuilder.build(); - } -} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/config/DmiConfiguration.java b/src/main/java/org/onap/cps/ncmp/dmi/config/DmiConfiguration.java new file mode 100644 index 00000000..9b8b05b2 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/config/DmiConfiguration.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.config; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +/** + * Provides access to cps base url and cps authentication. + */ +@Configuration +public class DmiConfiguration { + + @Getter + @Component + public static class CpsProperties { + + @Value("${cps-core.baseUrl}") + private String baseUrl; + @Value("${cps-core.dmiRegistrationUrl}") + private String dmiRegistrationUrl; + @Value("${cps-core.auth.username}") + private String authUsername; + @Value("${cps-core.auth.password}") + private String authPassword; + } + + @Getter + @Component + public static class SdncProperties { + + @Value("${sdnc.baseUrl}") + private String baseUrl; + @Value("${sdnc.auth.username}") + private String authUsername; + @Value("${sdnc.auth.password}") + private String authPassword; + @Value("${sdnc.topologyId}") + public String topologyId; + } + + @Bean + public RestTemplate restTemplate(final RestTemplateBuilder restTemplateBuilder) { + return restTemplateBuilder.build(); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiException.java b/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiException.java new file mode 100644 index 00000000..c099a1cc --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiException.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + + +package org.onap.cps.ncmp.dmi.exception; + +import lombok.Getter; + +/** + * Dmi exception. + */ +public class DmiException extends RuntimeException { + + private static final long serialVersionUID = 1481520410918497487L; + + @Getter + final String details; + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public DmiException(final String message, final String details) { + super(message); + this.details = details; + } + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + * @param cause the cause of the exception + */ + public DmiException(final String message, final String details, final Throwable cause) { + super(message, cause); + this.details = details; + } + +} diff --git a/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java b/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java new file mode 100644 index 00000000..9ad561fc --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.exception; + +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.dmi.model.ErrorMessage; +import org.onap.cps.ncmp.dmi.rest.controller.DmiRestController; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice(assignableTypes = {DmiRestController.class}) +public class DmiExceptionHandler { + + private DmiExceptionHandler() { + } + + /** + * Default exception handler. + * + * @param exception the exception to handle + * @return response with response code 500. + */ + @ExceptionHandler + public static ResponseEntity handleInternalServerErrorExceptions(final Exception exception) { + return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception); + } + + @ExceptionHandler({ModulesNotFoundException.class}) + public static ResponseEntity handleNotFoundExceptions(final DmiException exception) { + return buildErrorResponse(HttpStatus.NOT_FOUND, exception); + } + + @ExceptionHandler({DmiException.class}) + public static ResponseEntity handleAnyOtherDmiExceptions(final DmiException exception) { + return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception); + } + + private static ResponseEntity buildErrorResponse(final HttpStatus httpStatus, final Exception exception) { + logForNonDmiException(exception); + final var errorMessage = new ErrorMessage(); + errorMessage.setStatus(httpStatus.toString()); + errorMessage.setMessage(exception.getMessage()); + errorMessage.setDetails(exception instanceof DmiException ? ((DmiException) exception).getDetails() : + "Check logs for details."); + return new ResponseEntity<>(errorMessage, httpStatus); + } + + private static void logForNonDmiException(final Exception exception) { + if (exception.getCause() != null || !(exception instanceof DmiException)) { + log.error("Exception occurred", exception); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/exception/ModulesNotFoundException.java b/src/main/java/org/onap/cps/ncmp/dmi/exception/ModulesNotFoundException.java new file mode 100644 index 00000000..ded54d91 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/exception/ModulesNotFoundException.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.exception; + +public class ModulesNotFoundException extends DmiException { + + private static final long serialVersionUID = 980438585188332404L; + + private static final String ERROR_MESSAGE = "Not able to register the given cm-handles: "; + + /** + * Constructor. + * + * @param cmHandle cmHandle identifier + * @param details the error details + */ + public ModulesNotFoundException(final String cmHandle, final String details) { + super(ERROR_MESSAGE + cmHandle, details); + } +} diff --git a/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java b/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java index c4cbaece..8081b73d 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java @@ -20,8 +20,8 @@ package org.onap.cps.ncmp.dmi.rest.controller; +import org.onap.cps.ncmp.dmi.rest.api.DmiPluginApi; import org.onap.cps.ncmp.dmi.service.DmiService; -import org.onap.cps.ncmp.rest.api.DmiPluginApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -32,13 +32,17 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class DmiRestController implements DmiPluginApi { - @Autowired private DmiService dmiService; - @Override - public ResponseEntity helloWorld() { - final var helloWorld = dmiService.getHelloWorld(); - return new ResponseEntity<>(helloWorld, HttpStatus.OK); + @Autowired + public DmiRestController(final DmiService dmiService) { + this.dmiService = dmiService; } + @Override + public ResponseEntity getModulesForCmHandle(final String cmHandle) { + + final String modulesListAsJson = dmiService.getModulesForCmHandle(cmHandle); + return new ResponseEntity<>(modulesListAsJson, HttpStatus.OK); + } } diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java index 84c60d55..e595bd5f 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java @@ -20,12 +20,20 @@ package org.onap.cps.ncmp.dmi.service; +import org.onap.cps.ncmp.dmi.exception.DmiException; + /** * Interface for handling Dmi plugin Data. */ public interface DmiService { + /** - * Return Simple Hello World Statement. + * This method fetches all modules for given Cm Handle. + * + * @param cmHandle cm-handle to fetch the modules information + * @return {@code String} returns all modules + * @throws DmiException can throw dmi exception */ - String getHelloWorld(); + String getModulesForCmHandle(String cmHandle) throws DmiException; + } diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java index 5051b1ad..4367bf45 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java @@ -20,13 +20,37 @@ package org.onap.cps.ncmp.dmi.service; +import io.micrometer.core.instrument.util.StringUtils; +import org.onap.cps.ncmp.dmi.exception.DmiException; +import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException; +import org.onap.cps.ncmp.dmi.service.operation.SdncOperations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @Service public class DmiServiceImpl implements DmiService { + private SdncOperations sdncOperations; + + @Autowired + public DmiServiceImpl(final SdncOperations sdncOperations) { + this.sdncOperations = sdncOperations; + } + @Override - public String getHelloWorld() { - return "Hello World"; + public String getModulesForCmHandle(final String cmHandle) throws DmiException { + final ResponseEntity responseEntity = sdncOperations.getModulesFromNode(cmHandle); + if (responseEntity.getStatusCode() == HttpStatus.OK) { + final String responseBody = responseEntity.getBody(); + if (StringUtils.isEmpty(responseBody)) { + throw new ModulesNotFoundException(cmHandle, "SDNC returned no modules for given cm-handle."); + } + return responseBody; + } else { + throw new DmiException("SDNC is not able to process request.", + "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); + } } } diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/client/NcmpRestClient.java b/src/main/java/org/onap/cps/ncmp/dmi/service/client/NcmpRestClient.java index 2158e836..47651346 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/client/NcmpRestClient.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/client/NcmpRestClient.java @@ -20,7 +20,7 @@ package org.onap.cps.ncmp.dmi.service.client; -import org.onap.cps.ncmp.dmi.config.CpsConfiguration.CpsProperties; +import org.onap.cps.ncmp.dmi.config.DmiConfiguration.CpsProperties; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java b/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java new file mode 100644 index 00000000..cf7c50a5 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.service.client; + +import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class SdncRestconfClient { + private SdncProperties sdncProperties; + private RestTemplate restTemplate; + + public SdncRestconfClient(final SdncProperties sdncProperties, final RestTemplate restTemplate) { + this.sdncProperties = sdncProperties; + this.restTemplate = restTemplate; + } + + /** + * restconf get operation on sdnc. + * + * @param getResourceUrl sdnc get url + * + * @return the response entity + */ + public ResponseEntity getOperation(final String getResourceUrl) { + final String sdncBaseUrl = sdncProperties.getBaseUrl(); + final String sdncRestconfUrl = sdncBaseUrl.concat(getResourceUrl); + final var httpHeaders = new HttpHeaders(); + httpHeaders.setBasicAuth(sdncProperties.getAuthUsername(), sdncProperties.getAuthPassword()); + httpHeaders.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString()); + final var httpEntity = new HttpEntity<>(httpHeaders); + return restTemplate.getForEntity(sdncRestconfUrl, String.class, httpEntity); + } +} diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java b/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java new file mode 100644 index 00000000..4e4e7217 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.service.operation; + +import org.jetbrains.annotations.NotNull; +import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties; +import org.onap.cps.ncmp.dmi.service.client.SdncRestconfClient; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +@Component +public class SdncOperations { + + private static final String TOPOLOGY_URL_TEMPLATE = "/rests/data/network-topology:network-topology" + + "/topology={topologyId}"; + private static final String MOUNT_URL_TEMPLATE = "/node={nodeId}/yang-ext:mount"; + private static final String GET_SCHEMA_URL = "/ietf-netconf-monitoring:netconf-state/schemas"; + + private SdncProperties sdncProperties; + private SdncRestconfClient sdncRestconfClient; + private final String topologyUrl; + private final String topologyMountUrlTemplate; + + /** + * Constructor for {@code SdncOperations}. This method also manipulates + * url properties. + * + * @param sdncProperties {@code SdncProperties} + * @param sdncRestconfClient {@code SdncRestconfClient} + */ + + public SdncOperations(final SdncProperties sdncProperties, final SdncRestconfClient sdncRestconfClient) { + this.sdncProperties = sdncProperties; + this.sdncRestconfClient = sdncRestconfClient; + topologyUrl = TOPOLOGY_URL_TEMPLATE.replace("{topologyId}", this.sdncProperties.getTopologyId()); + topologyMountUrlTemplate = topologyUrl + MOUNT_URL_TEMPLATE; + } + + /** + * This method fetches list of modules usind sdnc client. + * + * @param nodeId node id for node + * @return returns {@code ResponseEntity} which contains list of modules + */ + public ResponseEntity getModulesFromNode(final String nodeId) { + final String urlWithNodeId = prepareGetSchemaUrl(nodeId); + return sdncRestconfClient.getOperation(urlWithNodeId); + } + + @NotNull + private String prepareGetSchemaUrl(final String nodeId) { + final String topologyMountUrl = topologyMountUrlTemplate; + final String topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId); + final String resourceUrl = topologyMountUrlWithNodeId.concat(GET_SCHEMA_URL); + return resourceUrl; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6a0cf975..408fc103 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -53,4 +53,11 @@ cps-core: dmiRegistrationUrl : /cps-ncmp/api/ncmp-dmi/v1/ch auth: username: ${CPS_CORE_USERNAME} - password: ${CPS_CORE_PASSWORD} \ No newline at end of file + password: ${CPS_CORE_PASSWORD} + +sdnc: + baseUrl: http://${SDNC_HOST}:${SDNC_PORT} + topologyId: ${SDNC_TOPOLOGY_ID:topology-netconf} + auth: + username: ${SDNC_USERNAME} + password: ${SDNC_PASSWORD} diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy index f8b4c015..f249de92 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy @@ -20,19 +20,21 @@ package org.onap.cps.ncmp.dmi.rest.controller +import org.onap.cps.ncmp.dmi.exception.DmiException +import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException import org.onap.cps.ncmp.dmi.service.DmiService - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get - import org.spockframework.spring.SpringBean -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc -import org.springframework.http.HttpStatus import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc import spock.lang.Specification +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post + @WebMvcTest @AutoConfigureMockMvc(addFilters = false) class DmiRestControllerSpec extends Specification { @@ -43,22 +45,40 @@ class DmiRestControllerSpec extends Specification { @Autowired private MockMvc mvc - @Value('${rest.api.dmi-base-path}') - def basePath - - def 'Get Hello World'() { - given: 'hello world endpoint' - def helloWorldEndpoint = "$basePath/v1/helloworld" + @Value('${rest.api.dmi-base-path}/v1') + def basePathV1 - when: 'get hello world api is invoked' - def response = mvc.perform( - get(helloWorldEndpoint) - ).andReturn().response - - then: 'Response Status is OK and contains expected text' + def 'Get all modules for given cm handle.'() { + given: 'REST endpoint for getting all modules' + def getModuleUrl = "$basePathV1/ch/node1/modules" + and: 'get modules for cm-handle returns a json' + def someJson = 'some-json' + mockDmiService.getModulesForCmHandle('node1') >> someJson + when: 'post is being called' + def response = mvc.perform( post(getModuleUrl) + .contentType(MediaType.APPLICATION_JSON)) + .andReturn().response + then: 'status is OK' response.status == HttpStatus.OK.value() - then: 'the java API was called with the correct parameters' - 1 * mockDmiService.getHelloWorld() + and: 'the response content matches the result from the DMI service' + response.getContentAsString() == someJson } + def 'Get all modules for given cm handle with exception handling of #scenario.'() { + given: 'REST endpoint for getting all modules' + def getModuleUrl = "$basePathV1/ch/node1/modules" + and: 'get modules for cm-handle throws #exceptionClass' + mockDmiService.getModulesForCmHandle('node1') >> { throw Mock(exceptionClass) } + when: 'post is invoked' + def response = mvc.perform( post(getModuleUrl) + .contentType(MediaType.APPLICATION_JSON)) + .andReturn().response + then: 'response status is #expectedResponse' + response.status == expectedResponse + where: 'the scenario is #scenario' + scenario | exceptionClass || expectedResponse + 'dmi service exception' | DmiException.class || HttpStatus.INTERNAL_SERVER_ERROR.value() + 'no modules found' | ModulesNotFoundException.class || HttpStatus.NOT_FOUND.value() + 'any other runtime exception' | RuntimeException.class || HttpStatus.INTERNAL_SERVER_ERROR.value() + } } diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy index 2124c9b4..66612960 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy @@ -20,15 +20,54 @@ package org.onap.cps.ncmp.dmi.service - +import org.onap.cps.ncmp.dmi.exception.DmiException +import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException +import org.onap.cps.ncmp.dmi.service.operation.SdncOperations +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity import spock.lang.Specification class DmiServiceImplSpec extends Specification { + def objectUnderTest = new DmiServiceImpl() - def 'Retrieve Hello World'() { - expect: 'Hello World is Returned' - objectUnderTest.getHelloWorld() == 'Hello World' + def mockSdncOperations = Mock(SdncOperations) + + def setup() { + objectUnderTest.sdncOperations = mockSdncOperations + } + + def 'Call get modules for cm-handle on dmi Service.'() { + given: 'cm handle id' + def cmHandle = 'node1' + and: 'request operation returns OK' + def body = 'body' + mockSdncOperations.getModulesFromNode(cmHandle) >> new ResponseEntity(body, HttpStatus.OK) + when: 'get modules for cm-handle is called' + def result = objectUnderTest.getModulesForCmHandle(cmHandle) + then: 'result is equal to the response from the SDNC service' + result == body + } + + def 'Call get modules for cm-handle and SDNC returns "bad request" status.'() { + given: 'cm handle id' + def cmHandle = 'node1' + and: 'get modules from node returns "bad request" status' + mockSdncOperations.getModulesFromNode(cmHandle) >> new ResponseEntity('body', HttpStatus.BAD_REQUEST) + when: 'get modules for cm-handle is called' + objectUnderTest.getModulesForCmHandle(cmHandle) + then: 'dmi exception is thrown' + thrown( DmiException ) } + def 'Call get modules for cm-handle and SDNC returns OK with empty body.'() { + given: 'cm handle id' + def cmHandle = 'node1' + and: 'get modules for cm-handle returns OK with empty body' + mockSdncOperations.getModulesFromNode(cmHandle) >> new ResponseEntity('', HttpStatus.OK) + when: 'get modules for cm-handle is called' + objectUnderTest.getModulesForCmHandle(cmHandle) + then: 'ModulesNotFoundException is thrown' + thrown( ModulesNotFoundException ) + } } diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/NcmpRestClientSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/NcmpRestClientSpec.groovy index 4f929865..f5c059c7 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/NcmpRestClientSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/NcmpRestClientSpec.groovy @@ -20,14 +20,14 @@ package org.onap.cps.ncmp.dmi.service.client -import org.onap.cps.ncmp.dmi.config.CpsConfiguration +import org.onap.cps.ncmp.dmi.config.DmiConfiguration import org.springframework.http.ResponseEntity import org.springframework.web.client.RestTemplate import spock.lang.Specification class NcmpRestClientSpec extends Specification { def objectUnderTest = new NcmpRestClient(mockCpsProperties, mockRestTemplate) - def mockCpsProperties = Mock(CpsConfiguration.CpsProperties) + def mockCpsProperties = Mock(DmiConfiguration.CpsProperties) def mockRestTemplate = Mock(RestTemplate) def setup() { @@ -45,12 +45,12 @@ class NcmpRestClientSpec extends Specification { mockCpsProperties.authPassword >> 'some-password' and: 'the rest template returns a valid response entity' def mockResponseEntity = Mock(ResponseEntity) - when: 'registerCmHandle is invoked' + when: 'register cm-handle with ncmp is invoked' def result = objectUnderTest.registerCmHandlesWithNcmp(jsonData) then: 'the rest template is called with the correct uri and json in the body' 1 * mockRestTemplate.postForEntity({ it.toString() == 'http://some-uri/some-url' }, { it.body.contains(jsonData) }, String.class) >> mockResponseEntity - and: 'the output of the method is the same as the output from the test template' + and: 'the output of the method is equal to the output from the test template' result == mockResponseEntity } } \ No newline at end of file diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy new file mode 100644 index 00000000..0b192f05 --- /dev/null +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.service.client + +import org.onap.cps.ncmp.dmi.config.DmiConfiguration +import org.springframework.http.HttpEntity +import org.springframework.http.HttpMethod +import org.springframework.http.ResponseEntity +import org.springframework.web.client.RestTemplate +import spock.lang.Specification + +class SdncRestconfClientSpec extends Specification { + + def mockSdncProperties = Mock(DmiConfiguration.SdncProperties) + def mockRestTemplate = Mock(RestTemplate) + def objectUnderTest = new SdncRestconfClient(mockSdncProperties, mockRestTemplate) + + def 'SDNC GET operation.'() { + given: 'a get url' + def getResourceUrl = '/getResourceUrl' + and: 'sdnc properties' + mockSdncProperties.baseUrl >> 'http://test-sdnc-uri' + mockSdncProperties.authUsername >> 'test-username' + mockSdncProperties.authPassword >> 'test-password' + mockSdncProperties.topologyId >> 'testTopologyId' + and: 'the rest template returns a valid response entity' + def mockResponseEntity = Mock(ResponseEntity) + mockRestTemplate.getForEntity({ it.toString() == 'http://test-sdnc-uri/getResourceUrl' }, String.class, _ as HttpEntity) >> mockResponseEntity + when: 'GET operation is invoked' + def result = objectUnderTest.getOperation(getResourceUrl) + then: 'the output of the method is equal to the output from the test template' + result == mockResponseEntity + } +} \ No newline at end of file diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy new file mode 100644 index 00000000..956834ad --- /dev/null +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy @@ -0,0 +1,44 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.service.operation + +import org.onap.cps.ncmp.dmi.config.DmiConfiguration +import org.onap.cps.ncmp.dmi.service.client.SdncRestconfClient +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import spock.lang.Specification + +class SdncOperationsSpec extends Specification { + def mockSdncProperties = Mock(DmiConfiguration.SdncProperties) + def mockSdncRestClient = Mock(SdncRestconfClient) + + def 'call get modules from node to SDNC.'() { + given: 'nodeid, topology-id, responseentity' + def nodeId = 'node1' + def expectedUrl = '/rests/data/network-topology:network-topology/topology=test-topology/node=node1/yang-ext:mount/ietf-netconf-monitoring:netconf-state/schemas' + mockSdncProperties.getTopologyId() >> 'test-topology' + def objectUnderTest = new SdncOperations(mockSdncProperties, mockSdncRestClient) + when: 'called get modules from node' + objectUnderTest.getModulesFromNode(nodeId) + then: 'the get operation is executed with the correct URL' + 1 * mockSdncRestClient.getOperation(expectedUrl) + } +} -- cgit 1.2.3-korg