Wrote some tests
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
package com.raychatter.common.annotation;
|
package com.raychatter.common.annotation;
|
||||||
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@@ -14,35 +12,39 @@ import java.util.Scanner;
|
|||||||
|
|
||||||
public class AnnotationHandler implements HandlerExceptionResolver {
|
public class AnnotationHandler implements HandlerExceptionResolver {
|
||||||
|
|
||||||
|
protected static final String DEFAULT_ERROR_STRING = "Error: %s";
|
||||||
|
protected static final String USER_TEMPLATE = "error.template";
|
||||||
|
protected static final String DEFAULT_TEMPLATE = "defaults/default.template";
|
||||||
|
private static final String UTF_8 = "UTF-8";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelAndView resolveException(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception thrownException) {
|
public ModelAndView resolveException(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception thrownException) {
|
||||||
final ExceptionHandler annotation = thrownException.getClass().getAnnotation(ExceptionHandler.class);
|
final ExceptionHandler annotation = thrownException.getClass().getAnnotation(ExceptionHandler.class);
|
||||||
|
|
||||||
// This still returns an empty ModelAndView
|
|
||||||
if (annotation == null) {
|
if (annotation == null) {
|
||||||
return new ModelAndView();
|
return new ModelAndView();
|
||||||
}
|
}
|
||||||
|
|
||||||
return doStuffWithAnnotation(annotation, thrownException, response);
|
return handleException(annotation, thrownException, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModelAndView doStuffWithAnnotation(final ExceptionHandler exceptionHandlerAnnotation, final Exception thrownException, final HttpServletResponse response) {
|
protected ModelAndView handleException(final ExceptionHandler annotation, final Exception thrownException, final HttpServletResponse response) {
|
||||||
|
response.setContentType(annotation.contentType());
|
||||||
// This is only outside of the try because the null annotation case is handled in resolveException
|
response.setStatus(annotation.httpStatus().value());
|
||||||
response.setContentType(exceptionHandlerAnnotation.contentType());
|
|
||||||
response.setStatus(exceptionHandlerAnnotation.httpStatus().value());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response.getWriter().write(formatMessage(thrownException));
|
final String message = formatMessage(thrownException);
|
||||||
|
response.getWriter().write(message);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
response.setContentType(MediaType.APPLICATION_XML_VALUE);
|
//TODO: Potentially this can be handled differently than the template errors
|
||||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
// response.setContentType(MediaType.APPLICATION_XML_VALUE);
|
||||||
|
// response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
try {
|
//
|
||||||
response.getWriter().write(formatDefaultMessage(thrownException));
|
// try {
|
||||||
} catch (IOException ex) {
|
// response.getWriter().write(formatDefaultMessage(thrownException));
|
||||||
ex.printStackTrace();
|
// } catch (IOException ex) {
|
||||||
}
|
// ex.printStackTrace();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ModelAndView();
|
return new ModelAndView();
|
||||||
@@ -57,22 +59,21 @@ public class AnnotationHandler implements HandlerExceptionResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String readTemplate() throws IOException {
|
protected String readTemplate() throws IOException {
|
||||||
final InputStream templateFile = new ClassPathResource("error.template").getInputStream();
|
final InputStream templateFile = getResource(USER_TEMPLATE);
|
||||||
return new Scanner(templateFile, "UTF-8").useDelimiter("\\A").next().trim();
|
return new Scanner(templateFile, UTF_8).useDelimiter("\\A").next().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract into a new protected method to grab input stream; spy that new method, returning null?
|
|
||||||
protected String readDefaultTemplate() {
|
protected String readDefaultTemplate() {
|
||||||
try {
|
try {
|
||||||
final InputStream templateFile = getInputStream("defaults/default.template");
|
final InputStream templateFile = getResource(DEFAULT_TEMPLATE);
|
||||||
return new Scanner(templateFile, "UTF-8").useDelimiter("\\A").next().trim();
|
return new Scanner(templateFile, UTF_8).useDelimiter("\\A").next().trim();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
return "Error: %s";
|
return DEFAULT_ERROR_STRING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InputStream getInputStream(String filepath) throws IOException {
|
protected InputStream getResource(final String resource) throws IOException {
|
||||||
return new ClassPathResource(filepath).getInputStream();
|
return new ClassPathResource(resource).getInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.raychatter.common.annotation;
|
package com.raychatter.common.annotation;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -17,6 +18,6 @@ import java.lang.annotation.Target;
|
|||||||
ElementType.PARAMETER,
|
ElementType.PARAMETER,
|
||||||
ElementType.TYPE})
|
ElementType.TYPE})
|
||||||
public @interface ExceptionHandler {
|
public @interface ExceptionHandler {
|
||||||
HttpStatus httpStatus() default HttpStatus.OK;
|
HttpStatus httpStatus() default HttpStatus.INTERNAL_SERVER_ERROR;
|
||||||
String contentType();
|
String contentType() default MediaType.TEXT_PLAIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,22 @@ package com.raychatter.common.annotation;
|
|||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class AnnotationHandlerTest {
|
public class AnnotationHandlerTest {
|
||||||
|
|
||||||
@@ -25,7 +35,8 @@ public class AnnotationHandlerTest {
|
|||||||
Assert.assertEquals(expectedResult, actual);
|
Assert.assertEquals(expectedResult, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void formatDefaultMessage_ShouldRenderDefaultUserTemplate_WhenNoUserTemplateGiven() throws Exception {
|
@Test
|
||||||
|
public void formatDefaultMessage_ShouldRenderDefaultUserTemplate_WhenNoUserTemplateGiven() throws Exception {
|
||||||
final String defaultTemplate = "DEFAULT TEMPLATE: %s";
|
final String defaultTemplate = "DEFAULT TEMPLATE: %s";
|
||||||
final String exceptionMessage = "AN ERROR MESSAGE";
|
final String exceptionMessage = "AN ERROR MESSAGE";
|
||||||
final String expectedMessage = "DEFAULT TEMPLATE: AN ERROR MESSAGE";
|
final String expectedMessage = "DEFAULT TEMPLATE: AN ERROR MESSAGE";
|
||||||
@@ -38,15 +49,144 @@ public class AnnotationHandlerTest {
|
|||||||
Assert.assertEquals(expectedMessage, actual);
|
Assert.assertEquals(expectedMessage, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void readDefaultTemplate_ShouldCatchIOException_WhenDefaultTemplateNotFound() throws Exception {
|
@Test
|
||||||
final String expectedTemplate = "Error: %s";
|
public void readDefaultTemplate_ShouldReturnDefaultErrorMessage_WhenIOError() throws Exception {
|
||||||
final String defaultFilepath = "defaults/default.template";
|
final String defaultTemplatePath = "defaults/default.template";
|
||||||
|
|
||||||
AnnotationHandler spyAnnotationHandler = spy(new AnnotationHandler());
|
AnnotationHandler spyAnnotationHandler = spy(new AnnotationHandler());
|
||||||
doThrow(new IOException()).when(spyAnnotationHandler).getInputStream(defaultFilepath);
|
doThrow(new IOException()).when(spyAnnotationHandler).getResource(defaultTemplatePath);
|
||||||
|
|
||||||
final String actualTemplate = spyAnnotationHandler.readDefaultTemplate();
|
final String actualTemplate = spyAnnotationHandler.readDefaultTemplate();
|
||||||
|
|
||||||
Assert.assertEquals(expectedTemplate, actualTemplate);
|
Assert.assertEquals(AnnotationHandler.DEFAULT_ERROR_STRING, actualTemplate);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
|
public void readTemplate_ShouldReturnUserTemplateString_WhenUserTemplateIsGiven() throws Exception {
|
||||||
|
// arrange
|
||||||
|
final String expectedUserTemplateString = "USER TEMPLATE";
|
||||||
|
final InputStream expectedInputStream = new ByteArrayInputStream(expectedUserTemplateString.getBytes());
|
||||||
|
|
||||||
|
// act
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(expectedInputStream).when(sut).getResource(anyString());
|
||||||
|
|
||||||
|
final String actual = sut.readTemplate();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.assertEquals(expectedUserTemplateString, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readDefaultTemplate_ShouldReturnDefaultTemplateString_WhenNoUserTemplateIsGiven() throws Exception {
|
||||||
|
// arrange
|
||||||
|
final String expectedDefaultTemplateString = "DEFAULT TEMPLATE";
|
||||||
|
final InputStream expectedInputStream = new ByteArrayInputStream(expectedDefaultTemplateString.getBytes());
|
||||||
|
|
||||||
|
// act
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(expectedInputStream).when(sut).getResource(anyString());
|
||||||
|
|
||||||
|
final String actual = sut.readDefaultTemplate();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.assertEquals(expectedDefaultTemplateString, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void handleException_ShouldRenderDefaultContentType_WhenNoAnnotationAttributesGiven() throws Exception {
|
||||||
|
final String emptyString = "";
|
||||||
|
|
||||||
|
final HttpServletResponse mockResponse = mock(HttpServletResponse.class);
|
||||||
|
final PrintWriter mockPrinter = mock(PrintWriter.class);
|
||||||
|
when(mockResponse.getWriter()).thenReturn(mockPrinter);
|
||||||
|
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(emptyString).when(sut).formatMessage(null);
|
||||||
|
doReturn(emptyString).when(sut).formatDefaultMessage(null);
|
||||||
|
|
||||||
|
sut.handleException(TestExceptionWithNoAnnotationAttributes.class.getAnnotation(ExceptionHandler.class), null, mockResponse);
|
||||||
|
|
||||||
|
verify(mockResponse).setContentType(MediaType.TEXT_PLAIN_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void handleException_ShouldRenderDefaultHttpStatusCode_WhenNoAnnotationAttributesGiven() throws Exception {
|
||||||
|
final String emptyString = "";
|
||||||
|
|
||||||
|
final HttpServletResponse mockResponse = mock(HttpServletResponse.class);
|
||||||
|
final PrintWriter mockPrinter = mock(PrintWriter.class);
|
||||||
|
when(mockResponse.getWriter()).thenReturn(mockPrinter);
|
||||||
|
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(emptyString).when(sut).formatMessage(null);
|
||||||
|
doReturn(emptyString).when(sut).formatDefaultMessage(null);
|
||||||
|
|
||||||
|
sut.handleException(TestExceptionWithNoAnnotationAttributes.class.getAnnotation(ExceptionHandler.class), null, mockResponse);
|
||||||
|
|
||||||
|
verify(mockResponse).setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void handleException_ShouldRenderNotFoundHttpStatusCode_WhenNotFoundAnnotationAttributeIsGiven() throws Exception {
|
||||||
|
final String emptyString = "";
|
||||||
|
|
||||||
|
final HttpServletResponse mockResponse = mock(HttpServletResponse.class);
|
||||||
|
final PrintWriter mockPrinter = mock(PrintWriter.class);
|
||||||
|
when(mockResponse.getWriter()).thenReturn(mockPrinter);
|
||||||
|
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(emptyString).when(sut).formatMessage(null);
|
||||||
|
doReturn(emptyString).when(sut).formatDefaultMessage(null);
|
||||||
|
|
||||||
|
sut.handleException(TestExceptionWithNotFoundStatusCode.class.getAnnotation(ExceptionHandler.class), null, mockResponse);
|
||||||
|
|
||||||
|
verify(mockResponse).setStatus(HttpStatus.NOT_FOUND.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void handleException_ShouldRenderXmlContentType_WhenXmlContentTypeAnnotationAttributeIsGiven() throws Exception {
|
||||||
|
final String emptyString = "";
|
||||||
|
|
||||||
|
final HttpServletResponse mockResponse = mock(HttpServletResponse.class);
|
||||||
|
final PrintWriter mockPrinter = mock(PrintWriter.class);
|
||||||
|
when(mockResponse.getWriter()).thenReturn(mockPrinter);
|
||||||
|
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(emptyString).when(sut).formatMessage(null);
|
||||||
|
doReturn(emptyString).when(sut).formatDefaultMessage(null);
|
||||||
|
|
||||||
|
sut.handleException(TestExceptionWithXmlContentType.class.getAnnotation(ExceptionHandler.class), null, mockResponse);
|
||||||
|
|
||||||
|
verify(mockResponse).setContentType(MediaType.APPLICATION_XML_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void handleException_ShouldRenderUserMessage_WhenUserTemplateIsGiven() throws Exception {
|
||||||
|
final String expectedUserTemplate = "USER TEMPLATE: %s";
|
||||||
|
final String expectedErrorMessage = "ERROR MESSAGE";
|
||||||
|
final String expectedErrorBody = "USER TEMPLATE: ERROR MESSAGE";
|
||||||
|
final TestExceptionWithNoAnnotationAttributes expectedException = new TestExceptionWithNoAnnotationAttributes(expectedErrorMessage);
|
||||||
|
|
||||||
|
final HttpServletResponse mockResponse = mock(HttpServletResponse.class);
|
||||||
|
final PrintWriter mockPrinter = mock(PrintWriter.class);
|
||||||
|
when(mockResponse.getWriter()).thenReturn(mockPrinter);
|
||||||
|
|
||||||
|
final AnnotationHandler sut = spy(new AnnotationHandler());
|
||||||
|
doReturn(new ByteArrayInputStream(expectedUserTemplate.getBytes())).when(sut).getResource(AnnotationHandler.USER_TEMPLATE);
|
||||||
|
|
||||||
|
sut.handleException(expectedException.getClass().getAnnotation(ExceptionHandler.class), expectedException, mockResponse);
|
||||||
|
|
||||||
|
verify(mockPrinter).write(expectedErrorBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler()
|
||||||
|
class TestExceptionWithNoAnnotationAttributes extends Exception {
|
||||||
|
public TestExceptionWithNoAnnotationAttributes(final String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(contentType = MediaType.APPLICATION_XML_VALUE)
|
||||||
|
class TestExceptionWithXmlContentType extends Exception { }
|
||||||
|
|
||||||
|
@ExceptionHandler(httpStatus = HttpStatus.NOT_FOUND)
|
||||||
|
class TestExceptionWithNotFoundStatusCode extends Exception { }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user