package com.vtence.molecule.middlewares; import com.vtence.molecule.Request; import com.vtence.molecule.Response; import org.junit.Test; import java.util.concurrent.ExecutionException; import static com.vtence.molecule.http.HttpStatus.INTERNAL_SERVER_ERROR; import static com.vtence.molecule.testing.ResponseAssert.assertThat; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.Matchers.not; public class FailsafeTest { Failsafe failsafe = new Failsafe(); String errorMessage = "An error occurred!"; Error error = newError(errorMessage); Request request = new Request(); Response response = new Response(); @Test public void setsStatusToInternalServerError() throws Exception { failsafe.connectTo((request, response) -> { throw error; }); failsafe.handle(request, response); response.done(); assertNoExecutionError(); assertThat(response).hasStatus(INTERNAL_SERVER_ERROR); } @Test public void rendersErrorStackTrace() throws Exception { failsafe.connectTo((request, response) -> { throw error; }); failsafe.handle(request, response); response.done(); assertNoExecutionError(); assertThat(response).hasBodyText(containsString(errorMessage)) .hasBodyText(containsString("stack.trace(line:1)")) .hasBodyText(containsString("stack.trace(line:2)")) .hasBodyText(not(containsString("Caused by:"))); } @Test public void rendersChainOfErrorCauses() throws Exception { Error rootCause = newError("root cause of error", null, stackFrame("root.cause.stack", 1)); Error cause = newError("cause of error", rootCause, stackFrame("cause.of.error.stack", 1)); Error errorWithCause = newError("this error has a cause", cause); failsafe.connectTo((request, response) -> { throw errorWithCause; }); failsafe.handle(request, response); response.done(); assertNoExecutionError(); assertThat(response).hasBodyText(containsString("Caused by: java.lang.Error: cause of error")) .hasBodyText(containsString("cause.of.error.stack.trace(line:1)")) .hasBodyText(containsString("Caused by: java.lang.Error: root cause")) .hasBodyText(containsString("root.cause.stack.trace(line:1)")); } @Test public void respondsWithHtmlContentUtf8Encoded() throws Exception { failsafe.connectTo((request, response) -> { throw error; }); failsafe.handle(request, response); assertThat(response).hasContentType("text/html; charset=utf-8").isDone(); } @Test public void recoversFromErrorsOccurringLater() throws Exception { failsafe.handle(request, response); response.done(error); assertNoExecutionError(); assertThat(response).hasStatus(INTERNAL_SERVER_ERROR) .hasBodyText(containsString(errorMessage)); } private Error newError(String errorMessage) { return newError(errorMessage, null); } private Error newError(String errorMessage, Error cause) { return newError(errorMessage, cause, stackFrame("error.stack", 1), stackFrame("error.stack", 2)); } private Error newError(String errorMessage, Error cause, StackTraceElement... stackTrace) { Error error = new Error(errorMessage, cause); error.setStackTrace(stackTrace); return error; } private StackTraceElement stackFrame(String className, int lineNumber) { return new StackTraceElement(className, "trace", "line", lineNumber); } private void assertNoExecutionError() throws ExecutionException, InterruptedException { response.await(); } }