From 1913ce7067662e9aee7319b3ae4700d90f3d79b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Tue, 15 Jul 2025 10:40:13 +0300 Subject: [PATCH 01/15] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=89=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/ItemRequestController.java | 12 ----- .../controller/ItemRequestController.java | 44 +++++++++++++++++++ .../shareit/request/dto/ItemRequestDto.java | 20 +++++++-- .../shareit/request/dto/ItemResponseDto.java | 23 ++++++++++ .../request/dto/mapper/ItemRequestMapper.java | 32 ++++++++++++++ .../request/{ => model}/ItemRequest.java | 5 +-- .../request/service/ItemRequestService.java | 16 +++++++ .../service/ItemRequestServiceImpl.java | 28 ++++++++++++ 8 files changed, 161 insertions(+), 19 deletions(-) delete mode 100644 src/main/java/ru/practicum/shareit/request/ItemRequestController.java create mode 100644 src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java create mode 100644 src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java create mode 100644 src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java rename src/main/java/ru/practicum/shareit/request/{ => model}/ItemRequest.java (80%) create mode 100644 src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java create mode 100644 src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java deleted file mode 100644 index 064e2e9..0000000 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ /dev/null @@ -1,12 +0,0 @@ -package ru.practicum.shareit.request; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * TODO Sprint add-item-requests. - */ -@RestController -@RequestMapping(path = "/requests") -public class ItemRequestController { -} diff --git a/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java new file mode 100644 index 0000000..1ab1d1d --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -0,0 +1,44 @@ +package ru.practicum.shareit.request.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.service.ItemRequestService; + +import java.util.List; + +@RequiredArgsConstructor +@Slf4j +@RestController +@RequestMapping(path = "/requests") +public class ItemRequestController { + private final ItemRequestService itemRequestService; + + @PostMapping + public ItemRequestDto createItemRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemRequestDto itemRequestDto) { + log.info("POST /requests"); + return itemRequestService.createItemRequest(userId, itemRequestDto); + } + + @GetMapping + public List findListOfYourQueriesWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId) { + log.info("GET /requests"); + return itemRequestService.findListOfYourQueriesWithAnswers(userId); + } + + @GetMapping("/all") + public List findListOfRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { + log.info("GET /requests/all"); + return itemRequestService.findListOfRequestsOtherUsers(userId, from, size); + } + + @GetMapping("/{requestId}") + public ItemResponseDto findYourQueryWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { + log.info("GET /requests/{}", requestId); + return itemRequestService.findYourQueryWithAnswers(userId, requestId); + } +} diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java index 7b3ed54..92c4972 100644 --- a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -1,7 +1,21 @@ package ru.practicum.shareit.request.dto; -/** - * TODO Sprint add-item-requests. - */ +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter public class ItemRequestDto { + @Size(max = 2000, message = "Описание не может быть длиннее 2000 символов") + @NotBlank(message = "Описание не может быть пустым") + private String description; + @NotNull(message = "UserId не может быть null") + private Long requestorId; } diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java new file mode 100644 index 0000000..d2fc0dc --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java @@ -0,0 +1,23 @@ +package ru.practicum.shareit.request.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ru.practicum.shareit.item.dto.ItemDto; + +import java.time.LocalDateTime; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class ItemResponseDto { + private String description; + private Long userId; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime created; + private List items; +} diff --git a/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java b/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java new file mode 100644 index 0000000..74c5518 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java @@ -0,0 +1,32 @@ +package ru.practicum.shareit.request.dto.mapper; + +import lombok.experimental.UtilityClass; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; + +@UtilityClass +public class ItemRequestMapper { + public static ItemResponseDto toItemResponseDto(ItemRequest itemRequest, List items) { + return new ItemResponseDto( + itemRequest.getDescription(), + itemRequest.getRequestor().getId(), + itemRequest.getCreated(), + items + ); + } + + public static ItemRequest toItemRequest(ItemRequestDto itemRequestDto, User user) { + return new ItemRequest( + null, + itemRequestDto.getDescription(), + user, + LocalDateTime.now() + ); + } +} diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java similarity index 80% rename from src/main/java/ru/practicum/shareit/request/ItemRequest.java rename to src/main/java/ru/practicum/shareit/request/model/ItemRequest.java index 89006f7..2edaef9 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequest.java +++ b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java @@ -1,4 +1,4 @@ -package ru.practicum.shareit.request; +package ru.practicum.shareit.request.model; import lombok.AllArgsConstructor; import lombok.Getter; @@ -7,9 +7,6 @@ import java.time.LocalDateTime; -/** - * TODO Sprint add-item-requests. - */ @AllArgsConstructor @Getter @Setter diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java b/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java new file mode 100644 index 0000000..3d87439 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.request.service; + +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; + +import java.util.List; + +public interface ItemRequestService { + ItemRequestDto createItemRequest(Long userId, ItemRequestDto itemRequestDto); + + List findListOfYourQueriesWithAnswers(Long userId); + + List findListOfRequestsOtherUsers(Long userId, int from, int size); + + ItemResponseDto findYourQueryWithAnswers(Long userId, Long requestId); +} diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java new file mode 100644 index 0000000..effbf25 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java @@ -0,0 +1,28 @@ +package ru.practicum.shareit.request.service; + +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; + +import java.util.List; + +public abstract class ItemRequestServiceImpl implements ItemRequestService { + @Override + public List findListOfRequestsOtherUsers(Long userId, int from, int size) { + return List.of(); + } + + @Override + public List findListOfYourQueriesWithAnswers(Long userId) { + return List.of(); + } + + @Override + public ItemResponseDto findYourQueryWithAnswers(Long userId, Long requestId) { + return null; + } + + @Override + public ItemRequestDto createItemRequest(Long userId, ItemRequestDto itemRequestDto) { + return null; + } +} From 62776a97ba17f81132bbe570a275be60aba9a853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Tue, 15 Jul 2025 12:00:31 +0300 Subject: [PATCH 02/15] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BE=D0=BF=D1=86=D0=B8=D1=8E=20=D0=BE=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D1=82=D0=B0=20=D0=BD=D0=B0=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/shareit/item/dto/ItemDto.java | 1 + .../shareit/item/dto/mapper/ItemMapper.java | 18 ++++++++++++++++-- .../ru/practicum/shareit/item/model/Item.java | 4 ++++ .../shareit/item/service/ItemServiceImpl.java | 19 ++++++++++++++++--- .../repository/ItemRequestRepository.java | 8 ++++++++ src/main/resources/schema.sql | 5 ++++- 6 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java index a750b8a..ca6eed4 100644 --- a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java @@ -17,4 +17,5 @@ public class ItemDto { private String description; @NotNull(message = "Поле доступ не может быть null") private Boolean available; + private Long requestId; } diff --git a/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java index 72cbccd..bc1f756 100644 --- a/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java +++ b/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java @@ -6,6 +6,7 @@ import ru.practicum.shareit.item.dto.ItemBookingDto; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.user.model.User; import java.util.List; @@ -17,7 +18,8 @@ public static ItemDto toItemDto(Item item) { item.getId(), item.getName(), item.getDescription(), - item.getAvailable() + item.getAvailable(), + item.getItemRequest() != null ? item.getItemRequest().getId() : null ); } @@ -27,7 +29,19 @@ public static Item toItem(User user, ItemDto itemDto) { itemDto.getName(), itemDto.getDescription(), itemDto.getAvailable(), - user + user, + null + ); + } + + public static Item toItem(User user, ItemDto itemDto, ItemRequest itemRequest) { + return new Item( + null, + itemDto.getName(), + itemDto.getDescription(), + itemDto.getAvailable(), + user, + itemRequest ); } diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/src/main/java/ru/practicum/shareit/item/model/Item.java index bf8fe78..ded119f 100644 --- a/src/main/java/ru/practicum/shareit/item/model/Item.java +++ b/src/main/java/ru/practicum/shareit/item/model/Item.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; import lombok.*; +import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.user.model.User; @NoArgsConstructor @@ -20,4 +21,7 @@ public class Item { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "owner_id") private User owner; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "item_request_id") + private ItemRequest itemRequest; } diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java index 33c7743..872be0d 100644 --- a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java @@ -18,6 +18,8 @@ import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.dto.mapper.ItemMapper; import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.repository.ItemRequestRepository; import ru.practicum.shareit.user.model.User; import ru.practicum.shareit.user.repository.UserRepository; @@ -34,14 +36,20 @@ public class ItemServiceImpl implements ItemService { private final UserRepository userRepository; private final BookingRepository bookingRepository; private final CommentRepository commentRepository; + private final ItemRequestRepository itemRequestRepository; @Override public ItemDto createItem(Long userId, ItemDto itemDto) { User user = validateUser(userId); - return ItemMapper.toItemDto(itemRepository.save( - ItemMapper.toItem(user, itemDto)) - ); + if (itemDto.getRequestId() != null) { + ItemRequest itemRequest = validateItemRequest(itemDto.getRequestId()); + return ItemMapper.toItemDto(itemRepository.save( + ItemMapper.toItem(user, itemDto, itemRequest))); + } else { + return ItemMapper.toItemDto(itemRepository.save( + ItemMapper.toItem(user, itemDto))); + } } @Override @@ -174,4 +182,9 @@ private Item validateItem(Long itemId) { return itemRepository.findById(itemId) .orElseThrow(() -> new NotFoundException("Элемент с данным id: " + itemId + " не найден")); } + + private ItemRequest validateItemRequest(Long requestId) { + return itemRequestRepository.findById(requestId) + .orElseThrow(() -> new NotFoundException("Запрос вещи с данным id: " + requestId + " не найден")); + } } diff --git a/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java b/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java new file mode 100644 index 0000000..146cb48 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.request.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.request.model.ItemRequest; + +public interface ItemRequestRepository extends JpaRepository { + +} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index fa318ff..8282b42 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -18,8 +18,10 @@ create TABLE IF NOT EXISTS items ( description VARCHAR(2000), available BOOLEAN DEFAULT TRUE, owner_id BIGINT NOT NULL, + item_request_id BIGINT, CONSTRAINT pk_item PRIMARY KEY (id), - CONSTRAINT fk_item_owner FOREIGN KEY (owner_id) REFERENCES users(id) + CONSTRAINT fk_item_owner FOREIGN KEY (owner_id) REFERENCES users(id), + CONSTRAINT fk_item_item_request FOREIGN KEY (item_request_id) REFERENCES requests(id) ); create TABLE IF NOT EXISTS bookings ( @@ -38,6 +40,7 @@ create TABLE IF NOT EXISTS requests ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, description VARCHAR(2000), requestor_id BIGINT NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, CONSTRAINT pk_request PRIMARY KEY (id), CONSTRAINT fk_request_requestor FOREIGN KEY (requestor_id) REFERENCES users(id) ); From b8739767c29aeda344355fb367658d0be564db42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Wed, 16 Jul 2025 11:21:35 +0300 Subject: [PATCH 03/15] =?UTF-8?q?=D0=9D=D0=B0=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B1=D0=B8=D0=B7=D0=BD=D0=B5=D1=81-=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D0=BA=D1=83=20=D0=B4=D0=BB=D1=8F=20ItemReque?= =?UTF-8?q?st?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../booking/dto/mapper/BookingMapper.java | 3 +- .../item/repository/ItemRepository.java | 2 + .../controller/ItemRequestController.java | 2 +- .../shareit/request/dto/ItemResponseDto.java | 1 + .../request/dto/mapper/ItemRequestMapper.java | 1 + .../shareit/request/model/ItemRequest.java | 9 ++ .../repository/ItemRequestRepository.java | 6 ++ .../request/service/ItemRequestService.java | 2 +- .../service/ItemRequestServiceImpl.java | 96 +++++++++++++++++-- src/main/resources/schema.sql | 18 ++-- 10 files changed, 120 insertions(+), 20 deletions(-) diff --git a/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java b/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java index e015d27..2c106f0 100644 --- a/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java +++ b/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java @@ -17,7 +17,8 @@ public static BookingResponseDto toBookingDto(Booking booking) { ItemDto itemDto = new ItemDto(booking.getItem().getId(), booking.getItem().getName(), booking.getItem().getDescription(), - booking.getItem().getAvailable() + booking.getItem().getAvailable(), + null ); UserDto bookerDto = new UserDto( diff --git a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java b/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java index b71ebeb..719cd63 100644 --- a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java +++ b/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java @@ -14,4 +14,6 @@ public interface ItemRepository extends JpaRepository { "WHERE UPPER(i.name) LIKE UPPER(CONCAT('%', ?1, '%')) " + " OR UPPER(i.description) LIKE UPPER(CONCAT('%', ?1, '%'))") List search(String text); + + List findAllByItemRequestIdIn(List requestIds); } diff --git a/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java index 1ab1d1d..a7e66bc 100644 --- a/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java +++ b/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -17,7 +17,7 @@ public class ItemRequestController { private final ItemRequestService itemRequestService; @PostMapping - public ItemRequestDto createItemRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemRequestDto itemRequestDto) { + public ItemResponseDto createItemRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemRequestDto itemRequestDto) { log.info("POST /requests"); return itemRequestService.createItemRequest(userId, itemRequestDto); } diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java index d2fc0dc..4a762bf 100644 --- a/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java +++ b/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java @@ -15,6 +15,7 @@ @Setter @Getter public class ItemResponseDto { + private Long id; private String description; private Long userId; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") diff --git a/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java b/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java index 74c5518..c5c36c9 100644 --- a/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java +++ b/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java @@ -14,6 +14,7 @@ public class ItemRequestMapper { public static ItemResponseDto toItemResponseDto(ItemRequest itemRequest, List items) { return new ItemResponseDto( + itemRequest.getId(), itemRequest.getDescription(), itemRequest.getRequestor().getId(), itemRequest.getCreated(), diff --git a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java index 2edaef9..2269eca 100644 --- a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java +++ b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java @@ -1,18 +1,27 @@ package ru.practicum.shareit.request.model; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import ru.practicum.shareit.user.model.User; import java.time.LocalDateTime; +@Entity +@Table(name = "requests") +@NoArgsConstructor @AllArgsConstructor @Getter @Setter public class ItemRequest { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String description; + @ManyToOne + @JoinColumn(name = "requestor_id") private User requestor; private LocalDateTime created; } diff --git a/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java b/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java index 146cb48..86ae310 100644 --- a/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java +++ b/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java @@ -1,8 +1,14 @@ package ru.practicum.shareit.request.repository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import ru.practicum.shareit.request.model.ItemRequest; +import java.util.List; + public interface ItemRequestRepository extends JpaRepository { + List findByRequestorIdOrderByCreatedDesc(Long requestorId); + Page findByRequestorIdNot(Long requestorId, Pageable pageable); } diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java b/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java index 3d87439..80d873a 100644 --- a/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java +++ b/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java @@ -6,7 +6,7 @@ import java.util.List; public interface ItemRequestService { - ItemRequestDto createItemRequest(Long userId, ItemRequestDto itemRequestDto); + ItemResponseDto createItemRequest(Long userId, ItemRequestDto itemRequestDto); List findListOfYourQueriesWithAnswers(Long userId); diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java index effbf25..9734bf4 100644 --- a/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java @@ -1,28 +1,108 @@ package ru.practicum.shareit.request.service; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.ItemRepository; import ru.practicum.shareit.request.dto.ItemRequestDto; import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.dto.mapper.ItemRequestMapper; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.repository.ItemRequestRepository; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +import org.springframework.data.domain.Pageable; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class ItemRequestServiceImpl implements ItemRequestService { + private final UserRepository userRepository; + private final ItemRequestRepository itemRequestRepository; + private final ItemRepository itemRepository; -public abstract class ItemRequestServiceImpl implements ItemRequestService { @Override - public List findListOfRequestsOtherUsers(Long userId, int from, int size) { - return List.of(); + public ItemResponseDto createItemRequest(Long userId, ItemRequestDto itemRequestDto) { + User user = validateUser(userId); + + return ItemRequestMapper.toItemResponseDto(itemRequestRepository + .save(ItemRequestMapper.toItemRequest(itemRequestDto, user)), List.of()); } @Override public List findListOfYourQueriesWithAnswers(Long userId) { - return List.of(); + validateUser(userId); + + List requests = itemRequestRepository.findByRequestorIdOrderByCreatedDesc(userId); + + return composeResponseForItemResponseDto(requests); } @Override - public ItemResponseDto findYourQueryWithAnswers(Long userId, Long requestId) { - return null; + public List findListOfRequestsOtherUsers(Long userId, int from, int size) { + validateUser(userId); + + Pageable pageable = PageRequest.of(from / size, size, Sort.by("created").descending()); + + List requests = itemRequestRepository.findByRequestorIdNot(userId, pageable).getContent(); + + return composeResponseForItemResponseDto(requests); } @Override - public ItemRequestDto createItemRequest(Long userId, ItemRequestDto itemRequestDto) { - return null; + public ItemResponseDto findYourQueryWithAnswers(Long userId, Long requestId) { + validateUser(userId); + + ItemRequest itemRequest = itemRequestRepository.findById(requestId) + .orElseThrow(() -> new NotFoundException("Запрос вещи с данным id: " + requestId + " не найден")); + + List items = itemRepository.findAllByItemRequestIdIn(List.of(itemRequest.getId())); + + return ItemRequestMapper.toItemResponseDto(itemRequest, + items + .stream() + .map(ItemMapper::toItemDto) + .collect(Collectors.toList())); + } + + private User validateUser(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new NotFoundException("Пользователь с данным id: " + userId + " не найден")); + } + + private List composeResponseForItemResponseDto(List requests) { + if (requests == null || requests.isEmpty()) { + return List.of(); + } + + List requestIds = requests + .stream() + .map(ItemRequest::getId) + .collect(Collectors.toList()); + + if (requestIds.isEmpty()) return List.of(); + + List items = itemRepository.findAllByItemRequestIdIn(requestIds); + + Map> itemsByRequest = items + .stream() + .map(ItemMapper::toItemDto) + .collect(Collectors.groupingBy(ItemDto::getRequestId)); + + return requests.stream() + .map(req -> ItemRequestMapper.toItemResponseDto( + req, + itemsByRequest.getOrDefault(req.getId(), List.of()) + )) + .collect(Collectors.toList()); } } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 8282b42..430494b 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -12,6 +12,15 @@ create TABLE IF NOT EXISTS users ( CONSTRAINT UQ_USER_EMAIL UNIQUE (email) ); +create TABLE IF NOT EXISTS requests ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + description VARCHAR(2000), + requestor_id BIGINT NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + CONSTRAINT pk_request PRIMARY KEY (id), + CONSTRAINT fk_request_requestor FOREIGN KEY (requestor_id) REFERENCES users(id) +); + create TABLE IF NOT EXISTS items ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, @@ -36,15 +45,6 @@ create TABLE IF NOT EXISTS bookings ( CONSTRAINT fk_booking_booker FOREIGN KEY (booker_id) REFERENCES users(id) ); -create TABLE IF NOT EXISTS requests ( - id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, - description VARCHAR(2000), - requestor_id BIGINT NOT NULL, - created TIMESTAMP WITHOUT TIME ZONE NOT NULL, - CONSTRAINT pk_request PRIMARY KEY (id), - CONSTRAINT fk_request_requestor FOREIGN KEY (requestor_id) REFERENCES users(id) -); - create TABLE IF NOT EXISTS comments ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, text VARCHAR(2000), From d6b29037d056c42b4962c24048d0cbe4fdd19cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Wed, 16 Jul 2025 18:52:14 +0300 Subject: [PATCH 04/15] =?UTF-8?q?=D0=9D=D0=B0=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20ItemRequest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compose.yaml | 23 ++- .../shareit/ItemRequestControllerTest.java | 182 ++++++++++++++++++ .../shareit/ItemRequestServiceTest.java | 63 ++++++ .../ru/practicum/shareit/ItemRequestTest.java | 152 +++++++++++++++ 4 files changed, 418 insertions(+), 2 deletions(-) create mode 100644 src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java create mode 100644 src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java create mode 100644 src/test/java/ru/practicum/shareit/ItemRequestTest.java diff --git a/compose.yaml b/compose.yaml index 35ebf89..2597319 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,7 +1,8 @@ services: - db: + # Основная БД + db-dev: image: postgres:16.1 - container_name: postgres5 + container_name: postgres-dev ports: - "5438:5432" volumes: @@ -10,6 +11,24 @@ services: - POSTGRES_DB=shareitdb - POSTGRES_USER=dbuser - POSTGRES_PASSWORD=12345 + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 + + # Тестовая БД + db-test: + image: postgres:16.1 + container_name: postgres-test + ports: + - "5439:5432" + volumes: + - ./volumes/postgres-test:/var/lib/postgresql/data/ + environment: + - POSTGRES_DB=test + - POSTGRES_USER=dbuser + - POSTGRES_PASSWORD=12345 healthcheck: test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER timeout: 5s diff --git a/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java b/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java new file mode 100644 index 0000000..b793a19 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java @@ -0,0 +1,182 @@ +package ru.practicum.shareit; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import ru.practicum.shareit.error.ErrorHandler; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.request.controller.ItemRequestController; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.service.ItemRequestService; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + +@ExtendWith(MockitoExtension.class) +public class ItemRequestControllerTest { + @Mock + private ItemRequestService itemRequestService; + + @InjectMocks + private ItemRequestController itemRequestController; + private final ObjectMapper mapper = new ObjectMapper(); + private MockMvc mvc; + private ItemRequestDto itemRequestDto; + private ItemDto itemDto; + private ItemResponseDto itemResponseDto; + private ItemResponseDto itemResponseDto2; + + @BeforeEach + void setUp() { + mapper.findAndRegisterModules(); + + mvc = MockMvcBuilders + .standaloneSetup(itemRequestController) + .setControllerAdvice(new ErrorHandler()) + .build(); + + itemRequestDto = new ItemRequestDto( + "Ищу строительный пылесос", + 1L + ); + + itemDto = new ItemDto( + 1L, + "Karcher WD 2 Plus", + "Строительный пылесос", + true, + 2L + ); + + itemResponseDto = new ItemResponseDto( + 1L, + "Ищу строительный пылесос", + 1L, + LocalDateTime.of(2025, 7, 16, 19, 40, 0), + List.of() + ); + + itemResponseDto2 = new ItemResponseDto( + 1L, + "Ищу строительный пылесос", + 1L, + LocalDateTime.of(2025, 7, 16, 19, 40, 0), + List.of(itemDto) + ); + } + + @Test + void mustCreateItemRequest() throws Exception { + when(itemRequestService.createItemRequest(eq(1L), any())) + .thenReturn(itemResponseDto); + + mvc.perform(post("/requests") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemRequestDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.description", is(itemRequestDto.getDescription()))) + .andExpect(jsonPath("$.userId", is(itemRequestDto.getRequestorId().intValue()))) + .andExpect(jsonPath("$.created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$.items").isArray()); + } + + @Test + void mustFindListOfYourQueriesWithAnswers() throws Exception { + when(itemRequestService.findListOfYourQueriesWithAnswers(1L)) + .thenReturn(List.of(itemResponseDto2)); + + mvc.perform(get("/requests") + .header("X-Sharer-User-Id", 1) + .characterEncoding(StandardCharsets.UTF_8) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].description", is("Ищу строительный пылесос"))) + .andExpect(jsonPath("$[0].userId", is(1))) + .andExpect(jsonPath("$[0].created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$[0].items").isArray()) + .andExpect(jsonPath("$[0].items[0].id", is(1))) + .andExpect(jsonPath("$[0].items[0].name", is("Karcher WD 2 Plus"))) + .andExpect(jsonPath("$[0].items[0].description", is("Строительный пылесос"))) + .andExpect(jsonPath("$[0].items[0].available", is(true))) + .andExpect(jsonPath("$[0].items[0].requestId", is(2))); + } + + @Test + void mustFindListOfRequestsOtherUsers() throws Exception { + when(itemRequestService.findListOfRequestsOtherUsers(1L, 0, 10)) + .thenReturn(List.of(itemResponseDto2)); + + mvc.perform(get("/requests/all") + .header("X-Sharer-User-Id", 1) + .param("from", "0") + .param("size", "10") + .characterEncoding(StandardCharsets.UTF_8) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].description", is("Ищу строительный пылесос"))) + .andExpect(jsonPath("$[0].userId", is(1))) + .andExpect(jsonPath("$[0].created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$[0].items").isArray()) + .andExpect(jsonPath("$[0].items[0].id", is(1))) + .andExpect(jsonPath("$[0].items[0].name", is("Karcher WD 2 Plus"))) + .andExpect(jsonPath("$[0].items[0].description", is("Строительный пылесос"))) + .andExpect(jsonPath("$[0].items[0].available", is(true))) + .andExpect(jsonPath("$[0].items[0].requestId", is(2))); + } + + @Test + void mustFindYourQueryWithAnswers() throws Exception { + when(itemRequestService.findYourQueryWithAnswers(1L, 1L)) + .thenReturn(itemResponseDto2); + + mvc.perform(get("/requests/1") + .header("X-Sharer-User-Id", 1) + .characterEncoding(StandardCharsets.UTF_8) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.description", is("Ищу строительный пылесос"))) + .andExpect(jsonPath("$.userId", is(1))) + .andExpect(jsonPath("$.created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$.items").isArray()) + .andExpect(jsonPath("$.items[0].id", is(1))) + .andExpect(jsonPath("$.items[0].name", is("Karcher WD 2 Plus"))); + } + + @Test + void mustReturn404IfItemRequestNotFound() throws Exception { + when(itemRequestService.findYourQueryWithAnswers(1L, 99L)) + .thenThrow(new NotFoundException("Запрос не найден")); + + mvc.perform(get("/requests/99") + .header("X-Sharer-User-Id", 1) + .characterEncoding(StandardCharsets.UTF_8) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } +} diff --git a/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java b/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java new file mode 100644 index 0000000..7b6bb61 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java @@ -0,0 +1,63 @@ +package ru.practicum.shareit; + +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.service.ItemRequestService; +import ru.practicum.shareit.user.model.User; + +import static org.assertj.core.api.Assertions.assertThat; + +@Transactional +@SpringBootTest( + properties = "spring.datasource.url=jdbc:postgresql://localhost:5439/test", + classes = ShareItApp.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemRequestServiceTest { + private final EntityManager em; + private final ItemRequestService itemRequestService; + + private Long userId; + + @BeforeEach + void setUo() { + User user = new User(); + user.setName("Егор"); + user.setEmail("egor@mail.ru"); + + em.persist(user); + em.flush(); + + userId = user.getId(); + } + + @Test + public void mustCreateItemRequest() { + ItemRequestDto itemRequestDto = new ItemRequestDto("Ищу строительный пылесос", userId); + + ItemResponseDto itemResponseDto = itemRequestService.createItemRequest(userId, itemRequestDto); + + assertThat(itemResponseDto.getId()).isNotNull(); + assertThat(itemResponseDto.getDescription()).isEqualTo(itemResponseDto.getDescription()); + assertThat(itemResponseDto.getUserId()).isEqualTo(userId); + assertThat(itemResponseDto.getCreated()).isNotNull(); + assertThat(itemResponseDto.getItems()).isEmpty(); + + + ItemRequest savedItemRequest = em.createQuery( + "SELECT ir FROM ItemRequest ir WHERE ir.id = :id", ItemRequest.class) + .setParameter("id", itemResponseDto.getId()) + .getSingleResult(); + + assertThat(savedItemRequest.getDescription()).isEqualTo("Ищу строительный пылесос"); + assertThat(savedItemRequest.getRequestor().getId()).isEqualTo(userId); + } +} diff --git a/src/test/java/ru/practicum/shareit/ItemRequestTest.java b/src/test/java/ru/practicum/shareit/ItemRequestTest.java new file mode 100644 index 0000000..d884dee --- /dev/null +++ b/src/test/java/ru/practicum/shareit/ItemRequestTest.java @@ -0,0 +1,152 @@ +package ru.practicum.shareit; + +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import org.springframework.test.context.ContextConfiguration; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.dto.ItemResponseDto; + +import jakarta.validation.Validator; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ContextConfiguration(classes = ShareItApp.class) +@JsonTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemRequestTest { + private final JacksonTester json; + private final JacksonTester jsonItemResponseDto; + private final JacksonTester jsonItemDto; + + private Validator validator; + + @BeforeEach + void setUp() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void shouldReturnItemRequestDto() throws Exception { + ItemRequestDto itemRequestDto = new ItemRequestDto( + "Ищу строительный пылесос", + 1L + ); + + JsonContent result = json.write(itemRequestDto); + + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("Ищу строительный пылесос"); + assertThat(result).extractingJsonPathNumberValue("$.requestorId").isEqualTo(1); + } + + @Test + void shouldReturnItemResponseDto() throws Exception { + ItemResponseDto itemResponseDto = new ItemResponseDto( + 2L, + "нужен фотоаппарат", + 3L, + LocalDateTime.of(2025, 7, 16, 18, 30, 0), + List.of() + ); + + JsonContent result = jsonItemResponseDto.write(itemResponseDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(2); + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("нужен фотоаппарат"); + assertThat(result).extractingJsonPathNumberValue("$.userId").isEqualTo(3); + assertThat(result).extractingJsonPathStringValue("$.created").isEqualTo("2025-07-16T18:30:00"); + assertThat(result).extractingJsonPathArrayValue("$.items").isEmpty(); + } + + @Test + void shouldReturnItemResponseDtoAndItemDto() throws Exception { + ItemDto itemDto = new ItemDto( + 5L, + "Canon 500d", + "Зеркальный фотоаппарат", + true, + 10L + ); + + ItemResponseDto itemResponseDto = new ItemResponseDto( + 2L, + "нужен фотоаппарат", + 3L, + LocalDateTime.of(2025, 7, 16, 18, 30, 0), + List.of(itemDto) + ); + + JsonContent result = jsonItemResponseDto.write(itemResponseDto); + JsonContent resultItemDto = jsonItemDto.write(itemDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(2); + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("нужен фотоаппарат"); + assertThat(result).extractingJsonPathNumberValue("$.userId").isEqualTo(3); + assertThat(result).extractingJsonPathStringValue("$.created").isEqualTo("2025-07-16T18:30:00"); + assertThat(resultItemDto).extractingJsonPathNumberValue("$.id").isEqualTo(5); + assertThat(resultItemDto).extractingJsonPathStringValue("$.name").isEqualTo("Canon 500d"); + assertThat(resultItemDto).extractingJsonPathStringValue("$.description").isEqualTo("Зеркальный фотоаппарат"); + assertThat(resultItemDto).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + assertThat(resultItemDto).extractingJsonPathNumberValue("$.requestId").isEqualTo(10); + } + + @Test + void shouldDeserializeItemResponseDtoFromJson() throws Exception { + String json = """ + { + "id": 2, + "description": "нужен фотоаппарат", + "userId": 3, + "created": "2025-07-16T18:30:00", + "items": [] + } + """; + + ItemResponseDto result = jsonItemResponseDto.parse(json).getObject(); + + assertThat(result.getId()).isEqualTo(2L); + assertThat(result.getDescription()).isEqualTo("нужен фотоаппарат"); + assertThat(result.getUserId()).isEqualTo(3L); + assertThat(result.getCreated()).isEqualTo(LocalDateTime.of(2025, 7, 16, 18, 30, 0)); + assertThat(result.getItems()).isEmpty(); + } + + @Test + void shouldSerializeAndValidateItemRequestDto() throws Exception { + ItemRequestDto validDto = new ItemRequestDto("Нужен фотоаппарат", 1L); + + JsonContent validJson = json.write(validDto); + assertThat(validJson).extractingJsonPathStringValue("$.description").isEqualTo("Нужен фотоаппарат"); + assertThat(validJson).extractingJsonPathNumberValue("$.requestorId").isEqualTo(1); + assertThat(validator.validate(validDto)).isEmpty(); + + ItemRequestDto invalidDto = new ItemRequestDto(" ", null); + var violations = validator.validate(invalidDto); + + assertThat(violations).hasSize(2); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("description")); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("requestorId")); + } + + @Test + void shouldFailValidationWhenDescriptionTooLong() { + String longDescription = "тест".repeat(2001); + ItemRequestDto itemRequestDto = new ItemRequestDto(longDescription, 1L); + + var violations = validator.validate(itemRequestDto); + assertThat(violations).hasSize(1); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("description")); + } +} + From be34774c42494ec40ecac5e308031ba679b88162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Sat, 19 Jul 2025 04:07:20 +0300 Subject: [PATCH 05/15] =?UTF-8?q?=D0=92=D1=8B=D0=B4=D0=B5=D0=BB=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8E=20=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compose.yaml | 36 ------ compose.yml | 42 ++++++ composeTest.yml | 90 +++++++++++++ gateway/Dockerfile | 5 + gateway/pom.xml | 70 ++++++++++ .../ru/practicum/shareit/ShareItGateway.java | 12 ++ .../shareit/booking/client/BookingClient.java | 55 ++++++++ .../booking/controller/BookingController.java | 54 ++++++++ .../booking/dto/BookingRequestDto.java | 0 .../booking/dto/BookingResponseDto.java | 0 .../shareit/booking/status/RentalStatus.java | 0 .../practicum/shareit/client/BaseClient.java | 121 ++++++++++++++++++ .../shareit/item/client/ItemClient.java | 55 ++++++++ .../item/comment/dto/CommentRequestDto.java | 5 +- .../item/comment/dto/CommentResponseDto.java | 0 .../item/controller/ItemController.java | 59 +++++++++ .../practicum/shareit/item/dto/ItemDto.java | 0 .../request/client/ItemRequestClient.java | 47 +++++++ .../controller/ItemRequestController.java | 42 ++++++ .../shareit/request/dto/ItemRequestDto.java | 0 .../shareit/request/dto/ItemResponseDto.java | 0 .../shareit/user/client/UserClient.java | 46 +++++++ .../user/controller/UserController.java | 51 ++++++++ .../practicum/shareit/user/dto/UserDto.java | 5 +- gateway/src/main/resources/application.yml | 17 +++ pom.xml | 83 +++++------- server/Dockerfile | 5 + server/pom.xml | 104 +++++++++++++++ .../java/ru/practicum/shareit/ShareItApp.java | 0 .../booking/controller/BookingController.java | 3 +- .../booking/dto/BookingRequestDto.java | 16 +++ .../booking/dto/BookingResponseDto.java | 25 ++++ .../booking/dto/SimplifiedBookingDto.java | 0 .../booking/dto/mapper/BookingMapper.java | 0 .../shareit/booking/model/Booking.java | 0 .../booking/repository/BookingRepository.java | 0 .../booking/service/BookingService.java | 0 .../booking/service/BookingServiceImpl.java | 0 .../shareit/booking/status/RentalStatus.java | 8 ++ .../practicum/shareit/error/ErrorHandler.java | 0 .../shareit/error/ErrorResponse.java | 0 .../exception/InternalServerException.java | 0 .../shareit/exception/NotFoundException.java | 0 .../exception/ValidationException.java | 0 .../item/comment/dto/CommentRequestDto.java | 11 ++ .../item/comment/dto/CommentResponseDto.java | 20 +++ .../comment/dto/mapper/CommentMapper.java | 0 .../shareit/item/comment/model/Comment.java | 0 .../comment/repository/CommentRepository.java | 0 .../item/controller/ItemController.java | 5 +- .../shareit/item/dto/ItemBookingDto.java | 0 .../practicum/shareit/item/dto/ItemDto.java | 16 +++ .../shareit/item/dto/mapper/ItemMapper.java | 0 .../ru/practicum/shareit/item/model/Item.java | 0 .../item/repository/ItemRepository.java | 0 .../shareit/item/service/ItemService.java | 0 .../shareit/item/service/ItemServiceImpl.java | 0 .../controller/ItemRequestController.java | 0 .../shareit/request/dto/ItemRequestDto.java | 15 +++ .../shareit/request/dto/ItemResponseDto.java | 24 ++++ .../request/dto/mapper/ItemRequestMapper.java | 0 .../shareit/request/model/ItemRequest.java | 0 .../repository/ItemRequestRepository.java | 0 .../request/service/ItemRequestService.java | 0 .../service/ItemRequestServiceImpl.java | 0 .../user/controller/UserController.java | 3 +- .../practicum/shareit/user/dto/UserDto.java | 13 ++ .../shareit/user/dto/mapper/UserMapper.java | 0 .../ru/practicum/shareit/user/model/User.java | 0 .../user/repository/UserRepository.java | 0 .../shareit/user/service/UserService.java | 0 .../shareit/user/service/UserServiceImpl.java | 0 server/src/main/resources/application.yml | 45 +++++++ {src => server/src}/main/resources/schema.sql | 0 .../shareit/ItemRequestControllerTest.java | 0 .../shareit/ItemRequestServiceTest.java | 4 +- .../ru/practicum/shareit/ItemRequestTest.java | 27 ---- .../ru/practicum/shareit/ShareItTests.java | 0 src/main/resources/application.yaml | 35 ----- 79 files changed, 1118 insertions(+), 156 deletions(-) delete mode 100644 compose.yaml create mode 100644 compose.yml create mode 100644 composeTest.yml create mode 100644 gateway/Dockerfile create mode 100644 gateway/pom.xml create mode 100644 gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/client/BookingClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/status/RentalStatus.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/item/client/ItemClient.java rename {src => gateway/src}/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java (80%) rename {src => gateway/src}/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/item/dto/ItemDto.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/request/client/ItemRequestClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/user/client/UserClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/user/controller/UserController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/user/dto/UserDto.java (82%) create mode 100644 gateway/src/main/resources/application.yml create mode 100644 server/Dockerfile create mode 100644 server/pom.xml rename {src => server/src}/main/java/ru/practicum/shareit/ShareItApp.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/controller/BookingController.java (94%) create mode 100644 server/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java rename {src => server/src}/main/java/ru/practicum/shareit/booking/dto/SimplifiedBookingDto.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/model/Booking.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/service/BookingService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java rename {src => server/src}/main/java/ru/practicum/shareit/error/ErrorHandler.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/error/ErrorResponse.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/InternalServerException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/NotFoundException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/ValidationException.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java rename {src => server/src}/main/java/ru/practicum/shareit/item/comment/dto/mapper/CommentMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/comment/model/Comment.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/comment/repository/CommentRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/controller/ItemController.java (91%) rename {src => server/src}/main/java/ru/practicum/shareit/item/dto/ItemBookingDto.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java rename {src => server/src}/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/model/Item.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/repository/ItemRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/service/ItemService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java rename {src => server/src}/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/model/ItemRequest.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/service/ItemRequestService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/controller/UserController.java (92%) create mode 100644 server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java rename {src => server/src}/main/java/ru/practicum/shareit/user/dto/mapper/UserMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/model/User.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/repository/UserRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/service/UserService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java (100%) create mode 100644 server/src/main/resources/application.yml rename {src => server/src}/main/resources/schema.sql (100%) rename {src => server/src}/test/java/ru/practicum/shareit/ItemRequestControllerTest.java (100%) rename {src => server/src}/test/java/ru/practicum/shareit/ItemRequestServiceTest.java (93%) rename {src => server/src}/test/java/ru/practicum/shareit/ItemRequestTest.java (79%) rename {src => server/src}/test/java/ru/practicum/shareit/ShareItTests.java (100%) delete mode 100644 src/main/resources/application.yaml diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index 2597319..0000000 --- a/compose.yaml +++ /dev/null @@ -1,36 +0,0 @@ -services: - # Основная БД - db-dev: - image: postgres:16.1 - container_name: postgres-dev - ports: - - "5438:5432" - volumes: - - ./volumes/postgres:/var/lib/postgresql/data/ - environment: - - POSTGRES_DB=shareitdb - - POSTGRES_USER=dbuser - - POSTGRES_PASSWORD=12345 - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - timeout: 5s - interval: 5s - retries: 10 - - # Тестовая БД - db-test: - image: postgres:16.1 - container_name: postgres-test - ports: - - "5439:5432" - volumes: - - ./volumes/postgres-test:/var/lib/postgresql/data/ - environment: - - POSTGRES_DB=test - - POSTGRES_USER=dbuser - - POSTGRES_PASSWORD=12345 - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - timeout: 5s - interval: 5s - retries: 10 \ No newline at end of file diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..0eabd3e --- /dev/null +++ b/compose.yml @@ -0,0 +1,42 @@ +services: + gateway: + build: gateway + image: shareit-gateway + container_name: shareit-gateway + ports: + - "8080:8080" + #- "8081:8081" + depends_on: + - server + environment: + - SHAREIT_SERVER_URL=http://server:9090 + + server: + build: server + image: shareit-server + container_name: shareit-server + ports: + - "9090:9090" + #- "9091:9091" + depends_on: + - db + environment: + - SPRING_PROFILES_ACTIVE=dev + - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/shareit + - SPRING_DATASOURCE_USERNAME=dbuser + - SPRING_DATASOURCE_PASSWORD=12345 + + db: + image: postgres:16.1 + container_name: postgres + ports: + - "6541:5432" + environment: + - POSTGRES_PASSWORD=12345 + - POSTGRES_USER=dbuser + - POSTGRES_DB=shareit + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 \ No newline at end of file diff --git a/composeTest.yml b/composeTest.yml new file mode 100644 index 0000000..6ad8203 --- /dev/null +++ b/composeTest.yml @@ -0,0 +1,90 @@ +services: + db: + image: postgres:16.1 + container_name: postgres + ports: + - "5445:5432" + volumes: + - ./volumes/shareit:/var/lib/postgresql/data/ + environment: + - SPRING_PROFILES_ACTIVE=dev + - POSTGRES_DB=shareit + - POSTGRES_USER=dbuser + - POSTGRES_PASSWORD=12345 + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 + + db-init: + image: postgres:16.1 + container_name: db-init-test + depends_on: + db: + condition: service_healthy + entrypoint: + - bash + - -c + - | + set -e + psql postgresql://dbuser:12345@db:5432/shareit -v ON_ERROR_STOP=1 <<-EOSQL + drop table IF EXISTS users CASCADE; + drop table IF EXISTS items CASCADE; + drop table IF EXISTS bookings CASCADE; + drop table IF EXISTS requests CASCADE; + drop table IF EXISTS comments CASCADE; + + create TABLE IF NOT EXISTS users ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + name VARCHAR(255) NOT NULL, + email VARCHAR(512) NOT NULL, + CONSTRAINT pk_user PRIMARY KEY (id), + CONSTRAINT UQ_USER_EMAIL UNIQUE (email) + ); + + create TABLE IF NOT EXISTS requests ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + description VARCHAR(2000), + requestor_id BIGINT NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + CONSTRAINT pk_request PRIMARY KEY (id), + CONSTRAINT fk_request_requestor FOREIGN KEY (requestor_id) REFERENCES users(id) + ); + + create TABLE IF NOT EXISTS items ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + name VARCHAR(255) NOT NULL, + description VARCHAR(2000), + available BOOLEAN DEFAULT TRUE, + owner_id BIGINT NOT NULL, + item_request_id BIGINT, + CONSTRAINT pk_item PRIMARY KEY (id), + CONSTRAINT fk_item_owner FOREIGN KEY (owner_id) REFERENCES users(id), + CONSTRAINT fk_item_item_request FOREIGN KEY (item_request_id) REFERENCES requests(id) + ); + + create TABLE IF NOT EXISTS bookings ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + start_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + end_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + item_id BIGINT NOT NULL, + booker_id BIGINT NOT NULL, + status VARCHAR(50), + CONSTRAINT pk_booking PRIMARY KEY (id), + CONSTRAINT fk_booking_item FOREIGN KEY (item_id) REFERENCES items(id), + CONSTRAINT fk_booking_booker FOREIGN KEY (booker_id) REFERENCES users(id) + ); + + create TABLE IF NOT EXISTS comments ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + text VARCHAR(2000), + item_id BIGINT NOT NULL, + author_id BIGINT NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + CONSTRAINT pk_comment PRIMARY KEY (id), + CONSTRAINT fk_comment_item FOREIGN KEY (item_id) REFERENCES items(id), + CONSTRAINT fk_comment_author FOREIGN KEY (author_id) REFERENCES users(id) + ); + EOSQL + diff --git a/gateway/Dockerfile b/gateway/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/gateway/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/gateway/pom.xml b/gateway/pom.xml new file mode 100644 index 0000000..f3394c1 --- /dev/null +++ b/gateway/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + ru.practicum + shareit + 0.0.1-SNAPSHOT + + + shareit-gateway + 0.0.1-SNAPSHOT + + ShareIt Gateway + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.hibernate.validator + hibernate-validator + + + + org.apache.httpcomponents.client5 + httpclient5 + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java b/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java new file mode 100644 index 0000000..0aa75c3 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java @@ -0,0 +1,12 @@ +package ru.practicum.shareit; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ShareItGateway { + public static void main(String[] args) { + SpringApplication.run(ShareItGateway.class, args); + } + +} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/client/BookingClient.java b/gateway/src/main/java/ru/practicum/shareit/booking/client/BookingClient.java new file mode 100644 index 0000000..887e62e --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/client/BookingClient.java @@ -0,0 +1,55 @@ +package ru.practicum.shareit.booking.client; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; + +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.client.BaseClient; + +@Service +public class BookingClient extends BaseClient { + private static final String API_PREFIX = "/bookings"; + + @Autowired + public BookingClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity createBooking(long userId, BookingRequestDto bookingRequestDto) { + return post("", userId, bookingRequestDto); + } + + public ResponseEntity updateBooking(Long userId, Long bookingId, Boolean approved) { + Map parameters = Map.of("approved", approved); + + return patch("/" + bookingId + "?approved={approved}", userId, parameters, null); + } + + public ResponseEntity findBookingById(long userId, Long bookingId) { + return get("/" + bookingId, userId); + } + + public ResponseEntity findUserBookings(Long userId, String state) { + Map parameters = Map.of("state", state); + + return get("?state={state}", userId, parameters); + } + + public ResponseEntity findOwnerReservedItems(Long userId, String state) { + Map parameters = Map.of("state", state); + + return get("/owner?state={state}", userId, parameters); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java b/gateway/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java new file mode 100644 index 0000000..b59123a --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java @@ -0,0 +1,54 @@ +package ru.practicum.shareit.booking.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import ru.practicum.shareit.booking.client.BookingClient; +import ru.practicum.shareit.booking.dto.BookingRequestDto; + + +@Controller +@RequestMapping(path = "/bookings") +@RequiredArgsConstructor +@Slf4j +@Validated +public class BookingController { + private final BookingClient bookingClient; + + @PostMapping + public ResponseEntity createBooking(@RequestHeader("X-Sharer-User-Id") long userId, + @RequestBody @Valid BookingRequestDto bookingRequestDto) { + log.info("Создание бронирования {}, userId={}", bookingRequestDto, userId); + return bookingClient.createBooking(userId, bookingRequestDto); + } + + @PatchMapping("/{bookingId}") + public ResponseEntity updateBooking(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable("bookingId") Long bookingId, @RequestParam(name = "approved") Boolean approved) { + log.info("Идентификатор бронирования {} по идентификатору пользователя {}", bookingId, userId); + return bookingClient.updateBooking(userId, bookingId, approved); + } + + @GetMapping("/{bookingId}") + public ResponseEntity findBookingById(@RequestHeader("X-Sharer-User-Id") long userId, + @PathVariable Long bookingId) { + log.info("Забронировать {}, userId={}", bookingId, userId); + return bookingClient.findBookingById(userId, bookingId); + } + + @GetMapping + public ResponseEntity findUserBookings(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestParam(name = "state", defaultValue = "ALL") String state) { + log.info("Получить бронирования {}.", state); + return bookingClient.findUserBookings(userId, state); + } + + @GetMapping("/owner") + public ResponseEntity findOwnerReservedItems(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestParam(name = "state", defaultValue = "ALL") String state) { + log.info("Получить зарезервированные товары владельца{}.", state); + return bookingClient.findOwnerReservedItems(userId, state); + } +} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java b/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java rename to gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java b/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java rename to gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java diff --git a/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java b/gateway/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java rename to gateway/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java diff --git a/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java b/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java new file mode 100644 index 0000000..1a2d33a --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java @@ -0,0 +1,121 @@ +package ru.practicum.shareit.client; + +import java.util.List; +import java.util.Map; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +public class BaseClient { + protected final RestTemplate rest; + + public BaseClient(RestTemplate rest) { + this.rest = rest; + } + + protected ResponseEntity get(String path) { + return get(path, null, null); + } + + protected ResponseEntity get(String path, long userId) { + return get(path, userId, null); + } + + protected ResponseEntity get(String path, Long userId, @Nullable Map parameters) { + return makeAndSendRequest(HttpMethod.GET, path, userId, parameters, null); + } + + protected ResponseEntity post(String path, T body) { + return post(path, null, null, body); + } + + protected ResponseEntity post(String path, long userId, T body) { + return post(path, userId, null, body); + } + + protected ResponseEntity post(String path, Long userId, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.POST, path, userId, parameters, body); + } + + protected ResponseEntity put(String path, long userId, T body) { + return put(path, userId, null, body); + } + + protected ResponseEntity put(String path, long userId, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.PUT, path, userId, parameters, body); + } + + protected ResponseEntity patch(String path, T body) { + return patch(path, null, null, body); + } + + protected ResponseEntity patch(String path, long userId) { + return patch(path, userId, null, null); + } + + protected ResponseEntity patch(String path, long userId, T body) { + return patch(path, userId, null, body); + } + + protected ResponseEntity patch(String path, Long userId, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.PATCH, path, userId, parameters, body); + } + + protected ResponseEntity delete(String path) { + return delete(path, null, null); + } + + protected ResponseEntity delete(String path, long userId) { + return delete(path, userId, null); + } + + protected ResponseEntity delete(String path, Long userId, @Nullable Map parameters) { + return makeAndSendRequest(HttpMethod.DELETE, path, userId, parameters, null); + } + + private ResponseEntity makeAndSendRequest(HttpMethod method, String path, Long userId, @Nullable Map parameters, @Nullable T body) { + HttpEntity requestEntity = new HttpEntity<>(body, defaultHeaders(userId)); + + ResponseEntity shareitServerResponse; + try { + if (parameters != null) { + shareitServerResponse = rest.exchange(path, method, requestEntity, Object.class, parameters); + } else { + shareitServerResponse = rest.exchange(path, method, requestEntity, Object.class); + } + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray()); + } + return prepareGatewayResponse(shareitServerResponse); + } + + private HttpHeaders defaultHeaders(Long userId) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + if (userId != null) { + headers.set("X-Sharer-User-Id", String.valueOf(userId)); + } + return headers; + } + + private static ResponseEntity prepareGatewayResponse(ResponseEntity response) { + if (response.getStatusCode().is2xxSuccessful()) { + return response; + } + + ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode()); + + if (response.hasBody()) { + return responseBuilder.body(response.getBody()); + } + + return responseBuilder.build(); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/item/client/ItemClient.java b/gateway/src/main/java/ru/practicum/shareit/item/client/ItemClient.java new file mode 100644 index 0000000..18d8c45 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/client/ItemClient.java @@ -0,0 +1,55 @@ +package ru.practicum.shareit.item.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; +import ru.practicum.shareit.client.BaseClient; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; +import ru.practicum.shareit.item.dto.ItemDto; + +import java.util.Map; + +@Service +public class ItemClient extends BaseClient { + private static final String API_PREFIX = "/items"; + + @Autowired + public ItemClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity createItem(Long userId, ItemDto itemDto) { + return (post("", userId, itemDto)); + } + + public ResponseEntity updateItem(Long userId, Long itemId, ItemDto itemDto) { + return (patch("/" + itemId, userId, itemDto)); + } + + public ResponseEntity findItemById(Long userId, Long itemId) { + return get("/" + itemId, userId); + } + + public ResponseEntity findUserItems(Long userId) { + return get("", userId); + } + + public ResponseEntity searchItem(Long userId, String text) { + Map parameters = Map.of("text", text); + + return get("/search?text={text}", userId, parameters); + } + + public ResponseEntity createComment(Long userId, Long itemId, CommentRequestDto commentRequestDto) { + return post("/" + itemId + "/comment", userId, commentRequestDto); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java b/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java similarity index 80% rename from src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java index 7943bae..e4efc14 100644 --- a/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java @@ -2,7 +2,10 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; @NoArgsConstructor @AllArgsConstructor diff --git a/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java b/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java diff --git a/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java b/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java new file mode 100644 index 0000000..f48db76 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java @@ -0,0 +1,59 @@ +package ru.practicum.shareit.item.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.item.client.ItemClient; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; +import ru.practicum.shareit.item.dto.ItemDto; + + +@RequiredArgsConstructor +@Slf4j +@RestController +@RequestMapping("/items") +//@Validated +public class ItemController { + private final ItemClient itemClient; + + @PostMapping + public ResponseEntity createItem(@RequestHeader("X-Sharer-User-Id") Long userId, @Valid @RequestBody ItemDto itemDto) { + log.info("POST /items"); + return itemClient.createItem(userId, itemDto); + } + + @PatchMapping("{itemId}") + public ResponseEntity updateItem(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable("itemId") Long itemId, @RequestBody ItemDto itemDto) { + log.info("PATCH /items/{}", itemId); + return itemClient.updateItem(itemId, userId, itemDto); + } + + @GetMapping("/{itemId}") + public ResponseEntity findItemById(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable("itemId") Long itemId) { + log.info("GET /items/{}", itemId); + return itemClient.findItemById(userId, itemId); + } + + @GetMapping + public ResponseEntity findUserItems(@RequestHeader("X-Sharer-User-Id") Long userId) { + log.info("GET /items"); + return itemClient.findUserItems(userId); + } + + @GetMapping("/search") + public ResponseEntity searchItem(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestParam(name = "text") String text) { + log.info("GET /items/search?text={}.", text); + return itemClient.searchItem(userId, text); + } + + @PostMapping("/{itemId}/comment") + public ResponseEntity createComment(@RequestHeader("X-Sharer-User-Id") Long userId, + @PathVariable("itemId") Long itemId, + @Valid @RequestBody CommentRequestDto commentRequestDto) { + log.info("POST /items/{}/comment", itemId); + return itemClient.createComment(userId, itemId, commentRequestDto); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/gateway/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/ItemDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java diff --git a/gateway/src/main/java/ru/practicum/shareit/request/client/ItemRequestClient.java b/gateway/src/main/java/ru/practicum/shareit/request/client/ItemRequestClient.java new file mode 100644 index 0000000..bfcfe9f --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/client/ItemRequestClient.java @@ -0,0 +1,47 @@ +package ru.practicum.shareit.request.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.util.DefaultUriBuilderFactory; +import ru.practicum.shareit.client.BaseClient; +import ru.practicum.shareit.request.dto.ItemRequestDto; + +import java.util.Map; + +@Service +public class ItemRequestClient extends BaseClient { + private static final String API_PREFIX = "/requests"; + + @Autowired + public ItemRequestClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity createItemRequest(Long userId, ItemRequestDto itemRequestDto) { + return post("", userId, itemRequestDto); + } + + public ResponseEntity findListOfYourQueriesWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId) { + return get("", userId); + } + + public ResponseEntity findListOfRequestsOtherUsers(Long userId, int from, int size) { + Map parameters = Map.of("from", from, "size", size); + + return get("/all?from={from}&size={size}", userId, parameters); + } + + public ResponseEntity findYourQueryWithAnswers(Long userId, Long requestId) { + return get("/" + requestId, userId); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java new file mode 100644 index 0000000..745a527 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.request.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.request.client.ItemRequestClient; +import ru.practicum.shareit.request.dto.ItemRequestDto; + +@RequiredArgsConstructor +@Slf4j +@RestController +@RequestMapping(path = "/requests") +public class ItemRequestController { + private final ItemRequestClient itemRequestClient; + + @PostMapping + public ResponseEntity createItemRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemRequestDto itemRequestDto) { + log.info("POST /requests"); + return itemRequestClient.createItemRequest(userId, itemRequestDto); + } + + @GetMapping + public ResponseEntity findListOfYourQueriesWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId) { + log.info("GET /requests"); + return itemRequestClient.findListOfYourQueriesWithAnswers(userId); + } + + @GetMapping("/all") + public ResponseEntity findListOfRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { + log.info("GET /requests/all"); + return itemRequestClient.findListOfRequestsOtherUsers(userId, from, size); + } + + @GetMapping("/{requestId}") + public ResponseEntity findYourQueryWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { + log.info("GET /requests/{}", requestId); + return itemRequestClient.findYourQueryWithAnswers(userId, requestId); + } +} diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java rename to gateway/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java b/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java rename to gateway/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java diff --git a/gateway/src/main/java/ru/practicum/shareit/user/client/UserClient.java b/gateway/src/main/java/ru/practicum/shareit/user/client/UserClient.java new file mode 100644 index 0000000..f87fa26 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/user/client/UserClient.java @@ -0,0 +1,46 @@ +package ru.practicum.shareit.user.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; +import ru.practicum.shareit.client.BaseClient; +import ru.practicum.shareit.user.dto.UserDto; + +@Service +public class UserClient extends BaseClient { + private static final String API_PREFIX = "/users"; + + @Autowired + public UserClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity findAllUsers() { + return get(""); + } + + public ResponseEntity findUserById(Long id) { + return get("/" + id); + } + + public ResponseEntity createUser(UserDto userDto) { + return post("", userDto); + } + + public ResponseEntity updateUser(Long id, UserDto userDto) { + return patch("/" + id, userDto); + } + + public ResponseEntity deleteUser(Long id) { + return delete("/" + id); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/user/controller/UserController.java b/gateway/src/main/java/ru/practicum/shareit/user/controller/UserController.java new file mode 100644 index 0000000..ace155b --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/user/controller/UserController.java @@ -0,0 +1,51 @@ +package ru.practicum.shareit.user.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.client.UserClient; + + +@Slf4j +@RequiredArgsConstructor +@RestController +@RequestMapping(path = "/users") +@Validated +public class UserController { + + private final UserClient userClient; + + @GetMapping + public ResponseEntity findAllUsers() { + log.info("GET /users"); + return userClient.findAllUsers(); + } + + @GetMapping("/{id}") + public ResponseEntity findUserById(@PathVariable("id") Long id) { + log.info("GET /users/{}", id); + return userClient.findUserById(id); + } + + @PostMapping + public ResponseEntity createUser(@Valid @RequestBody UserDto userDto) { + log.info("POST /users"); + return userClient.createUser(userDto); + } + + @PatchMapping("/{id}") + public ResponseEntity updateUser(@PathVariable("id") Long id, @RequestBody UserDto userDto) { + log.info("PATCH /users/{}", id); + return userClient.updateUser(id, userDto); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteUser(@PathVariable Long id) { + log.info("DELETE /users/{}", id); + return userClient.deleteUser(id); + } +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserDto.java b/gateway/src/main/java/ru/practicum/shareit/user/dto/UserDto.java similarity index 82% rename from src/main/java/ru/practicum/shareit/user/dto/UserDto.java rename to gateway/src/main/java/ru/practicum/shareit/user/dto/UserDto.java index bf78cf7..a7549a5 100644 --- a/src/main/java/ru/practicum/shareit/user/dto/UserDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/user/dto/UserDto.java @@ -2,7 +2,10 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; @NoArgsConstructor @AllArgsConstructor diff --git a/gateway/src/main/resources/application.yml b/gateway/src/main/resources/application.yml new file mode 100644 index 0000000..10ae9aa --- /dev/null +++ b/gateway/src/main/resources/application.yml @@ -0,0 +1,17 @@ +logging: + level: + org: + springframework: + web: + client: + RestTemplate: DEBUG +# apache: +# http: DEBUG +# httpclient: +# wire: DEBUG + +server: + port: 8080 + +shareit-server: + url: http://localhost:9090 \ No newline at end of file diff --git a/pom.xml b/pom.xml index b1f2886..ba25020 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ ru.practicum shareit + pom 0.0.1-SNAPSHOT ShareIt @@ -19,6 +20,11 @@ 21 + + gateway + server + + org.springframework.boot @@ -26,31 +32,28 @@ org.springframework.boot - spring-boot-starter-actuator + spring-boot-starter-data-jpa + + + org.postgresql + postgresql + runtime + + + com.h2database + h2 + runtime org.springframework.boot spring-boot-configuration-processor true - org.projectlombok lombok true - - - com.h2database - h2 - runtime - - - - org.postgresql - postgresql - runtime - org.springframework.boot spring-boot-starter-test @@ -61,34 +64,30 @@ spring-boot-starter-validation - org.springframework.boot - spring-boot-starter-data-jpa + org.apache.commons + commons-lang3 + 3.12.0 - - - src/main/resources - true - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + + org.projectlombok + lombok + + + + org.apache.maven.plugins maven-surefire-plugin @@ -235,17 +234,5 @@ - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - \ No newline at end of file diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/server/pom.xml b/server/pom.xml new file mode 100644 index 0000000..40811b7 --- /dev/null +++ b/server/pom.xml @@ -0,0 +1,104 @@ + + + 4.0.0 + + ru.practicum + shareit + 0.0.1-SNAPSHOT + + + shareit-server + 0.0.1-SNAPSHOT + + ShareIt Server + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.hibernate.validator + hibernate-validator + 8.0.2.Final + + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + + org.glassfish + jakarta.el + 4.0.2 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + + + + + diff --git a/src/main/java/ru/practicum/shareit/ShareItApp.java b/server/src/main/java/ru/practicum/shareit/ShareItApp.java similarity index 100% rename from src/main/java/ru/practicum/shareit/ShareItApp.java rename to server/src/main/java/ru/practicum/shareit/ShareItApp.java diff --git a/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java b/server/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java similarity index 94% rename from src/main/java/ru/practicum/shareit/booking/controller/BookingController.java rename to server/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java index a6a71d7..d692dfa 100644 --- a/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java +++ b/server/src/main/java/ru/practicum/shareit/booking/controller/BookingController.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.booking.controller; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @@ -18,7 +17,7 @@ public class BookingController { private final BookingService bookingService; @PostMapping - public BookingResponseDto createBooking(@RequestHeader("X-Sharer-User-Id") Long userId, @Valid @RequestBody BookingRequestDto bookingRequestDto) { + public BookingResponseDto createBooking(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody BookingRequestDto bookingRequestDto) { log.info("POST /bookings"); return bookingService.createBooking(userId, bookingRequestDto); } diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java new file mode 100644 index 0000000..933e991 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingRequestDto.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.booking.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@AllArgsConstructor +@Getter +@Setter +public class BookingRequestDto { + private Long itemId; + private LocalDateTime start; + private LocalDateTime end; +} diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java new file mode 100644 index 0000000..334abb1 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java @@ -0,0 +1,25 @@ +package ru.practicum.shareit.booking.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.user.dto.UserDto; + +import java.time.LocalDateTime; + +@AllArgsConstructor +@Getter +@Setter +public class BookingResponseDto { + private Long id; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime start; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime end; + private ItemDto item; + private UserDto booker; + private RentalStatus status; +} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/SimplifiedBookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/SimplifiedBookingDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/SimplifiedBookingDto.java rename to server/src/main/java/ru/practicum/shareit/booking/dto/SimplifiedBookingDto.java diff --git a/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java b/server/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java rename to server/src/main/java/ru/practicum/shareit/booking/dto/mapper/BookingMapper.java diff --git a/src/main/java/ru/practicum/shareit/booking/model/Booking.java b/server/src/main/java/ru/practicum/shareit/booking/model/Booking.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/model/Booking.java rename to server/src/main/java/ru/practicum/shareit/booking/model/Booking.java diff --git a/src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java b/server/src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java rename to server/src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingService.java b/server/src/main/java/ru/practicum/shareit/booking/service/BookingService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/service/BookingService.java rename to server/src/main/java/ru/practicum/shareit/booking/service/BookingService.java diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java b/server/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java b/server/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java new file mode 100644 index 0000000..a36dfb1 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/status/RentalStatus.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.booking.status; + +public enum RentalStatus { + WAITING, + APPROVED, + REJECTED, + CANCELED +} diff --git a/src/main/java/ru/practicum/shareit/error/ErrorHandler.java b/server/src/main/java/ru/practicum/shareit/error/ErrorHandler.java similarity index 100% rename from src/main/java/ru/practicum/shareit/error/ErrorHandler.java rename to server/src/main/java/ru/practicum/shareit/error/ErrorHandler.java diff --git a/src/main/java/ru/practicum/shareit/error/ErrorResponse.java b/server/src/main/java/ru/practicum/shareit/error/ErrorResponse.java similarity index 100% rename from src/main/java/ru/practicum/shareit/error/ErrorResponse.java rename to server/src/main/java/ru/practicum/shareit/error/ErrorResponse.java diff --git a/src/main/java/ru/practicum/shareit/exception/InternalServerException.java b/server/src/main/java/ru/practicum/shareit/exception/InternalServerException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/InternalServerException.java rename to server/src/main/java/ru/practicum/shareit/exception/InternalServerException.java diff --git a/src/main/java/ru/practicum/shareit/exception/NotFoundException.java b/server/src/main/java/ru/practicum/shareit/exception/NotFoundException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/NotFoundException.java rename to server/src/main/java/ru/practicum/shareit/exception/NotFoundException.java diff --git a/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/ValidationException.java rename to server/src/main/java/ru/practicum/shareit/exception/ValidationException.java diff --git a/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java b/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java new file mode 100644 index 0000000..c96626f --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentRequestDto.java @@ -0,0 +1,11 @@ +package ru.practicum.shareit.item.comment.dto; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class CommentRequestDto { + private String text; +} diff --git a/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java b/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java new file mode 100644 index 0000000..5708e07 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.item.comment.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@AllArgsConstructor +@Getter +@Setter +public class CommentResponseDto { + private Long id; + private String text; + private String authorName; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime created; + private Long itemId; +} diff --git a/src/main/java/ru/practicum/shareit/item/comment/dto/mapper/CommentMapper.java b/server/src/main/java/ru/practicum/shareit/item/comment/dto/mapper/CommentMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/comment/dto/mapper/CommentMapper.java rename to server/src/main/java/ru/practicum/shareit/item/comment/dto/mapper/CommentMapper.java diff --git a/src/main/java/ru/practicum/shareit/item/comment/model/Comment.java b/server/src/main/java/ru/practicum/shareit/item/comment/model/Comment.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/comment/model/Comment.java rename to server/src/main/java/ru/practicum/shareit/item/comment/model/Comment.java diff --git a/src/main/java/ru/practicum/shareit/item/comment/repository/CommentRepository.java b/server/src/main/java/ru/practicum/shareit/item/comment/repository/CommentRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/comment/repository/CommentRepository.java rename to server/src/main/java/ru/practicum/shareit/item/comment/repository/CommentRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/controller/ItemController.java b/server/src/main/java/ru/practicum/shareit/item/controller/ItemController.java similarity index 91% rename from src/main/java/ru/practicum/shareit/item/controller/ItemController.java rename to server/src/main/java/ru/practicum/shareit/item/controller/ItemController.java index a0293d0..3edbaee 100644 --- a/src/main/java/ru/practicum/shareit/item/controller/ItemController.java +++ b/server/src/main/java/ru/practicum/shareit/item/controller/ItemController.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.item.controller; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @@ -20,7 +19,7 @@ public class ItemController { private final ItemService itemService; @PostMapping - public ItemDto createItem(@RequestHeader("X-Sharer-User-Id") Long userId, @Valid @RequestBody ItemDto itemDto) { + public ItemDto createItem(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemDto itemDto) { log.info("POST /items"); return itemService.createItem(userId, itemDto); } @@ -52,7 +51,7 @@ public List searchItem(@RequestParam(name = "text") String text) { @PostMapping("/{itemId}/comment") public CommentResponseDto createComment(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable("itemId") Long itemId, - @Valid @RequestBody CommentRequestDto commentRequestDto) { + @RequestBody CommentRequestDto commentRequestDto) { log.info("POST /items/{}/comment", itemId); return itemService.createComment(userId, itemId, commentRequestDto); } diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemBookingDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/ItemBookingDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/ItemBookingDto.java rename to server/src/main/java/ru/practicum/shareit/item/dto/ItemBookingDto.java diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java new file mode 100644 index 0000000..8640224 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.item.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class ItemDto { + private Long id; + private String name; + private String description; + private Boolean available; + private Long requestId; +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java b/server/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java rename to server/src/main/java/ru/practicum/shareit/item/dto/mapper/ItemMapper.java diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/server/src/main/java/ru/practicum/shareit/item/model/Item.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/model/Item.java rename to server/src/main/java/ru/practicum/shareit/item/model/Item.java diff --git a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java b/server/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java rename to server/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemService.java b/server/src/main/java/ru/practicum/shareit/item/service/ItemService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/service/ItemService.java rename to server/src/main/java/ru/practicum/shareit/item/service/ItemService.java diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java b/server/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java diff --git a/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java rename to server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java new file mode 100644 index 0000000..0e4c064 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -0,0 +1,15 @@ +package ru.practicum.shareit.request.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class ItemRequestDto { + private String description; + private Long requestorId; +} diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java new file mode 100644 index 0000000..4a762bf --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java @@ -0,0 +1,24 @@ +package ru.practicum.shareit.request.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ru.practicum.shareit.item.dto.ItemDto; + +import java.time.LocalDateTime; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class ItemResponseDto { + private Long id; + private String description; + private Long userId; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime created; + private List items; +} diff --git a/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java b/server/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java rename to server/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java diff --git a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java b/server/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/model/ItemRequest.java rename to server/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java diff --git a/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java b/server/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java rename to server/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java rename to server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java diff --git a/src/main/java/ru/practicum/shareit/user/controller/UserController.java b/server/src/main/java/ru/practicum/shareit/user/controller/UserController.java similarity index 92% rename from src/main/java/ru/practicum/shareit/user/controller/UserController.java rename to server/src/main/java/ru/practicum/shareit/user/controller/UserController.java index b8c34a3..5cd25b5 100644 --- a/src/main/java/ru/practicum/shareit/user/controller/UserController.java +++ b/server/src/main/java/ru/practicum/shareit/user/controller/UserController.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.user.controller; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @@ -30,7 +29,7 @@ public UserDto findUserById(@PathVariable("id") Long id) { } @PostMapping - public UserDto createUser(@Valid @RequestBody UserDto userDto) { + public UserDto createUser(@RequestBody UserDto userDto) { log.info("POST /users"); return userService.createUser(userDto); } diff --git a/server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java b/server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java new file mode 100644 index 0000000..364c74b --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java @@ -0,0 +1,13 @@ +package ru.practicum.shareit.user.dto; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class UserDto { + private Long id; + private String name; + private String email; +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/mapper/UserMapper.java b/server/src/main/java/ru/practicum/shareit/user/dto/mapper/UserMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/dto/mapper/UserMapper.java rename to server/src/main/java/ru/practicum/shareit/user/dto/mapper/UserMapper.java diff --git a/src/main/java/ru/practicum/shareit/user/model/User.java b/server/src/main/java/ru/practicum/shareit/user/model/User.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/model/User.java rename to server/src/main/java/ru/practicum/shareit/user/model/User.java diff --git a/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java b/server/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/repository/UserRepository.java rename to server/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java diff --git a/src/main/java/ru/practicum/shareit/user/service/UserService.java b/server/src/main/java/ru/practicum/shareit/user/service/UserService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/service/UserService.java rename to server/src/main/java/ru/practicum/shareit/user/service/UserService.java diff --git a/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java b/server/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml new file mode 100644 index 0000000..eb319df --- /dev/null +++ b/server/src/main/resources/application.yml @@ -0,0 +1,45 @@ +spring: + profiles: + active: dev + +--- + +spring: + config: + activate: + on-profile: dev + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5445/shareit + username: dbuser + password: 12345 + jpa: + hibernate: + ddl-auto: none + properties: + hibernate: + dialect: org.hibernate.dialect.PostgreSQLDialect + +server: + port: 9090 + +--- + +spring: + config: + activate: + on-profile: test + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:shareit + username: dbuser + password: 12345 + jpa: + hibernate: + ddl-auto: create-drop + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect + +server: + port: 9090 \ No newline at end of file diff --git a/src/main/resources/schema.sql b/server/src/main/resources/schema.sql similarity index 100% rename from src/main/resources/schema.sql rename to server/src/main/resources/schema.sql diff --git a/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java b/server/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java similarity index 100% rename from src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java rename to server/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java diff --git a/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java b/server/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java similarity index 93% rename from src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java rename to server/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java index 7b6bb61..fadf0f3 100644 --- a/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; import ru.practicum.shareit.request.dto.ItemRequestDto; import ru.practicum.shareit.request.dto.ItemResponseDto; @@ -16,8 +17,9 @@ import static org.assertj.core.api.Assertions.assertThat; @Transactional +//@ActiveProfiles("dev") @SpringBootTest( - properties = "spring.datasource.url=jdbc:postgresql://localhost:5439/test", + //properties = "spring.datasource.url=jdbc:postgresql://db:5432/shareit", classes = ShareItApp.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) @RequiredArgsConstructor(onConstructor_ = @Autowired) diff --git a/src/test/java/ru/practicum/shareit/ItemRequestTest.java b/server/src/test/java/ru/practicum/shareit/ItemRequestTest.java similarity index 79% rename from src/test/java/ru/practicum/shareit/ItemRequestTest.java rename to server/src/test/java/ru/practicum/shareit/ItemRequestTest.java index d884dee..98ecc65 100644 --- a/src/test/java/ru/practicum/shareit/ItemRequestTest.java +++ b/server/src/test/java/ru/practicum/shareit/ItemRequestTest.java @@ -121,32 +121,5 @@ void shouldDeserializeItemResponseDtoFromJson() throws Exception { assertThat(result.getCreated()).isEqualTo(LocalDateTime.of(2025, 7, 16, 18, 30, 0)); assertThat(result.getItems()).isEmpty(); } - - @Test - void shouldSerializeAndValidateItemRequestDto() throws Exception { - ItemRequestDto validDto = new ItemRequestDto("Нужен фотоаппарат", 1L); - - JsonContent validJson = json.write(validDto); - assertThat(validJson).extractingJsonPathStringValue("$.description").isEqualTo("Нужен фотоаппарат"); - assertThat(validJson).extractingJsonPathNumberValue("$.requestorId").isEqualTo(1); - assertThat(validator.validate(validDto)).isEmpty(); - - ItemRequestDto invalidDto = new ItemRequestDto(" ", null); - var violations = validator.validate(invalidDto); - - assertThat(violations).hasSize(2); - assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("description")); - assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("requestorId")); - } - - @Test - void shouldFailValidationWhenDescriptionTooLong() { - String longDescription = "тест".repeat(2001); - ItemRequestDto itemRequestDto = new ItemRequestDto(longDescription, 1L); - - var violations = validator.validate(itemRequestDto); - assertThat(violations).hasSize(1); - assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("description")); - } } diff --git a/src/test/java/ru/practicum/shareit/ShareItTests.java b/server/src/test/java/ru/practicum/shareit/ShareItTests.java similarity index 100% rename from src/test/java/ru/practicum/shareit/ShareItTests.java rename to server/src/test/java/ru/practicum/shareit/ShareItTests.java diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml deleted file mode 100644 index f5599d8..0000000 --- a/src/main/resources/application.yaml +++ /dev/null @@ -1,35 +0,0 @@ -server: - port: 8080 - -spring: - sql: - init: - mode: always - jpa: - show-sql: true - hibernate: - ddl-auto: none - properties: - hibernate: - format_sql: true - jdbc: - time_zone: UTC - lob: - non_contextual_creation: true - - datasource: - url: jdbc:postgresql://localhost:5438/shareitdb - username: dbuser - password: 12345 - driver-class-name: org.postgresql.Driver - -logging: - level: - org: - springframework: - orm: - jpa: INFO - jpa.JpaTransactionManager: DEBUG - transaction: - interceptor: TRACE - transaction.interceptor: TRACE \ No newline at end of file From 131b56e3535e2e8c7302f7d51db259ab9ad7a626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Sun, 20 Jul 2025 21:29:17 +0300 Subject: [PATCH 06/15] =?UTF-8?q?=D0=9D=D0=B0=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D1=88=D0=B8=D0=B5?= =?UTF-8?q?=D1=81=D1=8F=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composeTest.yml => compose.test.yml | 0 compose.yml | 2 - .../ru/practicum/shareit/ShareItGateway.java | 6 +- .../item/controller/ItemController.java | 2 - .../controller/ItemRequestController.java | 4 +- .../BookingRequestDtoValidationTest.java | 85 ++++++ .../shareit/item/ItemDtoValidationTest.java | 62 +++++ .../CommentRequestDtoValidationTest.java | 53 ++++ .../ItemReqRequestDtoValidationTest.java | 63 +++++ .../shareit/user/UserDtoValidationTest.java | 59 +++++ .../java/ru/practicum/shareit/ShareItApp.java | 6 +- .../controller/ItemRequestController.java | 18 +- ...RequestDto.java => ItemReqRequestDto.java} | 2 +- ...sponseDto.java => ItemReqResponseDto.java} | 2 +- .../request/dto/mapper/ItemRequestMapper.java | 12 +- .../request/service/ItemRequestService.java | 12 +- .../service/ItemRequestServiceImpl.java | 16 +- server/src/main/resources/application.yml | 2 +- .../booking/BookingControllerTest.java | 237 +++++++++++++++++ .../BookingRequestAndResponseDtoTest.java | 120 +++++++++ .../shareit/booking/BookingServiceTest.java | 111 ++++++++ .../shareit/item/ItemAndBookingDtoTest.java | 168 ++++++++++++ .../shareit/item/ItemControllerTest.java | 246 ++++++++++++++++++ .../shareit/item/ItemServiceTest.java | 92 +++++++ .../CommentRequestAndResponseDtoTest.java | 84 ++++++ .../ItemReqRequestAndResponseDtoTest.java} | 48 ++-- .../ItemRequestControllerTest.java | 33 ++- .../{ => request}/ItemRequestServiceTest.java | 29 +-- .../shareit/user/UserControllerTest.java | 131 ++++++++++ .../practicum/shareit/user/UserDtoTest.java | 53 ++++ .../shareit/user/UserServiceTest.java | 50 ++++ 31 files changed, 1702 insertions(+), 106 deletions(-) rename composeTest.yml => compose.test.yml (100%) create mode 100644 gateway/src/test/java/ru/practicum/shareit/booking/BookingRequestDtoValidationTest.java create mode 100644 gateway/src/test/java/ru/practicum/shareit/item/ItemDtoValidationTest.java create mode 100644 gateway/src/test/java/ru/practicum/shareit/item/comment/CommentRequestDtoValidationTest.java create mode 100644 gateway/src/test/java/ru/practicum/shareit/request/ItemReqRequestDtoValidationTest.java create mode 100644 gateway/src/test/java/ru/practicum/shareit/user/UserDtoValidationTest.java rename server/src/main/java/ru/practicum/shareit/request/dto/{ItemRequestDto.java => ItemReqRequestDto.java} (89%) rename server/src/main/java/ru/practicum/shareit/request/dto/{ItemResponseDto.java => ItemReqResponseDto.java} (94%) create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java rename server/src/test/java/ru/practicum/shareit/{ItemRequestTest.java => request/ItemReqRequestAndResponseDtoTest.java} (72%) rename server/src/test/java/ru/practicum/shareit/{ => request}/ItemRequestControllerTest.java (89%) rename server/src/test/java/ru/practicum/shareit/{ => request}/ItemRequestServiceTest.java (64%) create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java diff --git a/composeTest.yml b/compose.test.yml similarity index 100% rename from composeTest.yml rename to compose.test.yml diff --git a/compose.yml b/compose.yml index 0eabd3e..ae83854 100644 --- a/compose.yml +++ b/compose.yml @@ -5,7 +5,6 @@ services: container_name: shareit-gateway ports: - "8080:8080" - #- "8081:8081" depends_on: - server environment: @@ -17,7 +16,6 @@ services: container_name: shareit-server ports: - "9090:9090" - #- "9091:9091" depends_on: - db environment: diff --git a/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java b/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java index 0aa75c3..e659d11 100644 --- a/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java +++ b/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java @@ -5,8 +5,8 @@ @SpringBootApplication public class ShareItGateway { - public static void main(String[] args) { - SpringApplication.run(ShareItGateway.class, args); - } + public static void main(String[] args) { + SpringApplication.run(ShareItGateway.class, args); + } } diff --git a/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java b/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java index f48db76..cc62894 100644 --- a/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java +++ b/gateway/src/main/java/ru/practicum/shareit/item/controller/ItemController.java @@ -4,7 +4,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import ru.practicum.shareit.item.client.ItemClient; import ru.practicum.shareit.item.comment.dto.CommentRequestDto; @@ -15,7 +14,6 @@ @Slf4j @RestController @RequestMapping("/items") -//@Validated public class ItemController { private final ItemClient itemClient; diff --git a/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java index 745a527..87d1351 100644 --- a/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java +++ b/gateway/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -28,8 +28,8 @@ public ResponseEntity findListOfYourQueriesWithAnswers(@RequestHeader("X @GetMapping("/all") public ResponseEntity findListOfRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, - @RequestParam(defaultValue = "0") int from, - @RequestParam(defaultValue = "10") int size) { + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { log.info("GET /requests/all"); return itemRequestClient.findListOfRequestsOtherUsers(userId, from, size); } diff --git a/gateway/src/test/java/ru/practicum/shareit/booking/BookingRequestDtoValidationTest.java b/gateway/src/test/java/ru/practicum/shareit/booking/BookingRequestDtoValidationTest.java new file mode 100644 index 0000000..40be203 --- /dev/null +++ b/gateway/src/test/java/ru/practicum/shareit/booking/BookingRequestDtoValidationTest.java @@ -0,0 +1,85 @@ +package ru.practicum.shareit.booking; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.booking.dto.BookingRequestDto; + +import java.time.LocalDateTime; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BookingRequestDtoValidationTest { + private static Validator validator; + + @BeforeAll + static void setupValidator() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void mustFailWhenItemIdIsNull() { + BookingRequestDto dto = new BookingRequestDto( + null, + LocalDateTime.now().plusHours(2), + LocalDateTime.now().plusDays(1) + ); + + Set> violations = validator.validate(dto); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("itemId")); + } + + @Test + void mustFailWhenStartIsInPast() { + BookingRequestDto dto = new BookingRequestDto( + 1L, + LocalDateTime.now().minusDays(1), + LocalDateTime.now().plusDays(1) + ); + + Set> violations = validator.validate(dto); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("start")); + } + + @Test + void mustFailWhenEndIsInPast() { + BookingRequestDto dto = new BookingRequestDto( + 1L, + LocalDateTime.now().plusHours(1), + LocalDateTime.now().minusHours(1) + ); + + Set> violations = validator.validate(dto); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("end")); + } + + @Test + void mustFailWhenStartOrEndIsNull() { + BookingRequestDto dto = new BookingRequestDto( + 1L, + null, + null + ); + + Set> violations = validator.validate(dto); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("start")); + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("end")); + } + + @Test + void mustPassValidation() { + BookingRequestDto dto = new BookingRequestDto( + 1L, + LocalDateTime.now().plusHours(2), + LocalDateTime.now().plusDays(1) + ); + + Set> violations = validator.validate(dto); + assertThat(violations).isEmpty(); + } +} diff --git a/gateway/src/test/java/ru/practicum/shareit/item/ItemDtoValidationTest.java b/gateway/src/test/java/ru/practicum/shareit/item/ItemDtoValidationTest.java new file mode 100644 index 0000000..91aa286 --- /dev/null +++ b/gateway/src/test/java/ru/practicum/shareit/item/ItemDtoValidationTest.java @@ -0,0 +1,62 @@ +package ru.practicum.shareit.item; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.item.dto.ItemDto; + +import java.util.Set; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class ItemDtoValidationTest { + private static Validator validator; + + @BeforeAll + static void setupValidator() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void mustFailValidationWhenNameIsBlank() { + ItemDto dto = new ItemDto(1L, " ", "Полупрофессиональная модель фотоаппарата", true, null); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("name")); + } + + @Test + void mustFailValidationWhenDescriptionIsBlank() { + ItemDto dto = new ItemDto(1L, "Canon 500d", " ", true, null); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("description")); + } + + @Test + void mustFailValidationWhenAvailableIsNull() { + ItemDto dto = new ItemDto(1L, "Canon 500d", "Полупрофессиональная модель фотоаппарата", null, null); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("available")); + } + + @Test + void mustPassValidationForValidDto() { + ItemDto dto = new ItemDto(1L, "Canon 500d", "Полупрофессиональная модель фотоаппарата", true, null); + + Set> violations = validator.validate(dto); + + assertThat(violations).isEmpty(); + } +} diff --git a/gateway/src/test/java/ru/practicum/shareit/item/comment/CommentRequestDtoValidationTest.java b/gateway/src/test/java/ru/practicum/shareit/item/comment/CommentRequestDtoValidationTest.java new file mode 100644 index 0000000..81ce72c --- /dev/null +++ b/gateway/src/test/java/ru/practicum/shareit/item/comment/CommentRequestDtoValidationTest.java @@ -0,0 +1,53 @@ +package ru.practicum.shareit.item.comment; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; + +import java.util.Set; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class CommentRequestDtoValidationTest { + private static Validator validator; + + @BeforeAll + static void setupValidator() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void mustFailValidationWhenTextIsBlank() { + CommentRequestDto dto = new CommentRequestDto(" "); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("text")); + } + + @Test + void mustFailValidationWhenTextIsTooLong() { + String longText = "Тест".repeat(2001); + CommentRequestDto dto = new CommentRequestDto(longText); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("text")); + } + + @Test + void mustPassValidationWhenTextIsValid() { + CommentRequestDto dto = new CommentRequestDto("Хорошая вещь. Все отлично!"); + + Set> violations = validator.validate(dto); + + assertThat(violations).isEmpty(); + } +} diff --git a/gateway/src/test/java/ru/practicum/shareit/request/ItemReqRequestDtoValidationTest.java b/gateway/src/test/java/ru/practicum/shareit/request/ItemReqRequestDtoValidationTest.java new file mode 100644 index 0000000..5938d1f --- /dev/null +++ b/gateway/src/test/java/ru/practicum/shareit/request/ItemReqRequestDtoValidationTest.java @@ -0,0 +1,63 @@ +package ru.practicum.shareit.request; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.request.dto.ItemRequestDto; + +import java.util.Set; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class ItemReqRequestDtoValidationTest { + private static Validator validator; + + @BeforeAll + static void setupValidator() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void mustFailValidationWhenDescriptionIsBlank() { + ItemRequestDto dto = new ItemRequestDto(" ", 1L); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("description")); + } + + @Test + void mustFailValidationWhenDescriptionTooLong() { + String longDescription = "test".repeat(2001); + ItemRequestDto dto = new ItemRequestDto(longDescription, 1L); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("description")); + } + + @Test + void mustFailValidationWhenRequestorIdIsNull() { + ItemRequestDto dto = new ItemRequestDto("Описание для теста", null); + + Set> violations = validator.validate(dto); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("requestorId")); + } + + @Test + void mustPassValidationForValidDto() { + ItemRequestDto dto = new ItemRequestDto("Описание для теста", 1L); + + Set> violations = validator.validate(dto); + + assertThat(violations).isEmpty(); + } +} diff --git a/gateway/src/test/java/ru/practicum/shareit/user/UserDtoValidationTest.java b/gateway/src/test/java/ru/practicum/shareit/user/UserDtoValidationTest.java new file mode 100644 index 0000000..37fec2c --- /dev/null +++ b/gateway/src/test/java/ru/practicum/shareit/user/UserDtoValidationTest.java @@ -0,0 +1,59 @@ +package ru.practicum.shareit.user; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.user.dto.UserDto; + +import java.util.Set; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class UserDtoValidationTest { + private static Validator validator; + + @BeforeAll + static void setupValidator() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void mustFailValidationWhenNameIsBlank() { + UserDto userDto = new UserDto(1L, "", "Max@mail.ru"); + + Set> violations = validator.validate(userDto); + + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("name")); + } + + @Test + void mustFailValidationWhenEmailIsInvalid() { + UserDto userDto = new UserDto(1L, "Макс Иванов", "Maxmail.ru"); + + Set> violations = validator.validate(userDto); + + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("email")); + } + + @Test + void mustFailValidationWhenEmailIsBlank() { + UserDto userDto = new UserDto(1L, "Макс Иванов", ""); + + Set> violations = validator.validate(userDto); + + assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("email")); + } + + @Test + void mustPassValidationWhenAllFieldsAreValid() { + UserDto userDto = new UserDto(1L, "Макс Иванов", "Max@mail.ru"); + + Set> violations = validator.validate(userDto); + + assertThat(violations).isEmpty(); + } +} diff --git a/server/src/main/java/ru/practicum/shareit/ShareItApp.java b/server/src/main/java/ru/practicum/shareit/ShareItApp.java index a00ad56..a10a87d 100644 --- a/server/src/main/java/ru/practicum/shareit/ShareItApp.java +++ b/server/src/main/java/ru/practicum/shareit/ShareItApp.java @@ -6,8 +6,8 @@ @SpringBootApplication public class ShareItApp { - public static void main(String[] args) { - SpringApplication.run(ShareItApp.class, args); - } + public static void main(String[] args) { + SpringApplication.run(ShareItApp.class, args); + } } diff --git a/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java index a7e66bc..36d80e1 100644 --- a/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java +++ b/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -3,8 +3,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import ru.practicum.shareit.request.dto.ItemRequestDto; -import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.dto.ItemReqRequestDto; +import ru.practicum.shareit.request.dto.ItemReqResponseDto; import ru.practicum.shareit.request.service.ItemRequestService; import java.util.List; @@ -17,27 +17,27 @@ public class ItemRequestController { private final ItemRequestService itemRequestService; @PostMapping - public ItemResponseDto createItemRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemRequestDto itemRequestDto) { + public ItemReqResponseDto createItemRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @RequestBody ItemReqRequestDto itemReqRequestDto) { log.info("POST /requests"); - return itemRequestService.createItemRequest(userId, itemRequestDto); + return itemRequestService.createItemRequest(userId, itemReqRequestDto); } @GetMapping - public List findListOfYourQueriesWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId) { + public List findListOfYourQueriesWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId) { log.info("GET /requests"); return itemRequestService.findListOfYourQueriesWithAnswers(userId); } @GetMapping("/all") - public List findListOfRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, - @RequestParam(defaultValue = "0") int from, - @RequestParam(defaultValue = "10") int size) { + public List findListOfRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { log.info("GET /requests/all"); return itemRequestService.findListOfRequestsOtherUsers(userId, from, size); } @GetMapping("/{requestId}") - public ItemResponseDto findYourQueryWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { + public ItemReqResponseDto findYourQueryWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { log.info("GET /requests/{}", requestId); return itemRequestService.findYourQueryWithAnswers(userId, requestId); } diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqRequestDto.java similarity index 89% rename from server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java rename to server/src/main/java/ru/practicum/shareit/request/dto/ItemReqRequestDto.java index 0e4c064..62ced4c 100644 --- a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqRequestDto.java @@ -9,7 +9,7 @@ @AllArgsConstructor @Setter @Getter -public class ItemRequestDto { +public class ItemReqRequestDto { private String description; private Long requestorId; } diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java similarity index 94% rename from server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java rename to server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java index 4a762bf..9d1c1ef 100644 --- a/server/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java @@ -14,7 +14,7 @@ @AllArgsConstructor @Setter @Getter -public class ItemResponseDto { +public class ItemReqResponseDto { private Long id; private String description; private Long userId; diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java b/server/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java index c5c36c9..9672b99 100644 --- a/server/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java +++ b/server/src/main/java/ru/practicum/shareit/request/dto/mapper/ItemRequestMapper.java @@ -3,8 +3,8 @@ import lombok.experimental.UtilityClass; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.request.model.ItemRequest; -import ru.practicum.shareit.request.dto.ItemRequestDto; -import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.dto.ItemReqRequestDto; +import ru.practicum.shareit.request.dto.ItemReqResponseDto; import ru.practicum.shareit.user.model.User; import java.time.LocalDateTime; @@ -12,8 +12,8 @@ @UtilityClass public class ItemRequestMapper { - public static ItemResponseDto toItemResponseDto(ItemRequest itemRequest, List items) { - return new ItemResponseDto( + public static ItemReqResponseDto toItemResponseDto(ItemRequest itemRequest, List items) { + return new ItemReqResponseDto( itemRequest.getId(), itemRequest.getDescription(), itemRequest.getRequestor().getId(), @@ -22,10 +22,10 @@ public static ItemResponseDto toItemResponseDto(ItemRequest itemRequest, List findListOfYourQueriesWithAnswers(Long userId); + List findListOfYourQueriesWithAnswers(Long userId); - List findListOfRequestsOtherUsers(Long userId, int from, int size); + List findListOfRequestsOtherUsers(Long userId, int from, int size); - ItemResponseDto findYourQueryWithAnswers(Long userId, Long requestId); + ItemReqResponseDto findYourQueryWithAnswers(Long userId, Long requestId); } diff --git a/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java index 9734bf4..6d83820 100644 --- a/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java +++ b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java @@ -9,8 +9,8 @@ import ru.practicum.shareit.item.dto.mapper.ItemMapper; import ru.practicum.shareit.item.model.Item; import ru.practicum.shareit.item.repository.ItemRepository; -import ru.practicum.shareit.request.dto.ItemRequestDto; -import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.dto.ItemReqRequestDto; +import ru.practicum.shareit.request.dto.ItemReqResponseDto; import ru.practicum.shareit.request.dto.mapper.ItemRequestMapper; import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.request.repository.ItemRequestRepository; @@ -31,15 +31,15 @@ public class ItemRequestServiceImpl implements ItemRequestService { private final ItemRepository itemRepository; @Override - public ItemResponseDto createItemRequest(Long userId, ItemRequestDto itemRequestDto) { + public ItemReqResponseDto createItemRequest(Long userId, ItemReqRequestDto itemReqRequestDto) { User user = validateUser(userId); return ItemRequestMapper.toItemResponseDto(itemRequestRepository - .save(ItemRequestMapper.toItemRequest(itemRequestDto, user)), List.of()); + .save(ItemRequestMapper.toItemRequest(itemReqRequestDto, user)), List.of()); } @Override - public List findListOfYourQueriesWithAnswers(Long userId) { + public List findListOfYourQueriesWithAnswers(Long userId) { validateUser(userId); List requests = itemRequestRepository.findByRequestorIdOrderByCreatedDesc(userId); @@ -48,7 +48,7 @@ public List findListOfYourQueriesWithAnswers(Long userId) { } @Override - public List findListOfRequestsOtherUsers(Long userId, int from, int size) { + public List findListOfRequestsOtherUsers(Long userId, int from, int size) { validateUser(userId); Pageable pageable = PageRequest.of(from / size, size, Sort.by("created").descending()); @@ -59,7 +59,7 @@ public List findListOfRequestsOtherUsers(Long userId, int from, } @Override - public ItemResponseDto findYourQueryWithAnswers(Long userId, Long requestId) { + public ItemReqResponseDto findYourQueryWithAnswers(Long userId, Long requestId) { validateUser(userId); ItemRequest itemRequest = itemRequestRepository.findById(requestId) @@ -79,7 +79,7 @@ private User validateUser(Long userId) { .orElseThrow(() -> new NotFoundException("Пользователь с данным id: " + userId + " не найден")); } - private List composeResponseForItemResponseDto(List requests) { + private List composeResponseForItemResponseDto(List requests) { if (requests == null || requests.isEmpty()) { return List.of(); } diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index eb319df..9c14e4f 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -1,6 +1,6 @@ spring: profiles: - active: dev + active: test --- diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java new file mode 100644 index 0000000..78302bc --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java @@ -0,0 +1,237 @@ +package ru.practicum.shareit.booking; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import ru.practicum.shareit.booking.controller.BookingController; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.service.BookingService; +import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.error.ErrorHandler; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.user.dto.UserDto; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +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.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +public class BookingControllerTest { + @Mock + private BookingService bookingService; + @InjectMocks + private BookingController bookingController; + private final ObjectMapper mapper = new ObjectMapper(); + private MockMvc mvc; + private BookingRequestDto bookingRequestDto; + private ItemDto itemDto; + private UserDto userDto; + private BookingResponseDto bookingResponseDto; + private BookingResponseDto bookingResponseDto2; + + @BeforeEach + void setUp() { + mapper.findAndRegisterModules(); + + mvc = MockMvcBuilders + .standaloneSetup(bookingController) + .setControllerAdvice(new ErrorHandler()) + .build(); + + bookingRequestDto = new BookingRequestDto( + 1L, + LocalDateTime.of(2025, 7, 20, 10, 0), + LocalDateTime.of(2025, 7, 20, 12, 0) + ); + + userDto = new UserDto( + 1L, + "Макс Иванов", + "Max@mail.ru" + ); + + itemDto = new ItemDto( + 1L, + "Canon 500d", + "Полупрофессиональная модель фотоаппарата", + true, + 5L + ); + + bookingResponseDto = new BookingResponseDto( + 1L, + LocalDateTime.of(2025, 7, 20, 10, 0), + LocalDateTime.of(2025, 7, 20, 12, 0), + itemDto, + userDto, + RentalStatus.APPROVED + ); + + bookingResponseDto2 = new BookingResponseDto( + 2L, + LocalDateTime.of(2025, 7, 20, 13, 0), + LocalDateTime.of(2025, 7, 20, 14, 0), + null, + null, + RentalStatus.APPROVED + ); + } + + @Test + void mustCreateBooking() throws Exception { + when(bookingService.createBooking(eq(1L), any())) + .thenReturn(bookingResponseDto); + + mvc.perform(post("/bookings") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(bookingRequestDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.start", is("2025-07-20T10:00:00"))) + .andExpect(jsonPath("$.end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.item.name", is("Canon 500d"))) + .andExpect(jsonPath("$.item.description", is("Полупрофессиональная модель фотоаппарата"))) + .andExpect(jsonPath("$.item.available", is(true))) + .andExpect(jsonPath("$.item.requestId", is(5))) + .andExpect(jsonPath("$.booker.id", is(1))) + .andExpect(jsonPath("$.booker.name", is("Макс Иванов"))) + .andExpect(jsonPath("$.booker.email", is("Max@mail.ru"))) + .andExpect(jsonPath("$.status", is("APPROVED"))); + } + + @Test + void mustUpdateBookingStatus() throws Exception { + bookingResponseDto.setStatus(RentalStatus.REJECTED); + + when(bookingService.updateBooking(1L, 1L, false)) + .thenReturn(bookingResponseDto); + + mvc.perform(post("/bookings/1") + .param("approved", "false") + .header("X-Sharer-User-Id", "1") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(request -> { + request.setMethod("PATCH"); + return request; + })) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.start", is("2025-07-20T10:00:00"))) + .andExpect(jsonPath("$.end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.item.name", is("Canon 500d"))) + .andExpect(jsonPath("$.item.description", is("Полупрофессиональная модель фотоаппарата"))) + .andExpect(jsonPath("$.item.available", is(true))) + .andExpect(jsonPath("$.item.requestId", is(5))) + .andExpect(jsonPath("$.booker.id", is(1))) + .andExpect(jsonPath("$.booker.name", is("Макс Иванов"))) + .andExpect(jsonPath("$.booker.email", is("Max@mail.ru"))) + .andExpect(jsonPath("$.status", is("REJECTED"))); + } + + @Test + void mustReturnBookingById() throws Exception { + when(bookingService.findBookingById(1L, 1L)) + .thenReturn(bookingResponseDto); + + mvc.perform(get("/bookings/1") + .header("X-Sharer-User-Id", "1") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.start", is("2025-07-20T10:00:00"))) + .andExpect(jsonPath("$.end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$.item.name", is("Canon 500d"))) + .andExpect(jsonPath("$.item.description", is("Полупрофессиональная модель фотоаппарата"))) + .andExpect(jsonPath("$.item.available", is(true))) + .andExpect(jsonPath("$.item.requestId", is(5))) + .andExpect(jsonPath("$.booker.id", is(1))) + .andExpect(jsonPath("$.booker.name", is("Макс Иванов"))) + .andExpect(jsonPath("$.booker.email", is("Max@mail.ru"))) + .andExpect(jsonPath("$.status", is("APPROVED"))); + } + + @Test + void mustReturnUserBookings() throws Exception { + List bookings = List.of(bookingResponseDto, bookingResponseDto2); + + when(bookingService.findUserBookings(1L, "ALL")) + .thenReturn(bookings); + + mvc.perform(get("/bookings") + .header("X-Sharer-User-Id", 1L) + .param("state", "ALL") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].start", is("2025-07-20T10:00:00"))) + .andExpect(jsonPath("$[0].end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$[0].item.name", is("Canon 500d"))) + .andExpect(jsonPath("$[0].item.description", is("Полупрофессиональная модель фотоаппарата"))) + .andExpect(jsonPath("$[0].item.available", is(true))) + .andExpect(jsonPath("$[0].item.requestId", is(5))) + .andExpect(jsonPath("$[0].booker.id", is(1))) + .andExpect(jsonPath("$[0].booker.name", is("Макс Иванов"))) + .andExpect(jsonPath("$[0].booker.email", is("Max@mail.ru"))) + .andExpect(jsonPath("$[0].status", is("APPROVED"))) + .andExpect(jsonPath("$[1].id", is(2))) + .andExpect(jsonPath("$[1].start", is("2025-07-20T13:00:00"))) + .andExpect(jsonPath("$[1].end", is("2025-07-20T14:00:00"))) + .andExpect(jsonPath("$[1].item").doesNotExist()) + .andExpect(jsonPath("$[1].booker").doesNotExist()) + .andExpect(jsonPath("$[1].status", is("APPROVED"))); + } + + @Test + void mustReturnOwnerReservedItems() throws Exception { + List bookings = List.of(bookingResponseDto, bookingResponseDto2); + + when(bookingService.findOwnerReservedItems(1L, "ALL")) + .thenReturn(bookings); + + mvc.perform(get("/bookings/owner") + .header("X-Sharer-User-Id", 1L) + .param("state", "ALL") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].start", is("2025-07-20T10:00:00"))) + .andExpect(jsonPath("$[0].end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$[0].item.name", is("Canon 500d"))) + .andExpect(jsonPath("$[0].item.description", is("Полупрофессиональная модель фотоаппарата"))) + .andExpect(jsonPath("$[0].item.available", is(true))) + .andExpect(jsonPath("$[0].item.requestId", is(5))) + .andExpect(jsonPath("$[0].booker.id", is(1))) + .andExpect(jsonPath("$[0].booker.name", is("Макс Иванов"))) + .andExpect(jsonPath("$[0].booker.email", is("Max@mail.ru"))) + .andExpect(jsonPath("$[0].status", is("APPROVED"))) + .andExpect(jsonPath("$[1].id", is(2))) + .andExpect(jsonPath("$[1].start", is("2025-07-20T13:00:00"))) + .andExpect(jsonPath("$[1].end", is("2025-07-20T14:00:00"))) + .andExpect(jsonPath("$[1].item").doesNotExist()) + .andExpect(jsonPath("$[1].booker").doesNotExist()) + .andExpect(jsonPath("$[1].status", is("APPROVED"))); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java new file mode 100644 index 0000000..0ccc9cd --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java @@ -0,0 +1,120 @@ +package ru.practicum.shareit.booking; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import org.springframework.test.context.ContextConfiguration; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.dto.SimplifiedBookingDto; +import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.user.dto.UserDto; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ContextConfiguration(classes = ShareItApp.class) +@JsonTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class BookingRequestAndResponseDtoTest { + private final JacksonTester jsonBookingRequestDto; + private final JacksonTester jsonBookingResponseDto; + private final JacksonTester jsonItemDto; + private final JacksonTester jsonUserDto; + private final JacksonTester jsonSimplifiedBookingDto; + + @Test + void shouldReturnBookingRequestDto() throws Exception { + BookingRequestDto bookingRequestDto = new BookingRequestDto( + 1L, + LocalDateTime.of(2025, 7, 20, 10, 0), + LocalDateTime.of(2025, 7, 20, 12, 0) + ); + JsonContent result = jsonBookingRequestDto.write(bookingRequestDto); + + assertThat(result).extractingJsonPathNumberValue("$.itemId").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.start").isEqualTo("2025-07-20T10:00:00"); + assertThat(result).extractingJsonPathStringValue("$.end").isEqualTo("2025-07-20T12:00:00"); + } + + @Test + void shouldReturnBookingResponseDto() throws Exception { + UserDto userDto = new UserDto( + 1L, + "Макс Иванов", + "Max@mail.ru" + ); + + ItemDto itemDto = new ItemDto( + 1L, + "Canon 500d", + "Полупрофессиональная модель фотоаппарата", + true, + 5L + ); + + BookingResponseDto bookingResponseDto = new BookingResponseDto( + 1L, + LocalDateTime.of(2025, 7, 20, 10, 0), + LocalDateTime.of(2025, 7, 20, 12, 0), + itemDto, + userDto, + RentalStatus.APPROVED + ); + + JsonContent resultUserDto = jsonUserDto.write(userDto); + JsonContent resultItemDto = jsonItemDto.write(itemDto); + JsonContent resultBookingResponseDto = jsonBookingResponseDto.write(bookingResponseDto); + + assertThat(resultBookingResponseDto).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(resultBookingResponseDto).extractingJsonPathStringValue("$.start").isEqualTo("2025-07-20T10:00:00"); + assertThat(resultBookingResponseDto).extractingJsonPathStringValue("$.end").isEqualTo("2025-07-20T12:00:00"); + assertThat(resultItemDto).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(resultItemDto).extractingJsonPathStringValue("$.name").isEqualTo("Canon 500d"); + assertThat(resultItemDto).extractingJsonPathStringValue("$.description").isEqualTo("Полупрофессиональная модель фотоаппарата"); + assertThat(resultItemDto).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + assertThat(resultItemDto).extractingJsonPathNumberValue("$.requestId").isEqualTo(5); + assertThat(resultUserDto).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(resultUserDto).extractingJsonPathStringValue("$.name").isEqualTo("Макс Иванов"); + assertThat(resultUserDto).extractingJsonPathStringValue("$.email").isEqualTo("Max@mail.ru"); + assertThat(resultBookingResponseDto).extractingJsonPathStringValue("$.status").isEqualTo("APPROVED"); + } + + @Test + void shouldReturnSimplifiedBookingDto() throws Exception { + SimplifiedBookingDto simplifiedBookingDto = new SimplifiedBookingDto( + 1L, + 1L + ); + + JsonContent resultSimplifiedBookingDto = jsonSimplifiedBookingDto.write(simplifiedBookingDto); + + assertThat(resultSimplifiedBookingDto).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(resultSimplifiedBookingDto).extractingJsonPathNumberValue("$.bookerId").isEqualTo(1); + } + + @Test + void shouldDeserializeBookingRequestDto() throws Exception { + String json = """ + { + "itemId": 1, + "start": "2025-07-20T10:00:00", + "end": "2025-07-20T12:00:00" + } + """; + + BookingRequestDto expected = new BookingRequestDto( + 1L, + LocalDateTime.of(2025, 7, 20, 10, 0), + LocalDateTime.of(2025, 7, 20, 12, 0) + ); + + assertThat(jsonBookingRequestDto.parse(json)).usingRecursiveComparison().isEqualTo(expected); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java new file mode 100644 index 0000000..a8697ae --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java @@ -0,0 +1,111 @@ +package ru.practicum.shareit.booking; + +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.booking.dto.BookingResponseDto; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.service.BookingService; +import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.exception.ValidationException; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Transactional +@ActiveProfiles("test") +@SpringBootTest( + classes = ShareItApp.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class BookingServiceTest { + private final EntityManager em; + private final BookingService bookingService; + + private Long ownerId; + private Long bookerId; + private Long bookingId; + + @BeforeEach + void setUp() { + User owner = new User(); + owner.setName("Владимир Петухов"); + owner.setEmail("Vladimir@mail.ru"); + em.persist(owner); + + User booker = new User(); + booker.setName("Петр Васильев"); + booker.setEmail("Petr@mail.ru"); + em.persist(booker); + + ownerId = owner.getId(); + bookerId = booker.getId(); + + Item item = new Item(); + item.setName("Canon 500d"); + item.setDescription("Зеркальный фотоаппарат"); + item.setAvailable(true); + item.setOwner(owner); + em.persist(item); + + Booking booking = new Booking(); + booking.setStart(LocalDateTime.now().plusHours(1)); + booking.setEnd(LocalDateTime.now().plusDays(1)); + booking.setItem(item); + booking.setBooker(booker); + booking.setStatus(RentalStatus.WAITING); + em.persist(booking); + + em.flush(); + em.clear(); + + bookingId = booking.getId(); + } + + @Test + void shouldApproveBooking() { + BookingResponseDto result = bookingService.updateBooking(ownerId, bookingId, true); + + assertThat(result.getId()).isEqualTo(bookingId); + assertThat(result.getStatus()).isEqualTo(RentalStatus.APPROVED); + } + + @Test + void shouldRejectBooking() { + BookingResponseDto result = bookingService.updateBooking(ownerId, bookingId, false); + + assertThat(result.getStatus()).isEqualTo(RentalStatus.REJECTED); + } + + @Test + void shouldThrowExceptionWhenNotOwner() { + ValidationException exception = assertThrows( + ValidationException.class, + () -> bookingService.updateBooking(bookerId, bookingId, true) + ); + + assertThat(exception.getMessage()).isEqualTo("Обновить аренду может только владелец вещи"); + } + + @Test + void shouldThrowWhenStatusAlreadySet() { + bookingService.updateBooking(ownerId, bookingId, true); + + ValidationException exception = assertThrows( + ValidationException.class, + () -> bookingService.updateBooking(ownerId, bookingId, false) + ); + + assertThat(exception.getMessage()).isEqualTo("Нельзя изменить статус: бронирование уже подтверждено или отклонено"); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java new file mode 100644 index 0000000..8de1fa5 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java @@ -0,0 +1,168 @@ +package ru.practicum.shareit.item; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import org.springframework.test.context.ContextConfiguration; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.booking.dto.SimplifiedBookingDto; +import ru.practicum.shareit.item.comment.dto.CommentResponseDto; +import ru.practicum.shareit.item.dto.ItemBookingDto; +import ru.practicum.shareit.item.dto.ItemDto; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ContextConfiguration(classes = ShareItApp.class) +@JsonTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemAndBookingDtoTest { + private final JacksonTester jsonItemDto; + private final JacksonTester jsonCommentResponseDto; + private final JacksonTester jsonSimplifiedBookingDto; + private final JacksonTester jsonItemBookingDto; + + + @Test + void shouldReturnItemDto() throws Exception { + ItemDto itemDto = new ItemDto( + 1L, + "Canon 500d", + "Полупрофессиональная модель фотоаппарата", + true, + 5L + ); + + JsonContent result = jsonItemDto.write(itemDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Canon 500d"); + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("Полупрофессиональная модель фотоаппарата"); + assertThat(result).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + assertThat(result).extractingJsonPathNumberValue("$.requestId").isEqualTo(5); + } + + @Test + void shouldReturnItemBookingDto() throws Exception { + + CommentResponseDto commentResponseDto = new CommentResponseDto( + 10L, + "Все понравилось. Рекомендую!", + "Александра Иванова", + LocalDateTime.of(2025, 7, 19, 17, 58, 0), + 2L + ); + + SimplifiedBookingDto simplifiedBookingDto = new SimplifiedBookingDto( + 1L, + 1L + ); + + SimplifiedBookingDto simplifiedBookingDto2 = new SimplifiedBookingDto( + 3L, + 2L + ); + + ItemBookingDto itemBookingDto = new ItemBookingDto( + 2L, + "Canon 500d", + "Полупрофессиональная модель фотоаппарата", + true, + simplifiedBookingDto, + simplifiedBookingDto2, + List.of(commentResponseDto) + ); + + JsonContent resultCommentResponseDto = jsonCommentResponseDto.write(commentResponseDto); + JsonContent resultItemDtoSimplifiedBookingDto = jsonSimplifiedBookingDto.write(simplifiedBookingDto); + JsonContent resultItemDtoSimplifiedBookingDto2 = jsonSimplifiedBookingDto.write(simplifiedBookingDto2); + JsonContent resultItemBookingDto = jsonItemBookingDto.write(itemBookingDto); + + assertThat(resultItemBookingDto).extractingJsonPathNumberValue("$.id").isEqualTo(2); + assertThat(resultItemBookingDto).extractingJsonPathStringValue("$.name").isEqualTo("Canon 500d"); + assertThat(resultItemBookingDto).extractingJsonPathStringValue("$.description").isEqualTo("Полупрофессиональная модель фотоаппарата"); + assertThat(resultItemBookingDto).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + assertThat(resultItemDtoSimplifiedBookingDto).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(resultItemDtoSimplifiedBookingDto).extractingJsonPathNumberValue("$.bookerId").isEqualTo(1); + assertThat(resultItemDtoSimplifiedBookingDto2).extractingJsonPathNumberValue("$.id").isEqualTo(3); + assertThat(resultItemDtoSimplifiedBookingDto2).extractingJsonPathNumberValue("$.bookerId").isEqualTo(2); + assertThat(resultCommentResponseDto).extractingJsonPathNumberValue("$.id").isEqualTo(10); + assertThat(resultCommentResponseDto).extractingJsonPathStringValue("$.text").isEqualTo("Все понравилось. Рекомендую!"); + assertThat(resultCommentResponseDto).extractingJsonPathStringValue("$.authorName").isEqualTo("Александра Иванова"); + assertThat(resultCommentResponseDto).extractingJsonPathStringValue("$.created").isEqualTo("2025-07-19T17:58:00"); + assertThat(resultCommentResponseDto).extractingJsonPathNumberValue("$.itemId").isEqualTo(2); + } + + @Test + void shouldDeserializeItemBookingDtoFromJson() throws Exception { + String json = """ + { + "id": 2, + "name": "Canon 500d", + "description": "Полупрофессиональная модель фотоаппарата", + "available": true, + "lastBooking": { + "id": 1, + "bookerId": 1 + }, + "nextBooking": { + "id": 3, + "bookerId": 2 + }, + "comments": [ + { + "id": 10, + "text": "Все понравилось. Рекомендую!", + "authorName": "Александра Иванова", + "created": "2025-07-19T17:58:00", + "itemId": 2 + } + ] + } + """; + + ItemBookingDto result = jsonItemBookingDto.parse(json).getObject(); + + assertThat(result.getId()).isEqualTo(2L); + assertThat(result.getName()).isEqualTo("Canon 500d"); + assertThat(result.getDescription()).isEqualTo("Полупрофессиональная модель фотоаппарата"); + assertThat(result.getAvailable()).isTrue(); + + assertThat(result.getLastBooking().getId()).isEqualTo(1L); + assertThat(result.getLastBooking().getBookerId()).isEqualTo(1L); + assertThat(result.getNextBooking().getId()).isEqualTo(3L); + assertThat(result.getNextBooking().getBookerId()).isEqualTo(2L); + + assertThat(result.getComments()).hasSize(1); + assertThat(result.getComments().get(0).getText()).isEqualTo("Все понравилось. Рекомендую!"); + } + + @Test + void shouldSerializeItemBookingDtoWithNullFields() throws Exception { + ItemBookingDto itemBookingDto = new ItemBookingDto( + 2L, + "Canon 500d", + "Полупрофессиональная модель фотоаппарата", + true, + null, + null, + null + ); + + JsonContent result = jsonItemBookingDto.write(itemBookingDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(2); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Canon 500d"); + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("Полупрофессиональная модель фотоаппарата"); + assertThat(result).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + + assertThat(result).hasJsonPath("$.lastBooking"); + assertThat(result).hasJsonPath("$.nextBooking"); + assertThat(result).hasJsonPath("$.comments"); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java new file mode 100644 index 0000000..43300f9 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java @@ -0,0 +1,246 @@ +package ru.practicum.shareit.item; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import ru.practicum.shareit.error.ErrorHandler; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; +import ru.practicum.shareit.item.comment.dto.CommentResponseDto; +import ru.practicum.shareit.item.controller.ItemController; +import ru.practicum.shareit.item.dto.ItemBookingDto; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.service.ItemService; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; + +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +public class ItemControllerTest { + @Mock + private ItemService itemService; + @InjectMocks + private ItemController itemController; + private final ObjectMapper mapper = new ObjectMapper(); + private MockMvc mvc; + private ItemDto itemDto; + private ItemDto updatedItemDto; + + @BeforeEach + void setUp() { + mapper.findAndRegisterModules(); + + mvc = MockMvcBuilders + .standaloneSetup(itemController) + .setControllerAdvice(new ErrorHandler()) + .build(); + + itemDto = new ItemDto( + 1L, + "Karcher WD 2 Plus", + "Строительный пылесос", + true, + 2L + ); + + updatedItemDto = new ItemDto( + 1L, + "Karcher WD 2 Plus", + "Промышленный пылесос", + true, + 2L + ); + } + + @Test + void mustCreateItem() throws Exception { + when(itemService.createItem(eq(1L), any())) + .thenReturn(itemDto); + + mvc.perform(post("/items") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("Karcher WD 2 Plus"))) + .andExpect(jsonPath("$.description", is("Строительный пылесос"))) + .andExpect(jsonPath("$.available", is(true))) + .andExpect(jsonPath("$.requestId", is(2))); + } + + @Test + void mustUpdateItem() throws Exception { + ItemDto patchDto = new ItemDto( + null, + null, + "Промышленный пылесос", + null, + null + ); + + when(itemService.updateItem(eq(1L), eq(1L), any())) + .thenReturn(updatedItemDto); + + mvc.perform(patch("/items/1") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(patchDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("Karcher WD 2 Plus"))) + .andExpect(jsonPath("$.description", is("Промышленный пылесос"))) + .andExpect(jsonPath("$.available", is(true))) + .andExpect(jsonPath("$.requestId", is(2))); + } + + @Test + void mustReturnItemById() throws Exception { + ItemBookingDto itemBookingDto = new ItemBookingDto( + 1L, + "Karcher WD 2 Plus", + "Строительный пылесос", + true, + null, + null, + List.of() + ); + + when(itemService.findItemById(eq(1L), eq(1L))) + .thenReturn(itemBookingDto); + + mvc.perform(get("/items/1") + .header("X-Sharer-User-Id", 1L) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("Karcher WD 2 Plus"))) + .andExpect(jsonPath("$.description", is("Строительный пылесос"))) + .andExpect(jsonPath("$.available", is(true))) + .andExpect(jsonPath("$.lastBooking").doesNotExist()) + .andExpect(jsonPath("$.nextBooking").doesNotExist()) + .andExpect(jsonPath("$.comments", is(empty()))); + } + + @Test + void mustReturnUserItems() throws Exception { + List items = List.of( + new ItemBookingDto( + 1L, + "Karcher WD 2 Plus", + "Строительный пылесос", + true, + null, + null, + List.of() + ), + new ItemBookingDto( + 2L, + "Bosch GSB 13 RE", + "Ударная дрель", + true, + null, + null, + List.of() + ) + ); + + when(itemService.findUserItems(1L)) + .thenReturn(items); + + mvc.perform(get("/items") + .header("X-Sharer-User-Id", 1L) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.size()", is(2))) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].name", is("Karcher WD 2 Plus"))) + .andExpect(jsonPath("$[1].id", is(2))) + .andExpect(jsonPath("$[1].name", is("Bosch GSB 13 RE"))); + } + + @Test + void mustSearchItemsByText() throws Exception { + List searchResults = List.of( + new ItemDto( + 1L, + "Bosch GSB 13 RE", + "Ударная дрель", + true, + null + ), + new ItemDto( + 2L, + "Makita HP1631K", + "Дрель с ударным механизмом", + true, + null + ) + ); + + when(itemService.searchItem("дрель")).thenReturn(searchResults); + + mvc.perform(get("/items/search") + .param("text", "дрель") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.size()", is(2))) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].name", is("Bosch GSB 13 RE"))) + .andExpect(jsonPath("$[1].id", is(2))) + .andExpect(jsonPath("$[1].name", is("Makita HP1631K"))); + } + + @Test + void mustReturnComment() throws Exception { + Long userId = 1L; + Long itemId = 1L; + + CommentRequestDto requestDto = new CommentRequestDto("Все хорошо!"); + + CommentResponseDto responseDto = new CommentResponseDto( + 1L, + "Все хорошо!", + "Макс Иванов", + LocalDateTime.of(2025, 7, 20, 11, 30), + 1L + ); + + when(itemService.createComment(eq(userId), eq(itemId), any())) + .thenReturn(responseDto); + + mvc.perform(post("/items/{itemId}/comment", itemId) + .header("X-Sharer-User-Id", userId) + .content(mapper.writeValueAsString(requestDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.text", is("Все хорошо!"))) + .andExpect(jsonPath("$.authorName", is("Макс Иванов"))) + .andExpect(jsonPath("$.created", is("2025-07-20T11:30:00"))); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java new file mode 100644 index 0000000..d038b55 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java @@ -0,0 +1,92 @@ +package ru.practicum.shareit.item; + +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.item.comment.model.Comment; +import ru.practicum.shareit.item.dto.ItemBookingDto; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.service.ItemService; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@Transactional +@ActiveProfiles("test") +@SpringBootTest( + classes = ShareItApp.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemServiceTest { + private final EntityManager em; + private final ItemService itemService; + + @Test + void mustReturnUserItems() { + User owner = new User(); + owner.setName("Владимир Петухов"); + owner.setEmail("Vladimir@mail.ru"); + em.persist(owner); + + User booker = new User(); + booker.setName("Петр Васильев"); + booker.setEmail("Petr@mail.ru"); + em.persist(booker); + + Item item = new Item(); + item.setName("Canon 500d"); + item.setDescription("Зеркальный фотоаппарат"); + item.setAvailable(true); + item.setOwner(owner); + em.persist(item); + + Booking pastBooking = new Booking(); + pastBooking.setStart(LocalDateTime.now().minusDays(4)); + pastBooking.setEnd(LocalDateTime.now().minusDays(1)); + pastBooking.setItem(item); + pastBooking.setBooker(booker); + pastBooking.setStatus(RentalStatus.APPROVED); + em.persist(pastBooking); + + Booking futureBooking = new Booking(); + futureBooking.setStart(LocalDateTime.now().plusDays(1)); + futureBooking.setEnd(LocalDateTime.now().plusDays(4)); + futureBooking.setItem(item); + futureBooking.setBooker(booker); + futureBooking.setStatus(RentalStatus.APPROVED); + em.persist(futureBooking); + + Comment comment = new Comment(); + comment.setText("Все понравилось. Рекомендую!"); + comment.setItem(item); + comment.setAuthor(booker); + comment.setCreated(LocalDateTime.now().minusHours(2)); + em.persist(comment); + + em.flush(); + em.clear(); + + List result = itemService.findUserItems(owner.getId()); + + assertThat(result).hasSize(1); + + ItemBookingDto itemBookingDto = result.get(0); + assertThat(itemBookingDto.getName()).isEqualTo("Canon 500d"); + assertThat(itemBookingDto.getDescription()).isEqualTo("Зеркальный фотоаппарат"); + assertThat(itemBookingDto.getAvailable()).isEqualTo(true); + assertThat(itemBookingDto.getLastBooking()).isNotNull(); + assertThat(itemBookingDto.getNextBooking()).isNotNull(); + assertThat(itemBookingDto.getComments()).hasSize(1); + assertThat(itemBookingDto.getComments().get(0).getText()).isEqualTo("Все понравилось. Рекомендую!"); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java new file mode 100644 index 0000000..05bf6b4 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java @@ -0,0 +1,84 @@ +package ru.practicum.shareit.item.comment; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import org.springframework.test.context.ContextConfiguration; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; +import ru.practicum.shareit.item.comment.dto.CommentResponseDto; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ContextConfiguration(classes = ShareItApp.class) +@JsonTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class CommentRequestAndResponseDtoTest { + private final JacksonTester jsonCommentRequestDto; + private final JacksonTester jsonCommentResponseDto; + + @Test + void shouldReturnCommentRequestDto() throws Exception { + CommentRequestDto commentRequestDto = new CommentRequestDto( + "Все понравилось. Рекомендую!" + ); + + JsonContent resultCommentRequestDto = jsonCommentRequestDto.write(commentRequestDto); + + assertThat(resultCommentRequestDto).extractingJsonPathStringValue("$.text").isEqualTo("Все понравилось. Рекомендую!"); + } + + @Test + void shouldReturnCommentResponseDto() throws Exception { + CommentResponseDto commentResponseDto = new CommentResponseDto( + 10L, + "Все понравилось. Рекомендую!", + "Александра Иванова", + LocalDateTime.of(2025, 7, 19, 17, 58, 0), + 2L + ); + + JsonContent resultCommentResponseDto = jsonCommentResponseDto.write(commentResponseDto); + + assertThat(resultCommentResponseDto).extractingJsonPathNumberValue("$.id").isEqualTo(10); + assertThat(resultCommentResponseDto).extractingJsonPathStringValue("$.text").isEqualTo("Все понравилось. Рекомендую!"); + assertThat(resultCommentResponseDto).extractingJsonPathStringValue("$.authorName").isEqualTo("Александра Иванова"); + assertThat(resultCommentResponseDto).extractingJsonPathStringValue("$.created").isEqualTo("2025-07-19T17:58:00"); + assertThat(resultCommentResponseDto).extractingJsonPathNumberValue("$.itemId").isEqualTo(2); + } + + @Test + void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception { + String json = """ + { + "text": "Все понравилось. Рекомендую!" + } + """; + + CommentRequestDto dto = jsonCommentRequestDto.parse(json).getObject(); + + assertThat(dto.getText()).isEqualTo("Все понравилось. Рекомендую!"); + } + + @Test + void shouldReturnSerializeCommentResponseDtoWithNullFields() throws Exception { + CommentResponseDto commentResponseDto = new CommentResponseDto( + 10L, + "Все понравилось. Рекомендую!", + null, + null, + 2L + ); + + JsonContent result = jsonCommentResponseDto.write(commentResponseDto); + + assertThat(result).hasJsonPath("$.authorName"); + assertThat(result).extractingJsonPathStringValue("$.authorName").isNull(); + assertThat(result).extractingJsonPathStringValue("$.created").isNull(); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/ItemRequestTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java similarity index 72% rename from server/src/test/java/ru/practicum/shareit/ItemRequestTest.java rename to server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java index 98ecc65..daf1f2e 100644 --- a/server/src/test/java/ru/practicum/shareit/ItemRequestTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java @@ -1,20 +1,16 @@ -package ru.practicum.shareit; +package ru.practicum.shareit.request; -import jakarta.validation.Validation; -import jakarta.validation.ValidatorFactory; import lombok.RequiredArgsConstructor; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.json.JsonTest; import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.json.JsonContent; import org.springframework.test.context.ContextConfiguration; +import ru.practicum.shareit.ShareItApp; import ru.practicum.shareit.item.dto.ItemDto; -import ru.practicum.shareit.request.dto.ItemRequestDto; -import ru.practicum.shareit.request.dto.ItemResponseDto; - -import jakarta.validation.Validator; +import ru.practicum.shareit.request.dto.ItemReqRequestDto; +import ru.practicum.shareit.request.dto.ItemReqResponseDto; import java.time.LocalDateTime; import java.util.List; @@ -24,35 +20,27 @@ @ContextConfiguration(classes = ShareItApp.class) @JsonTest @RequiredArgsConstructor(onConstructor_ = @Autowired) -public class ItemRequestTest { - private final JacksonTester json; - private final JacksonTester jsonItemResponseDto; +public class ItemReqRequestAndResponseDtoTest { + private final JacksonTester json; + private final JacksonTester jsonItemResponseDto; private final JacksonTester jsonItemDto; - private Validator validator; - - @BeforeEach - void setUp() { - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - validator = factory.getValidator(); - } - @Test - void shouldReturnItemRequestDto() throws Exception { - ItemRequestDto itemRequestDto = new ItemRequestDto( + void shouldReturnItemReqRequestDto() throws Exception { + ItemReqRequestDto itemReqRequestDto = new ItemReqRequestDto( "Ищу строительный пылесос", 1L ); - JsonContent result = json.write(itemRequestDto); + JsonContent result = json.write(itemReqRequestDto); assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("Ищу строительный пылесос"); assertThat(result).extractingJsonPathNumberValue("$.requestorId").isEqualTo(1); } @Test - void shouldReturnItemResponseDto() throws Exception { - ItemResponseDto itemResponseDto = new ItemResponseDto( + void shouldReturnItemReqResponseDto() throws Exception { + ItemReqResponseDto itemReqResponseDto = new ItemReqResponseDto( 2L, "нужен фотоаппарат", 3L, @@ -60,7 +48,7 @@ void shouldReturnItemResponseDto() throws Exception { List.of() ); - JsonContent result = jsonItemResponseDto.write(itemResponseDto); + JsonContent result = jsonItemResponseDto.write(itemReqResponseDto); assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(2); assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("нужен фотоаппарат"); @@ -70,7 +58,7 @@ void shouldReturnItemResponseDto() throws Exception { } @Test - void shouldReturnItemResponseDtoAndItemDto() throws Exception { + void shouldReturnItemReqResponseDtoAndItemDto() throws Exception { ItemDto itemDto = new ItemDto( 5L, "Canon 500d", @@ -79,7 +67,7 @@ void shouldReturnItemResponseDtoAndItemDto() throws Exception { 10L ); - ItemResponseDto itemResponseDto = new ItemResponseDto( + ItemReqResponseDto itemReqResponseDto = new ItemReqResponseDto( 2L, "нужен фотоаппарат", 3L, @@ -87,7 +75,7 @@ void shouldReturnItemResponseDtoAndItemDto() throws Exception { List.of(itemDto) ); - JsonContent result = jsonItemResponseDto.write(itemResponseDto); + JsonContent result = jsonItemResponseDto.write(itemReqResponseDto); JsonContent resultItemDto = jsonItemDto.write(itemDto); assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(2); @@ -102,7 +90,7 @@ void shouldReturnItemResponseDtoAndItemDto() throws Exception { } @Test - void shouldDeserializeItemResponseDtoFromJson() throws Exception { + void shouldDeserializeItemReqResponseDtoFromJson() throws Exception { String json = """ { "id": 2, @@ -113,7 +101,7 @@ void shouldDeserializeItemResponseDtoFromJson() throws Exception { } """; - ItemResponseDto result = jsonItemResponseDto.parse(json).getObject(); + ItemReqResponseDto result = jsonItemResponseDto.parse(json).getObject(); assertThat(result.getId()).isEqualTo(2L); assertThat(result.getDescription()).isEqualTo("нужен фотоаппарат"); diff --git a/server/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java similarity index 89% rename from server/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java rename to server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java index b793a19..b4e2110 100644 --- a/server/src/test/java/ru/practicum/shareit/ItemRequestControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java @@ -1,4 +1,4 @@ -package ru.practicum.shareit; +package ru.practicum.shareit.request; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; @@ -14,8 +14,8 @@ import ru.practicum.shareit.exception.NotFoundException; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.request.controller.ItemRequestController; -import ru.practicum.shareit.request.dto.ItemRequestDto; -import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.request.dto.ItemReqRequestDto; +import ru.practicum.shareit.request.dto.ItemReqResponseDto; import ru.practicum.shareit.request.service.ItemRequestService; import java.nio.charset.StandardCharsets; @@ -35,15 +35,14 @@ public class ItemRequestControllerTest { @Mock private ItemRequestService itemRequestService; - @InjectMocks private ItemRequestController itemRequestController; private final ObjectMapper mapper = new ObjectMapper(); private MockMvc mvc; - private ItemRequestDto itemRequestDto; + private ItemReqRequestDto itemReqRequestDto; private ItemDto itemDto; - private ItemResponseDto itemResponseDto; - private ItemResponseDto itemResponseDto2; + private ItemReqResponseDto itemReqResponseDto; + private ItemReqResponseDto itemReqResponseDto2; @BeforeEach void setUp() { @@ -54,7 +53,7 @@ void setUp() { .setControllerAdvice(new ErrorHandler()) .build(); - itemRequestDto = new ItemRequestDto( + itemReqRequestDto = new ItemReqRequestDto( "Ищу строительный пылесос", 1L ); @@ -67,7 +66,7 @@ void setUp() { 2L ); - itemResponseDto = new ItemResponseDto( + itemReqResponseDto = new ItemReqResponseDto( 1L, "Ищу строительный пылесос", 1L, @@ -75,7 +74,7 @@ void setUp() { List.of() ); - itemResponseDto2 = new ItemResponseDto( + itemReqResponseDto2 = new ItemReqResponseDto( 1L, "Ищу строительный пылесос", 1L, @@ -87,18 +86,18 @@ void setUp() { @Test void mustCreateItemRequest() throws Exception { when(itemRequestService.createItemRequest(eq(1L), any())) - .thenReturn(itemResponseDto); + .thenReturn(itemReqResponseDto); mvc.perform(post("/requests") .header("X-Sharer-User-Id", 1L) - .content(mapper.writeValueAsString(itemRequestDto)) + .content(mapper.writeValueAsString(itemReqRequestDto)) .characterEncoding(StandardCharsets.UTF_8) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(1))) - .andExpect(jsonPath("$.description", is(itemRequestDto.getDescription()))) - .andExpect(jsonPath("$.userId", is(itemRequestDto.getRequestorId().intValue()))) + .andExpect(jsonPath("$.description", is(itemReqRequestDto.getDescription()))) + .andExpect(jsonPath("$.userId", is(itemReqRequestDto.getRequestorId().intValue()))) .andExpect(jsonPath("$.created", is("2025-07-16T19:40:00"))) .andExpect(jsonPath("$.items").isArray()); } @@ -106,7 +105,7 @@ void mustCreateItemRequest() throws Exception { @Test void mustFindListOfYourQueriesWithAnswers() throws Exception { when(itemRequestService.findListOfYourQueriesWithAnswers(1L)) - .thenReturn(List.of(itemResponseDto2)); + .thenReturn(List.of(itemReqResponseDto2)); mvc.perform(get("/requests") .header("X-Sharer-User-Id", 1) @@ -128,7 +127,7 @@ void mustFindListOfYourQueriesWithAnswers() throws Exception { @Test void mustFindListOfRequestsOtherUsers() throws Exception { when(itemRequestService.findListOfRequestsOtherUsers(1L, 0, 10)) - .thenReturn(List.of(itemResponseDto2)); + .thenReturn(List.of(itemReqResponseDto2)); mvc.perform(get("/requests/all") .header("X-Sharer-User-Id", 1) @@ -152,7 +151,7 @@ void mustFindListOfRequestsOtherUsers() throws Exception { @Test void mustFindYourQueryWithAnswers() throws Exception { when(itemRequestService.findYourQueryWithAnswers(1L, 1L)) - .thenReturn(itemResponseDto2); + .thenReturn(itemReqResponseDto2); mvc.perform(get("/requests/1") .header("X-Sharer-User-Id", 1) diff --git a/server/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java similarity index 64% rename from server/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java rename to server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java index fadf0f3..a1e334d 100644 --- a/server/src/test/java/ru/practicum/shareit/ItemRequestServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java @@ -1,4 +1,4 @@ -package ru.practicum.shareit; +package ru.practicum.shareit.request; import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; @@ -8,8 +8,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; -import ru.practicum.shareit.request.dto.ItemRequestDto; -import ru.practicum.shareit.request.dto.ItemResponseDto; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.request.dto.ItemReqRequestDto; +import ru.practicum.shareit.request.dto.ItemReqResponseDto; import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.request.service.ItemRequestService; import ru.practicum.shareit.user.model.User; @@ -17,20 +18,18 @@ import static org.assertj.core.api.Assertions.assertThat; @Transactional -//@ActiveProfiles("dev") +@ActiveProfiles("test") @SpringBootTest( - //properties = "spring.datasource.url=jdbc:postgresql://db:5432/shareit", classes = ShareItApp.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) @RequiredArgsConstructor(onConstructor_ = @Autowired) public class ItemRequestServiceTest { private final EntityManager em; private final ItemRequestService itemRequestService; - private Long userId; @BeforeEach - void setUo() { + void setUp() { User user = new User(); user.setName("Егор"); user.setEmail("egor@mail.ru"); @@ -43,20 +42,20 @@ void setUo() { @Test public void mustCreateItemRequest() { - ItemRequestDto itemRequestDto = new ItemRequestDto("Ищу строительный пылесос", userId); + ItemReqRequestDto itemReqRequestDto = new ItemReqRequestDto("Ищу строительный пылесос", userId); - ItemResponseDto itemResponseDto = itemRequestService.createItemRequest(userId, itemRequestDto); + ItemReqResponseDto itemReqResponseDto = itemRequestService.createItemRequest(userId, itemReqRequestDto); - assertThat(itemResponseDto.getId()).isNotNull(); - assertThat(itemResponseDto.getDescription()).isEqualTo(itemResponseDto.getDescription()); - assertThat(itemResponseDto.getUserId()).isEqualTo(userId); - assertThat(itemResponseDto.getCreated()).isNotNull(); - assertThat(itemResponseDto.getItems()).isEmpty(); + assertThat(itemReqResponseDto.getId()).isNotNull(); + assertThat(itemReqResponseDto.getDescription()).isEqualTo(itemReqResponseDto.getDescription()); + assertThat(itemReqResponseDto.getUserId()).isEqualTo(userId); + assertThat(itemReqResponseDto.getCreated()).isNotNull(); + assertThat(itemReqResponseDto.getItems()).isEmpty(); ItemRequest savedItemRequest = em.createQuery( "SELECT ir FROM ItemRequest ir WHERE ir.id = :id", ItemRequest.class) - .setParameter("id", itemResponseDto.getId()) + .setParameter("id", itemReqResponseDto.getId()) .getSingleResult(); assertThat(savedItemRequest.getDescription()).isEqualTo("Ищу строительный пылесос"); diff --git a/server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java b/server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java new file mode 100644 index 0000000..92d3196 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java @@ -0,0 +1,131 @@ +package ru.practicum.shareit.user; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import ru.practicum.shareit.error.ErrorHandler; +import ru.practicum.shareit.user.controller.UserController; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.service.UserService; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +public class UserControllerTest { + @Mock + private UserService userService; + @InjectMocks + private UserController userController; + private final ObjectMapper mapper = new ObjectMapper(); + private MockMvc mvc; + private UserDto userDto; + + @BeforeEach + void setUp() { + mapper.findAndRegisterModules(); + + mvc = MockMvcBuilders + .standaloneSetup(userController) + .setControllerAdvice(new ErrorHandler()) + .build(); + + userDto = new UserDto( + 1L, + "Макс Иванов", + "Max@mail.ru" + ); + } + + @Test + void mustCreateUser() throws Exception { + when(userService.createUser(any())) + .thenReturn(userDto); + + mvc.perform(post("/users") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(userDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("Макс Иванов"))) + .andExpect(jsonPath("$.email", is("Max@mail.ru"))); + } + + @Test + void mustReturnAllUsers() throws Exception { + List users = List.of( + new UserDto(1L, "Артем Егоров", "Egorov@mail.ru"), + new UserDto(2L, "Аня Иванова", "Anya@mail.ru") + ); + + when(userService.findAllUsers()) + .thenReturn(users); + mvc.perform(get("/users") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.size()").value(2)) + .andExpect(jsonPath("$[0].id", is(1))) + .andExpect(jsonPath("$[0].name", is("Артем Егоров"))) + .andExpect(jsonPath("$[0].email", is("Egorov@mail.ru"))) + .andExpect(jsonPath("$[1].id", is(2))) + .andExpect(jsonPath("$[1].name", is("Аня Иванова"))) + .andExpect(jsonPath("$[1].email", is("Anya@mail.ru"))); + } + + @Test + void mustReturnUserById() throws Exception { + when(userService.findUserById(1L)) + .thenReturn(userDto); + + mvc.perform(get("/users/1") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("Макс Иванов"))) + .andExpect(jsonPath("$.email", is("Max@mail.ru"))); + } + + @Test + void mustUpdateUser() throws Exception { + UserDto updatedUser = new UserDto(1L, "Макс Иванов", "MaxIv@mail.ru"); + when(userService.updateUser(eq(1L), any(UserDto.class))) + .thenReturn(updatedUser); + + mvc.perform(patch("/users/1") + .content(mapper.writeValueAsString(updatedUser)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("Макс Иванов"))) + .andExpect(jsonPath("$.email", is("MaxIv@mail.ru"))); + } + + @Test + void mustDeleteUser() throws Exception { + mvc.perform(delete("/users/1")) + .andExpect(status().isOk()); + + verify(userService).deleteUser(1L); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java new file mode 100644 index 0000000..3e783d8 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java @@ -0,0 +1,53 @@ +package ru.practicum.shareit.user; + +import lombok.RequiredArgsConstructor; +import org.assertj.core.api.AssertionsForClassTypes; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import org.springframework.test.context.ContextConfiguration; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.user.dto.UserDto; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@ContextConfiguration(classes = ShareItApp.class) +@JsonTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class UserDtoTest { + private final JacksonTester jsonUserDto; + + @Test + void shouldReturnUserDto() throws Exception { + UserDto userDto = new UserDto( + 1L, + "Макс Иванов", + "Max@mail.ru" + ); + + JsonContent result = jsonUserDto.write(userDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Макс Иванов"); + assertThat(result).extractingJsonPathStringValue("$.email").isEqualTo("Max@mail.ru"); + } + + @Test + void shouldDeserializeUserDtoFromJson() throws Exception { + String json = """ + { + "id": 1, + "name": "Макс Иванов", + "email": "Max@mail.ru" + } + """; + + UserDto result = jsonUserDto.parse(json).getObject(); + + AssertionsForClassTypes.assertThat(result.getId()).isEqualTo(1L); + AssertionsForClassTypes.assertThat(result.getName()).isEqualTo("Макс Иванов"); + AssertionsForClassTypes.assertThat(result.getEmail()).isEqualTo("Max@mail.ru"); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java b/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java new file mode 100644 index 0000000..e4a2894 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java @@ -0,0 +1,50 @@ +package ru.practicum.shareit.user; + +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.service.UserService; + +import static org.assertj.core.api.Assertions.assertThat; + +@Transactional +@ActiveProfiles("test") +@SpringBootTest( + classes = ShareItApp.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class UserServiceTest { + private final EntityManager em; + private final UserService userService; + private Long userId; + + @BeforeEach + void setUp() { + User user = new User(); + user.setName("Макс Иванов"); + user.setEmail("Max@mail.ru"); + + em.persist(user); + em.flush(); + + userId = user.getId(); + } + + @Test + void mustReturnUserById() { + UserDto itemResponseDto = userService.findUserById(userId); + + assertThat(itemResponseDto.getId()).isNotNull(); + assertThat(itemResponseDto.getId()).isEqualTo(userId); + assertThat(itemResponseDto.getName()).isEqualTo("Макс Иванов"); + assertThat(itemResponseDto.getEmail()).isEqualTo("Max@mail.ru"); + } +} From 5c5173bebac5cdb34914d2cab402f11065a1c77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Sun, 20 Jul 2025 21:45:17 +0300 Subject: [PATCH 07/15] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Checkstyle-=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../booking/BookingRequestAndResponseDtoTest.java | 12 ++++++++---- .../shareit/item/ItemAndBookingDtoTest.java | 12 ++++++++---- .../comment/CommentRequestAndResponseDtoTest.java | 12 ++++++++---- .../request/ItemReqRequestAndResponseDtoTest.java | 12 ++++++++---- .../java/ru/practicum/shareit/user/UserDtoTest.java | 6 ++++-- 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java index 0ccc9cd..54df2ad 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java @@ -30,7 +30,8 @@ public class BookingRequestAndResponseDtoTest { private final JacksonTester jsonSimplifiedBookingDto; @Test - void shouldReturnBookingRequestDto() throws Exception { + void shouldReturnBookingRequestDto() throws Exception + { BookingRequestDto bookingRequestDto = new BookingRequestDto( 1L, LocalDateTime.of(2025, 7, 20, 10, 0), @@ -44,7 +45,8 @@ void shouldReturnBookingRequestDto() throws Exception { } @Test - void shouldReturnBookingResponseDto() throws Exception { + void shouldReturnBookingResponseDto() throws Exception + { UserDto userDto = new UserDto( 1L, "Макс Иванов", @@ -87,7 +89,8 @@ void shouldReturnBookingResponseDto() throws Exception { } @Test - void shouldReturnSimplifiedBookingDto() throws Exception { + void shouldReturnSimplifiedBookingDto() throws Exception + { SimplifiedBookingDto simplifiedBookingDto = new SimplifiedBookingDto( 1L, 1L @@ -100,7 +103,8 @@ void shouldReturnSimplifiedBookingDto() throws Exception { } @Test - void shouldDeserializeBookingRequestDto() throws Exception { + void shouldDeserializeBookingRequestDto() throws Exception + { String json = """ { "itemId": 1, diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java index 8de1fa5..f91f423 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java @@ -29,7 +29,8 @@ public class ItemAndBookingDtoTest { @Test - void shouldReturnItemDto() throws Exception { + void shouldReturnItemDto() throws Exception + { ItemDto itemDto = new ItemDto( 1L, "Canon 500d", @@ -48,7 +49,8 @@ void shouldReturnItemDto() throws Exception { } @Test - void shouldReturnItemBookingDto() throws Exception { + void shouldReturnItemBookingDto() throws Exception + { CommentResponseDto commentResponseDto = new CommentResponseDto( 10L, @@ -99,7 +101,8 @@ void shouldReturnItemBookingDto() throws Exception { } @Test - void shouldDeserializeItemBookingDtoFromJson() throws Exception { + void shouldDeserializeItemBookingDtoFromJson() throws Exception + { String json = """ { "id": 2, @@ -143,7 +146,8 @@ void shouldDeserializeItemBookingDtoFromJson() throws Exception { } @Test - void shouldSerializeItemBookingDtoWithNullFields() throws Exception { + void shouldSerializeItemBookingDtoWithNullFields() throws Exception + { ItemBookingDto itemBookingDto = new ItemBookingDto( 2L, "Canon 500d", diff --git a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java index 05bf6b4..5565b50 100644 --- a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java @@ -23,7 +23,8 @@ public class CommentRequestAndResponseDtoTest { private final JacksonTester jsonCommentResponseDto; @Test - void shouldReturnCommentRequestDto() throws Exception { + void shouldReturnCommentRequestDto() throws Exception + { CommentRequestDto commentRequestDto = new CommentRequestDto( "Все понравилось. Рекомендую!" ); @@ -34,7 +35,8 @@ void shouldReturnCommentRequestDto() throws Exception { } @Test - void shouldReturnCommentResponseDto() throws Exception { + void shouldReturnCommentResponseDto() throws Exception + { CommentResponseDto commentResponseDto = new CommentResponseDto( 10L, "Все понравилось. Рекомендую!", @@ -53,7 +55,8 @@ void shouldReturnCommentResponseDto() throws Exception { } @Test - void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception { + void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception + { String json = """ { "text": "Все понравилось. Рекомендую!" @@ -66,7 +69,8 @@ void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception { } @Test - void shouldReturnSerializeCommentResponseDtoWithNullFields() throws Exception { + void shouldReturnSerializeCommentResponseDtoWithNullFields() throws Exception + { CommentResponseDto commentResponseDto = new CommentResponseDto( 10L, "Все понравилось. Рекомендую!", diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java index daf1f2e..c4cd8a1 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java @@ -26,7 +26,8 @@ public class ItemReqRequestAndResponseDtoTest { private final JacksonTester jsonItemDto; @Test - void shouldReturnItemReqRequestDto() throws Exception { + void shouldReturnItemReqRequestDto() throws Exception + { ItemReqRequestDto itemReqRequestDto = new ItemReqRequestDto( "Ищу строительный пылесос", 1L @@ -39,7 +40,8 @@ void shouldReturnItemReqRequestDto() throws Exception { } @Test - void shouldReturnItemReqResponseDto() throws Exception { + void shouldReturnItemReqResponseDto() throws Exception + { ItemReqResponseDto itemReqResponseDto = new ItemReqResponseDto( 2L, "нужен фотоаппарат", @@ -58,7 +60,8 @@ void shouldReturnItemReqResponseDto() throws Exception { } @Test - void shouldReturnItemReqResponseDtoAndItemDto() throws Exception { + void shouldReturnItemReqResponseDtoAndItemDto() throws Exception + { ItemDto itemDto = new ItemDto( 5L, "Canon 500d", @@ -90,7 +93,8 @@ void shouldReturnItemReqResponseDtoAndItemDto() throws Exception { } @Test - void shouldDeserializeItemReqResponseDtoFromJson() throws Exception { + void shouldDeserializeItemReqResponseDtoFromJson() throws Exception + { String json = """ { "id": 2, diff --git a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java index 3e783d8..7153805 100644 --- a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java @@ -20,7 +20,8 @@ public class UserDtoTest { private final JacksonTester jsonUserDto; @Test - void shouldReturnUserDto() throws Exception { + void shouldReturnUserDto() throws Exception + { UserDto userDto = new UserDto( 1L, "Макс Иванов", @@ -35,7 +36,8 @@ void shouldReturnUserDto() throws Exception { } @Test - void shouldDeserializeUserDtoFromJson() throws Exception { + void shouldDeserializeUserDtoFromJson() throws Exception + { String json = """ { "id": 1, From c8410b9025de83214661e7a03e0b3aa1155ab6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Sun, 20 Jul 2025 21:55:25 +0300 Subject: [PATCH 08/15] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Checkstyle-=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D1=832?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../booking/BookingRequestAndResponseDtoTest.java | 12 ++++-------- .../shareit/item/ItemAndBookingDtoTest.java | 12 ++++-------- .../comment/CommentRequestAndResponseDtoTest.java | 12 ++++-------- .../request/ItemReqRequestAndResponseDtoTest.java | 12 ++++-------- .../java/ru/practicum/shareit/user/UserDtoTest.java | 6 ++---- 5 files changed, 18 insertions(+), 36 deletions(-) diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java index 54df2ad..0ccc9cd 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java @@ -30,8 +30,7 @@ public class BookingRequestAndResponseDtoTest { private final JacksonTester jsonSimplifiedBookingDto; @Test - void shouldReturnBookingRequestDto() throws Exception - { + void shouldReturnBookingRequestDto() throws Exception { BookingRequestDto bookingRequestDto = new BookingRequestDto( 1L, LocalDateTime.of(2025, 7, 20, 10, 0), @@ -45,8 +44,7 @@ void shouldReturnBookingRequestDto() throws Exception } @Test - void shouldReturnBookingResponseDto() throws Exception - { + void shouldReturnBookingResponseDto() throws Exception { UserDto userDto = new UserDto( 1L, "Макс Иванов", @@ -89,8 +87,7 @@ void shouldReturnBookingResponseDto() throws Exception } @Test - void shouldReturnSimplifiedBookingDto() throws Exception - { + void shouldReturnSimplifiedBookingDto() throws Exception { SimplifiedBookingDto simplifiedBookingDto = new SimplifiedBookingDto( 1L, 1L @@ -103,8 +100,7 @@ void shouldReturnSimplifiedBookingDto() throws Exception } @Test - void shouldDeserializeBookingRequestDto() throws Exception - { + void shouldDeserializeBookingRequestDto() throws Exception { String json = """ { "itemId": 1, diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java index f91f423..8de1fa5 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java @@ -29,8 +29,7 @@ public class ItemAndBookingDtoTest { @Test - void shouldReturnItemDto() throws Exception - { + void shouldReturnItemDto() throws Exception { ItemDto itemDto = new ItemDto( 1L, "Canon 500d", @@ -49,8 +48,7 @@ void shouldReturnItemDto() throws Exception } @Test - void shouldReturnItemBookingDto() throws Exception - { + void shouldReturnItemBookingDto() throws Exception { CommentResponseDto commentResponseDto = new CommentResponseDto( 10L, @@ -101,8 +99,7 @@ void shouldReturnItemBookingDto() throws Exception } @Test - void shouldDeserializeItemBookingDtoFromJson() throws Exception - { + void shouldDeserializeItemBookingDtoFromJson() throws Exception { String json = """ { "id": 2, @@ -146,8 +143,7 @@ void shouldDeserializeItemBookingDtoFromJson() throws Exception } @Test - void shouldSerializeItemBookingDtoWithNullFields() throws Exception - { + void shouldSerializeItemBookingDtoWithNullFields() throws Exception { ItemBookingDto itemBookingDto = new ItemBookingDto( 2L, "Canon 500d", diff --git a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java index 5565b50..05bf6b4 100644 --- a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java @@ -23,8 +23,7 @@ public class CommentRequestAndResponseDtoTest { private final JacksonTester jsonCommentResponseDto; @Test - void shouldReturnCommentRequestDto() throws Exception - { + void shouldReturnCommentRequestDto() throws Exception { CommentRequestDto commentRequestDto = new CommentRequestDto( "Все понравилось. Рекомендую!" ); @@ -35,8 +34,7 @@ void shouldReturnCommentRequestDto() throws Exception } @Test - void shouldReturnCommentResponseDto() throws Exception - { + void shouldReturnCommentResponseDto() throws Exception { CommentResponseDto commentResponseDto = new CommentResponseDto( 10L, "Все понравилось. Рекомендую!", @@ -55,8 +53,7 @@ void shouldReturnCommentResponseDto() throws Exception } @Test - void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception - { + void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception { String json = """ { "text": "Все понравилось. Рекомендую!" @@ -69,8 +66,7 @@ void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception } @Test - void shouldReturnSerializeCommentResponseDtoWithNullFields() throws Exception - { + void shouldReturnSerializeCommentResponseDtoWithNullFields() throws Exception { CommentResponseDto commentResponseDto = new CommentResponseDto( 10L, "Все понравилось. Рекомендую!", diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java index c4cd8a1..daf1f2e 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java @@ -26,8 +26,7 @@ public class ItemReqRequestAndResponseDtoTest { private final JacksonTester jsonItemDto; @Test - void shouldReturnItemReqRequestDto() throws Exception - { + void shouldReturnItemReqRequestDto() throws Exception { ItemReqRequestDto itemReqRequestDto = new ItemReqRequestDto( "Ищу строительный пылесос", 1L @@ -40,8 +39,7 @@ void shouldReturnItemReqRequestDto() throws Exception } @Test - void shouldReturnItemReqResponseDto() throws Exception - { + void shouldReturnItemReqResponseDto() throws Exception { ItemReqResponseDto itemReqResponseDto = new ItemReqResponseDto( 2L, "нужен фотоаппарат", @@ -60,8 +58,7 @@ void shouldReturnItemReqResponseDto() throws Exception } @Test - void shouldReturnItemReqResponseDtoAndItemDto() throws Exception - { + void shouldReturnItemReqResponseDtoAndItemDto() throws Exception { ItemDto itemDto = new ItemDto( 5L, "Canon 500d", @@ -93,8 +90,7 @@ void shouldReturnItemReqResponseDtoAndItemDto() throws Exception } @Test - void shouldDeserializeItemReqResponseDtoFromJson() throws Exception - { + void shouldDeserializeItemReqResponseDtoFromJson() throws Exception { String json = """ { "id": 2, diff --git a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java index 7153805..3e783d8 100644 --- a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java @@ -20,8 +20,7 @@ public class UserDtoTest { private final JacksonTester jsonUserDto; @Test - void shouldReturnUserDto() throws Exception - { + void shouldReturnUserDto() throws Exception { UserDto userDto = new UserDto( 1L, "Макс Иванов", @@ -36,8 +35,7 @@ void shouldReturnUserDto() throws Exception } @Test - void shouldDeserializeUserDtoFromJson() throws Exception - { + void shouldDeserializeUserDtoFromJson() throws Exception { String json = """ { "id": 1, From 58a5e21dfec98fc44aab37717513c5749a65c76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Sun, 20 Jul 2025 22:20:33 +0300 Subject: [PATCH 09/15] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Checkstyle-=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D1=833?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookingRequestAndResponseDtoTest.java | 8 +----- .../shareit/item/ItemAndBookingDtoTest.java | 26 +------------------ .../CommentRequestAndResponseDtoTest.java | 6 +---- .../ItemReqRequestAndResponseDtoTest.java | 10 +------ .../practicum/shareit/user/UserDtoTest.java | 8 +----- 5 files changed, 5 insertions(+), 53 deletions(-) diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java index 0ccc9cd..0804bd5 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingRequestAndResponseDtoTest.java @@ -101,13 +101,7 @@ void shouldReturnSimplifiedBookingDto() throws Exception { @Test void shouldDeserializeBookingRequestDto() throws Exception { - String json = """ - { - "itemId": 1, - "start": "2025-07-20T10:00:00", - "end": "2025-07-20T12:00:00" - } - """; + String json = "{ \"itemId\": 1, \"start\": \"2025-07-20T10:00:00\", \"end\": \"2025-07-20T12:00:00\" }"; BookingRequestDto expected = new BookingRequestDto( 1L, diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java index 8de1fa5..5ade920 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemAndBookingDtoTest.java @@ -100,31 +100,7 @@ void shouldReturnItemBookingDto() throws Exception { @Test void shouldDeserializeItemBookingDtoFromJson() throws Exception { - String json = """ - { - "id": 2, - "name": "Canon 500d", - "description": "Полупрофессиональная модель фотоаппарата", - "available": true, - "lastBooking": { - "id": 1, - "bookerId": 1 - }, - "nextBooking": { - "id": 3, - "bookerId": 2 - }, - "comments": [ - { - "id": 10, - "text": "Все понравилось. Рекомендую!", - "authorName": "Александра Иванова", - "created": "2025-07-19T17:58:00", - "itemId": 2 - } - ] - } - """; + String json = "{ \"id\": 2, \"name\": \"Canon 500d\", \"description\": \"Полупрофессиональная модель фотоаппарата\", \"available\": true, \"lastBooking\": { \"id\": 1, \"bookerId\": 1 }, \"nextBooking\": { \"id\": 3, \"bookerId\": 2 }, \"comments\": [ { \"id\": 10, \"text\": \"Все понравилось. Рекомендую!\", \"authorName\": \"Александра Иванова\", \"created\": \"2025-07-19T17:58:00\", \"itemId\": 2 } ] }"; ItemBookingDto result = jsonItemBookingDto.parse(json).getObject(); diff --git a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java index 05bf6b4..e7e03ce 100644 --- a/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/comment/CommentRequestAndResponseDtoTest.java @@ -54,11 +54,7 @@ void shouldReturnCommentResponseDto() throws Exception { @Test void shouldReturnDeserializeCommentRequestDtoFromJson() throws Exception { - String json = """ - { - "text": "Все понравилось. Рекомендую!" - } - """; + String json = "{ \"text\": \"Все понравилось. Рекомендую!\" }"; CommentRequestDto dto = jsonCommentRequestDto.parse(json).getObject(); diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java index daf1f2e..5f58d5b 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemReqRequestAndResponseDtoTest.java @@ -91,15 +91,7 @@ void shouldReturnItemReqResponseDtoAndItemDto() throws Exception { @Test void shouldDeserializeItemReqResponseDtoFromJson() throws Exception { - String json = """ - { - "id": 2, - "description": "нужен фотоаппарат", - "userId": 3, - "created": "2025-07-16T18:30:00", - "items": [] - } - """; + String json = "{ \"id\": 2, \"description\": \"нужен фотоаппарат\", \"userId\": 3, \"created\": \"2025-07-16T18:30:00\", \"items\": [] }"; ItemReqResponseDto result = jsonItemResponseDto.parse(json).getObject(); diff --git a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java index 3e783d8..278d3eb 100644 --- a/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/UserDtoTest.java @@ -36,13 +36,7 @@ void shouldReturnUserDto() throws Exception { @Test void shouldDeserializeUserDtoFromJson() throws Exception { - String json = """ - { - "id": 1, - "name": "Макс Иванов", - "email": "Max@mail.ru" - } - """; + String json = "{ \"id\": 1, \"name\": \"Макс Иванов\", \"email\": \"Max@mail.ru\" }"; UserDto result = jsonUserDto.parse(json).getObject(); From 43b7d85448eeb4e395fe7ab86c954a2a601c005e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Mon, 21 Jul 2025 01:38:46 +0300 Subject: [PATCH 10/15] =?UTF-8?q?=D0=A3=D0=B2=D0=B5=D0=BB=D0=B8=D1=87?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/practicum/shareit/ShareItTests.java | 2 - .../shareit/booking/BookingMapperTest.java | 100 +++++++++++++++++ .../shareit/item/ItemMapperTest.java | 102 ++++++++++++++++++ .../item/comment/CommentMapperTest.java | 44 ++++++++ .../shareit/user/UserMapperTest.java | 20 ++++ 5 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/comment/CommentMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java diff --git a/server/src/test/java/ru/practicum/shareit/ShareItTests.java b/server/src/test/java/ru/practicum/shareit/ShareItTests.java index 6dd7261..4d79052 100644 --- a/server/src/test/java/ru/practicum/shareit/ShareItTests.java +++ b/server/src/test/java/ru/practicum/shareit/ShareItTests.java @@ -1,4 +1,3 @@ -/* package ru.practicum.shareit; import org.junit.jupiter.api.Test; @@ -12,4 +11,3 @@ void contextLoads() { } } -*/ diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java new file mode 100644 index 0000000..6e34bc7 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java @@ -0,0 +1,100 @@ +package ru.practicum.shareit.booking; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.booking.dto.BookingRequestDto; +import ru.practicum.shareit.booking.dto.SimplifiedBookingDto; +import ru.practicum.shareit.booking.dto.mapper.BookingMapper; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class BookingMapperTest { + @Test + void shouldMapToBooking() { + LocalDateTime start = LocalDateTime.of(2025, 7, 21, 10, 0); + LocalDateTime end = LocalDateTime.of(2025, 7, 22, 10, 0); + + BookingRequestDto requestDto = new BookingRequestDto( + 1L, + start, + end + ); + + User booker = new User( + 1L, + "Макc Иванов", + "Max@mail.ru" + ); + + User owner = new User( + 2L, + "Петр Петров", + "Petr@mail.ru" + ); + + Item item = new Item( + 3L, + "Canon 500d", + "Зеркальный фотоаппарат", + true, + owner, + null + ); + + RentalStatus status = RentalStatus.WAITING; + + Booking booking = BookingMapper.toBooking(requestDto, item, booker, status); + + assertThat(booking.getId()).isNull(); + assertThat(booking.getStart()).isEqualTo(start); + assertThat(booking.getEnd()).isEqualTo(end); + assertThat(booking.getItem()).isEqualTo(item); + assertThat(booking.getBooker()).isEqualTo(booker); + assertThat(booking.getStatus()).isEqualTo(RentalStatus.WAITING); + } + + @Test + void mustMapToSimplifiedBookingDto() { + User owner = new User( + 1L, + "Макс Иванов", + "Max@mail.ru" + ); + + Item item = new Item( + 3L, + "Canon 500d", + "Зеркальный фотоаппарат", + true, + owner, + null + ); + Booking booking = new Booking( + 10L, + LocalDateTime.now(), + LocalDateTime.now().plusDays(1), + item, + owner, + RentalStatus.APPROVED + ); + + SimplifiedBookingDto dto = BookingMapper.toSimplifiedBookingDto(booking); + + assertThat(dto.getId()).isEqualTo(10L); + assertThat(dto.getBookerId()).isEqualTo(1L); + } + + @Test + void mustReturnNullSimplifiedBookingDto() { + SimplifiedBookingDto simplifiedBookingDto = BookingMapper.toSimplifiedBookingDto(null); + + assertThat(simplifiedBookingDto).isNull(); + } +} + + diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java new file mode 100644 index 0000000..2e944ef --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java @@ -0,0 +1,102 @@ +package ru.practicum.shareit.item; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class ItemMapperTest { + @Test + void mustMapItemToItemDtoWithRequest() { + ItemRequest itemRequest = new ItemRequest(); + itemRequest.setId(42L); + + Item item = new Item( + 1L, + "Canon 500d", + "Зеркальный фотоаппарат", + true, new User(), itemRequest + ); + + ItemDto itemDto = ItemMapper.toItemDto(item); + + assertThat(itemDto.getId()).isEqualTo(1L); + assertThat(itemDto.getName()).isEqualTo("Canon 500d"); + assertThat(itemDto.getDescription()).isEqualTo("Зеркальный фотоаппарат"); + assertThat(itemDto.getAvailable()).isTrue(); + assertThat(itemDto.getRequestId()).isEqualTo(42L); + } + + @Test + void mustMapItemToItemDtoWithNullRequest() { + Item item = new Item( + 1L, + "Canon 500d", + "Зеркальный фотоаппарат", + false, + new User(), + null + ); + + ItemDto itemDto = ItemMapper.toItemDto(item); + + assertThat(itemDto.getRequestId()).isNull(); + } + + @Test + void mustMapItemDtoToItemWithoutRequest() { + User user = new User( + 1L, + "Макс Иванов", + "Max@mail.com" + ); + + ItemDto itemDto = new ItemDto( + null, + "Canon 500d", + "Зеркальный фотоаппарат", + true, + null + ); + + Item item = ItemMapper.toItem(user, itemDto); + + assertThat(item.getId()).isNull(); + assertThat(item.getName()).isEqualTo("Canon 500d"); + assertThat(item.getDescription()).isEqualTo("Зеркальный фотоаппарат"); + assertThat(item.getAvailable()).isTrue(); + assertThat(item.getOwner()).isEqualTo(user); + assertThat(item.getItemRequest()).isNull(); + } + + @Test + void mustMapItemDtoToItemWithRequest() { + User user = new User( + 20L, + "Анна Иванова", + "Anna@mail.com" + ); + ItemRequest itemRequest = new ItemRequest(); + itemRequest.setId(100L); + + ItemDto itemDto = new ItemDto( + null, + "Canon 500d", + "Зеркальный фотоаппарат", + false, + 100L + ); + + Item item = ItemMapper.toItem(user, itemDto, itemRequest); + + assertThat(item.getName()).isEqualTo("Canon 500d"); + assertThat(item.getDescription()).isEqualTo("Зеркальный фотоаппарат"); + assertThat(item.getAvailable()).isFalse(); + assertThat(item.getOwner()).isEqualTo(user); + assertThat(item.getItemRequest()).isEqualTo(itemRequest); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/item/comment/CommentMapperTest.java b/server/src/test/java/ru/practicum/shareit/item/comment/CommentMapperTest.java new file mode 100644 index 0000000..88fe270 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/comment/CommentMapperTest.java @@ -0,0 +1,44 @@ +package ru.practicum.shareit.item.comment; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; +import ru.practicum.shareit.item.comment.dto.mapper.CommentMapper; +import ru.practicum.shareit.item.comment.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class CommentMapperTest { + @Test + void mustMapCommentRequestDtoToComment() { + + CommentRequestDto requestDto = new CommentRequestDto("Отличная вещь!"); + User author = new User( + 1L, + "Макс Иванов", + "Max@mail.ru" + ); + + Item item = new Item( + 2L, + "Canon 500d", + "Зеркальный фотоаппарат", + true, + author, + null + ); + + LocalDateTime before = LocalDateTime.now().minusSeconds(1); + Comment comment = CommentMapper.toComment(requestDto, author, item); + LocalDateTime after = LocalDateTime.now().plusSeconds(1); + + assertThat(comment.getId()).isNull(); + assertThat(comment.getText()).isEqualTo("Отличная вещь!"); + assertThat(comment.getAuthor()).isEqualTo(author); + assertThat(comment.getItem()).isEqualTo(item); + assertThat(comment.getCreated()).isAfterOrEqualTo(before).isBeforeOrEqualTo(after); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java b/server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java new file mode 100644 index 0000000..8058896 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.user; + +import org.assertj.core.api.AssertionsForClassTypes; +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.dto.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +public class UserMapperTest { + @Test + void shouldMapUserDtoToUser() { + UserDto dto = new UserDto(1L, "Макс Иванов", "max@mail.ru"); + + User result = UserMapper.toUser(dto); + + AssertionsForClassTypes.assertThat(result.getId()).isEqualTo(1L); + AssertionsForClassTypes.assertThat(result.getName()).isEqualTo("Макс Иванов"); + AssertionsForClassTypes.assertThat(result.getEmail()).isEqualTo("max@mail.ru"); + } +} From 2fe0e1e4d940fab291746f2a72fc183bddfa1c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Mon, 21 Jul 2025 12:38:57 +0300 Subject: [PATCH 11/15] =?UTF-8?q?=D0=A3=D0=B2=D0=B5=D0=BB=D0=B8=D1=87?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B22?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/practicum/shareit/ShareItTests.java | 6 +- .../shareit/booking/BookingServiceTest.java | 114 +++++++++ .../shareit/item/ItemServiceTest.java | 238 ++++++++++++++++++ .../request/ItemRequestServiceTest.java | 85 +++++++ .../shareit/user/UserServiceTest.java | 85 +++++++ 5 files changed, 525 insertions(+), 3 deletions(-) diff --git a/server/src/test/java/ru/practicum/shareit/ShareItTests.java b/server/src/test/java/ru/practicum/shareit/ShareItTests.java index 4d79052..8502acd 100644 --- a/server/src/test/java/ru/practicum/shareit/ShareItTests.java +++ b/server/src/test/java/ru/practicum/shareit/ShareItTests.java @@ -6,8 +6,8 @@ @SpringBootTest class ShareItTests { - @Test - void contextLoads() { - } + @Test + void contextLoads() { + } } diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java index a8697ae..ab3ff17 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceTest.java @@ -9,15 +9,18 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.booking.dto.BookingRequestDto; import ru.practicum.shareit.booking.dto.BookingResponseDto; import ru.practicum.shareit.booking.model.Booking; import ru.practicum.shareit.booking.service.BookingService; import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.exception.NotFoundException; import ru.practicum.shareit.exception.ValidationException; import ru.practicum.shareit.item.model.Item; import ru.practicum.shareit.user.model.User; import java.time.LocalDateTime; +import java.util.List; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -35,6 +38,7 @@ public class BookingServiceTest { private Long ownerId; private Long bookerId; private Long bookingId; + private Long itemId; @BeforeEach void setUp() { @@ -69,7 +73,10 @@ void setUp() { em.flush(); em.clear(); + ownerId = owner.getId(); + bookerId = booker.getId(); bookingId = booking.getId(); + itemId = item.getId(); } @Test @@ -108,4 +115,111 @@ void shouldThrowWhenStatusAlreadySet() { assertThat(exception.getMessage()).isEqualTo("Нельзя изменить статус: бронирование уже подтверждено или отклонено"); } + + @Test + void shouldCreateBooking() { + BookingRequestDto dto = new BookingRequestDto( + itemId, + LocalDateTime.now().plusHours(2), + LocalDateTime.now().plusDays(2) + ); + + BookingResponseDto result = bookingService.createBooking(bookerId, dto); + assertThat(result.getItem().getId()).isEqualTo(itemId); + assertThat(result.getStatus()).isEqualTo(RentalStatus.WAITING); + } + + @Test + void shouldThrowExceptionWhenBookerIsOwner() { + BookingRequestDto dto = new BookingRequestDto( + itemId, + LocalDateTime.now().plusHours(2), + LocalDateTime.now().plusDays(2) + ); + + ValidationException ve = assertThrows(ValidationException.class, + () -> bookingService.createBooking(ownerId, dto)); + assertThat(ve.getMessage()).isEqualTo("Владелец не может бронировать свою вещь"); + } + + @Test + void shouldThrowExceptionWhenItemUnavailable() { + Item item = em.find(Item.class, itemId); + item.setAvailable(false); + em.flush(); + + BookingRequestDto dto = new BookingRequestDto( + itemId, + LocalDateTime.now().plusHours(1), + LocalDateTime.now().plusDays(1) + ); + + ValidationException validationException = assertThrows(ValidationException.class, + () -> bookingService.createBooking(bookerId, dto)); + assertThat(validationException.getMessage()).isEqualTo("Данная вещь недоступна для бронирования"); + } + + @Test + void shouldThrowExceptionWhenStartAfterEnd() { + BookingRequestDto dto = new BookingRequestDto( + itemId, + LocalDateTime.now().plusDays(1), + LocalDateTime.now().plusHours(1) + ); + + ValidationException validationException = assertThrows(ValidationException.class, + () -> bookingService.createBooking(bookerId, dto)); + assertThat(validationException.getMessage()).isEqualTo("Период указан неверно"); + } + + @Test + void shouldFindBookingByBooker() { + BookingResponseDto result = bookingService.findBookingById(bookerId, bookingId); + assertThat(result.getId()).isEqualTo(bookingId); + } + + @Test + void shouldFindBookingByOwner() { + BookingResponseDto result = bookingService.findBookingById(ownerId, bookingId); + assertThat(result.getId()).isEqualTo(bookingId); + } + + @Test + void shouldThrowExceptionWhenOtherUserRequestsBooking() { + User otherUser = new User(); + otherUser.setName("Макс Иванов"); + otherUser.setEmail("Max@mail.com"); + em.persist(otherUser); + em.flush(); + + ValidationException validationException = assertThrows(ValidationException.class, + () -> bookingService.findBookingById(otherUser.getId(), bookingId)); + assertThat(validationException.getMessage()).isEqualTo("Данный пользователь не может получить информацию по бронированию"); + } + + @Test + void shouldReturnUserBookingsAll() { + List bookings = bookingService.findUserBookings(bookerId, "ALL"); + assertThat(bookings.size()).isEqualTo(1); + } + + @Test + void shouldReturnOwnerBookingsAll() { + List bookings = bookingService.findOwnerReservedItems(ownerId, "ALL"); + assertThat(bookings.size()).isEqualTo(1); + } + + @Test + void shouldThrowExceptionIfUserNotFoundInFindUserBookings() { + NotFoundException notFoundException = assertThrows(NotFoundException.class, + () -> bookingService.findUserBookings(999L, "ALL")); + assertThat(notFoundException.getMessage()).contains("Пользователь с данным id: " + 999L + " не найден"); + } + + @Test + void shouldThrowExceptionIfUserNotFoundInFindOwnerReservedItems() { + NotFoundException notFoundException = assertThrows(NotFoundException.class, + () -> bookingService.findOwnerReservedItems(999L, "ALL")); + assertThat(notFoundException.getMessage()).contains("Пользователь с данным id: " + 999L + " не найден"); + } } diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java index d038b55..e56c52d 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemServiceTest.java @@ -10,15 +10,20 @@ import ru.practicum.shareit.ShareItApp; import ru.practicum.shareit.booking.model.Booking; import ru.practicum.shareit.booking.status.RentalStatus; +import ru.practicum.shareit.item.comment.dto.CommentRequestDto; +import ru.practicum.shareit.item.comment.dto.CommentResponseDto; import ru.practicum.shareit.item.comment.model.Comment; import ru.practicum.shareit.item.dto.ItemBookingDto; +import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.model.Item; import ru.practicum.shareit.item.service.ItemService; +import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.user.model.User; import java.time.LocalDateTime; import java.util.List; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @Transactional @@ -89,4 +94,237 @@ void mustReturnUserItems() { assertThat(itemBookingDto.getComments()).hasSize(1); assertThat(itemBookingDto.getComments().get(0).getText()).isEqualTo("Все понравилось. Рекомендую!"); } + + @Test + void mustCreateItemWithRequestId() { + User user = new User(); + user.setName("Андрей Алексеев"); + user.setEmail("Andrey@mail.ru"); + em.persist(user); + + ItemRequest itemRequest = new ItemRequest(); + itemRequest.setDescription("Нужен строительный пылесос"); + itemRequest.setRequestor(user); + itemRequest.setCreated(LocalDateTime.now()); + em.persist(itemRequest); + em.flush(); + + ItemDto itemDto = new ItemDto(null, "Karcher WD 2 Plus", "Строительный пылесос", true, itemRequest.getId()); + + ItemDto result = itemService.createItem(user.getId(), itemDto); + + assertThat(result.getId()).isNotNull(); + assertThat(result.getRequestId()).isEqualTo(itemRequest.getId()); + } + + @Test + void mustCreateItemWithoutRequestId() { + User user = new User(); + user.setName("Макс Иванов"); + user.setEmail("Max@mail.ru"); + em.persist(user); + em.flush(); + + ItemDto itemDto = new ItemDto(null, "Dykemann", "Удобное кресло", true, null); + + ItemDto result = itemService.createItem(user.getId(), itemDto); + + assertThat(result.getId()).isNotNull(); + assertThat(result.getRequestId()).isNull(); + } + + @Test + void mustUpdateItemFields() { + User user = new User(); + user.setName("Макс Иванов"); + user.setEmail("Max@mail.ru"); + em.persist(user); + + Item item = new Item(); + item.setName("Стол для учебы"); + item.setDescription("Старый"); + item.setAvailable(true); + item.setOwner(user); + em.persist(item); + em.flush(); + + ItemDto updateItemDto = new ItemDto(null, "Новый стол для учебы", "Современный", false, null); + + ItemDto result = itemService.updateItem(item.getId(), user.getId(), updateItemDto); + + assertThat(result.getName()).isEqualTo("Новый стол для учебы"); + assertThat(result.getDescription()).isEqualTo("Современный"); + assertThat(result.getAvailable()).isFalse(); + } + + @Test + void mustReturnItemWithBookingsForOwner() { + User owner = new User(); + owner.setName("Макс Иванов"); + owner.setEmail("Max@mail.ru"); + em.persist(owner); + + User booker = new User(); + booker.setName("Андрей Алексеев"); + booker.setEmail("Andrey@mail.ru"); + em.persist(booker); + + Item item = new Item(); + item.setName("Yamaha PACIFICA 012 BL"); + item.setDescription("Электрогитара"); + item.setAvailable(true); + item.setOwner(owner); + em.persist(item); + + Booking pastBooking = new Booking(); + pastBooking.setItem(item); + pastBooking.setBooker(booker); + pastBooking.setStart(LocalDateTime.now().minusDays(5)); + pastBooking.setEnd(LocalDateTime.now().minusDays(2)); + pastBooking.setStatus(RentalStatus.APPROVED); + em.persist(pastBooking); + + Booking futureBooking = new Booking(); + futureBooking.setItem(item); + futureBooking.setBooker(booker); + futureBooking.setStart(LocalDateTime.now().plusDays(1)); + futureBooking.setEnd(LocalDateTime.now().plusDays(3)); + futureBooking.setStatus(RentalStatus.APPROVED); + em.persist(futureBooking); + + Comment comment = new Comment(); + comment.setText("Отличный инструмент!"); + comment.setAuthor(booker); + comment.setItem(item); + comment.setCreated(LocalDateTime.now().minusHours(1)); + em.persist(comment); + + em.flush(); + em.clear(); + + ItemBookingDto result = itemService.findItemById(owner.getId(), item.getId()); + + assertThat(result.getLastBooking()).isNotNull(); + assertThat(result.getNextBooking()).isNotNull(); + assertThat(result.getComments()).hasSize(1); + } + + @Test + void mustReturnItemWithoutBookingsForOtherUser() { + User owner = new User(); + owner.setName("Макс Иванов"); + owner.setEmail("Max@mail.ru"); + em.persist(owner); + + User booker = new User(); + booker.setName("Андрей Алексеев"); + booker.setEmail("Andrey@mail.ru"); + em.persist(booker); + + Item item = new Item(); + item.setName("Судьба человека"); + item.setDescription("Классическое произведение"); + item.setAvailable(true); + item.setOwner(owner); + em.persist(item); + + em.flush(); + + ItemBookingDto result = itemService.findItemById(booker.getId(), item.getId()); + + assertThat(result.getLastBooking()).isNull(); + assertThat(result.getNextBooking()).isNull(); + } + + @Test + void mustSearchOnlyAvailableItems() { + User user = new User(); + user.setName("Макс Иванов"); + user.setEmail("Max@mail.ru"); + em.persist(user); + + Item available = new Item(); + available.setName("Телевизор Samsung"); + available.setDescription("Smart TV"); + available.setAvailable(true); + available.setOwner(user); + em.persist(available); + + Item unavailable = new Item(); + unavailable.setName("Телевизор Rolsen"); + unavailable.setDescription("Аналоговый"); + unavailable.setAvailable(false); + unavailable.setOwner(user); + em.persist(unavailable); + + em.flush(); + + List result = itemService.searchItem("Телевизор"); + + assertThat(result).hasSize(1); + assertThat(result.get(0).getAvailable()).isTrue(); + } + + @Test + void mustCreateCommentAfterBooking() { + User owner = new User(); + owner.setName("Макс Иванов"); + owner.setEmail("Max@mail.ru"); + em.persist(owner); + + User booker = new User(); + booker.setName("Андрей Алексеев"); + booker.setEmail("Andrey@mail.ru"); + em.persist(booker); + + Item item = new Item(); + item.setName("Atom"); + item.setDescription("Велосипед горный"); + item.setAvailable(true); + item.setOwner(owner); + em.persist(item); + + Booking booking = new Booking(); + booking.setItem(item); + booking.setBooker(booker); + booking.setStart(LocalDateTime.now().minusDays(5)); + booking.setEnd(LocalDateTime.now().minusDays(2)); + booking.setStatus(RentalStatus.APPROVED); + em.persist(booking); + + em.flush(); + + CommentRequestDto dto = new CommentRequestDto("Крутой велосипед! Спасибо!"); + CommentResponseDto result = itemService.createComment(booker.getId(), item.getId(), dto); + + assertThat(result.getText()).isEqualTo("Крутой велосипед! Спасибо!"); + } + + @Test + void mustThrowWhenCommentWithoutBooking() { + User owner = new User(); + owner.setName("Макс Иванов"); + owner.setEmail("Max@mail.ru"); + em.persist(owner); + + User booker = new User(); + booker.setName("Андрей Алексеев"); + booker.setEmail("Andrey@mail.ru"); + em.persist(booker); + + Item item = new Item(); + item.setName("Canon 500d"); + item.setDescription("Зеркальный фотоаппарат"); + item.setAvailable(true); + item.setOwner(owner); + em.persist(item); + + em.flush(); + + CommentRequestDto dto = new CommentRequestDto("Хочу оставить отзыв"); + + assertThatThrownBy(() -> itemService.createComment(booker.getId(), item.getId(), dto)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Пользователь может оставить комментарий после аренды"); + } } diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java index a1e334d..b1ddf50 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java @@ -9,13 +9,17 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.item.model.Item; import ru.practicum.shareit.request.dto.ItemReqRequestDto; import ru.practicum.shareit.request.dto.ItemReqResponseDto; import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.request.service.ItemRequestService; import ru.practicum.shareit.user.model.User; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @Transactional @ActiveProfiles("test") @@ -61,4 +65,85 @@ public void mustCreateItemRequest() { assertThat(savedItemRequest.getDescription()).isEqualTo("Ищу строительный пылесос"); assertThat(savedItemRequest.getRequestor().getId()).isEqualTo(userId); } + + @Test + void mustReturnListOfYourQueriesWithAnswers() { + ItemRequest itemRequest = new ItemRequest(); + itemRequest.setDescription("Нужен фотоаппарат"); + itemRequest.setRequestor(em.find(User.class, userId)); + em.persist(itemRequest); + em.flush(); + + List results = itemRequestService.findListOfYourQueriesWithAnswers(userId); + + assertThat(results).hasSize(1); + assertThat(results.get(0).getDescription()).isEqualTo("Нужен фотоаппарат"); + assertThat(results.get(0).getItems()).isEmpty(); + } + + @Test + void mustReturnListOfRequestsFromOtherUsers() { + User requestor = new User(); + requestor.setName("Катя Петрова"); + requestor.setEmail("Katya@mail.ru"); + em.persist(requestor); + + ItemRequest itemRequest = new ItemRequest(); + itemRequest.setDescription("Нужен фотоаппарат"); + itemRequest.setRequestor(requestor); + em.persist(itemRequest); + em.flush(); + + List results = itemRequestService.findListOfRequestsOtherUsers(userId, 0, 10); + + assertThat(results).hasSize(1); + assertThat(results.get(0).getDescription()).isEqualTo("Нужен фотоаппарат"); + } + + @Test + void mustReturnSingleRequestWithAnswers() { + User requestor = new User(); + requestor.setName("Катя Петрова"); + requestor.setEmail("Katya@mail.ru"); + em.persist(requestor); + + ItemRequest itemRequest = new ItemRequest(); + itemRequest.setDescription("Ищу гитару"); + itemRequest.setRequestor(requestor); + em.persist(itemRequest); + + Item item = new Item(); + item.setName("Yamaha PACIFICA 012 BL"); + item.setDescription("Электрогитара"); + item.setAvailable(true); + item.setOwner(em.find(User.class, userId)); + item.setItemRequest(itemRequest); + em.persist(item); + + em.flush(); + + ItemReqResponseDto result = itemRequestService.findYourQueryWithAnswers(userId, itemRequest.getId()); + + assertThat(result.getId()).isEqualTo(itemRequest.getId()); + assertThat(result.getItems()).hasSize(1); + assertThat(result.getItems().get(0).getName()).isEqualTo("Yamaha PACIFICA 012 BL"); + } + + @Test + void mustThrowWhenUserNotFound() { + assertThatThrownBy(() -> itemRequestService.findListOfYourQueriesWithAnswers(999L)) + .isInstanceOf(ru.practicum.shareit.exception.NotFoundException.class); + } + + @Test + void mustThrowWhenRequestNotFound() { + assertThatThrownBy(() -> itemRequestService.findYourQueryWithAnswers(userId, 999L)) + .isInstanceOf(ru.practicum.shareit.exception.NotFoundException.class); + } + + @Test + void mustReturnEmptyListWhenNoRequests() { + var result = itemRequestService.findListOfYourQueriesWithAnswers(userId); + assertThat(result).isEmpty(); + } } diff --git a/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java b/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java index e4a2894..e8f1468 100644 --- a/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/UserServiceTest.java @@ -2,6 +2,7 @@ import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -9,6 +10,8 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; import ru.practicum.shareit.ShareItApp; +import ru.practicum.shareit.exception.InternalServerException; +import ru.practicum.shareit.exception.NotFoundException; import ru.practicum.shareit.user.dto.UserDto; import ru.practicum.shareit.user.model.User; import ru.practicum.shareit.user.service.UserService; @@ -47,4 +50,86 @@ void mustReturnUserById() { assertThat(itemResponseDto.getName()).isEqualTo("Макс Иванов"); assertThat(itemResponseDto.getEmail()).isEqualTo("Max@mail.ru"); } + + + @Test + void shouldReturnException() { + Assertions.assertThrows(NotFoundException.class, () -> userService.findUserById(999999L)); + } + + @Test + void mustUpdateName() { + UserDto updateDto = new UserDto(); + updateDto.setName("Макс Алексеев"); + updateDto.setEmail(null); + + UserDto updated = userService.updateUser(userId, updateDto); + + assertThat(updated.getName()).isEqualTo("Макс Алексеев"); + assertThat(updated.getEmail()).isEqualTo("Max@mail.ru"); + } + + @Test + void mustUpdateEmail() { + UserDto updateDto = new UserDto(); + updateDto.setName(null); + updateDto.setEmail("newMax@mail.ru"); + + UserDto updated = userService.updateUser(userId, updateDto); + + assertThat(updated.getEmail()).isEqualTo("newMax@mail.ru"); + assertThat(updated.getName()).isEqualTo("Макс Иванов"); + } + + @Test + void emptyFieldsShouldIgnoredWhenUpdating() { + UserDto updateDto = new UserDto(); + updateDto.setName(" "); + updateDto.setEmail(" "); + + UserDto updated = userService.updateUser(userId, updateDto); + + assertThat(updated.getName()).isEqualTo("Макс Иванов"); + assertThat(updated.getEmail()).isEqualTo("Max@mail.ru"); + } + + @Test + void shouldSuccessfullyCreateTheUser() { + UserDto newUser = new UserDto(); + newUser.setName("Иван Петров"); + newUser.setEmail("ivan.petrov@mail.ru"); + + UserDto created = userService.createUser(newUser); + + assertThat(created.getId()).isNotNull(); + assertThat(created.getName()).isEqualTo("Иван Петров"); + assertThat(created.getEmail()).isEqualTo("ivan.petrov@mail.ru"); + } + + @Test + void exceptionMustBeThrown() { + UserDto newUser = new UserDto(); + newUser.setName("Макс Егоров"); + newUser.setEmail("Max@mail.ru"); + + Assertions.assertThrows(InternalServerException.class, () -> userService.createUser(newUser)); + } + + @Test + void deleteUserExistingIdSuccess() { + Assertions.assertDoesNotThrow(() -> userService.deleteUser(userId)); + } + + @Test + void shouldReturnExceptionOnDelete() { + Assertions.assertDoesNotThrow(() -> userService.deleteUser(999999L)); + } + + @Test + void shouldReturnAllUsers() { + var allUsers = userService.findAllUsers(); + + assertThat(allUsers).isNotEmpty(); + assertThat(allUsers.stream().anyMatch(u -> u.getId().equals(userId))).isTrue(); + } } From 9d33fdf4c688e13005ef0cc614b9dd8cb98b4300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Mon, 21 Jul 2025 12:52:26 +0300 Subject: [PATCH 12/15] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B9=D1=82?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D1=84=D0=B8=D0=BB?= =?UTF-8?q?=D1=8C=20dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 9c14e4f..eb319df 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -1,6 +1,6 @@ spring: profiles: - active: test + active: dev --- From 5d9e478ab97cae43ed8e0d20a505f26af29bcd0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Mon, 21 Jul 2025 13:28:51 +0300 Subject: [PATCH 13/15] =?UTF-8?q?=D0=A1=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20applic?= =?UTF-8?q?ation.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gateway/src/main/resources/application.yml | 4 ---- server/src/main/resources/application.yml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/gateway/src/main/resources/application.yml b/gateway/src/main/resources/application.yml index 10ae9aa..8fce774 100644 --- a/gateway/src/main/resources/application.yml +++ b/gateway/src/main/resources/application.yml @@ -5,10 +5,6 @@ logging: web: client: RestTemplate: DEBUG -# apache: -# http: DEBUG -# httpclient: -# wire: DEBUG server: port: 8080 diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index eb319df..28c23b3 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -10,7 +10,7 @@ spring: on-profile: dev datasource: driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5445/shareit + url: jdbc:postgresql://localhost:5432/shareit username: dbuser password: 12345 jpa: From e2db3226927b4fb1e8f8b02602fa2f15991681d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Mon, 21 Jul 2025 13:53:16 +0300 Subject: [PATCH 14/15] =?UTF-8?q?=D0=A1=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20applic?= =?UTF-8?q?ation.yml2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 28c23b3..8e2fa4a 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -15,7 +15,7 @@ spring: password: 12345 jpa: hibernate: - ddl-auto: none + ddl-auto: create properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect From a2da02dbbd83e50df100646d113fa2a901e847e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?= Date: Mon, 21 Jul 2025 16:55:54 +0300 Subject: [PATCH 15/15] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../booking/dto/BookingResponseDto.java | 3 - .../item/comment/dto/CommentResponseDto.java | 2 - .../shareit/request/dto/ItemResponseDto.java | 2 - server/pom.xml | 12 --- .../booking/dto/BookingResponseDto.java | 3 - .../item/comment/dto/CommentResponseDto.java | 2 - .../controller/ItemRequestController.java | 16 ++-- .../request/dto/ItemReqResponseDto.java | 2 - .../request/service/ItemRequestService.java | 6 +- .../service/ItemRequestServiceImpl.java | 6 +- .../booking/BookingControllerTest.java | 84 +++++++++++++++---- .../shareit/item/ItemControllerTest.java | 6 +- .../request/ItemRequestControllerTest.java | 32 +++++-- .../request/ItemRequestServiceTest.java | 12 +-- 14 files changed, 119 insertions(+), 69 deletions(-) diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java b/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java index 334abb1..67e3ef1 100644 --- a/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.booking.dto; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -15,9 +14,7 @@ @Setter public class BookingResponseDto { private Long id; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime start; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime end; private ItemDto item; private UserDto booker; diff --git a/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java b/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java index 5708e07..798ec01 100644 --- a/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.item.comment.dto; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -14,7 +13,6 @@ public class CommentResponseDto { private Long id; private String text; private String authorName; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime created; private Long itemId; } diff --git a/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java b/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java index 4a762bf..e372466 100644 --- a/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemResponseDto.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.request.dto; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,7 +17,6 @@ public class ItemResponseDto { private Long id; private String description; private Long userId; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime created; private List items; } diff --git a/server/pom.xml b/server/pom.xml index 40811b7..c561c04 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -64,18 +64,6 @@ hibernate-validator 8.0.2.Final - - - jakarta.validation - jakarta.validation-api - 3.0.2 - - - - org.glassfish - jakarta.el - 4.0.2 - diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java index 334abb1..67e3ef1 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingResponseDto.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.booking.dto; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -15,9 +14,7 @@ @Setter public class BookingResponseDto { private Long id; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime start; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime end; private ItemDto item; private UserDto booker; diff --git a/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java b/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java index 5708e07..798ec01 100644 --- a/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java +++ b/server/src/main/java/ru/practicum/shareit/item/comment/dto/CommentResponseDto.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.item.comment.dto; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -14,7 +13,6 @@ public class CommentResponseDto { private Long id; private String text; private String authorName; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime created; private Long itemId; } diff --git a/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java b/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java index 36d80e1..1461442 100644 --- a/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java +++ b/server/src/main/java/ru/practicum/shareit/request/controller/ItemRequestController.java @@ -23,22 +23,22 @@ public ItemReqResponseDto createItemRequest(@RequestHeader("X-Sharer-User-Id") L } @GetMapping - public List findListOfYourQueriesWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId) { + public List getRequests(@RequestHeader("X-Sharer-User-Id") Long userId) { log.info("GET /requests"); - return itemRequestService.findListOfYourQueriesWithAnswers(userId); + return itemRequestService.getRequests(userId); } @GetMapping("/all") - public List findListOfRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, - @RequestParam(defaultValue = "0") int from, - @RequestParam(defaultValue = "10") int size) { + public List getRequestsOtherUsers(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(defaultValue = "0") int from, + @RequestParam(defaultValue = "10") int size) { log.info("GET /requests/all"); - return itemRequestService.findListOfRequestsOtherUsers(userId, from, size); + return itemRequestService.getRequestsOtherUsers(userId, from, size); } @GetMapping("/{requestId}") - public ItemReqResponseDto findYourQueryWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { + public ItemReqResponseDto getRequestWithAnswers(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { log.info("GET /requests/{}", requestId); - return itemRequestService.findYourQueryWithAnswers(userId, requestId); + return itemRequestService.getRequestWithAnswers(userId, requestId); } } diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java index 9d1c1ef..ac1de19 100644 --- a/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemReqResponseDto.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.request.dto; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,7 +17,6 @@ public class ItemReqResponseDto { private Long id; private String description; private Long userId; - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") private LocalDateTime created; private List items; } diff --git a/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java index 32d0a1f..cee70e5 100644 --- a/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java +++ b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java @@ -8,9 +8,9 @@ public interface ItemRequestService { ItemReqResponseDto createItemRequest(Long userId, ItemReqRequestDto itemReqRequestDto); - List findListOfYourQueriesWithAnswers(Long userId); + List getRequests(Long userId); - List findListOfRequestsOtherUsers(Long userId, int from, int size); + List getRequestsOtherUsers(Long userId, int from, int size); - ItemReqResponseDto findYourQueryWithAnswers(Long userId, Long requestId); + ItemReqResponseDto getRequestWithAnswers(Long userId, Long requestId); } diff --git a/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java index 6d83820..a3ea652 100644 --- a/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java +++ b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java @@ -39,7 +39,7 @@ public ItemReqResponseDto createItemRequest(Long userId, ItemReqRequestDto itemR } @Override - public List findListOfYourQueriesWithAnswers(Long userId) { + public List getRequests(Long userId) { validateUser(userId); List requests = itemRequestRepository.findByRequestorIdOrderByCreatedDesc(userId); @@ -48,7 +48,7 @@ public List findListOfYourQueriesWithAnswers(Long userId) { } @Override - public List findListOfRequestsOtherUsers(Long userId, int from, int size) { + public List getRequestsOtherUsers(Long userId, int from, int size) { validateUser(userId); Pageable pageable = PageRequest.of(from / size, size, Sort.by("created").descending()); @@ -59,7 +59,7 @@ public List findListOfRequestsOtherUsers(Long userId, int fr } @Override - public ItemReqResponseDto findYourQueryWithAnswers(Long userId, Long requestId) { + public ItemReqResponseDto getRequestWithAnswers(Long userId, Long requestId) { validateUser(userId); ItemRequest itemRequest = itemRequestRepository.findById(requestId) diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java index 78302bc..db60a85 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java @@ -107,8 +107,16 @@ void mustCreateBooking() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(1))) - .andExpect(jsonPath("$.start", is("2025-07-20T10:00:00"))) - .andExpect(jsonPath("$.end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$.start[0]", is(2025))) + .andExpect(jsonPath("$.start[1]", is(7))) + .andExpect(jsonPath("$.start[2]", is(20))) + .andExpect(jsonPath("$.start[3]", is(10))) + .andExpect(jsonPath("$.start[4]", is(0))) + .andExpect(jsonPath("$.end[0]", is(2025))) + .andExpect(jsonPath("$.end[1]", is(7))) + .andExpect(jsonPath("$.end[2]", is(20))) + .andExpect(jsonPath("$.end[3]", is(12))) + .andExpect(jsonPath("$.end[4]", is(0))) .andExpect(jsonPath("$.id", is(1))) .andExpect(jsonPath("$.item.name", is("Canon 500d"))) .andExpect(jsonPath("$.item.description", is("Полупрофессиональная модель фотоаппарата"))) @@ -138,8 +146,16 @@ void mustUpdateBookingStatus() throws Exception { })) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(1))) - .andExpect(jsonPath("$.start", is("2025-07-20T10:00:00"))) - .andExpect(jsonPath("$.end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$.start[0]", is(2025))) + .andExpect(jsonPath("$.start[1]", is(7))) + .andExpect(jsonPath("$.start[2]", is(20))) + .andExpect(jsonPath("$.start[3]", is(10))) + .andExpect(jsonPath("$.start[4]", is(0))) + .andExpect(jsonPath("$.end[0]", is(2025))) + .andExpect(jsonPath("$.end[1]", is(7))) + .andExpect(jsonPath("$.end[2]", is(20))) + .andExpect(jsonPath("$.end[3]", is(12))) + .andExpect(jsonPath("$.end[4]", is(0))) .andExpect(jsonPath("$.id", is(1))) .andExpect(jsonPath("$.item.name", is("Canon 500d"))) .andExpect(jsonPath("$.item.description", is("Полупрофессиональная модель фотоаппарата"))) @@ -161,8 +177,16 @@ void mustReturnBookingById() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(1))) - .andExpect(jsonPath("$.start", is("2025-07-20T10:00:00"))) - .andExpect(jsonPath("$.end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$.start[0]", is(2025))) + .andExpect(jsonPath("$.start[1]", is(7))) + .andExpect(jsonPath("$.start[2]", is(20))) + .andExpect(jsonPath("$.start[3]", is(10))) + .andExpect(jsonPath("$.start[4]", is(0))) + .andExpect(jsonPath("$.end[0]", is(2025))) + .andExpect(jsonPath("$.end[1]", is(7))) + .andExpect(jsonPath("$.end[2]", is(20))) + .andExpect(jsonPath("$.end[3]", is(12))) + .andExpect(jsonPath("$.end[4]", is(0))) .andExpect(jsonPath("$.item.name", is("Canon 500d"))) .andExpect(jsonPath("$.item.description", is("Полупрофессиональная модель фотоаппарата"))) .andExpect(jsonPath("$.item.available", is(true))) @@ -186,8 +210,16 @@ void mustReturnUserBookings() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$[0].id", is(1))) - .andExpect(jsonPath("$[0].start", is("2025-07-20T10:00:00"))) - .andExpect(jsonPath("$[0].end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$[0].start[0]", is(2025))) + .andExpect(jsonPath("$[0].start[1]", is(7))) + .andExpect(jsonPath("$[0].start[2]", is(20))) + .andExpect(jsonPath("$[0].start[3]", is(10))) + .andExpect(jsonPath("$[0].start[4]", is(0))) + .andExpect(jsonPath("$[0].end[0]", is(2025))) + .andExpect(jsonPath("$[0].end[1]", is(7))) + .andExpect(jsonPath("$[0].end[2]", is(20))) + .andExpect(jsonPath("$[0].end[3]", is(12))) + .andExpect(jsonPath("$[0].end[4]", is(0))) .andExpect(jsonPath("$[0].item.name", is("Canon 500d"))) .andExpect(jsonPath("$[0].item.description", is("Полупрофессиональная модель фотоаппарата"))) .andExpect(jsonPath("$[0].item.available", is(true))) @@ -197,8 +229,16 @@ void mustReturnUserBookings() throws Exception { .andExpect(jsonPath("$[0].booker.email", is("Max@mail.ru"))) .andExpect(jsonPath("$[0].status", is("APPROVED"))) .andExpect(jsonPath("$[1].id", is(2))) - .andExpect(jsonPath("$[1].start", is("2025-07-20T13:00:00"))) - .andExpect(jsonPath("$[1].end", is("2025-07-20T14:00:00"))) + .andExpect(jsonPath("$[1].start[0]", is(2025))) + .andExpect(jsonPath("$[1].start[1]", is(7))) + .andExpect(jsonPath("$[1].start[2]", is(20))) + .andExpect(jsonPath("$[1].start[3]", is(13))) + .andExpect(jsonPath("$[1].start[4]", is(0))) + .andExpect(jsonPath("$[1].end[0]", is(2025))) + .andExpect(jsonPath("$[1].end[1]", is(7))) + .andExpect(jsonPath("$[1].end[2]", is(20))) + .andExpect(jsonPath("$[1].end[3]", is(14))) + .andExpect(jsonPath("$[1].end[4]", is(0))) .andExpect(jsonPath("$[1].item").doesNotExist()) .andExpect(jsonPath("$[1].booker").doesNotExist()) .andExpect(jsonPath("$[1].status", is("APPROVED"))); @@ -217,8 +257,16 @@ void mustReturnOwnerReservedItems() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$[0].id", is(1))) - .andExpect(jsonPath("$[0].start", is("2025-07-20T10:00:00"))) - .andExpect(jsonPath("$[0].end", is("2025-07-20T12:00:00"))) + .andExpect(jsonPath("$[0].start[0]", is(2025))) + .andExpect(jsonPath("$[0].start[1]", is(7))) + .andExpect(jsonPath("$[0].start[2]", is(20))) + .andExpect(jsonPath("$[0].start[3]", is(10))) + .andExpect(jsonPath("$[0].start[4]", is(0))) + .andExpect(jsonPath("$[0].end[0]", is(2025))) + .andExpect(jsonPath("$[0].end[1]", is(7))) + .andExpect(jsonPath("$[0].end[2]", is(20))) + .andExpect(jsonPath("$[0].end[3]", is(12))) + .andExpect(jsonPath("$[0].end[4]", is(0))) .andExpect(jsonPath("$[0].item.name", is("Canon 500d"))) .andExpect(jsonPath("$[0].item.description", is("Полупрофессиональная модель фотоаппарата"))) .andExpect(jsonPath("$[0].item.available", is(true))) @@ -228,8 +276,16 @@ void mustReturnOwnerReservedItems() throws Exception { .andExpect(jsonPath("$[0].booker.email", is("Max@mail.ru"))) .andExpect(jsonPath("$[0].status", is("APPROVED"))) .andExpect(jsonPath("$[1].id", is(2))) - .andExpect(jsonPath("$[1].start", is("2025-07-20T13:00:00"))) - .andExpect(jsonPath("$[1].end", is("2025-07-20T14:00:00"))) + .andExpect(jsonPath("$[1].start[0]", is(2025))) + .andExpect(jsonPath("$[1].start[1]", is(7))) + .andExpect(jsonPath("$[1].start[2]", is(20))) + .andExpect(jsonPath("$[1].start[3]", is(13))) + .andExpect(jsonPath("$[1].start[4]", is(0))) + .andExpect(jsonPath("$[1].end[0]", is(2025))) + .andExpect(jsonPath("$[1].end[1]", is(7))) + .andExpect(jsonPath("$[1].end[2]", is(20))) + .andExpect(jsonPath("$[1].end[3]", is(14))) + .andExpect(jsonPath("$[1].end[4]", is(0))) .andExpect(jsonPath("$[1].item").doesNotExist()) .andExpect(jsonPath("$[1].booker").doesNotExist()) .andExpect(jsonPath("$[1].status", is("APPROVED"))); diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java index 43300f9..f563227 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java @@ -241,6 +241,10 @@ void mustReturnComment() throws Exception { .andExpect(jsonPath("$.id", is(1))) .andExpect(jsonPath("$.text", is("Все хорошо!"))) .andExpect(jsonPath("$.authorName", is("Макс Иванов"))) - .andExpect(jsonPath("$.created", is("2025-07-20T11:30:00"))); + .andExpect(jsonPath("$.created[0]", is(2025))) + .andExpect(jsonPath("$.created[1]", is(7))) + .andExpect(jsonPath("$.created[2]", is(20))) + .andExpect(jsonPath("$.created[3]", is(11))) + .andExpect(jsonPath("$.created[4]", is(30))); } } diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java index b4e2110..b79dbd7 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java @@ -98,13 +98,17 @@ void mustCreateItemRequest() throws Exception { .andExpect(jsonPath("$.id", is(1))) .andExpect(jsonPath("$.description", is(itemReqRequestDto.getDescription()))) .andExpect(jsonPath("$.userId", is(itemReqRequestDto.getRequestorId().intValue()))) - .andExpect(jsonPath("$.created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$.created[0]", is(2025))) + .andExpect(jsonPath("$.created[1]", is(7))) + .andExpect(jsonPath("$.created[2]", is(16))) + .andExpect(jsonPath("$.created[3]", is(19))) + .andExpect(jsonPath("$.created[4]", is(40))) .andExpect(jsonPath("$.items").isArray()); } @Test void mustFindListOfYourQueriesWithAnswers() throws Exception { - when(itemRequestService.findListOfYourQueriesWithAnswers(1L)) + when(itemRequestService.getRequests(1L)) .thenReturn(List.of(itemReqResponseDto2)); mvc.perform(get("/requests") @@ -115,7 +119,11 @@ void mustFindListOfYourQueriesWithAnswers() throws Exception { .andExpect(jsonPath("$[0].id", is(1))) .andExpect(jsonPath("$[0].description", is("Ищу строительный пылесос"))) .andExpect(jsonPath("$[0].userId", is(1))) - .andExpect(jsonPath("$[0].created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$[0].created[0]", is(2025))) + .andExpect(jsonPath("$[0].created[1]", is(7))) + .andExpect(jsonPath("$[0].created[2]", is(16))) + .andExpect(jsonPath("$[0].created[3]", is(19))) + .andExpect(jsonPath("$[0].created[4]", is(40))) .andExpect(jsonPath("$[0].items").isArray()) .andExpect(jsonPath("$[0].items[0].id", is(1))) .andExpect(jsonPath("$[0].items[0].name", is("Karcher WD 2 Plus"))) @@ -126,7 +134,7 @@ void mustFindListOfYourQueriesWithAnswers() throws Exception { @Test void mustFindListOfRequestsOtherUsers() throws Exception { - when(itemRequestService.findListOfRequestsOtherUsers(1L, 0, 10)) + when(itemRequestService.getRequestsOtherUsers(1L, 0, 10)) .thenReturn(List.of(itemReqResponseDto2)); mvc.perform(get("/requests/all") @@ -139,7 +147,11 @@ void mustFindListOfRequestsOtherUsers() throws Exception { .andExpect(jsonPath("$[0].id", is(1))) .andExpect(jsonPath("$[0].description", is("Ищу строительный пылесос"))) .andExpect(jsonPath("$[0].userId", is(1))) - .andExpect(jsonPath("$[0].created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$[0].created[0]", is(2025))) + .andExpect(jsonPath("$[0].created[1]", is(7))) + .andExpect(jsonPath("$[0].created[2]", is(16))) + .andExpect(jsonPath("$[0].created[3]", is(19))) + .andExpect(jsonPath("$[0].created[4]", is(40))) .andExpect(jsonPath("$[0].items").isArray()) .andExpect(jsonPath("$[0].items[0].id", is(1))) .andExpect(jsonPath("$[0].items[0].name", is("Karcher WD 2 Plus"))) @@ -150,7 +162,7 @@ void mustFindListOfRequestsOtherUsers() throws Exception { @Test void mustFindYourQueryWithAnswers() throws Exception { - when(itemRequestService.findYourQueryWithAnswers(1L, 1L)) + when(itemRequestService.getRequestWithAnswers(1L, 1L)) .thenReturn(itemReqResponseDto2); mvc.perform(get("/requests/1") @@ -161,7 +173,11 @@ void mustFindYourQueryWithAnswers() throws Exception { .andExpect(jsonPath("$.id", is(1))) .andExpect(jsonPath("$.description", is("Ищу строительный пылесос"))) .andExpect(jsonPath("$.userId", is(1))) - .andExpect(jsonPath("$.created", is("2025-07-16T19:40:00"))) + .andExpect(jsonPath("$.created[0]", is(2025))) + .andExpect(jsonPath("$.created[1]", is(7))) + .andExpect(jsonPath("$.created[2]", is(16))) + .andExpect(jsonPath("$.created[3]", is(19))) + .andExpect(jsonPath("$.created[4]", is(40))) .andExpect(jsonPath("$.items").isArray()) .andExpect(jsonPath("$.items[0].id", is(1))) .andExpect(jsonPath("$.items[0].name", is("Karcher WD 2 Plus"))); @@ -169,7 +185,7 @@ void mustFindYourQueryWithAnswers() throws Exception { @Test void mustReturn404IfItemRequestNotFound() throws Exception { - when(itemRequestService.findYourQueryWithAnswers(1L, 99L)) + when(itemRequestService.getRequestWithAnswers(1L, 99L)) .thenThrow(new NotFoundException("Запрос не найден")); mvc.perform(get("/requests/99") diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java index b1ddf50..4c53a50 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceTest.java @@ -74,7 +74,7 @@ void mustReturnListOfYourQueriesWithAnswers() { em.persist(itemRequest); em.flush(); - List results = itemRequestService.findListOfYourQueriesWithAnswers(userId); + List results = itemRequestService.getRequests(userId); assertThat(results).hasSize(1); assertThat(results.get(0).getDescription()).isEqualTo("Нужен фотоаппарат"); @@ -94,7 +94,7 @@ void mustReturnListOfRequestsFromOtherUsers() { em.persist(itemRequest); em.flush(); - List results = itemRequestService.findListOfRequestsOtherUsers(userId, 0, 10); + List results = itemRequestService.getRequestsOtherUsers(userId, 0, 10); assertThat(results).hasSize(1); assertThat(results.get(0).getDescription()).isEqualTo("Нужен фотоаппарат"); @@ -122,7 +122,7 @@ void mustReturnSingleRequestWithAnswers() { em.flush(); - ItemReqResponseDto result = itemRequestService.findYourQueryWithAnswers(userId, itemRequest.getId()); + ItemReqResponseDto result = itemRequestService.getRequestWithAnswers(userId, itemRequest.getId()); assertThat(result.getId()).isEqualTo(itemRequest.getId()); assertThat(result.getItems()).hasSize(1); @@ -131,19 +131,19 @@ void mustReturnSingleRequestWithAnswers() { @Test void mustThrowWhenUserNotFound() { - assertThatThrownBy(() -> itemRequestService.findListOfYourQueriesWithAnswers(999L)) + assertThatThrownBy(() -> itemRequestService.getRequests(999L)) .isInstanceOf(ru.practicum.shareit.exception.NotFoundException.class); } @Test void mustThrowWhenRequestNotFound() { - assertThatThrownBy(() -> itemRequestService.findYourQueryWithAnswers(userId, 999L)) + assertThatThrownBy(() -> itemRequestService.getRequestWithAnswers(userId, 999L)) .isInstanceOf(ru.practicum.shareit.exception.NotFoundException.class); } @Test void mustReturnEmptyListWhenNoRequests() { - var result = itemRequestService.findListOfYourQueriesWithAnswers(userId); + var result = itemRequestService.getRequests(userId); assertThat(result).isEmpty(); } }