diff --git a/pom.xml b/pom.xml index 67931c2..f502e59 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.6 + 3.2.0 diff --git a/src/main/java/com/alura/aluraflixapi/controller/VideoController.java b/src/main/java/com/alura/aluraflixapi/controller/VideoController.java index 552bf6d..57f7157 100644 --- a/src/main/java/com/alura/aluraflixapi/controller/VideoController.java +++ b/src/main/java/com/alura/aluraflixapi/controller/VideoController.java @@ -12,8 +12,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -36,7 +34,7 @@ @SecurityRequirement(name = "bearer-key") public class VideoController { - private static final String LOGGIN_PREFIX = "[VideoController]"; + private static final String LOGGING_PREFIX = "[VideoController]"; private final VideoService service; @@ -47,10 +45,10 @@ public VideoController(final VideoService service) { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity> getVideos(Pageable pageable) { - log.info("{} Request to get All videos", LOGGIN_PREFIX); + log.info("{} Request to get All videos", LOGGING_PREFIX); final Page videos = this.service.getVideos(pageable); if (videos.hasContent()) { - log.info("{} Response {}: ", LOGGIN_PREFIX, videos); + log.info("{} Response {}: ", LOGGING_PREFIX, videos); return ResponseEntity.ok().body(videos); } else { return ResponseEntity.noContent().build(); @@ -60,7 +58,7 @@ public ResponseEntity> getVideos(Pageable pageable) { @GetMapping("/{id}") public ResponseEntity getById(@NotBlank @PathVariable final String id) { - log.info("{} Request to get a video by ID: {}", LOGGIN_PREFIX, id); + log.info("{} Request to get a video by ID: {}", LOGGING_PREFIX, id); return Optional.ofNullable(service.getById(id)) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); @@ -70,7 +68,7 @@ public ResponseEntity getById(@NotBlank @PathVariable final String id) @PostMapping public ResponseEntity save(@Valid @RequestBody final VideoDto dto, final UriComponentsBuilder uriBuilder) { - log.info("{} Request to Save a new video: {}", LOGGIN_PREFIX, dto); + log.info("{} Request to Save a new video: {}", LOGGING_PREFIX, dto); final VideoDto videoDto = this.service.save(dto); //good practices to return the Location in the Header to be search by Id //return Http code 201 and Localtion with Id @@ -81,10 +79,10 @@ public ResponseEntity save(@Valid @RequestBody final VideoDto dto, @PutMapping public ResponseEntity update(@Valid @RequestBody final UpdateVideoDto dto, final UriComponentsBuilder uriBuilder) { - log.info("{} Request to update a video: {}", LOGGIN_PREFIX, dto); + log.info("{} Request to update a video: {}", LOGGING_PREFIX, dto); final var videoDto = this.service.updateMovie(dto); //good practices to return the Location in the Header to be search by Id - //return Http code 201 and Localtion with Id + //return Http code 201 and Location with Id return ResponseEntity.created(uriBuilder.path("/videos/{id}") .buildAndExpand(videoDto.id()) .toUri()).body(videoDto); @@ -93,16 +91,16 @@ public ResponseEntity update(@Valid @RequestBody final UpdateVid @DeleteMapping("/{id}") @Secured("ROLE_ADMIN") public ResponseEntity delete(@NotBlank @PathVariable final String id) { - log.info("{} Request to Delete a video by ID: {}", LOGGIN_PREFIX, id); + log.info("{} Request to Delete a video by ID: {}", LOGGING_PREFIX, id); final Optional dto = this.service.delete(id); return dto.map(videoDto -> ResponseEntity.status(HttpStatus.NO_CONTENT).body(videoDto)) .orElseGet(() -> ResponseEntity.noContent().build()); } - @GetMapping("/search") + @GetMapping("/title") public ResponseEntity> getVideosByTitle( @NotBlank @RequestParam("title") final String title) { - log.info("{} Request to get a video by title: {}", LOGGIN_PREFIX, title); + log.info("{} Request to get a video by title: {}", LOGGING_PREFIX, title); final var videosByTitle = this.service.getVideosByTitle(title); if (videosByTitle.isEmpty()) { return ResponseEntity.noContent().build(); diff --git a/src/test/java/com/alura/aluraflixapi/controller/CategoryControllerTest.java b/src/test/java/com/alura/aluraflixapi/controller/CategoryControllerTest.java index fa343c1..aed72f2 100644 --- a/src/test/java/com/alura/aluraflixapi/controller/CategoryControllerTest.java +++ b/src/test/java/com/alura/aluraflixapi/controller/CategoryControllerTest.java @@ -25,7 +25,6 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import java.util.Arrays; import java.util.List; diff --git a/src/test/java/com/alura/aluraflixapi/controller/VideoControllerTest.java b/src/test/java/com/alura/aluraflixapi/controller/VideoControllerTest.java index 277c677..2c948c2 100644 --- a/src/test/java/com/alura/aluraflixapi/controller/VideoControllerTest.java +++ b/src/test/java/com/alura/aluraflixapi/controller/VideoControllerTest.java @@ -1,12 +1,5 @@ package com.alura.aluraflixapi.controller; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - import com.alura.aluraflixapi.domain.category.Rating; import com.alura.aluraflixapi.domain.category.dto.CategoryDto; import com.alura.aluraflixapi.domain.video.dto.UpdateVideoDto; @@ -19,16 +12,12 @@ import com.alura.aluraflixapi.infraestructure.service.CategoryService; import com.alura.aluraflixapi.infraestructure.service.UserService; import com.alura.aluraflixapi.infraestructure.service.VideoServiceImpl; +import com.alura.aluraflixapi.jsonutils.ParseJson; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -36,9 +25,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.*; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; @@ -46,8 +33,16 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultHandlers; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @ExtendWith(SpringExtension.class) @@ -55,7 +50,9 @@ @WebMvcTest //this annotation can be replaced at each test method scope @WithMockUser(value = "admin", username = "admin", password = "admin", roles = "ADMIN") -class VideoControllerTest { +class VideoControllerTest extends ParseJson { + + private static final String PREFIX_PATH = "/video/"; private static ObjectMapper mapper; @@ -105,13 +102,15 @@ static void setup() { } @Test + @DisplayName("Should return all videos and response 200 OK") void get_all_videos_test() throws Exception { //Given - final List videos = buildVideosDto(); + final var jsonFile = getJsonFile(PREFIX_PATH + "getAllVideos_response_ok.json"); + final var videosExpect = Arrays.stream(parseToJavaObject(jsonFile, VideoDto[].class)).toList(); //Workaround to fix JsonSerialize on Spring boot version 3.2.0 final var pageable = PageRequest.of(0, 10); when(this.videoService.getVideos(Mockito.any())) - .thenReturn(new PageImpl<>(videos, pageable, videos.size())); + .thenReturn(new PageImpl<>(videosExpect, pageable, videosExpect.size())); final MvcResult response = this.mockMvc.perform(MockMvcRequestBuilders.get("/videos") .contentType(MediaType.APPLICATION_JSON)) @@ -124,38 +123,54 @@ void get_all_videos_test() throws Exception { class)); //Then assertNotNull(videosDtos); - assertEquals(4, videosDtos.size()); + assertEquals(videosExpect.size(), videosDtos.size()); } @Test + @DisplayName("Should not return all videos and response No Content") + void get_all_videos_response_no_content_test() throws Exception { + //Given + when(this.videoService.getVideos(Mockito.any())) + .thenReturn(Page.empty()); + + //Then + this.mockMvc.perform(MockMvcRequestBuilders.get("/videos") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().is2xxSuccessful()); + } + + @Test + @DisplayName("Should return a video by Id and response 200 OK") void get_video_by_id() throws Exception { //Given - final VideoDto request = buildVideosDto().get(0); - + final var jsonFile = getJsonFile(PREFIX_PATH + "getById_video_response_ok.json"); + final var videoDto = parseToJavaObject(jsonFile, VideoDto.class); when(this.videoService.getById(Mockito.anyString())) - .thenReturn(request); + .thenReturn(videoDto); //When - final MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get("/videos/{id}", "1") + final MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get("/videos/{id}", "63680c011892283477b3e9b9") .contentType(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().is2xxSuccessful()) .andReturn(); //Then - VideoDto videoDto = mapper.readValue(mvcResult.getResponse().getContentAsString(), + VideoDto response = mapper.readValue(mvcResult.getResponse().getContentAsString(), VideoDto.class); assertNotNull(videoDto); - assertAll(() -> assertEquals(request.id(), videoDto.id()), - () -> Assertions.assertEquals(request.url(), videoDto.url()), - () -> Assertions.assertEquals(request.description(), videoDto.description()), - () -> Assertions.assertEquals(request.title(), videoDto.title()) + assertAll(() -> assertEquals(response.id(), videoDto.id()), + () -> Assertions.assertEquals(response.url(), videoDto.url()), + () -> Assertions.assertEquals(response.description(), videoDto.description()), + () -> Assertions.assertEquals(response.title(), videoDto.title()) ); } @Test + @DisplayName("Should create a new Video and response 200 OK") void save_a_new_video_test() throws Exception { //Given @@ -189,15 +204,11 @@ void save_a_new_video_test() throws Exception { } @Test + @DisplayName("Should update a video by Id and return 200 OK") void update_video_by_id_test() throws Exception { - //Given - final var videoToUpdate = - new UpdateVideoDto(UUID.randomUUID().toString(), - "Hobbit: La batalla de los cincos ejercitos", "La batalla de los cincos ejercitos", - "www.thehobbit2.com", - new CategoryDto(UUID.randomUUID().toString(), Rating.FANTASY.name(), "Fantasy", - "#FFD700")); + final var jsonFile = getJsonFile(PREFIX_PATH + "getById_video_response_ok.json"); + final var videoToUpdate = parseToJavaObject(jsonFile, UpdateVideoDto.class); when(this.videoService.updateMovie(Mockito.any())) .thenReturn(videoToUpdate); @@ -229,6 +240,7 @@ void update_video_by_id_test() throws Exception { } @Test + @DisplayName("Should allow delete a video by id and response No Content") void delete_video_by_id_test() throws Exception { //Given @@ -241,38 +253,42 @@ void delete_video_by_id_test() throws Exception { .andExpect(status().isNoContent()); } + @Test + @DisplayName("Should return a list of videos searched by title response OK") + void getVideosByTitle_test() throws Exception { + //Given + final var jsonFile = getJsonFile(PREFIX_PATH + "getVideoByTitle_response_ok.json"); + final var videosByTitleExpected = Arrays.stream(parseToJavaObject(jsonFile, VideoDto[].class)).toList(); + when(this.videoService.getVideosByTitle(Mockito.anyString())) + .thenReturn(videosByTitleExpected); + + final MvcResult response = this.mockMvc.perform(MockMvcRequestBuilders.get("/videos/title") + .param("title", "The Hobbit - The battle of five armies") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isFound()) + .andReturn(); + + //Then + assertNotNull(response); + final var videosByTitleResponse = Arrays.stream(mapper.readValue(response.getResponse().getContentAsString(), + VideoDto[].class)).toList(); + org.assertj.core.api.Assertions.assertThat(videosByTitleResponse).usingRecursiveComparison() + .isEqualTo(videosByTitleExpected); + } + + @Test + @DisplayName("Should not return a list of videos searched by title response No Content") + void getVideosByTitle_response_no_content_test() throws Exception { + //Given + when(this.videoService.getVideosByTitle(Mockito.anyString())) + .thenReturn(List.of()); - private static List buildVideosDto() { - final var categoryDto = new CategoryDto(UUID.randomUUID().toString(), Rating.FREE.name(), - "Fantasy", "#FFD700"); - return List.of(VideoDto.builder() - .id(UUID.randomUUID().toString()) - .title("Lord of the rings - fellowship of the ring") - .description("Lord of the rings - fellowship of the ring") - .url("http://www.lordoftherings.com") - .category(categoryDto) - .build(), - VideoDto.builder() - .id(UUID.randomUUID().toString()) - .title("Lord of the rings - return of the king") - .description("Lord of the rings - return of the king") - .url("http://www.lordoftherings.com") - .category(categoryDto) - .build(), - VideoDto.builder() - .id(UUID.randomUUID().toString()) - .title("Lord of the rings - The Two towers") - .description("Lord of the rings - The Two towers") - .url("http://www.lordoftherings.com") - .category(categoryDto) - .build(), - VideoDto.builder() - .id(UUID.randomUUID().toString()) - .title("The hobbit - unnespect adventure") - .description("The hobbit - unnespect adventure") - .url("http://www.thehobbit.com") - .category(categoryDto) - .build() - ); + final MvcResult response = this.mockMvc.perform(MockMvcRequestBuilders.get("/videos/title") + .param("title", "The Hobbit - The battle of five armies") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isNoContent()) + .andReturn(); } } \ No newline at end of file diff --git a/src/test/resources/json/video/getVideoByTitle_response_ok.json b/src/test/resources/json/video/getVideoByTitle_response_ok.json new file mode 100644 index 0000000..78ae321 --- /dev/null +++ b/src/test/resources/json/video/getVideoByTitle_response_ok.json @@ -0,0 +1,14 @@ +[ + { + "id": "63680c011892283477b3e9b9", + "title": "The Hobbit - The battle of Five armies", + "description": "best movie ever", + "url": "https://theHobbitThebattleofivearmies.com", + "category": { + "id": "63f67ec16295ed744dd460cd", + "rating": "FREE", + "title": "Fantasy", + "colorHex": "#ffff83" + } + } +] \ No newline at end of file