diff --git a/src/main/java/facades/JokeFacade.java b/src/main/java/facades/JokeFacade.java index 09ec898..64e5b57 100644 --- a/src/main/java/facades/JokeFacade.java +++ b/src/main/java/facades/JokeFacade.java @@ -45,10 +45,14 @@ private EntityManager getEntityManager() { public long getJokeCount() { EntityManager em = getEntityManager(); try { - return (long) em.createQuery("SELECT COUNT(r) FROM Joke r").getSingleResult(); + Long result = (long) em.createQuery("SELECT COUNT(r) FROM Joke r").getSingleResult(); + if (result == 0) { + throw new IllegalStateException("Database is empty"); + } + return result; } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get joke count" + ex.getMessage()); + throw new IllegalArgumentException("Could not get joke count -> " + ex.getMessage()); } finally { em.close(); } @@ -63,10 +67,15 @@ public long getJokeCount() { public List getAllJokes() { EntityManager em = getEntityManager(); try { - return em.createQuery("SELECT r FROM Joke r", Joke.class).getResultList(); + List result = em.createQuery("SELECT r FROM Joke r", Joke.class).getResultList(); + if (result == null || result.isEmpty()) { + throw new IllegalStateException("Database is empty"); + } else { + return result; + } } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get all jokes" + ex.getMessage()); + throw new IllegalArgumentException("Could not get all jokes -> " + ex.getMessage()); } finally { em.close(); } @@ -80,10 +89,15 @@ public List getAllJokes() { public List getAllJokesAsDTO() { EntityManager em = getEntityManager(); try { - return em.createQuery("SELECT NEW dto.JokeDTO(j) FROM Joke j", JokeDTO.class).getResultList(); + List result = em.createQuery("SELECT NEW dto.JokeDTO(j) FROM Joke j", JokeDTO.class).getResultList(); + if (result == null || result.isEmpty()) { + throw new IllegalArgumentException("Database is empty. (DTO)"); + } else { + return result; + } } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get all jokes (DTO)" + ex.getMessage()); + throw new IllegalArgumentException("Could not get all jokes (DTO) -> " + ex.getMessage()); } finally { em.close(); } @@ -101,10 +115,14 @@ public List getAllJokesAsDTO() { public Joke getJokeById(Long id) { EntityManager em = getEntityManager(); try { - return em.find(Joke.class, id); + Joke result = em.find(Joke.class, id); + if (result == null) { + throw new IllegalStateException("Database is empty or joke doesn't exist."); + } + return result; } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get joke by ID" + ex.getMessage()); + throw new IllegalArgumentException("Could not get joke by ID -> " + ex.getMessage()); } finally { em.close(); } @@ -119,10 +137,16 @@ public Joke getJokeById(Long id) { public JokeDTO getJokeByIdAsDTO(Long id) { EntityManager em = getEntityManager(); try { - return new JokeDTO(em.find(Joke.class, id)); + Joke result = em.find(Joke.class, id); + if (result == null) { + throw new IllegalStateException("Database is empty or joke doesn't exist."); + } else { + return new JokeDTO(result); + } + } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get joke by ID" + ex.getMessage()); + throw new IllegalArgumentException("Could not get joke (DTO) by ID -> " + ex.getMessage()); } finally { em.close(); } @@ -145,7 +169,7 @@ public Joke getJokeByRandom() { return em.find(Joke.class, id); } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get joke by random" + ex.getMessage()); + throw new IllegalArgumentException("Could not get joke by random -> " + ex.getMessage()); } finally { em.close(); } @@ -168,7 +192,7 @@ public JokeDTO getJokeByRandomAsDTO() { return new JokeDTO(em.find(Joke.class, id)); } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get joke by ID" + ex.getMessage()); + throw new IllegalArgumentException("Could not get joke by ID (DTO) -> " + ex.getMessage()); } finally { em.close(); } @@ -185,10 +209,16 @@ public JokeDTO getJokeByRandomAsDTO() { private List getJokeIds() { EntityManager em = getEntityManager(); try { - return em.createQuery("SELECT r.id FROM Joke r").getResultList(); + List result = em.createQuery("SELECT r.id FROM Joke r").getResultList(); + if (result == null || result.isEmpty()) + { + throw new IllegalStateException("Database is empty"); + } else{ + return result; + } } catch (Exception ex) { //em.getTransaction().rollback(); - throw new IllegalArgumentException("Could not get joke IDs" + ex.getMessage()); + throw new IllegalArgumentException("Could not get joke IDs -> " + ex.getMessage()); } finally { em.close(); } diff --git a/src/main/java/rest/ApplicationConfig.java b/src/main/java/rest/ApplicationConfig.java index c921712..4f23fbe 100644 --- a/src/main/java/rest/ApplicationConfig.java +++ b/src/main/java/rest/ApplicationConfig.java @@ -21,6 +21,7 @@ public Set> getClasses() { */ private void addRestResourceClasses(Set> resources) { resources.add(org.glassfish.jersey.server.wadl.internal.WadlResource.class); + resources.add(rest.JokeResource.class); resources.add(rest.RenameMeResource.class); } diff --git a/src/main/java/rest/JokeResource.java b/src/main/java/rest/JokeResource.java new file mode 100644 index 0000000..40b2a90 --- /dev/null +++ b/src/main/java/rest/JokeResource.java @@ -0,0 +1,109 @@ +package rest; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import utils.EMF_Creator; +import facades.JokeFacade; +import javax.persistence.EntityManagerFactory; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +//Todo Remove or change relevant parts before ACTUAL use +@Path("jokes") +public class JokeResource { + + private static final EntityManagerFactory EMF = EMF_Creator.createEntityManagerFactory(EMF_Creator.DbSelector.DEV, EMF_Creator.Strategy.DROP_AND_CREATE); + private static final JokeFacade FACADE = JokeFacade.getFacadeExample(EMF); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + @GET + @Produces({MediaType.APPLICATION_JSON}) + public String demo() { + return "{\"msg\":\"ACCESS GRANTED\"}"; + } + + @Path("/count") + @GET + @Produces({MediaType.APPLICATION_JSON}) + public String getJokeCount() { + try { + JsonObject count = new JsonObject(); + count.addProperty("count", FACADE.getJokeCount()); + return GSON.toJson(count); + } catch (Exception ex) { + return "{\"error\": \"" + ex.getMessage() + "\"}"; + } + } + + @GET + @Path("/all") + @Produces({MediaType.APPLICATION_JSON}) + public String getAllJokes() throws Exception { + try { + return GSON.toJson(FACADE.getAllJokes()); + } catch (Exception ex) { + return "{\"error\": \"" + ex.getMessage() + "\"}"; + } + } + + @GET + @Path("/all/dto") + @Produces({MediaType.APPLICATION_JSON}) + public String getAllJokesAsDTO() throws Exception { + try { + return GSON.toJson(FACADE.getAllJokesAsDTO()); + } catch (Exception ex) { + return "{\"error\": \"" + ex.getMessage() + "\"}"; + } + } + + + @GET + @Path("/{id}") + @Produces({MediaType.APPLICATION_JSON}) + public String getJokeByID(@PathParam("id") Long id) throws Exception { + try { + return GSON.toJson(FACADE.getJokeById(id)); + } catch (Exception ex) { + return "{\"error\": \"" + ex.getMessage() + "\"}"; + } + } + + @GET + @Path("/{id}/dto") + @Produces({MediaType.APPLICATION_JSON}) + public String getJokeDTOByID(@PathParam("id") Long id) throws Exception { + try { + return GSON.toJson(FACADE.getJokeByIdAsDTO(id)); + } catch (Exception ex) { + return "{\"error\": \"" + ex.getMessage() + "\"}"; + } + } + + @GET + @Path("/random") + @Produces({MediaType.APPLICATION_JSON}) + public String getJokeRandom() throws Exception { + try { + return GSON.toJson(FACADE.getJokeByRandom()); + } catch (Exception ex) { + return "{\"error\": \"" + ex.getMessage() + "\"}"; + } + } + + @GET + @Path("/random/dto") + @Produces({MediaType.APPLICATION_JSON}) + public String getJokeRandomAsDTO() throws Exception { + try { + return GSON.toJson(FACADE.getJokeByRandomAsDTO()); + } catch (Exception ex) { + return "[\"error\": \"" + ex.getMessage() + "\"}"; + } + } + +} diff --git a/src/test/java/facades/JokeFacadeTest.java b/src/test/java/facades/JokeFacadeTest.java index 6a8e01a..e74a4c5 100644 --- a/src/test/java/facades/JokeFacadeTest.java +++ b/src/test/java/facades/JokeFacadeTest.java @@ -7,10 +7,12 @@ import utils.EMF_Creator; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; +import javax.persistence.Query; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -55,7 +57,9 @@ public void setUp() { try { em.getTransaction().begin(); - em.createNamedQuery("Joke.deleteAllRows").executeUpdate(); + Query query = em.createNativeQuery("truncate table CA1_test.JOKE;"); + query.executeUpdate(); + //em.createNamedQuery("Joke.deleteAllRows").executeUpdate(); em.getTransaction().commit(); for (Joke j : jokes) { em.getTransaction().begin(); @@ -74,7 +78,7 @@ public void tearDown() { @Test public void testGetJokeCount() { - assertEquals(jokes.size(), facade.getJokeCount(), "Expects three rows in the database"); + assertEquals(jokes.size(), facade.getJokeCount(), "Expects four rows in the database"); } @Test @@ -135,19 +139,25 @@ public void testGetJokeById() { /** * em.find in getJokeByID does not actually throw an exception, but returns * null. + * + * + * I made a guard for that and throw an IllegalStateException. */ @Test public void testGetJokeByIdError() { //Arrange - Joke expResult = null; - Joke result; + Throwable expResult = new IllegalArgumentException("Could not get joke by ID -> Database is empty or joke doesn't exist."); + Throwable result; + long id = 99L; //Act - result = facade.getJokeById(99L); + result = assertThrows(IllegalArgumentException.class, () -> { + facade.getJokeById(id); + }); //Assert - Assertions.assertNull(result); - assertEquals(expResult, result); //does the same as above + Assertions.assertNotNull(result); + assertEquals(expResult.getCause(), result.getCause()); } @Test diff --git a/src/test/java/rest/JokeResourceTest.java b/src/test/java/rest/JokeResourceTest.java new file mode 100644 index 0000000..518fbed --- /dev/null +++ b/src/test/java/rest/JokeResourceTest.java @@ -0,0 +1,265 @@ +package rest; + +import dto.JokeDTO; +import entities.Joke; +import utils.EMF_Creator; +import io.restassured.RestAssured; +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import io.restassured.parsing.Parser; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Query; +import javax.ws.rs.core.UriBuilder; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.util.HttpStatus; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.server.ResourceConfig; +import org.hamcrest.MatcherAssert; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import utils.EMF_Creator.DbSelector; +import utils.EMF_Creator.Strategy; + +//Uncomment the line below, to temporarily disable this test +//@Disabled +/** + * Joke.java contains more than JokeDTO.java, therefore I test twice, to ensure + * all information is serialized. + * + * + * @author runin + */ +public class JokeResourceTest { + + private static final int SERVER_PORT = 7777; + private static final String SERVER_URL = "http://localhost/api"; + //Read this line from a settings-file since used several places + //private static final String TEST_DB = "jdbc:mysql://localhost:3307/startcode_test"; + + static final URI BASE_URI = UriBuilder.fromUri(SERVER_URL).port(SERVER_PORT).build(); + private static HttpServer httpServer; + private static EntityManagerFactory emf; + List jokes; + List jokesDTO; + + static HttpServer startServer() { + ResourceConfig rc = ResourceConfig.forApplication(new ApplicationConfig()); + return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc); + } + + @BeforeAll + public static void setUpClass() { + emf = EMF_Creator.createEntityManagerFactory(DbSelector.TEST, Strategy.CREATE); + + //NOT Required if you use the version of EMF_Creator.createEntityManagerFactory used above + //System.setProperty("IS_TEST", TEST_DB); + //We are using the database on the virtual Vagrant image, so username password are the same for all dev-databases + httpServer = startServer(); + + //Setup RestAssured + RestAssured.baseURI = SERVER_URL; + RestAssured.port = SERVER_PORT; + + RestAssured.defaultParser = Parser.JSON; + } + + @AfterAll + public static void closeTestServer() { + //System.in.read(); + httpServer.shutdownNow(); + } + + // Setup the DataBase (used by the test-server and this test) in a known state BEFORE EACH TEST + //TODO -- Make sure to change the script below to use YOUR OWN entity class + @BeforeEach + public void setUp() { + EntityManager em = emf.createEntityManager(); + + jokes = new ArrayList(); //init + jokesDTO = new ArrayList(); //init + + //add to collection + jokes.add(new Joke("A programmer puts two glasses on his bedside table before going to sleep. A full one, in case he gets thirsty, and an empty one, in case he doesn’t.", "https://redd.it/1kvhmz", "case-handling", 10)); + jokes.add(new Joke("A programmer is heading out to the grocery store, so his wife tells him \"get a gallon of milk, and if they have eggs, get a dozen.\" He returns with 13 gallons of milk.", "https://redd.it/1kvhmz", "numbers", 9)); + jokes.add(new Joke("What do programmers do before sex? Initialize
for
-play.", "https://redd.it/1kvhmz", "naughty", 7)); + jokes.add(new Joke("A programmer heads out to the store. His wife says \"while you're out, get some milk.\"", "https://redd.it/1kvhmz", "loops", 5)); + + try { + em.getTransaction().begin(); + Query query = em.createNativeQuery("truncate table CA1_test.JOKE;"); + query.executeUpdate(); + em.getTransaction().commit(); + for (Joke j : jokes) { + em.getTransaction().begin(); + em.persist(j); + em.getTransaction().commit(); + } + } finally { + em.close(); + } + + jokes.forEach(e -> jokesDTO.add(new JokeDTO(e))); + } + + @Test + public void testServerIsUp() { + System.out.println("Testing is server UP"); + given().when().get("/jokes").then().statusCode(200); + } + + //This test assumes the database contains two rows + @Test + public void testDummyMsg() throws Exception { + given() + .contentType("application/json") + .get("/jokes").then() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("msg", equalTo("ACCESS GRANTED")); + } + + @Test + public void testGetJokeCount() throws Exception { + given() + .contentType("application/json") + .get("/jokes/count").then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("count", equalTo(jokes.size())); + } + + @Test + public void testGetAllJokes() throws Exception { + given() + .contentType("application/json") + .get("/jokes/all").then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("[0].reference", equalTo(jokes.get(0).getReference())) + .body("[1].reference", equalTo(jokes.get(1).getReference())) + .body("[2].type", equalTo(jokes.get(2).getType())) + .body("[3].type", equalTo(jokes.get(3).getType())); + } + + @Test + public void testGetAllJokesAsDTO() throws Exception { + given() + .contentType("application/json") + .get("/jokes/all/dto").then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("[0].joke", equalTo(jokesDTO.get(0).getJoke())) + .body("[1].joke", equalTo(jokesDTO.get(1).getJoke())) + .body("[2].rating", equalTo(jokesDTO.get(2).getRating())) + .body("[3].rating", equalTo(jokesDTO.get(3).getRating())); + } + + @Test + public void testGetJokeByID_SIMPLE() throws Exception { + given() + .contentType("application/json") + .get("/jokes/{id}", jokes.get(1).getId()).then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("joke", equalTo(jokes.get(1).getJoke())); + } + + @Test + public void testGetJokeByID_ADVANCED() throws Exception { + Joke result = get("jokes/{id}", jokes.get(3).getId()).then() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .extract() + .as(Joke.class); + + MatcherAssert.assertThat((result), equalTo(jokes.get(3))); + } + + @Test + public void testGetJokeByIDError() throws Exception { + given() + .contentType("application/json") + .get("/jokes/{id}", 999).then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("error", equalTo("Could not get joke by ID -> Database is empty or joke doesn't exist.")); + } + + @Test + public void testGetJokeByIDAsDTO_SIMPLE() throws Exception { + given() + .contentType("application/json") + .get("/jokes/{id}/dto", jokesDTO.get(2).getId()).then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("joke", equalTo(jokesDTO.get(2).getJoke())); + } + + @Test + public void testGetJokeByIDAsDTO_ADVANCED() throws Exception { + JokeDTO result = get("jokes/{id}/dto", jokesDTO.get(3).getId()).then() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .extract() + .as(JokeDTO.class); + + MatcherAssert.assertThat((result), equalTo(jokesDTO.get(3))); + } + + @Test + public void testGetJokeByIDAsDTOError() throws Exception { + given() + .contentType("application/json") + .get("/jokes/{id}/dto", 888).then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("error", equalTo("Could not get joke (DTO) by ID -> Database is empty or joke doesn't exist.")); + } + + @Test + public void testGetJokeByRandom() throws Exception { + given() + .contentType("application/json") + .get("/jokes/random").then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("id", notNullValue()) + .body("joke", notNullValue()) + .body("reference", notNullValue()) + .body("type", notNullValue()) + .body("rating", notNullValue()); + } + + @Test + public void testGetJokeDTOByRandom() throws Exception { + given() + .contentType("application/json") + .get("/jokes/random/dto").then().log().body() + .assertThat() + .statusCode(HttpStatus.OK_200.getStatusCode()) + .body("id", notNullValue()) + .body("joke", notNullValue()) + .body("$", not(hasKey("reference"))) + .body("$", not(hasKey("type"))) + .body("rating", notNullValue()); + } + + public static void main(String[] args) throws IOException { + HttpServer server = startServer(); + System.in.read(); + server.shutdownNow(); + System.out.println("done"); + } + +}