package org.webpieces.webserver.async; import java.util.List; import java.util.concurrent.CompletableFuture; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.webpieces.httpcommon.Requests; import org.webpieces.httpcommon.api.RequestId; import org.webpieces.httpcommon.api.RequestListener; import org.webpieces.httpparser.api.dto.HttpRequest; import org.webpieces.httpparser.api.dto.KnownHttpMethod; import org.webpieces.httpparser.api.dto.KnownStatusCode; import org.webpieces.router.api.exceptions.NotFoundException; import org.webpieces.util.file.VirtualFileClasspath; import org.webpieces.webserver.ResponseExtract; import org.webpieces.webserver.WebserverForTest; import org.webpieces.webserver.basic.app.biz.SomeLib; import org.webpieces.webserver.basic.app.biz.SomeOtherLib; import org.webpieces.webserver.mock.MockSomeLib; import org.webpieces.webserver.mock.MockSomeOtherLib; import org.webpieces.webserver.test.Asserts; import org.webpieces.webserver.test.FullResponse; import org.webpieces.webserver.test.MockResponseSender; import org.webpieces.webserver.test.PlatformOverridesForTest; import com.google.inject.Binder; import com.google.inject.Module; /** * @author dhiller * */ public class TestAsynchronousErrors { private RequestListener server; //In the future, we may develop a FrontendSimulator that can be used instead of MockResponseSender that would follow //any redirects in the application properly.. private MockResponseSender socket = new MockResponseSender(); private MockSomeOtherLib mockNotFoundLib = new MockSomeOtherLib(); private MockSomeLib mockInternalSvrErrorLib = new MockSomeLib(); @Before public void setUp() throws InterruptedException, ClassNotFoundException { Asserts.assertWasCompiledWithParamNames("test"); VirtualFileClasspath metaFile = new VirtualFileClasspath("asyncMeta.txt", WebserverForTest.class.getClassLoader()); WebserverForTest webserver = new WebserverForTest(new PlatformOverridesForTest(), new AppOverridesModule(), false, metaFile); server = webserver.start(); } @Test public void testNotFoundRoute() { //NOTE: This is adding future to the notFound route CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/route/that/does/not/exist"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); //now resolve the future (which would be done on another thread) future.complete(22); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_404_NOTFOUND); response.assertContains("Your page was not found"); } @Test public void testWebappThrowsNotFound() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); CompletableFuture<Integer> future2 = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future2); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/throwNotFound"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); future.completeExceptionally(new NotFoundException("some async NotFound")); List<FullResponse> responses3 = socket.getResponses(); Assert.assertEquals(0, responses3.size()); future2.complete(55); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_404_NOTFOUND); response.assertContains("Your page was not found"); } @Test public void testNotFoundHandlerThrowsNotFound() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/route/that/does/not/exist"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); future.completeExceptionally(new NotFoundException("testing notfound from notfound route")); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR); response.assertContains("There was a bug in our software...sorry about that"); } @Test public void testNotFoundThrowsException() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/route/that/does/not/exist"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); future.completeExceptionally(new RuntimeException("testing notfound from notfound route")); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR); response.assertContains("There was a bug in our software...sorry about that"); } @Test public void testNotFoundThrowsThenInternalSvrErrorHandlerThrows() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); CompletableFuture<Integer> future2 = new CompletableFuture<Integer>(); mockInternalSvrErrorLib.queueFuture(future2); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/route/that/does/not/exist"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); future.completeExceptionally(new RuntimeException("fail notfound route")); List<FullResponse> responses3 = socket.getResponses(); Assert.assertEquals(0, responses3.size()); future2.completeExceptionally(new RuntimeException("fail internal server error route")); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR); response.assertContains("The webpieces platform saved them"); } /** * This tests bug in your webapp "/another" route, you could also test you have a bug in that route AND a bug in your internal * server route as well!!! */ @Test public void testWebAppHasBugRenders500Route() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); future.completeExceptionally(new RuntimeException("test async exception")); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR); response.assertContains("There was a bug in our software...sorry about that"); } @Test public void testWebAppHasBugAndRender500HasBug() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future); CompletableFuture<Integer> future2 = new CompletableFuture<Integer>(); mockInternalSvrErrorLib.queueFuture(future2); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/"); server.incomingRequest(req, new RequestId(0), true, socket); List<FullResponse> responses2 = socket.getResponses(); Assert.assertEquals(0, responses2.size()); future.completeExceptionally(new RuntimeException("fail notfound route")); List<FullResponse> responses3 = socket.getResponses(); Assert.assertEquals(0, responses3.size()); future2.completeExceptionally(new RuntimeException("fail internal server error route")); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR); response.assertContains("The webpieces platform saved them"); } @Test public void testCompletePromiseAnotherThreadAndPageParamMissing() { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); mockNotFoundLib.queueFuture(future ); HttpRequest req = Requests.createRequest(KnownHttpMethod.GET, "/asyncFailRoute"); server.incomingRequest(req, new RequestId(0), true, socket); //now have the server complete processing future.complete(5); FullResponse response = ResponseExtract.assertSingleResponse(socket); response.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR); response.assertContains("There was a bug in our software"); } private class AppOverridesModule implements Module { @Override public void configure(Binder binder) { binder.bind(SomeOtherLib.class).toInstance(mockNotFoundLib); binder.bind(SomeLib.class).toInstance(mockInternalSvrErrorLib); } } }