From 04c607ef77edb757a43b24c8bff233fad6ede4de Mon Sep 17 00:00:00 2001 From: "Benjamin, Max (mb388a)" Date: Mon, 17 Sep 2018 09:47:02 -0400 Subject: Accept header not honored when building exception added accept headers to http entity request mappers were looking at "Content-Type" and not "Accept" modified test to no longer share global headers added additional tests and corrected comparison errors Fixing issue with comparing media types, the equals method in MediaType.class uses parameters as well to compare, added a method to just compare the type and subtype and get done with it Fixing test failures, getMEdiaType would come as null in most cases, this causes the defautl serialization mode to be picked which is xml. tests now pass with exception providers in place exception providers now handle JSON and XML Dumy push to re-trigger the build which failed at sonar evaluation Trying to fix the build by removing different spy's Returning XML instead of JSON in cases of error for endpoints. Removed exceptions and its generic handler which is a good thought, however given that the exceptionhandlers are generic it gets tough to return to handle exceptions which require different namesaces in response amongst other problems. Change-Id: I684fe3b0047693093a99aa999faf261d7713f404 Issue-ID: SO-1058 Signed-off-by: Benjamin, Max (mb388a) --- .../exceptions/ApiExceptionMapper.java | 58 +++++++- .../so/apihandlerinfra/ApiExceptionMapperTest.java | 97 ------------- .../exceptions/ApiExceptionMapperTest.java | 160 +++++++++++++++++++++ 3 files changed, 213 insertions(+), 102 deletions(-) delete mode 100644 mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/ApiExceptionMapperTest.java create mode 100644 mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapperTest.java (limited to 'mso-api-handlers/mso-api-handler-common') diff --git a/mso-api-handlers/mso-api-handler-common/src/main/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapper.java b/mso-api-handlers/mso-api-handler-common/src/main/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapper.java index 0e581cb48a..7c49eeadcc 100644 --- a/mso-api-handlers/mso-api-handler-common/src/main/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapper.java +++ b/mso-api-handlers/mso-api-handler-common/src/main/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapper.java @@ -20,11 +20,21 @@ package org.onap.so.apihandlerinfra.exceptions; +import java.io.StringWriter; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; import org.onap.so.apihandlerinfra.logging.AlarmLoggerInfo; import org.onap.so.apihandlerinfra.logging.ErrorLoggerInfo; @@ -34,7 +44,6 @@ import org.onap.so.logger.MsoLogger; import org.onap.so.serviceinstancebeans.RequestError; import org.onap.so.serviceinstancebeans.ServiceException; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -45,6 +54,22 @@ public class ApiExceptionMapper implements ExceptionMapper { private static MsoLogger logger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, ApiExceptionMapper.class); private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger(); + + private final JAXBContext context; + private final Marshaller marshaller; + + @Context + private HttpHeaders headers; + + public ApiExceptionMapper() { + try { + context = JAXBContext.newInstance(RequestError.class); + marshaller = context.createMarshaller(); + } catch (JAXBException e) { + logger.debug("could not create JAXB marshaller"); + throw new IllegalStateException(e); + } + } @Override public Response toResponse(ApiException exception) { @@ -64,12 +89,23 @@ public class ApiExceptionMapper implements ExceptionMapper { } writeErrorLog(exception, errorText, errorLoggerInfo, alarmLoggerInfo); + + List typeList = Optional.ofNullable(headers.getAcceptableMediaTypes()).orElse(new ArrayList<>()); + List typeListString = typeList.stream().map(item -> item.toString()).collect(Collectors.toList()); + MediaType type; + if (typeListString.stream().anyMatch(item -> item.contains(MediaType.APPLICATION_XML))) { + type = MediaType.APPLICATION_XML_TYPE; + } else if (typeListString.stream().anyMatch(item -> typeListString.contains(MediaType.APPLICATION_JSON))) { + type = MediaType.APPLICATION_JSON_TYPE; + } else { + type = MediaType.APPLICATION_JSON_TYPE; + } - return buildServiceErrorResponse(errorText,messageId,variables); + return buildServiceErrorResponse(errorText,messageId,variables, type); } - protected String buildServiceErrorResponse(String errorText, String messageId, List variables){ + protected String buildServiceErrorResponse(String errorText, String messageId, List variables, MediaType type){ RequestError re = new RequestError(); ServiceException se = new ServiceException(); se.setMessageId(messageId); @@ -83,11 +119,18 @@ public class ApiExceptionMapper implements ExceptionMapper { String requestErrorStr; ObjectMapper mapper = createObjectMapper(); + mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true); mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT); try { - requestErrorStr = mapper.writeValueAsString(re); - } catch (JsonProcessingException e) { + if (MediaType.APPLICATION_JSON_TYPE.equals(type)) { + requestErrorStr = mapper.writeValueAsString(re); + } else { + StringWriter sw = new StringWriter(); + this.getMarshaller().marshal(re, sw); + requestErrorStr = sw.toString(); + } + } catch (JsonProcessingException | JAXBException e) { String errorMsg = "Exception in buildServiceErrorResponse writing exceptionType to string " + e.getMessage(); logger.error(MessageEnum.GENERAL_EXCEPTION, "BuildServiceErrorResponse", "", "", MsoLogger.ErrorCode.DataError, errorMsg, e); return errorMsg; @@ -109,4 +152,9 @@ public class ApiExceptionMapper implements ExceptionMapper { public ObjectMapper createObjectMapper(){ return new ObjectMapper(); } + + public Marshaller getMarshaller() { + return marshaller; + } + } diff --git a/mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/ApiExceptionMapperTest.java b/mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/ApiExceptionMapperTest.java deleted file mode 100644 index b98c47490a..0000000000 --- a/mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/ApiExceptionMapperTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.so.apihandlerinfra; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.junit.Test; -import org.mockito.Mockito; -import org.onap.so.apihandler.common.ErrorNumbers; -import org.onap.so.apihandlerinfra.exceptions.*; - -import org.apache.http.HttpStatus; -import javax.ws.rs.core.Response; - - -import java.io.IOException; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.anyObject; -import static org.hamcrest.core.StringStartsWith.startsWith; - -public class ApiExceptionMapperTest { - - ApiExceptionMapper mapper = new ApiExceptionMapper(); - - - @Test - public void testObjectMapperError() throws JsonProcessingException { - ObjectMapper mockedMapper = Mockito.mock(ObjectMapper.class); - Mockito.when(mockedMapper.writeValueAsString(anyObject())).thenThrow(JsonProcessingException.class); - ValidateException validateException = new ValidateException.Builder("Test", 0 , null).build(); - ApiExceptionMapper mockedException = Mockito.spy(new ApiExceptionMapper()); - Mockito.doReturn(mockedMapper).when(mockedException).createObjectMapper(); - Response resp = mockedException.toResponse((ApiException) validateException); - - /// assertEquals(resp.getStatus(), HttpStatus.SC_BAD_REQUEST); - assertThat(resp.getEntity().toString(),startsWith("Exception in buildServiceErrorResponse writing exceptionType to string")); - } - - @Test - public void testValidateResponse(){ - ValidateException validateException = new ValidateException.Builder("Test Message", HttpStatus.SC_BAD_REQUEST, ErrorNumbers.SVC_BAD_PARAMETER).build(); - Response resp = mapper.toResponse((ApiException) validateException); - - assertEquals(resp.getStatus(), HttpStatus.SC_BAD_REQUEST); - } - - @Test - public void testBPMNFailureResponse(){ - BPMNFailureException bpmnException = new BPMNFailureException.Builder("Test Message", HttpStatus.SC_NOT_FOUND, ErrorNumbers.SVC_BAD_PARAMETER).build(); - Response resp = mapper.toResponse((ApiException) bpmnException); - - assertEquals(resp.getStatus(), HttpStatus.SC_NOT_FOUND); - } - @Test - public void testClientConnectionResponse(){ - ClientConnectionException clientConnectionException = new ClientConnectionException.Builder("test", HttpStatus.SC_INTERNAL_SERVER_ERROR,ErrorNumbers.SVC_BAD_PARAMETER).build(); - Response resp = mapper.toResponse((ApiException) clientConnectionException); - - assertEquals(resp.getStatus(), HttpStatus.SC_INTERNAL_SERVER_ERROR); - } - @Test - public void testVFModuleResponse() { - VfModuleNotFoundException vfModuleException = new VfModuleNotFoundException.Builder("Test Message", HttpStatus.SC_CONFLICT,ErrorNumbers.SVC_BAD_PARAMETER).build(); - Response resp = mapper.toResponse((ApiException) vfModuleException); - - assertEquals(resp.getStatus(), HttpStatus.SC_CONFLICT); - } - @Test - public void testDuplicateRequestResponse() throws IOException { - DuplicateRequestException duplicateRequestException = new DuplicateRequestException.Builder("Test1", "Test2","Test3","Test4", HttpStatus.SC_BAD_GATEWAY,ErrorNumbers.SVC_BAD_PARAMETER).build(); - Response resp = mapper.toResponse((ApiException) duplicateRequestException); - - assertEquals(resp.getStatus(), HttpStatus.SC_BAD_GATEWAY); - } -} diff --git a/mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapperTest.java b/mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapperTest.java new file mode 100644 index 0000000000..e666df34f9 --- /dev/null +++ b/mso-api-handlers/mso-api-handler-common/src/test/java/org/onap/so/apihandlerinfra/exceptions/ApiExceptionMapperTest.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.apihandlerinfra.exceptions; + + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringStartsWith.startsWith; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.Writer; +import java.util.Arrays; +import java.util.List; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; + +import org.apache.http.HttpStatus; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.so.apihandler.common.ErrorNumbers; +import org.onap.so.apihandlerinfra.exceptions.ApiException; +import org.onap.so.apihandlerinfra.exceptions.ApiExceptionMapper; +import org.onap.so.apihandlerinfra.exceptions.BPMNFailureException; +import org.onap.so.apihandlerinfra.exceptions.ClientConnectionException; +import org.onap.so.apihandlerinfra.exceptions.DuplicateRequestException; +import org.onap.so.apihandlerinfra.exceptions.ValidateException; +import org.onap.so.apihandlerinfra.exceptions.VfModuleNotFoundException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + + +@RunWith(MockitoJUnitRunner.class) +public class ApiExceptionMapperTest { + + @Mock + private HttpHeaders headers; + @Mock + private Marshaller marshaller; + + @InjectMocks + ApiExceptionMapper mapper = new ApiExceptionMapper(); + + + @Before + public void setUp() { + when(headers.getAcceptableMediaTypes()).thenReturn(Arrays.asList(MediaType.APPLICATION_JSON_TYPE)); + } + @Test + public void testObjectMapperError() throws JsonProcessingException { + ObjectMapper mockedMapper = Mockito.mock(ObjectMapper.class); + Mockito.when(mockedMapper.writeValueAsString(anyObject())).thenThrow(JsonProcessingException.class); + ValidateException validateException = new ValidateException.Builder("Test", 0 , null).build(); + ApiExceptionMapper mockedException = Mockito.spy(mapper); + Mockito.doReturn(mockedMapper).when(mockedException).createObjectMapper(); + Response resp = mockedException.toResponse((ApiException) validateException); + + /// assertEquals(resp.getStatus(), HttpStatus.SC_BAD_REQUEST); + assertThat(resp.getEntity().toString(),startsWith("Exception in buildServiceErrorResponse writing exceptionType to string")); + } + + @Test + public void testValidateResponse(){ + ValidateException validateException = new ValidateException.Builder("Test Message", HttpStatus.SC_BAD_REQUEST, ErrorNumbers.SVC_BAD_PARAMETER).build(); + Response resp = mapper.toResponse((ApiException) validateException); + + assertEquals(resp.getStatus(), HttpStatus.SC_BAD_REQUEST); + } + + @Test + public void testBPMNFailureResponse(){ + BPMNFailureException bpmnException = new BPMNFailureException.Builder("Test Message", HttpStatus.SC_NOT_FOUND, ErrorNumbers.SVC_BAD_PARAMETER).build(); + Response resp = mapper.toResponse((ApiException) bpmnException); + + assertEquals(resp.getStatus(), HttpStatus.SC_NOT_FOUND); + } + @Test + public void testClientConnectionResponse(){ + ClientConnectionException clientConnectionException = new ClientConnectionException.Builder("test", HttpStatus.SC_INTERNAL_SERVER_ERROR,ErrorNumbers.SVC_BAD_PARAMETER).build(); + Response resp = mapper.toResponse((ApiException) clientConnectionException); + + assertEquals(resp.getStatus(), HttpStatus.SC_INTERNAL_SERVER_ERROR); + } + @Test + public void testVFModuleResponse() { + VfModuleNotFoundException vfModuleException = new VfModuleNotFoundException.Builder("Test Message", HttpStatus.SC_CONFLICT,ErrorNumbers.SVC_BAD_PARAMETER).build(); + Response resp = mapper.toResponse((ApiException) vfModuleException); + + assertEquals(resp.getStatus(), HttpStatus.SC_CONFLICT); + } + @Test + public void testDuplicateRequestResponse() throws IOException { + DuplicateRequestException duplicateRequestException = new DuplicateRequestException.Builder("Test1", "Test2","Test3","Test4", HttpStatus.SC_BAD_GATEWAY,ErrorNumbers.SVC_BAD_PARAMETER).build(); + Response resp = mapper.toResponse((ApiException) duplicateRequestException); + + assertEquals(resp.getStatus(), HttpStatus.SC_BAD_GATEWAY); + } + + @Test + public void verifyXMLPath() throws JAXBException { + when(headers.getAcceptableMediaTypes()).thenReturn(Arrays.asList(MediaType.APPLICATION_XML_TYPE)); + BPMNFailureException bpmnException = new BPMNFailureException.Builder("Test Message", HttpStatus.SC_NOT_FOUND, ErrorNumbers.SVC_BAD_PARAMETER).build(); + ApiExceptionMapper mapperSpy = Mockito.spy(mapper); + doReturn(marshaller).when(mapperSpy).getMarshaller(); + Response resp = mapperSpy.toResponse((ApiException) bpmnException); + verify(marshaller, times(1)).marshal(any(Object.class), any(Writer.class)); + } + + @Test + public void verifyMediaType() { + ApiExceptionMapper mapperSpy = Mockito.spy(mapper); + BPMNFailureException bpmnException = new BPMNFailureException.Builder("Test Message", HttpStatus.SC_NOT_FOUND, ErrorNumbers.SVC_BAD_PARAMETER).build(); + when(headers.getAcceptableMediaTypes()).thenReturn(Arrays.asList(MediaType.APPLICATION_XML_TYPE.withCharset("UTF-8"))); + mapperSpy.toResponse(bpmnException); + verify(mapperSpy, times(1)).buildServiceErrorResponse(any(String.class), any(String.class), any(List.class), eq(MediaType.APPLICATION_XML_TYPE)); + when(headers.getAcceptableMediaTypes()).thenReturn(Arrays.asList(MediaType.APPLICATION_JSON_TYPE.withCharset("UTF-8"))); + mapperSpy = Mockito.spy(mapper); + mapperSpy.toResponse(bpmnException); + verify(mapperSpy, times(1)).buildServiceErrorResponse(any(String.class), any(String.class), any(List.class), eq(MediaType.APPLICATION_JSON_TYPE)); + when(headers.getAcceptableMediaTypes()).thenReturn(null); + mapperSpy = Mockito.spy(mapper); + mapperSpy.toResponse(bpmnException); + verify(mapperSpy, times(1)).buildServiceErrorResponse(any(String.class), any(String.class), any(List.class), eq(MediaType.APPLICATION_JSON_TYPE)); + } +} -- cgit 1.2.3-korg