Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package br.com.clickbus.challenge.controller;


import br.com.clickbus.challenge.dto.PlaceDTO;
import br.com.clickbus.challenge.entity.Place;
import br.com.clickbus.challenge.exception.PlaceNotFoundException;
import br.com.clickbus.challenge.queryfilters.PlaceQueryFilter;
import br.com.clickbus.challenge.service.PlaceService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -16,6 +17,7 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

import javax.validation.Valid;

Expand All @@ -24,29 +26,39 @@
@RequestMapping("places")
public class PlaceController {

@Autowired
private PlaceService service;

@PostMapping
public ResponseEntity create(@RequestBody @Valid PlaceDTO dto) {
return new ResponseEntity(service.save(dto.buildPlace()).convertToDTO(), HttpStatus.CREATED);
public ResponseEntity<PlaceDTO> create(@RequestBody @Valid PlaceDTO dto) {
return new ResponseEntity<PlaceDTO>(service.save(dto.buildPlace()).convertToDTO(), HttpStatus.CREATED);
}

@GetMapping("{id}")
public ResponseEntity findById(@PathVariable Long id) {
public ResponseEntity<PlaceDTO> findById(@PathVariable Long id) {
return service.findById(id)
.map(place -> ResponseEntity.ok(place.convertToDTO()))
.orElseThrow(() -> new PlaceNotFoundException(HttpStatus.NOT_FOUND));
.map(place -> ResponseEntity.ok(place.convertToDTO()))
.orElseThrow(() -> new PlaceNotFoundException(HttpStatus.NOT_FOUND));
}

@GetMapping
public ResponseEntity findAll() {
Iterable<PlaceDTO> places = PlaceDTO.convertToList(service.findAll());
return ResponseEntity.ok(places);
public ResponseEntity<Object> findAll(PlaceQueryFilter filter) {
Iterable<PlaceDTO> places;
if (filter.getName() != null) {
places = PlaceDTO.convertToList(service.findByName(filter.getName()));
long size = places.spliterator().getExactSizeIfKnown();
if (filter.getName().isBlank() || size == 0) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nenhum lugar encontrado com esse nome.");
}
} else {
places = PlaceDTO.convertToList(service.findAll());
}
return ResponseEntity.status(HttpStatus.OK).body(places);
}

@PutMapping("/{id}")
public ResponseEntity alter(@PathVariable Long id, @RequestBody @Valid PlaceDTO placeDTO) {
public ResponseEntity<PlaceDTO> alter(@PathVariable Long id, @RequestBody @Valid PlaceDTO placeDTO) {
Place place = service.findById(id).orElseThrow(null);
return new ResponseEntity(service.alter(place, placeDTO).convertToDTO(), HttpStatus.OK);
return new ResponseEntity<PlaceDTO>(service.alter(place, placeDTO).convertToDTO(), HttpStatus.OK);
}
}
3 changes: 2 additions & 1 deletion src/main/java/br/com/clickbus/challenge/entity/Place.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package br.com.clickbus.challenge.entity;


import br.com.clickbus.challenge.dto.PlaceDTO;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
Expand All @@ -15,6 +15,7 @@

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Place {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package br.com.clickbus.challenge.queryfilters;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class PlaceQueryFilter {
private String name;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import br.com.clickbus.challenge.entity.Place;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface PlaceRepository extends JpaRepository<Place, Long> {
public interface PlaceRepository extends JpaRepository<Place, Long>, JpaSpecificationExecutor<Place> {
List<Place> findByName(String name);
}
25 changes: 17 additions & 8 deletions src/main/java/br/com/clickbus/challenge/service/PlaceService.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package br.com.clickbus.challenge.service;


import br.com.clickbus.challenge.dto.PlaceDTO;
import br.com.clickbus.challenge.entity.Place;
import br.com.clickbus.challenge.repository.PlaceRepository;
import lombok.AllArgsConstructor;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import javax.validation.constraints.NotNull;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.NotImplementedException;

@Service
@AllArgsConstructor
Expand All @@ -19,22 +23,27 @@ public class PlaceService {
private PlaceRepository repository;

public List<Place> findAll() {
throw new NotImplementedException("Metodo nao implementado");
return repository.findAll();
}

public Optional<Place> findById(@NotNull Long id) {
throw new NotImplementedException("Metodo nao implementado");
return repository.findById(id);
}

public Place save(@NotNull Place place) {
throw new NotImplementedException("Metodo nao implementado");
return repository.save(place);
}

public List<Place> findByName(@NotNull String name) {
throw new NotImplementedException("Metodo nao implementado");
return repository.findByName(name);
}

public Place alter(@NotNull Place place,@NotNull PlaceDTO placeDTO) {
throw new NotImplementedException("Metodo nao implementado");
public Place alter(@NotNull Place place, @NotNull PlaceDTO placeDTO) {
place.setName(placeDTO.getName());
place.setSlug(placeDTO.getSlug());
place.setCity(placeDTO.getCity());
place.setState(placeDTO.getState());
place.setUpdatedAt(LocalDateTime.now());
return repository.save(place);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package br.com.clickbus.challenge.contoller;


import br.com.clickbus.challenge.controller.PlaceController;
import br.com.clickbus.challenge.dto.PlaceDTO;
import br.com.clickbus.challenge.entity.Place;
Expand Down Expand Up @@ -35,7 +34,6 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@ExtendWith(SpringExtension.class)
@WebMvcTest(PlaceController.class)
public class PlaceControllerTest {
Expand Down Expand Up @@ -63,15 +61,14 @@ public void whenFindAllPlacesThenReturnASimpleItem() throws Exception {

mockMvc.perform(get("/places")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name", is("Butanta")))
.andExpect(jsonPath("$[0].slug", is("bt")))
.andExpect(jsonPath("$[0].city", is("Sao Paulo")))
.andExpect(jsonPath("$[0].state", is("SP")))
.andReturn().getResponse();

.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name", is("Butanta")))
.andExpect(jsonPath("$[0].slug", is("bt")))
.andExpect(jsonPath("$[0].city", is("Sao Paulo")))
.andExpect(jsonPath("$[0].state", is("SP")))
.andReturn().getResponse();

verify(service, atLeastOnce()).findAll();

Expand All @@ -83,13 +80,13 @@ public void whenFindByIdThenReturnOk() throws Exception {

mockMvc.perform(get("/places/{id}", 1L)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$.name", is("Butanta")))
.andExpect(jsonPath("$.slug", is("bt")))
.andExpect(jsonPath("$.city", is("Sao Paulo")))
.andExpect(jsonPath("$.state", is("SP")))
.andReturn().getResponse();
.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$.name", is("Butanta")))
.andExpect(jsonPath("$.slug", is("bt")))
.andExpect(jsonPath("$.city", is("Sao Paulo")))
.andExpect(jsonPath("$.state", is("SP")))
.andReturn().getResponse();

verify(service, atLeastOnce()).findById(anyLong());
}
Expand All @@ -100,9 +97,9 @@ public void whenFindByIdThenReturnNotFound() throws Exception {

mockMvc.perform(get("/places/{id}", 1L)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound())
.andDo(print())
.andReturn().getResponse();
.andExpect(status().isNotFound())
.andDo(print())
.andReturn().getResponse();

verify(service, atLeastOnce()).findById(anyLong());
}
Expand All @@ -113,30 +110,27 @@ public void whenFindByNameThenReturnOk() throws Exception {

mockMvc.perform(get("/places/?name={name}", "Butanta")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name", is("Butanta")))
.andExpect(jsonPath("$[0].slug", is("bt")))
.andExpect(jsonPath("$[0].city", is("Sao Paulo")))
.andExpect(jsonPath("$[0].state", is("SP")))
.andReturn().getResponse();

.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name", is("Butanta")))
.andExpect(jsonPath("$[0].slug", is("bt")))
.andExpect(jsonPath("$[0].city", is("Sao Paulo")))
.andExpect(jsonPath("$[0].state", is("SP")))
.andReturn().getResponse();

verify(service, atLeastOnce()).findByName(anyString());
}

@Test
public void whenFindByNameThenReturnNotFound() throws Exception {

when(service.findByName("Cotia")).thenReturn(Collections.emptyList());

mockMvc.perform(get("/places/?name={name}", "Cotia")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound())
.andDo(print())
.andReturn().getResponse();

.andExpect(status().isNotFound())
.andDo(print())
.andReturn().getResponse();

verify(service, atLeastOnce()).findByName(anyString());
}
Expand All @@ -151,9 +145,9 @@ public void whenSaveThenReturnCreated() throws Exception {
.content(objectMapper.writeValueAsString(place))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated())
.andDo(print())
.andReturn().getResponse();
.andExpect(status().isCreated())
.andDo(print())
.andReturn().getResponse();
}

@Test
Expand All @@ -165,9 +159,9 @@ public void whenSaveInvalidThenReturnBadRequest() throws Exception {
.content(objectMapper.writeValueAsString(place))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andDo(print())
.andReturn().getResponse();
.andExpect(status().isBadRequest())
.andDo(print())
.andReturn().getResponse();
}

@Test
Expand All @@ -181,9 +175,9 @@ public void whenEdiWithPlaceInvalidThenReturnBadRequest() throws Exception {
.content(objectMapper.writeValueAsString(place))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andDo(print())
.andReturn().getResponse();
.andExpect(status().isBadRequest())
.andDo(print())
.andReturn().getResponse();
}

@Test
Expand All @@ -197,8 +191,8 @@ public void whenEdiWithPlaceThenReturnOk() throws Exception {
.content(objectMapper.writeValueAsString(place))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andReturn().getResponse();
.andExpect(status().isOk())
.andDo(print())
.andReturn().getResponse();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package br.com.clickbus.challenge.service;


import br.com.clickbus.challenge.dto.PlaceDTO;
import br.com.clickbus.challenge.entity.Place;
import br.com.clickbus.challenge.repository.PlaceRepository;
Expand All @@ -11,22 +10,19 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


@ExtendWith(MockitoExtension.class)
class PlaceServiceTest {

Expand Down Expand Up @@ -60,7 +56,6 @@ void whenFindByIdOk() {
verify(repository, atLeastOnce()).findById(anyLong());
}


@Test
void whenFindByIdThenReturnEmpty() {
when(repository.findById(1L)).thenReturn(Optional.empty());
Expand Down