Skip to content

Commit

Permalink
Merge pull request #10 from vanderleik/PPI-10-Criar-ProductController
Browse files Browse the repository at this point in the history
Ppi 10 criar product controller
  • Loading branch information
vanderleik authored Jul 10, 2024
2 parents 0b33a5f + 8ab6375 commit 249814b
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.produtopedidoitens.api.adapters.web.controllers;

import com.produtopedidoitens.api.adapters.web.requests.ProductRequest;
import com.produtopedidoitens.api.adapters.web.responses.ProductResponse;
import com.produtopedidoitens.api.application.port.ProductInputPort;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api/v1/products")
@RestController
public class ProductController {

private final ProductInputPort productInputPort;

@PostMapping
public ResponseEntity<ProductResponse> create(@Valid @RequestBody ProductRequest productRequest) {
log.info("create:: Recebendo requisição para criar um produto com os dados: {}", productRequest);
return ResponseEntity.ok(productInputPort.create(productRequest));
}

@GetMapping
public ResponseEntity<List<ProductResponse>> listAll() {
log.info("listAll:: Recebendo requisição para listar todos os produtos");
return ResponseEntity.ok(productInputPort.list());
}

@GetMapping("/{id}")
public ResponseEntity<ProductResponse> read(@PathVariable String id) {
log.info("read:: Recebendo requisição para buscar um produto pelo id: {}", id);
return ResponseEntity.ok(productInputPort.read(UUID.fromString(id)));
}

@PutMapping("/{id}")
public ResponseEntity<ProductResponse> update(@PathVariable String id, @Valid @RequestBody ProductRequest productRequest) {
log.info("update:: Recebendo requisição para atualizar um produto com os dados: {}", productRequest);
return ResponseEntity.ok(productInputPort.update(UUID.fromString(id), productRequest));
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable String id) {
log.info("delete:: Recebendo requisição para deletar um produto pelo id: {}", id);
productInputPort.delete(UUID.fromString(id));
return ResponseEntity.noContent().build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.produtopedidoitens.api.adapters.web.controllers.exceptions;

import com.produtopedidoitens.api.adapters.web.responses.ErrorResponseDTO;
import com.produtopedidoitens.api.application.exceptions.BadRequestException;
import com.produtopedidoitens.api.application.exceptions.ProductNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ProductExceptionHandler {

@ExceptionHandler(BadRequestException.class)
public ResponseEntity<ErrorResponseDTO> handleBadRequestException(BadRequestException e) {
return ResponseEntity.badRequest().body(new ErrorResponseDTO(e.getMessage()));
}

@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponseDTO> handleProductNotFoundException(ProductNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponseDTO(e.getMessage()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.produtopedidoitens.api.adapters.web.responses;

public record ErrorResponseDTO(
String message
) {
}
5 changes: 5 additions & 0 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ spring:

config:
import: optional:file:.env[.*]

flyway:
enabled: true
locations: classpath:db/migration
out-of-order: true
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE TABLE tbproduct (
CREATE TABLE IF NOT EXISTS tbproduct (
idproduct UUID PRIMARY KEY DEFAULT gen_random_uuid(),
productname VARCHAR(60) NOT NULL,
price NUMERIC(19,2) NOT NULL CHECK (price > 0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE TABLE tborder (
CREATE TABLE IF NOT EXISTS tborder (
idorder UUID PRIMARY KEY DEFAULT gen_random_uuid(),
orderdate DATE NOT NULL,
status VARCHAR(255) NOT NULL,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE TABLE tborderitem (
CREATE TABLE IF NOT EXISTS tborderitem (
idorderitem UUID PRIMARY KEY DEFAULT gen_random_uuid(),
orderid UUID NOT NULL,
productid UUID NOT NULL,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package com.produtopedidoitens.api.adapters.web.controllers;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.produtopedidoitens.api.adapters.web.requests.ProductRequest;
import com.produtopedidoitens.api.adapters.web.responses.ProductResponse;
import com.produtopedidoitens.api.application.domain.enums.EnumProductType;
import com.produtopedidoitens.api.application.exceptions.BadRequestException;
import com.produtopedidoitens.api.application.exceptions.ProductNotFoundException;
import com.produtopedidoitens.api.application.port.ProductInputPort;
import com.produtopedidoitens.api.utils.MessagesConstants;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
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 org.springframework.web.context.WebApplicationContext;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;

@WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {

private final String URL = "/api/v1/products";

@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private WebApplicationContext webApplicationContext;

@MockBean
private ProductInputPort productInputPort;

private ProductRequest productRequest;
private ProductResponse productResponse;

@BeforeEach
void setUp() {
productRequest = ProductRequest.builder()
.productName("Product 1")
.price("100.0")
.type("Produto")
.active("true")
.build();

productResponse = ProductResponse.builder()
.id(UUID.fromString("f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b"))
.productName("Product 1")
.price(BigDecimal.valueOf(100.0))
.type(EnumProductType.PRODUCT)
.active(true)
.dthreg(LocalDateTime.now())
.dthalt(LocalDateTime.now())
.version(0L)
.build();
}

@Test
@DisplayName("Deve criar um produto")
void testCreate() throws Exception {
when(productInputPort.create(productRequest)).thenReturn(productResponse);

mockMvc.perform(MockMvcRequestBuilders.post(URL)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(productRequest)))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(productResponse)));
}

@Test
@DisplayName("Deve retornar um erro ao criar um produto")
void testCreateError() throws Exception {
when(productInputPort.create(productRequest)).thenThrow(new BadRequestException(MessagesConstants.ERROR_SAVE_PRODUCT));

mockMvc.perform(MockMvcRequestBuilders.post(URL)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(productRequest)))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isBadRequest())
.andExpect(MockMvcResultMatchers.content().json("{\"message\":\"Erro ao salvar produto/serviço\"}"));
}

@Test
@DisplayName("Deve listar todos os produtos")
void testList() throws Exception {
when(productInputPort.list()).thenReturn(List.of(productResponse));

mockMvc.perform(MockMvcRequestBuilders.get(URL)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(List.of(productResponse))));
}

@Test
@DisplayName("Deve retornar um erro ao listar todos os produtos")
void testListError() throws Exception {
when(productInputPort.list()).thenThrow(new ProductNotFoundException(MessagesConstants.ERROR_PRODUCT_NOT_FOUND));

mockMvc.perform(MockMvcRequestBuilders.get(URL)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isNotFound())
.andExpect(MockMvcResultMatchers.content().json("{\"message\":\"Nenhum produto/serviço encontrado\"}"));
}

@Test
@DisplayName("Deve buscar um produto pelo id")
void testRead() throws Exception {
when(productInputPort.read(UUID.fromString("f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b"))).thenReturn(productResponse);

mockMvc.perform(MockMvcRequestBuilders.get(URL + "/f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(productResponse)));
}

@Test
@DisplayName("Deve retornar um erro ao buscar um produto pelo id")
void testReadError() throws Exception {
when(productInputPort.read(UUID.fromString("f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")))
.thenThrow(new ProductNotFoundException(MessagesConstants.ERROR_PRODUCT_NOT_FOUND));

mockMvc.perform(MockMvcRequestBuilders.get(URL + "/f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isNotFound())
.andExpect(MockMvcResultMatchers.content().json("{\"message\":\"Nenhum produto/serviço encontrado\"}"));
}

@Test
@DisplayName("Deve atualizar um produto")
void testUpdate() throws Exception {
when(productInputPort.update(UUID.fromString("f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b"), productRequest)).thenReturn(productResponse);

mockMvc.perform(MockMvcRequestBuilders.put(URL + "/f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(productRequest)))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(productResponse)));
}

@Test
@DisplayName("Deve retornar um erro ao atualizar um produto")
void testUpdateError() throws Exception {
when(productInputPort.update(UUID.fromString("f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b"), productRequest))
.thenThrow(new BadRequestException(MessagesConstants.ERROR_UPDATE_PRODUCT));

mockMvc.perform(MockMvcRequestBuilders.put(URL + "/f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(productRequest)))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isBadRequest())
.andExpect(MockMvcResultMatchers.content().json("{\"message\":\"Erro ao atualizar produto/serviço\"}"));
}

@Test
@DisplayName("Deve deletar um produto")
void testDelete() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.delete(URL + "/f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isNoContent());
}

@Test
@DisplayName("Deve retornar um erro ao deletar um produto")
void testDeleteError() throws Exception {
doThrow(new BadRequestException(MessagesConstants.ERROR_DELETE_PRODUCT))
.when(productInputPort).delete(UUID.fromString("f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b"));

mockMvc.perform(MockMvcRequestBuilders.delete(URL + "/f7f6b1e3-4b7b-4b6b-8b7b-4b7b6b8b7b4b")
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isBadRequest())
.andExpect(MockMvcResultMatchers.content().json("{\"message\":\"Erro ao deletar produto/serviço\"}"));
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
spring:

datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
Expand All @@ -18,4 +17,5 @@ spring:
path: /h2-console

flyway:
locations: classpath:db/migration/test
locations: classpath:db/migration/test
out-of-order: true

0 comments on commit 249814b

Please sign in to comment.