From ad6e337caa5d7f77632701012af87da73e61c9e9 Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Sun, 11 Dec 2016 18:51:02 +0100 Subject: [PATCH] CompletableFutureCarControllerIntegrationTest --- .../controller/CompletableFutureCarController.java | 105 +++++++++++++++++ .../rest/controller/DeferrableCarController.java | 105 ----------------- ...pletableFutureCarControllerIntegrationTest.java | 128 +++++++++++++++++++++ 3 files changed, 233 insertions(+), 105 deletions(-) create mode 100644 SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/CompletableFutureCarController.java delete mode 100644 SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/DeferrableCarController.java create mode 100644 SpringJava/RxJava/web-services-spring-rxjava-server/src/test/java/de/spring/webservices/rest/controller/CompletableFutureCarControllerIntegrationTest.java diff --git a/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/CompletableFutureCarController.java b/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/CompletableFutureCarController.java new file mode 100644 index 0000000..9b199f0 --- /dev/null +++ b/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/CompletableFutureCarController.java @@ -0,0 +1,105 @@ +package de.spring.webservices.rest.controller; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import static de.spring.webservices.rest.controller.adapters.CompletableFutureAdapter.deferredAdapter; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.async.DeferredResult; + +import de.spring.webservices.domain.Car; +import de.spring.webservices.rest.business.service.CompletableFutureBusinessLogic; + +@RestController +@RequestMapping("/api/completablefuture/cars/") +public class CompletableFutureCarController { + private static final Logger LOGGER = LoggerFactory.getLogger(CompletableFutureCarController.class); + private static final int PAGE = 2; + private static final int PAGE_SIZE = 10; + + private final CompletableFutureBusinessLogic completableFutureBusinessLogic; + + @Inject + public CompletableFutureCarController(CompletableFutureBusinessLogic completableFutureBusinessLogic) { + this.completableFutureBusinessLogic = completableFutureBusinessLogic; + } + + @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET) + @ResponseStatus(HttpStatus.OK) + public DeferredResult> cars() { + + return deferredAdapter(completableFutureBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE))); + } + + @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET) + @ResponseStatus(HttpStatus.OK) + public DeferredResult car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader, + @PathVariable("id") long id, + @RequestParam Map params, + @RequestParam(value = "wheel", required = false) String[] wheelParams) { + + if (specialHeader != null) { + LOGGER.info("SPECIAL HEADER: " + specialHeader); + } + + if (params.get("mirror") != null) { + LOGGER.info("MIRROR: " + params.get("mirror")); + } + + if (params.get("window") != null) { + LOGGER.info("WINDOW: " + params.get("window")); + } + + if (wheelParams != null) { + for(String wheel : wheelParams) { + LOGGER.info(wheel); + } + } + + return deferredAdapter(completableFutureBusinessLogic.findById(id)); + + } + + @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, + produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST) + @ResponseStatus(HttpStatus.CREATED) + public DeferredResult> create(@RequestBody Car car) { + + return deferredAdapter(createAsync(car)); + } + + + private CompletableFuture> createAsync(Car car) { + + return completableFutureBusinessLogic + .createThrowable(car) + .thenComposeAsync(newCar -> + CompletableFuture.supplyAsync(() -> createResponseCar(newCar)) + + ); + } + + private ResponseEntity createResponseCar(Car car) { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.LOCATION, "/api/completablefuture/cars/" + car.getId()); + return new ResponseEntity<>(car, headers, HttpStatus.CREATED); + } +} diff --git a/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/DeferrableCarController.java b/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/DeferrableCarController.java deleted file mode 100644 index caf35b4..0000000 --- a/SpringJava/RxJava/web-services-spring-rxjava-server/src/main/java/de/spring/webservices/rest/controller/DeferrableCarController.java +++ /dev/null @@ -1,105 +0,0 @@ -package de.spring.webservices.rest.controller; - -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -import static de.spring.webservices.rest.controller.adapters.CompletableFutureAdapter.deferredAdapter; - -import javax.inject.Inject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.request.async.DeferredResult; - -import de.spring.webservices.domain.Car; -import de.spring.webservices.rest.business.service.CompletableFutureBusinessLogic; - -@RestController -@RequestMapping("/api/deferrable/cars/") -public class DeferrableCarController { - private static final Logger LOGGER = LoggerFactory.getLogger(DeferrableCarController.class); - private static final int PAGE = 2; - private static final int PAGE_SIZE = 10; - - private final CompletableFutureBusinessLogic completableFutureBusinessLogic; - - @Inject - public DeferrableCarController(CompletableFutureBusinessLogic completableFutureBusinessLogic) { - this.completableFutureBusinessLogic = completableFutureBusinessLogic; - } - - @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET) - @ResponseStatus(HttpStatus.OK) - public DeferredResult> cars() { - - return deferredAdapter(completableFutureBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE))); - } - - @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET) - @ResponseStatus(HttpStatus.OK) - public DeferredResult car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader, - @PathVariable("id") long id, - @RequestParam Map params, - @RequestParam(value = "wheel", required = false) String[] wheelParams) { - - if (specialHeader != null) { - LOGGER.info("SPECIAL HEADER: " + specialHeader); - } - - if (params.get("mirror") != null) { - LOGGER.info("MIRROR: " + params.get("mirror")); - } - - if (params.get("window") != null) { - LOGGER.info("WINDOW: " + params.get("window")); - } - - if (wheelParams != null) { - for(String wheel : wheelParams) { - LOGGER.info(wheel); - } - } - - return deferredAdapter(completableFutureBusinessLogic.findById(id)); - - } - - @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, - produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST) - @ResponseStatus(HttpStatus.CREATED) - public DeferredResult> create(@RequestBody Car car) { - - return deferredAdapter(createAsync(car)); - } - - - private CompletableFuture> createAsync(Car car) { - - return completableFutureBusinessLogic - .createThrowable(car) - .thenComposeAsync(newCar -> - CompletableFuture.supplyAsync(() -> createResponseCar(newCar)) - - ); - } - - private ResponseEntity createResponseCar(Car car) { - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.LOCATION, "/api/cars/" + car.getId()); - return new ResponseEntity<>(car, headers, HttpStatus.CREATED); - } -} diff --git a/SpringJava/RxJava/web-services-spring-rxjava-server/src/test/java/de/spring/webservices/rest/controller/CompletableFutureCarControllerIntegrationTest.java b/SpringJava/RxJava/web-services-spring-rxjava-server/src/test/java/de/spring/webservices/rest/controller/CompletableFutureCarControllerIntegrationTest.java new file mode 100644 index 0000000..8c41608 --- /dev/null +++ b/SpringJava/RxJava/web-services-spring-rxjava-server/src/test/java/de/spring/webservices/rest/controller/CompletableFutureCarControllerIntegrationTest.java @@ -0,0 +1,128 @@ +package de.spring.webservices.rest.controller; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.Matchers.any; +import static org.hamcrest.Matchers.is; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.spring.webservices.domain.Car; +import de.spring.webservices.rest.business.service.CompletableFutureBusinessLogic; + + +// jsonPath, how to: https://github.com/jayway/JsonPath | http://jsonpath.herokuapp.com/ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ "classpath*:spring-configuration/mvc/rest/*.xml"}) +public class CompletableFutureCarControllerIntegrationTest { + private static final int PAGE = 2; + private static final int PAGE_SIZE = 10; + private static final String TEMPLATE = "Car: %s"; + + private CompletableFutureBusinessLogic completableFutureBusinessLogic; + private CompletableFutureCarController controller; + private MockMvc mockMvc; + + @Before + public void setup() { + completableFutureBusinessLogic = mock(CompletableFutureBusinessLogic.class); + controller = new CompletableFutureCarController(completableFutureBusinessLogic); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + public void testWhenGetAllCarsThenRetrieveJsonValues() throws Exception { + final List cars = new ArrayList<>(); + cars.add(new Car(1L, String.format(TEMPLATE, 1))); + CompletableFuture> future = CompletableFuture.supplyAsync(() -> new PageImpl<>(cars)); + given(completableFutureBusinessLogic.findAll(new PageRequest(PAGE, PAGE_SIZE))).willReturn(future); + + MvcResult result = mockMvc.perform(get("/api/completablefuture/cars/") + .accept(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(request().asyncStarted()) + .andExpect(request().asyncResult(instanceOf(Page.class))) + .andReturn(); + + mockMvc.perform(asyncDispatch(result)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.content[0].id", any(Integer.class))) + .andExpect(jsonPath("$.content[0].id", any(Integer.class))) + .andExpect(jsonPath("$.content[0].content", is("Car: 1"))) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)); + } + + @Test + public void testWhenGetOneCarThenRetrieveJsonValue() throws Exception { + CompletableFuture expected = CompletableFuture.supplyAsync(() -> new Car(1L, String.format(TEMPLATE, 1))); + given(completableFutureBusinessLogic.findById(1L)).willReturn(expected); + + MvcResult result = mockMvc.perform(get("/api/completablefuture/cars/{id}", 1L) + .accept(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(request().asyncStarted()) + .andExpect(request().asyncResult(instanceOf(Car.class))) + .andReturn(); + + mockMvc.perform(asyncDispatch(result)) + .andExpect(status().isOk()) + .andExpect(jsonPath("id", any(Integer.class))) + .andExpect(jsonPath("content", is("Car: 1"))) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)); + } + + @Test + public void testWhenCreateNewCarThenRetrieveJsonValue() throws Exception { + Car car = new Car(null, "nothing"); + CompletableFuture expected = CompletableFuture.supplyAsync(() -> new Car(1L, String.format(TEMPLATE, 1))); + given(completableFutureBusinessLogic.createThrowable(car)).willReturn(expected); + + MvcResult result = mockMvc.perform(post("/api/completablefuture/cars/") + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(asJsonString(car)) + .accept(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(request().asyncStarted()) + .andExpect(request().asyncResult(instanceOf(ResponseEntity.class))) + .andReturn(); + + mockMvc.perform(asyncDispatch(result)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("id", any(Integer.class))) + .andExpect(jsonPath("content", is("Car: 1"))) + .andExpect(header().string(HttpHeaders.LOCATION, "/api/completablefuture/cars/1")) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)); + } + + private static String asJsonString(final Object obj) throws JsonProcessingException { + final ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(obj); + } +} -- 2.1.4