diff --git a/src/main/java/cx/catapult/animals/service/BaseService.java b/src/main/java/cx/catapult/animals/service/BaseService.java index fa0810e..573eb8a 100644 --- a/src/main/java/cx/catapult/animals/service/BaseService.java +++ b/src/main/java/cx/catapult/animals/service/BaseService.java @@ -1,8 +1,11 @@ package cx.catapult.animals.service; import cx.catapult.animals.domain.Animal; +import org.apache.commons.lang3.StringUtils; import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; public abstract class BaseService implements Service { @@ -25,4 +28,33 @@ public T create(T animal) { public T get(String id) { return items.get(id); } + + + @Override + public boolean delete(String id) { + if (items.containsKey(id)) { + T removed = items.remove(id); + return true; + } + return false; + } + + @Override + public boolean update(T animal) { + String id = animal.getId(); + if (id != null && items.containsKey(id)) { + T update = items.put(id, animal); + return true; + } + return false; + } + + @Override + public Collection search(String name, String description) { + Collection animals = all(); + Predicate namePredicate = item -> StringUtils.containsIgnoreCase(item.getName(), name); + Predicate descPredicate = item -> StringUtils.containsIgnoreCase(item.getDescription(), description); + Collection filtered = animals.stream().filter(namePredicate).filter(descPredicate).collect(Collectors.toList()); + return filtered; + } } diff --git a/src/main/java/cx/catapult/animals/service/Service.java b/src/main/java/cx/catapult/animals/service/Service.java index e33b4f6..4c8e28c 100644 --- a/src/main/java/cx/catapult/animals/service/Service.java +++ b/src/main/java/cx/catapult/animals/service/Service.java @@ -12,4 +12,9 @@ public interface Service { public T get(String id); + public boolean delete(String id); + + boolean update(T animal); + + public Collection search(String name, String description); } diff --git a/src/main/java/cx/catapult/animals/web/CatsController.java b/src/main/java/cx/catapult/animals/web/CatsController.java index bc88c5f..7c65149 100644 --- a/src/main/java/cx/catapult/animals/web/CatsController.java +++ b/src/main/java/cx/catapult/animals/web/CatsController.java @@ -5,10 +5,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Collection; +@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600) @RestController @RequestMapping(path = "/api/1/cats", produces = MediaType.APPLICATION_JSON_VALUE) public class CatsController { @@ -35,4 +37,32 @@ Cat get(@PathVariable String id) { create(@RequestBody Cat cat) { return service.create(cat); } + + @DeleteMapping(value = "/{id}") + public @ResponseBody + ResponseEntity delete(@PathVariable String id) { + boolean deleted = service.delete(id); + return ResponseEntity.ok().body(deleted); +// if (deleted) { +// return ResponseEntity.noContent().build(); +// } else { +// return ResponseEntity.notFound().build(); +// } + } + + @PutMapping(value = "/update") + @ResponseStatus(HttpStatus.OK) + public @ResponseBody + boolean edit(@RequestBody Cat cat) { + return service.update(cat); + } + + + @GetMapping(value = "/search") + @ResponseStatus(HttpStatus.OK) + public @ResponseBody + Collection search(@RequestParam(name = "name", required = false) String name, @RequestParam(name = "desc", required = false) String desc) { + return service.search(name, desc); + } + } diff --git a/src/test/java/cx/catapult/animals/service/CatsServiceTest.java b/src/test/java/cx/catapult/animals/service/CatsServiceTest.java index 98acd6d..d1c864c 100644 --- a/src/test/java/cx/catapult/animals/service/CatsServiceTest.java +++ b/src/test/java/cx/catapult/animals/service/CatsServiceTest.java @@ -1,8 +1,11 @@ package cx.catapult.animals.service; import cx.catapult.animals.domain.Cat; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.Collection; + import static org.assertj.core.api.Assertions.assertThat; public class CatsServiceTest { @@ -37,4 +40,60 @@ public void getShouldWork() throws Exception { assertThat(actual.getDescription()).isEqualTo(cat.getDescription()); assertThat(actual.getGroup()).isEqualTo(cat.getGroup()); } + + @Test + public void updateShouldWork() throws Exception { + service.create(cat); + Cat actual = service.get(cat.getId()); + assertThat(actual).isEqualTo(cat); + actual.setName("nameUpdated"); + actual.setDescription("descUpdated"); + Assertions.assertTrue(service.update(actual)); + + Cat updated = service.get(actual.getId()); + System.out.println(updated); + assertThat(actual.getName()).isEqualTo(updated.getName()); + assertThat(actual.getDescription()).isEqualTo(updated.getDescription()); + } + + @Test + public void updateShouldNotWork() throws Exception { + service.create(cat); + Cat actual = service.get(cat.getId()); + assertThat(actual).isEqualTo(cat); + actual.setName("nameUpdated"); + actual.setDescription("descUpdated"); + actual.setId("some invalid id"); + Assertions.assertFalse(service.update(actual)); + } + + @Test + public void deleteShouldWork() throws Exception { + Cat created = service.create(cat); + assertThat(service.all().size()).isEqualTo(1); + boolean deleted = service.delete(created.getId()); + assertThat(deleted).isEqualTo(true); + assertThat(service.all().size()).isEqualTo(0); + } + + @Test + public void searchShouldWork() throws Exception { + Cat first = service.create(cat); + assertThat(service.all().size()).isEqualTo(1); + + Cat thisCat = new Cat(); + thisCat.setName("Jerry"); + thisCat.setDescription("Mouse Cat"); + Cat second = service.create(thisCat); + assertThat(service.all().size()).isEqualTo(2); + + Collection results = service.search("", ""); + assertThat(results.size()).isEqualTo(2); + results = service.search("tom", ""); + assertThat(results.size()).isEqualTo(1); + results = service.search("", "Mouse"); + assertThat(results.size()).isEqualTo(1); + results = service.search("", "cat"); + assertThat(results.size()).isEqualTo(2); + } } diff --git a/src/test/java/cx/catapult/animals/web/CatsControllerIT.java b/src/test/java/cx/catapult/animals/web/CatsControllerIT.java index 2016ba8..280aaca 100644 --- a/src/test/java/cx/catapult/animals/web/CatsControllerIT.java +++ b/src/test/java/cx/catapult/animals/web/CatsControllerIT.java @@ -1,6 +1,7 @@ package cx.catapult.animals.web; +import com.fasterxml.jackson.databind.ObjectMapper; import cx.catapult.animals.domain.Cat; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -8,10 +9,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import java.net.URL; +import java.util.Arrays; import java.util.Collection; import static org.assertj.core.api.Assertions.assertThat; @@ -30,6 +31,8 @@ public class CatsControllerIT { @Autowired private TestRestTemplate template; + private ObjectMapper objectMapper = new ObjectMapper(); + @BeforeEach public void setUp() throws Exception { this.base = new URL("http://localhost:" + port + "/api/1/cats"); @@ -64,4 +67,70 @@ Cat create(String name) { assertThat(created.getName()).isEqualTo(name); return created; } + + + + @Test + public void updateShouldWork() throws Exception { + ResponseEntity response = template.postForEntity(base.toString(), cat, Cat.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + + Cat created = response.getBody(); + created.setName("updatedName"); + created.setDescription("updatedDesc"); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity requestEntity = new HttpEntity<>(created, headers); + ResponseEntity responseEntity = template.exchange(base.toString() + "/update", HttpMethod.PUT, requestEntity, Boolean.class, created.getId()); + boolean updated = responseEntity.getBody(); + assertThat(updated).isTrue(); + + response = template.getForEntity(base.toString() + "/" + created.getId(), Cat.class); + assertThat(response.getBody().getName()).isEqualTo(created.getName()); + assertThat(response.getBody().getDescription()).isEqualTo(created.getDescription()); + } + + @Test + public void updateShouldNotWork() throws Exception { + ResponseEntity response = template.postForEntity(base.toString(), cat, Cat.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + + Cat created = response.getBody(); + created.setId("invalid id"); + created.setName("updatedName"); + created.setDescription("updatedDesc"); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity requestEntity = new HttpEntity<>(created, headers); + ResponseEntity responseEntity = template.exchange(base.toString() + "/update", HttpMethod.PUT, requestEntity, Boolean.class, created.getId()); + boolean updated = responseEntity.getBody(); + assertThat(updated).isFalse(); + } + + @Test + public void deleteShouldWork() throws Exception { + ResponseEntity response = template.postForEntity(base.toString(), cat, Cat.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody().getId()).isNotEmpty(); + Cat created = response.getBody(); + + ResponseEntity deleted = template.exchange(base.toString() + "/" + created.getId(), HttpMethod.DELETE, null, Void.class); + assertThat(deleted.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(deleted.getBody()).isNull(); + + response = template.getForEntity(base.toString() + "/" + created.getId(), Cat.class); + assertThat(response.getBody()).isNull(); + } + + @Test + public void searchShouldWork() throws Exception { + String name = ""; + String desc = ""; + ResponseEntity response = template.getForEntity(base.toString() + "/search?name="+name +"&desc=" +desc, Collection.class); + assertThat(response.getBody().size()).isGreaterThanOrEqualTo(7); + + name = "tiger"; + response = template.getForEntity(base.toString() + "/search?name="+name +"&desc=" +desc, Collection.class); + assertThat(response.getBody().size()).isGreaterThanOrEqualTo(1); + } } diff --git a/src/test/java/cx/catapult/animals/web/CatsControllerTest.java b/src/test/java/cx/catapult/animals/web/CatsControllerTest.java index 1264b57..74b99df 100644 --- a/src/test/java/cx/catapult/animals/web/CatsControllerTest.java +++ b/src/test/java/cx/catapult/animals/web/CatsControllerTest.java @@ -1,5 +1,7 @@ package cx.catapult.animals.web; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import cx.catapult.animals.domain.Cat; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -9,6 +11,9 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -23,6 +28,8 @@ public class CatsControllerTest { private Cat cat = new Cat("Tom", "Bob cat"); private String json = "{ \"name\": \"Tom\", \"description\": \"Bob cat\" }"; + private ObjectMapper objectMapper = new ObjectMapper(); + @Test public void all() throws Exception { mvc.perform(MockMvcRequestBuilders.get("/api/1/cats").accept(MediaType.APPLICATION_JSON)) @@ -40,4 +47,50 @@ public void create() throws Exception { mvc.perform(MockMvcRequestBuilders.post("/api/1/cats").content(json).contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(status().isCreated()); } + + + @Test + public void update() throws Exception { + json = "{ \"name\": \"Tom updated\", \"description\": \"Bob cat updated\" }"; + mvc.perform(MockMvcRequestBuilders.put("/api/1/cats/update").content(json).contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()); + } + + + @Test + public void delete() throws Exception { + + String response = mvc.perform(MockMvcRequestBuilders.post("/api/1/cats").content(json).contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()).andReturn().getResponse().getContentAsString(); + Cat created = objectMapper.readValue(response, Cat.class); + String id = created.getId(); + + mvc.perform(MockMvcRequestBuilders.delete("/api/1/cats/" + id).content(json).contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()); + + String invalidId = "some non existing id"; + mvc.perform(MockMvcRequestBuilders.delete("/api/1/cats/" + invalidId).content(json).contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()); + + } + + @Test + public void search() throws Exception { + + String response = mvc.perform(MockMvcRequestBuilders.get("/api/1/cats").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + Collection cats = objectMapper.readValue(response, Collection.class); + String nameQueryString = "Tiger"; + String descQueryString = ""; + String searchResponse = mvc.perform(MockMvcRequestBuilders.get("/api/1/cats/search") + .param("name", nameQueryString).param("desc", descQueryString)) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + Collection searchedCats = objectMapper.readValue(searchResponse, new TypeReference>() { + }); + assertThat(searchedCats).hasSize(1); + + Cat resultCat = searchedCats.iterator().next(); + assertThat(resultCat.getName()).isEqualTo("Tiger"); + assertThat(resultCat.getDescription()).isEqualTo("Large cat"); + } } \ No newline at end of file