package WEBPIECESxPACKAGE;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.webpieces.ddl.api.JdbcApi;
import org.webpieces.ddl.api.JdbcConstants;
import org.webpieces.ddl.api.JdbcFactory;
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.KnownStatusCode;
import org.webpieces.plugins.hibernate.HibernatePlugin;
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;
import WEBPIECESxPACKAGE.base.libs.RemoteService;
import WEBPIECESxPACKAGE.base.libs.SomeLibrary;
import WEBPIECESxPACKAGE.mock.MockRemoteSystem;
import WEBPIECESxPACKAGE.mock.MockSomeLibrary;
/**
* Error/Failure testing is something that tends to get missed but it can be pretty important to make sure you render a nice message
* when errors happen with links to other things. The same goes for not found pages too so these are good tests to have/modify for
* your use case. I leave it to the test sendResponse to add one where rendering the 500 or 404 page fails ;). On render 500 failure, our
* platform swaps in a page of our own....ie. don't let your 500 page fail in the first place as our page does not match the style of
* your website but at least let's the user know there was a bug (on top of a bug).
*
* These are working examples of tests that sometimes are better done with the BasicSeleniumTest example but are here for completeness
* so you can test the way you would like to test.
*
* @author dhiller
*
*/
public class TestLesson2Errors {
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 mockResponseSocket = new MockResponseSender();
//see below comments in AppOverrideModule
private MockRemoteSystem mockRemote = new MockRemoteSystem(); //our your favorite mock library
private MockSomeLibrary mockLibrary = new MockSomeLibrary();
private JdbcApi jdbc = JdbcFactory.create(JdbcConstants.jdbcUrl, JdbcConstants.jdbcUser, JdbcConstants.jdbcPassword);
private static String pUnit = HibernatePlugin.PERSISTENCE_TEST_UNIT;
@Before
public void setUp() throws InterruptedException, ClassNotFoundException {
Asserts.assertWasCompiledWithParamNames("test");
//clear in-memory database
jdbc.dropAllTablesFromDatabase();
//you may want to create this server ONCE in a static method BUT if you do, also remember to clear out all your
//mocks after every test AND you can no longer run single threaded(tradeoffs, tradeoffs)
//This is however pretty fast to do in many systems...
Server webserver = new Server(
new PlatformOverridesForTest(), new AppOverridesModule(), new ServerConfig(pUnit));
server = webserver.start();
}
/**
* 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() {
mockLibrary.addExceptionToThrow(() -> {
throw new RuntimeException("test internal bug page");
});
HttpRequest req = TestLesson1BasicRequestResponse.createRequest("/");
server.incomingRequest(req, new RequestId(0), true, mockResponseSocket);
List<FullResponse> responses = mockResponseSocket.getResponses();
Assert.assertEquals(1, responses.size());
FullResponse httpPayload = responses.get(0);
httpPayload.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR);
httpPayload.assertContains("You encountered a 5xx in your server");
}
/**
* You could also test notFound route fails with exception too...
*/
@Test
public void testNotFound() {
HttpRequest req = TestLesson1BasicRequestResponse.createRequest("/route/that/does/not/exist");
server.incomingRequest(req, new RequestId(0), true, mockResponseSocket);
List<FullResponse> responses = mockResponseSocket.getResponses();
Assert.assertEquals(1, responses.size());
FullResponse httpPayload = responses.get(0);
httpPayload.assertStatusCode(KnownStatusCode.HTTP_404_NOTFOUND);
httpPayload.assertContains("Your page was not found");
}
/**
* Tests a remote asynchronous system fails and a 500 error page is rendered
*/
@Test
public void testRemoteSystemDown() {
CompletableFuture<Integer> future = new CompletableFuture<Integer>();
mockRemote.addValueToReturn(future);
HttpRequest req = TestLesson1BasicRequestResponse.createRequest("/async");
server.incomingRequest(req, new RequestId(0), true, mockResponseSocket);
List<FullResponse> responses = mockResponseSocket.getResponses();
Assert.assertEquals(0, responses.size());
//notice that the thread returned but there is no response back to browser yet such that thread can do more work.
//next, simulate remote system returning a value..
future.completeExceptionally(new RuntimeException("complete future with exception"));
List<FullResponse> responses2 = mockResponseSocket.getResponses();
Assert.assertEquals(1, responses2.size());
FullResponse httpPayload = responses2.get(0);
httpPayload.assertStatusCode(KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR);
httpPayload.assertContains("You encountered a 5xx in your server");
}
private class AppOverridesModule implements Module {
@Override
public void configure(Binder binder) {
//Add overrides here generally using mocks from fields in the test class
binder.bind(RemoteService.class).toInstance(mockRemote); //see above comment on the field mockRemote
binder.bind(SomeLibrary.class).toInstance(mockLibrary);
}
}
}