</configOptions>
</configuration>
</execution>
- <execution>
- <id>ncmp-code-gen-provmns</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <inputSpec>https://forge.3gpp.org/rep/all/5G_APIs/-/raw/REL-18/TS28532_ProvMnS.yaml</inputSpec>
- <invokerPackage>org.onap.cps.ncmp.rest.provmns.controller</invokerPackage>
- <modelPackage>org.onap.cps.ncmp.rest.provmns.model</modelPackage>
- <apiPackage>org.onap.cps.ncmp.rest.provmns.api</apiPackage>
- <generatorName>spring</generatorName>
- <generateSupportingFiles>false</generateSupportingFiles>
- <configOptions>
- <sourceFolder>src/gen/java</sourceFolder>
- <dateLibrary>java11</dateLibrary>
- <interfaceOnly>true</interfaceOnly>
- <useSpringBoot3>true</useSpringBoot3>
- <useTags>true</useTags>
- <openApiNullable>false</openApiNullable>
- <skipDefaultInterface>true</skipDefaultInterface>
- </configOptions>
- <importMappings>
- <importMapping>Resource=org.onap.cps.ncmp.rest.provmns.model.Resource</importMapping>
- <importMapping>ClassNameIdGetDataNodeSelectorParameter=org.onap.cps.ncmp.rest.provmns.model.ClassNameIdGetDataNodeSelectorParameter</importMapping>
- </importMappings>
- <ignoreFileOverride>${project.basedir}/.openapi-generator-ignore-provmns</ignoreFileOverride>
- </configuration>
- </execution>
<execution>
<id>ncmp-inventory-openapi-yaml-gen</id>
<goals>
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.List;
+import org.onap.cps.ncmp.impl.provmns.model.ClassNameIdGetDataNodeSelectorParameter;
+import org.onap.cps.ncmp.impl.provmns.model.ClassNameIdPatchDefaultResponse;
+import org.onap.cps.ncmp.impl.provmns.model.ErrorResponseDefault;
+import org.onap.cps.ncmp.impl.provmns.model.ErrorResponseGet;
+import org.onap.cps.ncmp.impl.provmns.model.Resource;
+import org.onap.cps.ncmp.impl.provmns.model.Scope;
import org.onap.cps.ncmp.rest.model.ErrorMessage;
-import org.onap.cps.ncmp.rest.provmns.model.ClassNameIdGetDataNodeSelectorParameter;
-import org.onap.cps.ncmp.rest.provmns.model.ClassNameIdPatchDefaultResponse;
-import org.onap.cps.ncmp.rest.provmns.model.ErrorResponseDefault;
-import org.onap.cps.ncmp.rest.provmns.model.ErrorResponseGet;
-import org.onap.cps.ncmp.rest.provmns.model.Resource;
-import org.onap.cps.ncmp.rest.provmns.model.Scope;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@Tag(name = "ProvMnS", description = "Provisioning Management Service")
public interface ProvMnS {
- /**
- * DELETE /{URI-LDN-first-part}/{className}={id} : Deletes one resource
- * With HTTP DELETE one resource is deleted. The resources to be deleted is identified with the target URI.
- *
- * @param httpServletRequest (required)
- * @return Success case "200 OK". This status code is returned, when the resource has been successfully deleted.
- * The response body is empty. (status code 200)
- * or Error case. (status code 200)
- */
- @Operation(
- operationId = "deleteMoi",
- summary = "Deletes one resource",
- description = "With HTTP DELETE one resource is deleted. "
- + "The resources to be deleted is identified with the target URI.",
- responses = {
- @ApiResponse(responseCode = "200",
- description = "Success case (\"200 OK\"). This status code is returned, "
- + "when the resource has been successfully deleted. The response body is empty."),
- @ApiResponse(responseCode = "422", description = "Invalid Path Exception", content = {
- @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorMessage.class))
- }),
- @ApiResponse(responseCode = "default", description = "Error case.", content = {
- @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponseDefault.class))
- })
- }
- )
- @DeleteMapping(
- value = "v1/**",
- produces = { "application/json" }
- )
- ResponseEntity<Void> deleteMoi(HttpServletRequest httpServletRequest);
-
-
/**
* GET /{URI-LDN-first-part}/{className}={id} : Reads one or multiple resources
* With HTTP GET resources are read. The resources to be retrieved are identified with the target URI.
@Valid @RequestBody Resource resource
);
+ /**
+ * DELETE /{URI-LDN-first-part}/{className}={id} : Deletes one resource
+ * With HTTP DELETE one resource is deleted. The resources to be deleted is identified with the target URI.
+ *
+ * @param httpServletRequest (required)
+ * @return Success case "200 OK". This status code is returned, when the resource has been successfully deleted.
+ * The response body is empty. (status code 200)
+ * or Error case. (status code 200)
+ */
+ @Operation(
+ operationId = "deleteMoi",
+ summary = "Deletes one resource",
+ description = "With HTTP DELETE one resource is deleted. "
+ + "The resources to be deleted is identified with the target URI.",
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Success case (\"200 OK\"). This status code is returned, "
+ + "when the resource has been successfully deleted. The response body is empty."),
+ @ApiResponse(responseCode = "422", description = "Invalid Path Exception", content = {
+ @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorMessage.class))
+ }),
+ @ApiResponse(responseCode = "default", description = "Error case.", content = {
+ @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponseDefault.class))
+ })
+ }
+ )
+ @DeleteMapping(
+ value = "v1/**",
+ produces = { "application/json" }
+ )
+ ResponseEntity<Void> deleteMoi(HttpServletRequest httpServletRequest);
+
}
\ No newline at end of file
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.rest.provmns.model.ClassNameIdGetDataNodeSelectorParameter;
-import org.onap.cps.ncmp.rest.provmns.model.Resource;
-import org.onap.cps.ncmp.rest.provmns.model.Scope;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+import org.onap.cps.ncmp.impl.provmns.model.ClassNameIdGetDataNodeSelectorParameter;
+import org.onap.cps.ncmp.impl.provmns.model.Resource;
+import org.onap.cps.ncmp.impl.provmns.model.Scope;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.onap.cps.ncmp.rest.util.ProvMnSParametersMapper;
import org.onap.cps.ncmp.rest.util.ProvMnsRequestParameters;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-@Slf4j
@RestController
@RequestMapping("${rest.api.provmns-base-path}")
@RequiredArgsConstructor
public class ProvMnsController implements ProvMnS {
- /**
- * Replaces a complete single resource or creates it if it does not exist.
- *
- * @param httpServletRequest URI request including path
- * @param resource Resource representation of the resource to be created or replaced
- * @return {@code ResponseEntity} The representation of the updated resource is returned in the response
- * message body.
- */
- @Override
- public ResponseEntity<Resource> putMoi(final HttpServletRequest httpServletRequest, final Resource resource) {
- final ProvMnsRequestParameters provMnsRequestParameters =
- ProvMnsRequestParameters.toProvMnsRequestParameters(httpServletRequest);
- return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
- }
+ private final AlternateIdMatcher alternateIdMatcher;
+ private final DmiRestClient dmiRestClient;
+ private final InventoryPersistence inventoryPersistence;
+ private final ProvMnSParametersMapper provMnsParametersMapper;
- /**
- * Reads one or multiple resources.
- *
- * @param httpServletRequest URI request including path
- * @param scope Extends the set of targeted resources beyond the base
- * resource identified with the authority and path component of
- * the URI.
- * @param filter Reduces the targeted set of resources by applying a filter to
- * the scoped set of resource representations. Only resources
- * representations for which the filter construct evaluates to
- * "true" are targeted.
- * @param attributes Attributes of the scoped resources to be returned. The
- * value is a comma-separated list of attribute names.
- * @param fields Attribute fields of the scoped resources to be returned. The
- * value is a comma-separated list of JSON pointers to the
- * attribute fields.
- * @param dataNodeSelector dataNodeSelector object
- * @return {@code ResponseEntity} The resources identified in the request for retrieval are returned
- * in the response message body.
- */
@Override
public ResponseEntity<Resource> getMoi(final HttpServletRequest httpServletRequest, final Scope scope,
final String filter, final List<String> attributes,
final List<String> fields,
final ClassNameIdGetDataNodeSelectorParameter dataNodeSelector) {
final ProvMnsRequestParameters requestParameters =
- ProvMnsRequestParameters.toProvMnsRequestParameters(httpServletRequest);
- return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ ProvMnsRequestParameters.extractProvMnsRequestParameters(httpServletRequest);
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(
+ alternateIdMatcher.getCmHandleId(requestParameters.getAlternateId()));
+ provMnsParametersMapper.checkDataProducerIdentifier(yangModelCmHandle);
+ final UrlTemplateParameters urlTemplateParameters = provMnsParametersMapper.getUrlTemplateParameters(scope,
+ filter, attributes,
+ fields, dataNodeSelector,
+ yangModelCmHandle);
+ return dmiRestClient.synchronousGetOperation(
+ RequiredDmiService.DATA, urlTemplateParameters, OperationType.READ);
}
- /**
- * Patches (Create, Update or Delete) one or multiple resources.
- *
- * @param httpServletRequest URI request including path
- * @param resource Resource representation of the resource to be created or replaced
- * @return {@code ResponseEntity} The updated resource representations are returned in the response message body.
- */
@Override
public ResponseEntity<Resource> patchMoi(final HttpServletRequest httpServletRequest, final Resource resource) {
final ProvMnsRequestParameters requestParameters =
- ProvMnsRequestParameters.toProvMnsRequestParameters(httpServletRequest);
+ ProvMnsRequestParameters.extractProvMnsRequestParameters(httpServletRequest);
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+
+ @Override
+ public ResponseEntity<Resource> putMoi(final HttpServletRequest httpServletRequest, final Resource resource) {
+ final ProvMnsRequestParameters provMnsRequestParameters =
+ ProvMnsRequestParameters.extractProvMnsRequestParameters(httpServletRequest);
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
- /**
- * Delete one or multiple resources.
- *
- * @param httpServletRequest URI request including path
- * @return {@code ResponseEntity} The response body is empty, HTTP status returned.
- */
@Override
public ResponseEntity<Void> deleteMoi(final HttpServletRequest httpServletRequest) {
final ProvMnsRequestParameters requestParameters =
- ProvMnsRequestParameters.toProvMnsRequestParameters(httpServletRequest);
+ ProvMnsRequestParameters.extractProvMnsRequestParameters(httpServletRequest);
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 OpenInfra Foundation Europe
+ * ================================================================================
+ * 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.rest.util;
+
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.exceptions.NcmpException;
+import org.onap.cps.ncmp.impl.dmi.DmiServiceAuthenticationProperties;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.provmns.model.ClassNameIdGetDataNodeSelectorParameter;
+import org.onap.cps.ncmp.impl.provmns.model.Scope;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class ProvMnSParametersMapper {
+
+ private final DmiServiceAuthenticationProperties dmiServiceAuthenticationProperties;
+
+ /**
+ * Creates a UrlTemplateParameters object containing the relevant fields for a get.
+ *
+ * @param scope Provided className parameter.
+ * @param filter Filter string.
+ * @param attributes Attributes List.
+ * @param fields Fields list
+ * @param dataNodeSelector dataNodeSelector parameter
+ * @param yangModelCmHandle yangModelCmHandle object for resolved alternate ID
+ * @return UrlTemplateParameters object.
+ */
+ public UrlTemplateParameters getUrlTemplateParameters(final Scope scope, final String filter,
+ final List<String> attributes, final List<String> fields,
+ final ClassNameIdGetDataNodeSelectorParameter dataNodeSelector,
+ final YangModelCmHandle yangModelCmHandle) {
+
+ return RestServiceUrlTemplateBuilder.newInstance()
+ .queryParameter("scopeType", scope.getScopeType() != null
+ ? scope.getScopeType().getValue() : null)
+ .queryParameter("scopeLevel", scope.getScopeLevel() != null
+ ? scope.getScopeLevel().toString() : null)
+ .queryParameter("filter", filter)
+ .queryParameter("attributes", attributes != null ? attributes.toString() : null)
+ .queryParameter("fields", fields != null ? fields.toString() : null)
+ .queryParameter("dataNodeSelector", dataNodeSelector.getDataNodeSelector() != null
+ ? dataNodeSelector.getDataNodeSelector() : null)
+ .createUrlTemplateParameters(yangModelCmHandle.getDmiServiceName(), "ProvMnS");
+ }
+
+ /**
+ * Check if dataProducerIdentifier is empty or null, if so throw exception.
+ *
+ * @param yangModelCmHandle given yangModelCmHandle.
+ */
+ public void checkDataProducerIdentifier(final YangModelCmHandle yangModelCmHandle) {
+ if (yangModelCmHandle.getDataProducerIdentifier() == null
+ || yangModelCmHandle.getDataProducerIdentifier().isEmpty()) {
+ throw new NcmpException("No data producer identifier registered for cm handle",
+ "Cm Handle " + yangModelCmHandle.getId() + " has empty data producer identifier");
+ }
+ }
+}
private static final String PROVMNS_BASE_PATH = "ProvMnS/v\\d+/";
+ /**
+ * Gets alternate id from combining URI-LDN-First-Part, className and Id.
+ *
+ * @return String of Alternate Id.
+ */
+ public String getAlternateId() {
+ return uriLdnFirstPart + "/" + className + "=" + id;
+ }
+
/**
* Converts HttpServletRequest to ProvMnsRequestParameters.
*
* @param httpServletRequest HttpServletRequest object containing the path
* @return ProvMnsRequestParameters object containing parsed parameters
*/
- public static ProvMnsRequestParameters toProvMnsRequestParameters(final HttpServletRequest httpServletRequest) {
+ public static ProvMnsRequestParameters extractProvMnsRequestParameters(
+ final HttpServletRequest httpServletRequest) {
final String uriPath = (String) httpServletRequest.getAttribute(
"org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping");
import org.onap.cps.ncmp.impl.data.NcmpCachedResourceRequestHandler
import org.onap.cps.ncmp.impl.data.NcmpPassthroughResourceRequestHandler
import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient
import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
import org.onap.cps.ncmp.rest.provmns.exception.InvalidPathException
import org.onap.cps.ncmp.rest.util.CmHandleStateMapper
import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper
import org.onap.cps.api.exceptions.CpsException
import org.onap.cps.api.exceptions.DataNodeNotFoundException
import org.onap.cps.api.exceptions.DataValidationException
+import org.onap.cps.ncmp.rest.util.ProvMnSParametersMapper
import org.onap.cps.ncmp.rest.util.RestOutputCmHandleMapper
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
@SpringBean
RestOutputCmHandleMapper mockRestOutputCmHandleMapper = Mock()
+ @SpringBean
+ ProvMnSParametersMapper provMnSParametersMapper = Mock()
+
+ @SpringBean
+ AlternateIdMatcher alternateIdMatcher = Mock()
+
+ @SpringBean
+ DmiRestClient dmiRestClient = Mock()
+
@Value('${rest.api.ncmp-base-path}')
def basePathNcmp
package org.onap.cps.ncmp.rest.controller
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.rest.provmns.model.ResourceOneOf
+import jakarta.servlet.ServletException
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.ncmp.impl.provmns.model.ResourceOneOf
+import org.onap.cps.ncmp.rest.util.ProvMnSParametersMapper
import org.onap.cps.utils.JsonObjectMapper
+import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.HttpStatus
+import org.springframework.http.HttpStatusCode
import org.springframework.http.MediaType
+import org.springframework.http.ResponseEntity
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification
@WebMvcTest(ProvMnsController)
class ProvMnsControllerSpec extends Specification {
+ @SpringBean
+ ProvMnSParametersMapper provMnSParametersMapper = new ProvMnSParametersMapper()
+
+ @SpringBean
+ AlternateIdMatcher alternateIdMatcher = Mock()
+
+ @SpringBean
+ InventoryPersistence inventoryPersistence = Mock()
+
+ @SpringBean
+ DmiRestClient dmiRestClient = Mock()
+
@Autowired
MockMvc mvc
@Value('${rest.api.provmns-base-path}')
def provMnSBasePath
- def 'Get Resource Data from provmns interface.'() {
+ def 'Get Resource Data from provmns interface #scenario.'() {
given: 'resource data url'
- def getUrl = "$provMnSBasePath/v1/A=1/B=2/C=3"
+ def getUrl = "$provMnSBasePath/v1/someUriLdnFirstPart/someClassName=someId"+path
+ and: 'request classes return correct information'
+ inventoryPersistence.getYangModelCmHandle("cm-1") >> new YangModelCmHandle(dmiServiceName: "someDmiService", dataProducerIdentifier: 'someUriLdnFirstPart/someClassName=someId')
+ alternateIdMatcher.getCmHandleId("someUriLdnFirstPart/someClassName=someId") >> "cm-1"
+ dmiRestClient.synchronousGetOperation(*_) >> new ResponseEntity<Object>(HttpStatusCode.valueOf(200))
when: 'get data resource request is performed'
def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
- then: 'response status is Not Implemented (501)'
- assert response.status == HttpStatus.NOT_IMPLEMENTED.value()
+ then: 'response status is OK (200)'
+ assert response.status == HttpStatus.OK.value()
+ where:
+ scenario | path
+ 'with no query params' | ''
+ 'with query params' | '?attributes=[test,query,param]'
}
- def 'Put Resource Data from provmns interface.'() {
+ def 'Patch Resource Data from provmns interface.'() {
given: 'resource data url'
- def putUrl = "$provMnSBasePath/v1/A=1/B=2/C=3"
+ def patchUrl = "$provMnSBasePath/v1/someUriLdnFirstPart/someClassName=someId"
and: 'an example resource json object'
def jsonBody = jsonObjectMapper.asJsonString(new ResourceOneOf('test'))
- when: 'put data resource request is performed'
- def response = mvc.perform(put(putUrl)
- .contentType(MediaType.APPLICATION_JSON)
+ when: 'patch data resource request is performed'
+ def response = mvc.perform(patch(patchUrl)
+ .contentType(new MediaType('application', 'json-patch+json'))
.content(jsonBody))
.andReturn().response
then: 'response status is Not Implemented (501)'
assert response.status == HttpStatus.NOT_IMPLEMENTED.value()
}
- def 'Patch Resource Data from provmns interface.'() {
+ def 'Put Resource Data from provmns interface.'() {
given: 'resource data url'
- def patchUrl = "$provMnSBasePath/v1/A=1/B=2/C=3"
+ def putUrl = "$provMnSBasePath/v1/someUriLdnFirstPart/someClassName=someId"
and: 'an example resource json object'
def jsonBody = jsonObjectMapper.asJsonString(new ResourceOneOf('test'))
- when: 'patch data resource request is performed'
- def response = mvc.perform(patch(patchUrl)
- .contentType(new MediaType('application', 'json-patch+json'))
+ when: 'put data resource request is performed'
+ def response = mvc.perform(put(putUrl)
+ .contentType(MediaType.APPLICATION_JSON)
.content(jsonBody))
.andReturn().response
then: 'response status is Not Implemented (501)'
def 'Delete Resource Data from provmns interface.'() {
given: 'resource data url'
- def deleteUrl = "$provMnSBasePath/v1/A=1/B=2/C=3"
+ def deleteUrl = "$provMnSBasePath/v1/someUriLdnFirstPart/someClassName=someId"
when: 'delete data resource request is performed'
def response = mvc.perform(delete(deleteUrl)).andReturn().response
then: 'response status is Not Implemented (501)'
assert response.status == HttpStatus.NOT_IMPLEMENTED.value()
}
- def 'Get Resource Data from provmns interface with query param.'() {
- given: 'resource data url with query parameter'
- def getUrl = "$provMnSBasePath/v1/A=1/B=2/C=3?attributes=[test,query,param]"
+ def 'Invalid path passed in to provmns interface, #scenario'() {
+ given: 'an invalid path'
+ def url = "$provMnSBasePath/v1/" + invalidPath
when: 'get data resource request is performed'
- def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
- then: 'response status is Not Implemented (501)'
- assert response.status == HttpStatus.NOT_IMPLEMENTED.value()
+ mvc.perform(get(url).contentType(MediaType.APPLICATION_JSON))
+ then: 'invalid path exception is thrown'
+ thrown(ServletException)
+ where:
+ scenario | invalidPath
+ 'Missing URI-LDN-first-part' | 'someClassName=someId'
+ 'Missing ClassName and Id' | 'someUriLdnFirstPart/'
}
}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 OpenInfra Foundation Europe. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.cps.ncmp.rest.util
+
+import org.onap.cps.ncmp.api.exceptions.NcmpException
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.impl.provmns.model.ClassNameIdGetDataNodeSelectorParameter
+import org.onap.cps.ncmp.impl.provmns.model.Scope
+import spock.lang.Specification
+
+class ProvMnSParametersMapperSpec extends Specification{
+
+ def objectUnderTest = new ProvMnSParametersMapper()
+
+ def 'Extract url template parameters for GET'() {
+ when:'a set of given parameters from a call are passed in'
+ def result = objectUnderTest.getUrlTemplateParameters(new Scope(scopeLevel: 1, scopeType: 'BASE_ALL'),
+ 'some-filter', ['some-attribute'], ['some-field'], new ClassNameIdGetDataNodeSelectorParameter(dataNodeSelector: 'some-dataSelector'),
+ new YangModelCmHandle(dmiServiceName: 'some-dmi-service'))
+ then:'verify object has been mapped correctly'
+ result.urlVariables().get('filter') == 'some-filter'
+ }
+
+ def 'Data Producer Identifier validation.'() {
+ given:'a yangModelCmHandle'
+ def yangModelCmHandle = new YangModelCmHandle(dataProducerIdentifier: 'some-dataProducer-ID')
+ when:'a yangModelCmHandle is passed in'
+ def result = objectUnderTest.checkDataProducerIdentifier(yangModelCmHandle)
+ then: 'no exception thrown for yangModelCmHandle when a data producer is present'
+ noExceptionThrown()
+ }
+
+ def 'Data Producer Identifier validation with #scenario.'() {
+ given:'a yangModelCmHandle'
+ def yangModelCmHandle = new YangModelCmHandle(dataProducerIdentifier: dataProducerId)
+ when:'a data producer identifier is checked'
+ def result = objectUnderTest.checkDataProducerIdentifier(yangModelCmHandle)
+ then: 'exception thrown'
+ thrown(NcmpException)
+ where:
+ scenario | dataProducerId
+ 'null' | null
+ 'blank' | ''
+
+ }
+}
# Ignore generation of all the models for ProvMns
-target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/*.java
-target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/api/*.java
+target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/*.java
+target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/api/*.java
# Allow generation of the below model for ProvMns
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ClassNameIdPatchDefaultResponse.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ErrorResponseDefault.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ErrorResponseDefaultOtherProblemsInner.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ErrorResponseGet.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ErrorResponseGetOtherProblemsInner.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ErrorResponsePatch.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ErrorResponsePatchOtherProblemsInner.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/PatchItem.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/PatchOperation.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ResourceOneOf.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/Scope.java
-!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/rest/provmns/model/ScopeType.java
\ No newline at end of file
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ClassNameIdPatchDefaultResponse.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ErrorResponseDefault.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ErrorResponseDefaultOtherProblemsInner.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ErrorResponseGet.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ErrorResponseGetOtherProblemsInner.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ErrorResponsePatch.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ErrorResponsePatchOtherProblemsInner.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/PatchItem.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/PatchOperation.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ResourceOneOf.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/Scope.java
+!target/generated-sources/openapi/src/gen/java/org/onap/cps/ncmp/impl/provmns/model/ScopeType.java
\ No newline at end of file
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ </dependency>
</dependencies>
+ <build>
+ <plugins>
+ <!-- Swagger code generation. -->
+ <plugin>
+ <groupId>org.openapitools</groupId>
+ <artifactId>openapi-generator-maven-plugin</artifactId>
+ <version>7.12.0</version>
+ <executions>
+ <execution>
+ <id>ncmp-code-gen-provmns</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>https://forge.3gpp.org/rep/all/5G_APIs/-/raw/REL-18/TS28532_ProvMnS.yaml</inputSpec>
+ <invokerPackage>org.onap.cps.ncmp.impl.provmns.controller</invokerPackage>
+ <modelPackage>org.onap.cps.ncmp.impl.provmns.model</modelPackage>
+ <apiPackage>org.onap.cps.ncmp.impl.provmns.api</apiPackage>
+ <generatorName>spring</generatorName>
+ <generateSupportingFiles>false</generateSupportingFiles>
+ <configOptions>
+ <sourceFolder>src/gen/java</sourceFolder>
+ <dateLibrary>java11</dateLibrary>
+ <interfaceOnly>true</interfaceOnly>
+ <useSpringBoot3>true</useSpringBoot3>
+ <useTags>true</useTags>
+ <openApiNullable>false</openApiNullable>
+ <skipDefaultInterface>true</skipDefaultInterface>
+ </configOptions>
+ <importMappings>
+ <importMapping>Resource=org.onap.cps.ncmp.impl.provmns.model.Resource</importMapping>
+ <importMapping>ClassNameIdGetDataNodeSelectorParameter=org.onap.cps.ncmp.impl.provmns.model.ClassNameIdGetDataNodeSelectorParameter</importMapping>
+ </importMappings>
+ <ignoreFileOverride>${project.basedir}/.openapi-generator-ignore-provmns</ignoreFileOverride>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(cmResourceAddress
.datastoreName(), yangModelCmHandle, cmResourceAddress.resourceIdentifier(), options, topic);
- return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ,
+ return dmiRestClient.asynchronousPostOperation(DATA, urlTemplateParameters, jsonRequestBody, READ,
authorization);
}
final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(
PASSTHROUGH_OPERATIONAL.getDatastoreName(), yangModelCmHandle, "/", options,
null);
- return dmiRestClient.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ,
+ return dmiRestClient.synchronousPostOperation(DATA, urlTemplateParameters, jsonRequestBody, READ,
DmiRestClient.NO_AUTHORIZATION);
}
final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(
PASSTHROUGH_RUNNING.getDatastoreName(), yangModelCmHandle, resourceId, null,
null);
- return dmiRestClient.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody,
+ return dmiRestClient.synchronousPostOperation(DATA, urlTemplateParameters, jsonRequestBody,
operationType, authorization);
}
final List<DmiDataOperation> dmiDataOperations = entry.getValue();
final String dmiDataOperationRequestAsJsonString
= createDmiDataOperationRequestAsJsonString(dmiDataOperations);
- return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters,
+ return dmiRestClient.asynchronousPostOperation(DATA, urlTemplateParameters,
dmiDataOperationRequestAsJsonString, READ, authorization)
.then()
.onErrorResume(DmiClientRequestException.class, dmiClientRequestException -> {
final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(dataJobMetadata.destination(),
producerKey);
- final ResponseEntity<Object> responseEntity = dmiRestClient.synchronousPostOperationWithJsonData(
+ final ResponseEntity<Object> responseEntity = dmiRestClient.synchronousPostOperation(
RequiredDmiService.DATA,
urlTemplateParameters,
jsonObjectMapper.asJsonString(subJobWriteRequest),
import org.onap.cps.ncmp.api.data.models.OperationType;
import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException;
import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+import org.onap.cps.ncmp.impl.provmns.model.Resource;
import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
* @return ResponseEntity containing the response from the DMI.
* @throws DmiClientRequestException If there is an error during the DMI request.
*/
- public ResponseEntity<Object> synchronousPostOperationWithJsonData(final RequiredDmiService requiredDmiService,
- final UrlTemplateParameters
- urlTemplateParameters,
- final String requestBodyAsJsonString,
- final OperationType operationType,
- final String authorization) {
+ public ResponseEntity<Object> synchronousPostOperation(final RequiredDmiService requiredDmiService,
+ final UrlTemplateParameters urlTemplateParameters,
+ final String requestBodyAsJsonString,
+ final OperationType operationType,
+ final String authorization) {
final Mono<ResponseEntity<Object>> responseEntityMono =
- asynchronousPostOperationWithJsonData(requiredDmiService,
+ asynchronousPostOperation(requiredDmiService,
urlTemplateParameters,
requestBodyAsJsonString,
operationType,
* @param authorization The authorization token to be added to the request headers.
* @return A Mono emitting the response entity containing the server's response.
*/
- public Mono<ResponseEntity<Object>> asynchronousPostOperationWithJsonData(final RequiredDmiService
+ public Mono<ResponseEntity<Object>> asynchronousPostOperation(final RequiredDmiService
requiredDmiService,
final UrlTemplateParameters
urlTemplateParameters,
.onErrorMap(throwable -> handleDmiClientException(throwable, operationType.getOperationName()));
}
+ /**
+ * Sends a synchronous (blocking) GET operation to the DMI.
+ *
+ * @param requiredDmiService Determines if the required service is for a data or model operation.
+ * @param urlTemplateParameters The DMI resource URL template with variables.
+ * @param operationType The type of operation being executed (for error reporting only).
+ * @return ResponseEntity containing the response from the DMI.
+ * @throws DmiClientRequestException If there is an error during the DMI request.
+ */
+ public ResponseEntity<Resource> synchronousGetOperation(final RequiredDmiService requiredDmiService,
+ final UrlTemplateParameters
+ urlTemplateParameters,
+ final OperationType operationType) {
+ return getWebClient(requiredDmiService)
+ .get()
+ .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
+ .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
+ .retrieve()
+ .toEntity(Resource.class)
+ .onErrorMap(throwable -> handleDmiClientException(throwable, operationType.getOperationName()))
+ .block();
+ }
+
/**
* Retrieves the health status of the DMI plugin.
* This method performs an HTTP GET request to the DMI health check endpoint specified by the URL template
.variablePathSegment("cmHandleId", cmHandle)
.fixedPathSegment(resourceName)
.createUrlTemplateParameters(dmiServiceName, dmiServiceAuthenticationProperties.getDmiBasePath());
- return dmiRestClient.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, jsonRequestBody, READ,
+ return dmiRestClient.synchronousPostOperation(MODEL, urlTemplateParameters, jsonRequestBody, READ,
null);
}
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.provmns.model;
+package org.onap.cps.ncmp.impl.provmns.model;
import lombok.Getter;
import lombok.Setter;
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.provmns.model;
+package org.onap.cps.ncmp.impl.provmns.model;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.onap.cps.ncmp.impl.provmns.model.ResourceOneOf;
/**
* This interface serves as a replacement for the generated Resource class, which has dependencies on the NRM-related
def responseFromDmi = Mono.just(new ResponseEntity<Object>('{some-key:some-value}', HttpStatus.OK))
def expectedUrlTemplateWithVariables = getExpectedUrlTemplateWithVariables(expectedOptions, expectedDataStore)
def expectedJson = '{"operation":"read","cmHandleProperties":' + expectedProperties + ',"moduleSetTag":""}'
- mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
+ mockDmiRestClient.asynchronousPostOperation(DATA, expectedUrlTemplateWithVariables, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get resource data is invoked'
def cmResourceAddress = new CmResourceAddress(expectedDataStore.datastoreName, cmHandleId, resourceIdentifier)
def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, expectedOptions, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER).block()
def responseFromDmi = Mono.just(new ResponseEntity<Object>(HttpStatus.ACCEPTED))
def expectedUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/data?requestId={requestId}&topic={topic}', ['requestId': 'requestId', 'topic': 'my-topic-name'])
def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","moduleSetTag":"","cmHandleProperties":{"prop1":"val1"}}]}]}'
- mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, _, READ, NO_AUTH_HEADER) >> responseFromDmi
+ mockDmiRestClient.asynchronousPostOperation(DATA, expectedUrlTemplateWithVariables, _, READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get resource data for group of cm handles is invoked'
objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER)
then: 'the post operation was called with the expected URL and JSON request body'
- 1 * mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
+ 1 * mockDmiRestClient.asynchronousPostOperation(DATA, expectedUrlTemplateWithVariables, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
}
def 'Execute (async) data operation from DMI service with Exception.'() {
def actualDataOperationCloudEvent = null
eventsProducer.sendCloudEvent('my-topic-name', 'my-request-id', _) >> { args -> actualDataOperationCloudEvent = args[2] }
and: 'a DMI client request exception is thrown when DMI service is called'
- mockDmiRestClient.asynchronousPostOperationWithJsonData(*_) >> { Mono.error(new DmiClientRequestException(123, '', '', UNKNOWN_ERROR)) }
+ mockDmiRestClient.asynchronousPostOperation(*_) >> { Mono.error(new DmiClientRequestException(123, '', '', UNKNOWN_ERROR)) }
when: 'attempt to get resource data for group of cm handles is invoked'
objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'my-request-id', NO_AUTH_HEADER)
then: 'the event contains the expected error details'
def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
def expectedTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}&options={options}', ['resourceIdentifier': '/', 'datastore': 'ncmp-datastore:passthrough-operational', 'cmHandleId': cmHandleId, 'options': OPTIONS_PARAM])
def expectedJson = '{"operation":"read","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":"my-module-set-tag"}'
- mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedTemplateWithVariables, expectedJson, READ, null) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperation(DATA, expectedTemplateWithVariables, expectedJson, READ, null) >> responseFromDmi
when: 'get resource data is invoked'
def result = objectUnderTest.getAllResourceDataFromDmi(cmHandleId, NO_REQUEST_ID, OPTIONS_PARAM)
then: 'the result is the response from the DMI service'
def expectedUrlTemplateParameters = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}', ['resourceIdentifier': resourceIdentifier, 'datastore': 'ncmp-datastore:passthrough-running', 'cmHandleId': cmHandleId])
def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":""}'
def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
- mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedUrlTemplateParameters, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperation(DATA, expectedUrlTemplateParameters, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi
when: 'write resource method is invoked'
def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER)
then: 'the result is the response from the DMI service'
def responseAsKeyValuePairs = [subJobId:'my-sub-job-id']
def responseEntity = new ResponseEntity<>(responseAsKeyValuePairs, HttpStatus.OK)
def expectedJson = '{"destination":"d1","dataAcceptType":"t1","dataContentType":"t2","dataProducerId":"prod1","dataJobId":"some-job-id","data":[{"path":"p","op":"operation","moduleSetTag":"tag","value":null,"operationId":"o1"}]}'
- mockDmiRestClient.synchronousPostOperationWithJsonData(RequiredDmiService.DATA, _, expectedJson, OperationType.CREATE, authorization) >> responseEntity
+ mockDmiRestClient.synchronousPostOperation(RequiredDmiService.DATA, _, expectedJson, OperationType.CREATE, authorization) >> responseEntity
when: 'sending request to DMI invoked'
objectUnderTest.sendRequestsToDmi(authorization, dataJobId, dataJobMetadata, dmiWriteOperationsPerProducerKey)
then: 'the result contains the expected sub-job id'
mockDataServicesWebClient.post() >> mockRequestBody
mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Data service', HttpStatus.I_AM_A_TEAPOT))
when: 'POST operation is invoked fro Data Service'
- def response = objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
+ def response = objectUnderTest.synchronousPostOperation(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
then: 'the output of the method is equal to the output from the test template'
assert response.statusCode == HttpStatus.I_AM_A_TEAPOT
assert response.body == 'from Data service'
mockModelServicesWebClient.post() >> mockRequestBody
mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Model service', HttpStatus.I_AM_A_TEAPOT))
when: 'POST operation is invoked for Model Service'
- def response = objectUnderTest.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
+ def response = objectUnderTest.synchronousPostOperation(MODEL, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
then: 'the output of the method is equal to the output from the test template'
assert response.statusCode == HttpStatus.I_AM_A_TEAPOT
assert response.body == 'from Model service'
mockDataServicesWebClient.post() >> mockRequestBody
mockResponse.toEntity(Object.class) >> Mono.error(exceptionType)
when: 'POST operation is invoked'
- objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
+ objectUnderTest.synchronousPostOperation(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
then: 'a http client exception is thrown'
def thrown = thrown(DmiClientRequestException)
and: 'the exception has the relevant details from the error response'
and: 'a positive response from DMI service when it is called with the expected parameters'
def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']]
def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK)
- mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperation(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG)
then: 'the result consists of expected module references'
and: 'any response from DMI service when it is called with the expected parameters'
// TODO (toine): production code ignores any error code from DMI, this should be improved in future
def responseFromDmi = new ResponseEntity(bodyAsMap, HttpStatus.NO_CONTENT)
- mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperation(*_) >> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG)
then: 'the result is empty'
mockYangModelCmHandleRetrieval(additionalProperties)
and: 'a positive response from DMI service when it is called with tha expected parameters'
def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
- mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables,
+ mockDmiRestClient.synchronousPostOperation(MODEL, expectedModulesUrlTemplateWithVariables,
'{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'a get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG)
def responseFromDmi = new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'],
[moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK)
def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
- mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
+ mockDmiRestClient.synchronousPostOperation(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
'{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, newModuleReferences)
and: 'a positive response from DMI service when it is called with tha expected parameters'
// TODO (toine): production code ignores any error code from DMI, this should be improved in future
def responseFromDmi = new ResponseEntity(responseFromDmiBody, HttpStatus.NO_CONTENT)
- mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperation(*_) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, newModuleReferences)
then: 'the result is empty'
mockYangModelCmHandleRetrieval(additionalProperties)
and: 'a positive response from DMI service when it is called with the expected moduleSetTag, modules and properties'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
- mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
+ mockDmiRestClient.synchronousPostOperation(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
'{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}',
READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
mockYangModelCmHandleRetrieval([], moduleSetTag)
and: 'a positive response from DMI service when it is called with the expected moduleSetTag'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
- mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
+ mockDmiRestClient.synchronousPostOperation(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
'{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, moduleSetTag, newModuleReferences)
then: 'no resources are returned'
assert result == [:]
and: 'no request is sent to DMI'
- 0 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_)
+ 0 * mockDmiRestClient.synchronousPostOperation(*_)
}
def 'Retrieving yang resources from DMI with null DMI properties.'() {
when: 'get module references is called'
objectUnderTest.getModuleReferences(yangModelCmHandle, 'NEW-TAG')
then: 'a request was sent to DMI with the NEW module set tag in the body'
- 1 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> { args ->
+ 1 * mockDmiRestClient.synchronousPostOperation(*_) >> { args ->
def requestBodyAsJson = args[2] as String
assert requestBodyAsJson.contains('"moduleSetTag":"NEW-TAG"')
return new ResponseEntity([schemas: [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']]], HttpStatus.OK)
when: 'get new yang resources from DMI service'
objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, 'NEW-TAG', newModuleReferences)
then: 'a request was sent to DMI with the NEW module set tag in the body'
- 1 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> { args ->
+ 1 * mockDmiRestClient.synchronousPostOperation(*_) >> { args ->
def requestBodyAsJson = args[2] as String
assert requestBodyAsJson.contains('"moduleSetTag":"NEW-TAG"')
return new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'],
<exclude>org/onap/cps/rest/model/*</exclude>
<exclude>org/onap/cps/cpspath/parser/antlr4/*</exclude>
<exclude>org/onap/cps/ncmp/rest/model/*</exclude>
- <exclude>org/onap/cps/ncmp/rest/provmns/model/*</exclude>
<exclude>org/onap/cps/**/*MapperImpl.class</exclude>
<exclude>org/onap/cps/ncmp/rest/stub/*</exclude>
<exclude>org/onap/cps/policyexecutor/stub/model/*</exclude>
+ <exclude>org/onap/cps/ncmp/impl/provmns/model/*</exclude>
<exclude>**/pom.xml</exclude>
</excludes>
</configuration>
case ~'^/dmi/v1/cmwriteJob(.*)$':
return mockWriteJobResponse(request)
+ // provmns endpoint
+ case ~'^/ProvMnS/v1(.*)$':
+ dmiResourceDataUrl = request.path
+ return mockResponseWithBody(HttpStatus.OK, '{}')
+
default:
throw new IllegalArgumentException('Mock DMI does not implement endpoint ' + request.path)
}
package org.onap.cps.integration.functional.ncmp.provmns
import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.onap.cps.ncmp.rest.provmns.model.ResourceOneOf
+import org.onap.cps.ncmp.impl.provmns.model.ResourceOneOf
import org.springframework.http.MediaType
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
class ProvMnSRestApiSpec extends CpsIntegrationSpecBase{
def 'Get Resource Data from provmns interface.'() {
+ given: 'a registered cm handle'
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'A=1/B=2/C=3')
expect: 'not implemented response on GET endpoint'
mvc.perform(get("/ProvMnS/v1/A=1/B=2/C=3"))
- .andExpect(status().isNotImplemented())
+ .andExpect(status().is2xxSuccessful())
+ cleanup: 'deregister CM handles'
+ deregisterCmHandle(DMI1_URL, 'ch-1')
}
def 'Put Resource Data from provmns interface.'() {