diff --git a/src/main/java/com/palettee/chat/controller/dto/response/ChatCustomResponse.java b/src/main/java/com/palettee/chat/controller/dto/response/ChatCustomResponse.java new file mode 100644 index 00000000..9e4fa8ac --- /dev/null +++ b/src/main/java/com/palettee/chat/controller/dto/response/ChatCustomResponse.java @@ -0,0 +1,40 @@ +package com.palettee.chat.controller.dto.response; + +import com.palettee.chat.domain.Chat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class ChatCustomResponse { + private List chats; + + private boolean hasNext; + + private LocalDateTime lastSendAt; + + public static ChatCustomResponse toResponseFromEntity(List chats, boolean hasNext, + LocalDateTime nextChatTimeStamp) { + return new ChatCustomResponse( + chats.stream() + .map(ChatResponse::toResponseFromEntity) + .toList(), + hasNext, + nextChatTimeStamp + ); + } + + public static ChatCustomResponse toResponseFromDto(List chats, boolean hasNext, + LocalDateTime nextChatTimeStamp) { + return new ChatCustomResponse( + chats, + hasNext, + nextChatTimeStamp + ); + } +} diff --git a/src/main/java/com/palettee/chat_room/controller/ChatRoomController.java b/src/main/java/com/palettee/chat_room/controller/ChatRoomController.java index 553c6041..4c67c86e 100644 --- a/src/main/java/com/palettee/chat_room/controller/ChatRoomController.java +++ b/src/main/java/com/palettee/chat_room/controller/ChatRoomController.java @@ -1,5 +1,7 @@ package com.palettee.chat_room.controller; +import com.palettee.chat.controller.dto.response.ChatCustomResponse; +import com.palettee.chat.service.ChatRedisService; import com.palettee.chat_room.controller.dto.request.ChatRoomCreateRequest; import com.palettee.chat_room.controller.dto.response.ChatRoomResponse; import com.palettee.chat_room.service.ChatRoomService; @@ -7,11 +9,14 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; + @RestController @RequiredArgsConstructor @RequestMapping("/chat-room") public class ChatRoomController { private final ChatRoomService chatRoomService; + private final ChatRedisService chatRedisService; // 채팅방 생성 @PostMapping @@ -32,4 +37,11 @@ public void participateChatRoom(@PathVariable Long chatRoomId, @PathVariable Lon public void leaveChatRoom(@PathVariable Long chatRoomId, @PathVariable Long userId) { chatRoomService.leave(chatRoomId, userId); } + + @GetMapping("/chats/{chatRoomId}") + public ChatCustomResponse getChats(@PathVariable Long chatRoomId, + @RequestParam(value = "size") int size, + @RequestParam(value = "lastSendAt", required = false) LocalDateTime lastSendAt) { + return chatRedisService.getChats(chatRoomId, size, lastSendAt); + } } diff --git a/src/test/java/com/palettee/chat/ChatRedisServiceTest.java b/src/test/java/com/palettee/chat/ChatRedisServiceTest.java new file mode 100644 index 00000000..a939db3c --- /dev/null +++ b/src/test/java/com/palettee/chat/ChatRedisServiceTest.java @@ -0,0 +1,279 @@ +package com.palettee.chat; + +import com.palettee.chat.controller.dto.request.ChatRequest; +import com.palettee.chat.controller.dto.response.ChatCustomResponse; +import com.palettee.chat.controller.dto.response.ChatImgUrl; +import com.palettee.chat.controller.dto.response.ChatResponse; +import com.palettee.chat.domain.Chat; +import com.palettee.chat.repository.ChatRepository; +import com.palettee.chat.service.ChatRedisService; +import com.palettee.chat_room.domain.ChatCategory; +import com.palettee.chat_room.domain.ChatRoom; +import com.palettee.chat_room.repository.ChatRoomRepository; +import com.palettee.global.redis.utils.TypeConverter; +import com.palettee.user.domain.MajorJobGroup; +import com.palettee.user.domain.MinorJobGroup; +import com.palettee.user.domain.User; +import com.palettee.user.repository.UserRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ZSetOperations; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.*; + +@SpringBootTest +@Transactional +public class ChatRedisServiceTest { + + @Autowired UserRepository userRepository; + @Autowired ChatRoomRepository chatRoomRepository; + @Autowired ChatRepository chatRepository; + @Autowired ChatRedisService chatRedisService; + @Qualifier("chatRedisTemplate") @Autowired RedisTemplate redisTemplate; + + private ZSetOperations zSetOperations; + private User savedUser; + private ChatRoom savedChatRoom; + + @BeforeEach + void beforeEach() { + zSetOperations = redisTemplate.opsForZSet(); + + savedUser = userRepository.save(new User("email", "imageUrl","name", "briefIntro", MajorJobGroup.DEVELOPER, MinorJobGroup.BACKEND)); + savedChatRoom = chatRoomRepository.save(new ChatRoom(ChatCategory.COFFEE_CHAT)); + } + + @AfterEach + void afterEach() { + userRepository.deleteAll(); + chatRoomRepository.deleteAll(); + chatRepository.deleteAll(); + + redisTemplate.delete(String.valueOf(savedChatRoom.getId())); + } + + @Test + @DisplayName("채팅 저장") + void saveChat() { + // given + String userEmail = savedUser.getEmail(); + Long chatRoomId = savedChatRoom.getId(); + List urls = new ArrayList<>(); + ChatRequest chatRequest = new ChatRequest("Hi", urls); + + // when + ChatResponse chatResponse = chatRedisService.addChat(userEmail, chatRoomId, chatRequest); + Double sendAt = TypeConverter.LocalDateTimeToDouble(TypeConverter.StringToLocalDateTime(chatResponse.getSendAt())); + List results = zSetOperations.rangeByScore(String.valueOf(chatResponse.getChatRoomId()), sendAt, sendAt).stream().toList(); + + // then + assertThat(results.size()).isEqualTo(1); + assertThat(results.get(0).getContent()).isEqualTo("Hi"); + } + + @Test + @DisplayName("redis에서 조회 && DB에 데이터 X") + void getChatsSituation1() { + //given + String userEmail = savedUser.getEmail(); + Long chatRoomId = savedChatRoom.getId(); + + List urls1 = new ArrayList<>(); + List urls2 = new ArrayList<>(); + List urls3 = new ArrayList<>(); + + ChatRequest chatRequest1 = new ChatRequest("Hi1", urls1); + ChatRequest chatRequest2 = new ChatRequest("Hi2", urls2); + ChatRequest chatRequest3 = new ChatRequest("Hi3", urls3); + + chatRedisService.addChat(userEmail, chatRoomId, chatRequest1); + chatRedisService.addChat(userEmail, chatRoomId, chatRequest2); + chatRedisService.addChat(userEmail, chatRoomId, chatRequest3); + + //when + ChatCustomResponse chatCustomResponse = chatRedisService.getChats(chatRoomId, 3, null); + + //then + assertThat(chatCustomResponse.getChats().size()).isEqualTo(3); + assertThat(chatCustomResponse.isHasNext()).isFalse(); + assertThat(chatCustomResponse.getLastSendAt()).isNull(); + } + + @Test + @DisplayName("redis에 전혀 없고 DB에만 있을 때") + void getChatsSituation2() { + //given + Chat chat1 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 12, 123_123_000)) + .content("Hi1") + .build(); + + Chat chat2 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 13, 123_123_000)) + .content("Hi2") + .build(); + + Chat chat3 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 14, 123_123_000)) + .content("Hi3") + .build(); + + List chats = new ArrayList<>(); + chats.add(chat1); + chats.add(chat2); + chats.add(chat3); + + chatRepository.saveAll(chats); + + //when + ChatCustomResponse chatCustomResponse = chatRedisService.getChats(savedChatRoom.getId(), 3, null); + + //then + assertThat(chatCustomResponse.getChats().size()).isEqualTo(3); + assertThat(chatCustomResponse.isHasNext()).isFalse(); + assertThat(chatCustomResponse.getLastSendAt()).isNull(); + } + + @Test + @DisplayName("redis에 1개 DB에 2개 있을 때") + void getChatsSituation3() { + //given + Chat chat1 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 12, 123_123_000)) + .content("Hi1") + .build(); + + Chat chat2 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 13, 123_123_000)) + .content("Hi2") + .build(); + + + List chats = new ArrayList<>(); + chats.add(chat1); + chats.add(chat2); + + chatRepository.saveAll(chats); + + List urls1 = new ArrayList<>(); + ChatRequest chatRequest1 = new ChatRequest("Hi", urls1); + + chatRedisService.addChat(savedUser.getEmail(), savedChatRoom.getId(), chatRequest1); + + //when + ChatCustomResponse chatCustomResponse = chatRedisService.getChats(savedChatRoom.getId(), 3, null); + + //then + assertThat(chatCustomResponse.getChats().size()).isEqualTo(3); + assertThat(chatCustomResponse.isHasNext()).isFalse(); + assertThat(chatCustomResponse.getLastSendAt()).isNull(); + } + + @Test + @DisplayName("redis에 1개 DB에 3개 있을 때") + void getChatsSituation4() { + //given + Chat chat1 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 12, 123_123_000)) + .content("Hi1") + .build(); + + Chat chat2 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 13, 123_123_000)) + .content("Hi2") + .build(); + + Chat chat3 = Chat.builder() + .id(UUID.randomUUID().toString()) + .user(savedUser) + .chatRoom(savedChatRoom) + .sendAt(LocalDateTime.of(2024, 12, 4, 11, 10, 14, 123_123_000)) + .content("Hi3") + .build(); + + + List chats = new ArrayList<>(); + chats.add(chat1); + chats.add(chat2); + chats.add(chat3); + + chatRepository.saveAll(chats); + + List urls1 = new ArrayList<>(); + ChatRequest chatRequest1 = new ChatRequest("Hi", urls1); + + chatRedisService.addChat(savedUser.getEmail(), savedChatRoom.getId(), chatRequest1); + + //when + ChatCustomResponse chatCustomResponse = chatRedisService.getChats(savedChatRoom.getId(), 3, null); + + //then + assertThat(chatCustomResponse.getChats().size()).isEqualTo(3); + assertThat(chatCustomResponse.isHasNext()).isTrue(); + assertThat(chatCustomResponse.getLastSendAt()).isEqualTo(chat2.getSendAt()); + } + + @Test + @DisplayName("redis 데이터 4개") + void getChatsSituation5() { + //given + String userEmail = savedUser.getEmail(); + Long chatRoomId = savedChatRoom.getId(); + + List urls1 = new ArrayList<>(); + List urls2 = new ArrayList<>(); + List urls3 = new ArrayList<>(); + List urls4 = new ArrayList<>(); + + ChatRequest chatRequest1 = new ChatRequest("Hi1", urls1); + ChatRequest chatRequest2 = new ChatRequest("Hi2", urls2); + ChatRequest chatRequest3 = new ChatRequest("Hi3", urls3); + ChatRequest chatRequest4 = new ChatRequest("Hi4", urls4); + + chatRedisService.addChat(userEmail, chatRoomId, chatRequest1); + ChatResponse chatResponse = chatRedisService.addChat(userEmail, chatRoomId, chatRequest2); + chatRedisService.addChat(userEmail, chatRoomId, chatRequest3); + chatRedisService.addChat(userEmail, chatRoomId, chatRequest4); + + //when + ChatCustomResponse chatCustomResponse = chatRedisService.getChats(chatRoomId, 3, null); + + //then + assertThat(chatCustomResponse.getChats().size()).isEqualTo(3); + assertThat(chatCustomResponse.isHasNext()).isTrue(); + assertThat(chatCustomResponse.getLastSendAt()).isEqualTo(chatResponse.getSendAt()); + } +}