package org.onap.cps.ncmp.rest.controller;
import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE;
-import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE;
import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA;
import static org.onap.cps.ncmp.impl.provmns.ParameterMapper.NO_OP;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.CONFLICT;
+import static org.springframework.http.HttpStatus.GATEWAY_TIMEOUT;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.NOT_ACCEPTABLE;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE;
+import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import io.netty.handler.timeout.TimeoutException;
import jakarta.servlet.http.HttpServletRequest;
if (patchItems.size() > maxNumberOfPatchOperations) {
final String title = patchItems.size() + " operations in request, this exceeds the maximum of "
+ maxNumberOfPatchOperations;
- throw new ProvMnSException(httpServletRequest.getMethod(), HttpStatus.PAYLOAD_TOO_LARGE, title, NO_OP);
+ throw new ProvMnSException(httpServletRequest.getMethod(), PAYLOAD_TOO_LARGE, title, NO_OP);
}
final RequestParameters requestParameters = parameterMapper.extractRequestParameters(httpServletRequest);
try {
final YangModelCmHandle yangModelCmHandle = getAndValidateYangModelCmHandle(requestParameters);
final CreateOperationDetails createOperationDetails =
operationDetailsFactory.buildCreateOperationDetails(CREATE, requestParameters, resource);
- checkPermission(yangModelCmHandle, CREATE, requestParameters.toTargetFdn(), createOperationDetails);
+ checkPermission(yangModelCmHandle, requestParameters.toTargetFdn(), createOperationDetails);
final String targetFdn = requestParameters.toTargetFdn();
final UrlTemplateParameters urlTemplateParameters =
parametersBuilder.createUrlTemplateParametersForWrite(yangModelCmHandle, targetFdn);
final YangModelCmHandle yangModelCmHandle = getAndValidateYangModelCmHandle(requestParameters);
final DeleteOperationDetails deleteOperationDetails =
operationDetailsFactory.buildDeleteOperationDetails(requestParameters.toTargetFdn());
- checkPermission(yangModelCmHandle, DELETE, requestParameters.toTargetFdn(), deleteOperationDetails);
+ checkPermission(yangModelCmHandle, requestParameters.toTargetFdn(), deleteOperationDetails);
final String targetFdn = requestParameters.toTargetFdn();
final UrlTemplateParameters urlTemplateParameters =
parametersBuilder.createUrlTemplateParametersForWrite(yangModelCmHandle, targetFdn);
final String cmHandleId = alternateIdMatcher.getCmHandleIdByLongestMatchingAlternateId(alternateId, "/");
final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
if (!StringUtils.hasText(yangModelCmHandle.getDataProducerIdentifier())) {
- throw new ProvMnSException(requestParameters.getHttpMethodName(), HttpStatus.UNPROCESSABLE_ENTITY,
+ throw new ProvMnSException(requestParameters.getHttpMethodName(), UNPROCESSABLE_ENTITY,
PROVMNS_NOT_SUPPORTED_ERROR_MESSAGE, NO_OP);
}
if (yangModelCmHandle.getCompositeState().getCmHandleState() != CmHandleState.READY) {
final String title = yangModelCmHandle.getId() + " is not in READY state. Current state: "
+ yangModelCmHandle.getCompositeState().getCmHandleState().name();
- throw new ProvMnSException(requestParameters.getHttpMethodName(), HttpStatus.NOT_ACCEPTABLE,
- title, NO_OP);
+ throw new ProvMnSException(requestParameters.getHttpMethodName(), NOT_ACCEPTABLE, title, NO_OP);
}
return yangModelCmHandle;
} catch (final NoAlternateIdMatchFoundException noAlternateIdMatchFoundException) {
final String title = alternateId + " not found";
- throw new ProvMnSException(requestParameters.getHttpMethodName(), HttpStatus.NOT_FOUND, title, NO_OP);
+ throw new ProvMnSException(requestParameters.getHttpMethodName(), NOT_FOUND, title, NO_OP);
}
}
private void checkPermission(final YangModelCmHandle yangModelCmHandle,
- final OperationType operationType,
final String alternateId,
final OperationDetails operationDetails) {
+ final OperationType operationType = OperationType.fromOperationName(operationDetails.operation());
final String operationDetailsAsJson = jsonObjectMapper.asJsonString(operationDetails);
policyExecutor.checkPermission(yangModelCmHandle, operationType, NO_AUTHORIZATION, alternateId,
operationDetailsAsJson);
for (final PatchItem patchItem : patchItems) {
final OperationDetails operationDetails =
operationDetailsFactory.buildOperationDetails(requestParameters, patchItem);
- final OperationType operationType = OperationType.fromOperationName(operationDetails.operation());
try {
- checkPermission(yangModelCmHandle, operationType, requestParameters.toTargetFdn(), operationDetails);
+ checkPermission(yangModelCmHandle, requestParameters.toTargetFdn(), operationDetails);
} catch (final Exception exception) {
- throw toProvMnSException("PATCH", exception, operationType.name());
+ final String httpMethodName = "PATCH";
+ final OperationType operationType = OperationType.fromOperationName(operationDetails.operation());
+ throw toProvMnSException(httpMethodName, exception, operationType.name());
}
}
}
provMnSException.setBadOp(badOp);
final HttpStatus httpStatus;
if (exception instanceof PolicyExecutorException) {
- httpStatus = HttpStatus.CONFLICT;
+ httpStatus = CONFLICT;
} else if (exception instanceof DataValidationException) {
- httpStatus = HttpStatus.BAD_REQUEST;
+ httpStatus = BAD_REQUEST;
} else if (exception.getCause() instanceof TimeoutException) {
- httpStatus = HttpStatus.GATEWAY_TIMEOUT;
+ httpStatus = GATEWAY_TIMEOUT;
} else {
- httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
+ httpStatus = INTERNAL_SERVER_ERROR;
}
provMnSException.setHttpStatus(httpStatus);
log.warn("ProvMns Exception: {}", provMnSException.getTitle());
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.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.test.web.servlet.MockMvc
import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.ADVISED
import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.READY
+import static org.springframework.http.HttpStatus.BAD_REQUEST
+import static org.springframework.http.HttpStatus.CONFLICT
+import static org.springframework.http.HttpStatus.GATEWAY_TIMEOUT
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
+import static org.springframework.http.HttpStatus.I_AM_A_TEAPOT
+import static org.springframework.http.HttpStatus.NOT_ACCEPTABLE
+import static org.springframework.http.HttpStatus.NOT_FOUND
+import static org.springframework.http.HttpStatus.OK
+import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE
+import static org.springframework.http.HttpStatus.SEE_OTHER
+import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY
+import static org.springframework.http.HttpStatus.UNSUPPORTED_MEDIA_TYPE
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
int maxNumberOfPatchOperations
static def NO_CONTENT = ''
- static def STATUS_NOT_RELEVANT = HttpStatus.SEE_OTHER
+ static def STATUS_NOT_RELEVANT = SEE_OTHER
def 'Get resource data #scenario.'() {
given: 'resource data url'
and: 'the content is whatever the DMI returned'
assert response.contentAsString == responseContentFromDmi
where: 'following responses returned by DMI'
- scenario | responseStatusFromDmi | responseContentFromDmi
- 'happy flow' | HttpStatus.OK | 'content from DMI'
- 'error from DMI' | HttpStatus.I_AM_A_TEAPOT | 'error details from DMI'
+ scenario | responseStatusFromDmi | responseContentFromDmi
+ 'happy flow' | OK | 'content from DMI'
+ 'error from DMI' | I_AM_A_TEAPOT | 'error details from DMI'
}
def 'Get resource data request with #scenario.'() {
and: 'persistence service returns yangModelCmHandle'
mockInventoryPersistence.getYangModelCmHandle('ch-1') >> yangModelCmHandle
and: 'dmi provides a response'
- mockDmiRestClient.synchronousGetOperation(*_) >> new ResponseEntity<>('Response from DMI service', HttpStatus.OK)
+ mockDmiRestClient.synchronousGetOperation(*_) >> new ResponseEntity<>('Response from DMI service', OK)
when: 'get data resource request is performed'
def response = mvc.perform(get(getUrl)).andReturn().response
then: 'response status as expected'
assert response.status == expectedHttpStatus.value()
- and: 'the body contains the expected data'
- assert response.contentAsString.contains(expectedInResponseBody)
+ and: 'the body contains the expected type'
+ assert response.contentAsString.contains('"type":"' + expectedType)
+ and: 'the body contains the expected title'
+ assert response.contentAsString.contains('"title":"' + expectedTitle)
where: 'following scenario'
- scenario | yangModelCmHandle || expectedHttpStatus | expectedInResponseBody
- 'no data producer id' | cmHandleWithoutDataProducer || HttpStatus.UNPROCESSABLE_ENTITY | '"title":"Registered DMI does not support the ProvMnS interface."'
- 'cm Handle NOT READY' | cmHandleNotReady || HttpStatus.NOT_ACCEPTABLE | '"title":"ch-1 is not in READY state. Current state: ADVISED"'
+ scenario | yangModelCmHandle || expectedHttpStatus | expectedType | expectedTitle
+ 'no data producer id' | cmHandleWithoutDataProducer || UNPROCESSABLE_ENTITY | 'SERVER_LIMITATION' | 'Registered DMI does not support the ProvMnS interface.'
+ 'cm Handle NOT READY' | cmHandleNotReady || NOT_ACCEPTABLE | 'APPLICATION_LAYER_ERROR' | 'ch-1 is not in READY state. Current state: ADVISED'
}
def 'Get resource data request with Exception: #exceptionDuringProcessing.'() {
def response = mvc.perform(get(getUrl)).andReturn().response
then: 'response status is #expectedHttpStatus'
assert response.status == expectedHttpStatus.value()
- and: 'the title in the response indicates the fdn that cannot be found'
- assert response.contentAsString.contains(expectedContent)
+ and: 'the body contains the expected type'
+ assert response.contentAsString.contains('"type":"' + expectedType)
+ and: 'the body contains the expected title'
+ assert response.contentAsString.contains('"title":"' + expectedTitle)
where: 'following exceptions occur'
- exceptionDuringProcessing || expectedHttpStatus || expectedContent
- new NoAlternateIdMatchFoundException('myTarget') || HttpStatus.NOT_FOUND || '"title":"/myClass=id1 not found"'
- new Exception("my message", new TimeoutException()) || HttpStatus.GATEWAY_TIMEOUT || '"title":"my message"'
- new Exception("my message") || HttpStatus.INTERNAL_SERVER_ERROR || '"title":"my message"'
+ exceptionDuringProcessing || expectedHttpStatus | expectedType | expectedTitle
+ new NoAlternateIdMatchFoundException('myTarget') || NOT_FOUND | 'IE_NOT_FOUND' | '/myClass=id1 not found'
+ new Exception("my message", new TimeoutException()) || GATEWAY_TIMEOUT | 'APPLICATION_LAYER_ERROR' | 'my message'
+ new Exception("my message") || INTERNAL_SERVER_ERROR | 'APPLICATION_LAYER_ERROR' | 'my message'
}
1 * mockDmiRestClient.synchronousGetOperation(*_) >> {arguments -> def urlTemplateParameters = arguments[1]
assert urlTemplateParameters.urlTemplate.contains(expectedParameterInUri)
assert urlTemplateParameters.urlVariables().get(parameterName) == expectedParameterValuesInDmiRequest
- return new ResponseEntity<>('Some response from DMI service', HttpStatus.OK)
+ return new ResponseEntity<>('Some response from DMI service', OK)
}
where: 'attributes is populated with the following '
scenario | parameterName | parameterInProvMnsRequest || expectedParameterInUri || expectedParameterValuesInDmiRequest
and: 'the response contains the expected content'
assert response.contentAsString.contains(expectedResponseContent)
where: 'following scenarios are applied'
- scenario | contentMediaType | jsonBody | responseStatusFromDmi | expectedResponseContent || expectedRespinsStatusFromProvMnS
- 'happy flow 3gpp' | patchMediaType3gpp | patchJsonBody3gpp | HttpStatus.OK | 'content from DMI' || HttpStatus.OK
- 'happy flow' | patchMediaType | patchJsonBody | HttpStatus.OK | 'content from DMI' || HttpStatus.OK
- 'error from DMI' | patchMediaType | patchJsonBody | HttpStatus.I_AM_A_TEAPOT | 'content from DMI' || HttpStatus.I_AM_A_TEAPOT
- 'invalid Json' | patchMediaType | patchJsonBodyInvalid | STATUS_NOT_RELEVANT | '"title":"Parsing error' || HttpStatus.BAD_REQUEST
- 'malformed Json' | patchMediaType | '{malformed]' | STATUS_NOT_RELEVANT | NO_CONTENT || HttpStatus.BAD_REQUEST
+ scenario | contentMediaType | jsonBody | responseStatusFromDmi || expectedResponseContent | expectedRespinsStatusFromProvMnS
+ 'happy flow 3gpp' | patchMediaType3gpp | patchJsonBody3gpp | OK || 'content from DMI' | OK
+ 'happy flow' | patchMediaType | patchJsonBody | OK || 'content from DMI' | OK
+ 'error from DMI' | patchMediaType | patchJsonBody | I_AM_A_TEAPOT || 'content from DMI' | I_AM_A_TEAPOT
+ 'invalid Json' | patchMediaType | patchJsonBodyInvalid | STATUS_NOT_RELEVANT || '"type":"VALIDATION_ERROR"' | BAD_REQUEST
+ 'malformed Json' | patchMediaType | '{malformed]' | STATUS_NOT_RELEVANT || NO_CONTENT | BAD_REQUEST
}
def 'Patch request with no permission from Coordination Management (aka Policy Executor).'() {
.content(patchJsonBody))
.andReturn().response
then: 'response status is CONFLICT (409)'
- assert response.status == HttpStatus.CONFLICT.value()
+ assert response.status == CONFLICT.value()
+ and: 'response contains the correct type'
+ assert response.contentAsString.contains('"type":"APPLICATION_LAYER_ERROR"')
and: 'response contains the message from Policy Executor (as title)'
assert response.contentAsString.contains('"title":"denied for test"')
}
then: 'response status is #expectedHttpStatus'
assert response.status == expectedHttpStatus.value()
where: 'following media types are used'
- scenario | contentType | acceptType || expectedHttpStatus
- 'Content Type Wrong' | MediaType.TEXT_XML | MediaType.APPLICATION_JSON || HttpStatus.UNSUPPORTED_MEDIA_TYPE
- 'Accept Type Wrong' | patchMediaType | MediaType.TEXT_XML || HttpStatus.NOT_ACCEPTABLE
+ scenario | contentType | acceptType || expectedHttpStatus
+ 'Content Type Wrong' | MediaType.TEXT_XML | MediaType.APPLICATION_JSON || UNSUPPORTED_MEDIA_TYPE
+ 'Accept Type Wrong' | patchMediaType | MediaType.TEXT_XML || NOT_ACCEPTABLE
}
def 'Patch request with too many operations.'() {
.content(patchItemsJsonRequestBody))
.andReturn().response
then: 'response status is PAYLOAD_TOO_LARGE (413)'
- assert response.status == HttpStatus.PAYLOAD_TOO_LARGE.value()
+ assert response.status == PAYLOAD_TOO_LARGE.value()
+ and: 'response contains the correct type'
+ assert response.contentAsString.contains('"type":"SERVER_LIMITATION"')
and: 'response contains a title detail the limitations with the number of operations'
assert response.contentAsString.contains('"title":"11 operations in request, this exceeds the maximum of 10"')
}
and: 'the content is whatever the DMI returned'
assert response.contentAsString == responseContentFromDmi
where: 'following responses returned by DMI'
- scenario | responseStatusFromDmi | responseContentFromDmi
- 'happy flow' | HttpStatus.OK | 'content from DMI'
- 'error from DMI' | HttpStatus.I_AM_A_TEAPOT | 'error details from DMI'
+ scenario | responseStatusFromDmi | responseContentFromDmi
+ 'happy flow' | OK | 'content from DMI'
+ 'error from DMI' | I_AM_A_TEAPOT | 'error details from DMI'
}
def 'Put resource data request when cm handle not found.'() {
.content(resourceAsJson))
.andReturn().response
then: 'response status NOT FOUND (404)'
- assert response.status == HttpStatus.NOT_FOUND.value()
+ assert response.status == NOT_FOUND.value()
and: 'the content indicates the FDN could not be found'
assert response.contentAsString.contains('"title":"/myClass=id1 not found"')
}
and: 'the content is whatever the DMI returned'
assert response.contentAsString == responseContentFromDmi
where: 'following responses returned by DMI'
- scenario | responseStatusFromDmi | responseContentFromDmi
- 'happy flow' | HttpStatus.OK | 'content from DMI'
- 'error from DMI' | HttpStatus.I_AM_A_TEAPOT | 'error details from DMI'
+ scenario | responseStatusFromDmi | responseContentFromDmi
+ 'happy flow' | OK | 'content from DMI'
+ 'error from DMI' | I_AM_A_TEAPOT | 'error details from DMI'
}
def 'Delete resource data request when cm handle not found.'() {
when: 'Delete data resource request is performed'
def response = mvc.perform(delete(deleteUrl)).andReturn().response
then: 'response status is the same as what DMI gave'
- assert response.status == HttpStatus.NOT_FOUND.value()
+ assert response.status == NOT_FOUND.value()
and: 'the content indicates the FDN could not be found'
assert response.contentAsString.contains('"title":"/myClass=id1 not found"')
}