From 4fff19dea751358158c85da6625f01983ae0ea16 Mon Sep 17 00:00:00 2001 From: HwangboGyumin Date: Sun, 31 Dec 2023 17:03:01 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[dev]=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=20CRUD=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/participant/ParticipantRequest.java | 36 ++++++++++ .../java/chatting/chat/config/JpaConfig.java | 2 +- .../api/ParticipantController.java | 71 +++++++++++++++++++ .../service/ParticipantService.java | 6 +- .../service/ParticipantServiceImpl.java | 38 +++++++++- .../web/filter/UserContextInterceptor.java | 25 ++++++- 6 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 common-dto/src/main/java/com/example/commondto/dto/participant/ParticipantRequest.java create mode 100644 spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/api/ParticipantController.java diff --git a/common-dto/src/main/java/com/example/commondto/dto/participant/ParticipantRequest.java b/common-dto/src/main/java/com/example/commondto/dto/participant/ParticipantRequest.java new file mode 100644 index 0000000..1231fc8 --- /dev/null +++ b/common-dto/src/main/java/com/example/commondto/dto/participant/ParticipantRequest.java @@ -0,0 +1,36 @@ +package com.example.commondto.dto.participant; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +public class ParticipantRequest { + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @Getter + @Setter + @ToString + public static class RemoveParticipantDto { + private Long roomId; + + @Builder + public RemoveParticipantDto(Long roomId) { + this.roomId = roomId; + } + } + + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @Getter + @Setter + @ToString + public static class AddParticipantRequest { + private Long roomId; + + @Builder + public AddParticipantRequest(Long roomId) { + this.roomId = roomId; + } + } +} diff --git a/spring-chatting-backend-server/src/main/java/chatting/chat/config/JpaConfig.java b/spring-chatting-backend-server/src/main/java/chatting/chat/config/JpaConfig.java index 2ebdfeb..6cce69e 100644 --- a/spring-chatting-backend-server/src/main/java/chatting/chat/config/JpaConfig.java +++ b/spring-chatting-backend-server/src/main/java/chatting/chat/config/JpaConfig.java @@ -58,7 +58,7 @@ public RoomService roomService() { @Bean public ParticipantService participantService() { - return new ParticipantServiceImpl(participantRepository, userRepository); + return new ParticipantServiceImpl(participantRepository, userRepository, roomRepository); } } diff --git a/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/api/ParticipantController.java b/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/api/ParticipantController.java new file mode 100644 index 0000000..d1c8451 --- /dev/null +++ b/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/api/ParticipantController.java @@ -0,0 +1,71 @@ +package chatting.chat.domain.participant.api; + +import chatting.chat.domain.participant.dto.ParticipantDto; +import chatting.chat.domain.participant.service.ParticipantService; +import chatting.chat.web.filter.UserContext; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import java.util.List; + +@Slf4j +@RestController +@AllArgsConstructor +public class ParticipantController { + + private final ParticipantService participantService; + + /** + * 내가 참여중인 채팅방에서 나가기 + * @param roomId + * @implNote {@link UserContext#getUserId()} 가 필요합니다. + * {@link UserContext#setUserId(String)} 를 통해 userId 를 저장해주세요. + * UserConext 의 userId 는 {@link chatting.chat.web.filter.UserContextInterceptor} 에서 자동으로 설정됩니다. + * @return if success return "success" else throw {@link com.example.commondto.error.CustomException} + */ + @DeleteMapping("/participant") + @Operation(summary = "Delete a participant") + public String removeParticipant(@RequestParam Long roomId) { + return participantService.remove(roomId, UserContext.getUserId()); + } + + /** + * 채팅방에 참여 + * @param roomId + * @implNote {@link UserContext#getUserId()} 가 필요합니다. + * {@link UserContext#setUserId(String)} 를 통해 userId 를 저장해주세요. + * UserConext 의 userId 는 {@link chatting.chat.web.filter.UserContextInterceptor} 에서 자동으로 설정됩니다. + * @return if success return "success" else throw {@link com.example.commondto.error.CustomException} + */ + @PostMapping("/participant") + @Operation(summary = "Add a participant") + public String addParticipant(@RequestParam Long roomId) { + return participantService.addParticipant(roomId, UserContext.getUserId()); + } + + /** + * 채팅방에 참여중인 유저 목록 조회 + * @return List {@link ParticipantDto} + */ + @GetMapping("/participants") + @Operation(summary = "Get List of participants by room id") + public List getParticipants(@RequestParam Long roomId) { + return participantService.findParticipantByRoomId(roomId); + } + + /** + * 내가 참여중인 채팅방 목록 조회 + * @return List {@link ParticipantDto} + */ + @GetMapping("/participant") + @Operation(summary = "Get List of my participants") + public List getParticipant() { + return participantService.findAllByUserId(UserContext.getUserId()); + } +} diff --git a/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantService.java b/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantService.java index 18e7d47..37eca3e 100644 --- a/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantService.java +++ b/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantService.java @@ -4,12 +4,16 @@ import chatting.chat.domain.participant.entity.Participant; import chatting.chat.domain.user.entity.User; +import com.example.commondto.dto.participant.ParticipantRequest; +import com.example.commondto.error.CustomException; import java.util.List; public interface ParticipantService { List findAllByUserId(String userId); List findParticipantByRoomId(Long roomId); String save(Participant participant); - String remove(Participant participant); + String remove(Long roomId, String userId) throws CustomException; + String addParticipant(Long roomId, String userId) throws CustomException; + } diff --git a/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantServiceImpl.java b/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantServiceImpl.java index 28c47d3..50640bb 100644 --- a/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantServiceImpl.java +++ b/spring-chatting-backend-server/src/main/java/chatting/chat/domain/participant/service/ParticipantServiceImpl.java @@ -3,8 +3,12 @@ import chatting.chat.domain.participant.dto.ParticipantDto; import chatting.chat.domain.participant.entity.Participant; import chatting.chat.domain.participant.repository.ParticipantRepository; +import chatting.chat.domain.room.entity.Room; +import chatting.chat.domain.room.repository.RoomRepository; import chatting.chat.domain.user.entity.User; import chatting.chat.domain.user.repository.UserRepository; +import com.example.commondto.dto.participant.ParticipantRequest; +import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,13 +24,20 @@ public class ParticipantServiceImpl implements ParticipantService{ private final ParticipantRepository participantRepository; private final UserRepository userRepository; + private final RoomRepository roomRepository; public ParticipantServiceImpl(ParticipantRepository participantRepository, - UserRepository userRepository) { + UserRepository userRepository, RoomRepository roomRepository) { this.participantRepository = participantRepository; this.userRepository = userRepository; + this.roomRepository = roomRepository; } + /** + * 유저 아이디로 현재 참여중인 채팅방 조회 + * @param userId + * @return List {@link ParticipantDto} + */ @Override public List findAllByUserId(String userId) { return participantRepository.findAllByUserId(userId).stream().map(Participant::toDto).toList(); @@ -51,8 +62,29 @@ public String save(Participant participant) throws CustomException { } @Override - public String remove(Participant participant) { + public String remove(Long roomId, String userId) throws CustomException { + Participant participant = participantRepository.findByRoomIdAndUserId(roomId, userId); + if (participant == null){ + throw new CustomException(INVALID_PARTICIPANT); + } participantRepository.delete(participant); - return null; + return "success"; + } + + @Override + public String addParticipant(Long roomId, String userId) throws CustomException { + User user = userRepository.findByUserId(userId) + .orElseThrow(() -> new CustomException(CANNOT_FIND_USER)); + + Room room = roomRepository.findById(roomId) + .orElseThrow(() -> new CustomException(CANNOT_FIND_ROOM)); + + Participant participant = Participant.builder() + .room(room) + .user(user) + .build(); + + participantRepository.save(participant); + return "success"; } } diff --git a/spring-chatting-backend-server/src/main/java/chatting/chat/web/filter/UserContextInterceptor.java b/spring-chatting-backend-server/src/main/java/chatting/chat/web/filter/UserContextInterceptor.java index a02b984..aafe0a0 100644 --- a/spring-chatting-backend-server/src/main/java/chatting/chat/web/filter/UserContextInterceptor.java +++ b/spring-chatting-backend-server/src/main/java/chatting/chat/web/filter/UserContextInterceptor.java @@ -17,6 +17,10 @@ import java.util.Optional; import java.util.*; +/** + * 초기 요청 시, 쿠키에서 userId 를 추출하여 {@link UserRedisSessionRepository} 를 통해 Redis 에서 userId 에 해당하는 + * {@link UserRedisSession} 을 가져옵니다. 이후 {@link UserContext} 에 userId 를 저장합니다. + */ @Slf4j @Component public class UserContextInterceptor implements HandlerInterceptor { @@ -24,8 +28,12 @@ public class UserContextInterceptor implements HandlerInterceptor { private final UserRedisSessionRepository userRedisSessionRepository; private final Map> whiteList = new HashMap<>(); -// private final List whiteList = Arrays.asList("/health","/user"); + /** + * @param userRedisSessionRepository + * @implNote WhiteList를 설정할 수 있으며 등록된 path 는 {@link UserContextInterceptor#preHandle} 에서 검증하지 + * 않습니다. + */ public UserContextInterceptor(UserRedisSessionRepository userRedisSessionRepository) { this.userRedisSessionRepository = userRedisSessionRepository; @@ -34,6 +42,11 @@ public UserContextInterceptor(UserRedisSessionRepository userRedisSessionReposit addWhiteList("/health", HttpMethod.GET); } + /** + * @param path + * @param method + * @implNote WhiteList 에 path 를 추가합니다. + */ private void addWhiteList(String path, HttpMethod method) { if (whiteList.containsKey(path)) { whiteList.get(path).add(method); @@ -42,6 +55,16 @@ private void addWhiteList(String path, HttpMethod method) { } } + /** + * @param request current HTTP request + * @param response current HTTP response + * @param handler chosen handler to execute, for type and/or instance evaluation + * @return {@code true} if the execution chain should proceed with the next interceptor or the + * handler itself. + * @throws Exception + * @implNote 요청이 들어올 때마다 userId 를 추출하여 {@link UserContext} 에 저장합니다. 추출된 userId 가 없을 경우 401 을 + * 반환합니다. 또한 Redis 에 refreshToken 이 저장되어있지 않을 때도 401 에러를 반환합니다. 테스트 시 {@link UserContext#setUserId} 로 ThreadLocal 에 저장해주세요. + */ @Override @Timed(value = "interceptor.preHandle") public boolean preHandle(HttpServletRequest request, HttpServletResponse response, From a0719c300460128a123a696a799b57dfb6881821 Mon Sep 17 00:00:00 2001 From: HwangboGyumin Date: Sun, 31 Dec 2023 17:24:26 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[dev]=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/ParticipantControllerTest.java | 102 +++++++++++ .../service/ParticipantServiceImplTest.java | 172 ++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java diff --git a/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java new file mode 100644 index 0000000..b3c12b7 --- /dev/null +++ b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java @@ -0,0 +1,102 @@ +package chatting.chat.domain.participant.api; + +import static com.example.commondto.error.ErrorCode.CANNOT_FIND_ROOM; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.*; +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; + +import chatting.chat.domain.participant.service.ParticipantServiceImpl; +import chatting.chat.domain.user.api.UserController; +import chatting.chat.domain.user.entity.User; +import chatting.chat.domain.user.service.UserService; +import chatting.chat.web.error.GlobalExceptionHandler; +import chatting.chat.web.filter.UserContextInterceptor; +import chatting.chat.web.sessionCluster.redis.UserRedisSession; +import chatting.chat.web.sessionCluster.redis.UserRedisSessionRepository; +import com.example.commondto.error.CustomException; +import jakarta.servlet.http.Cookie; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +@ExtendWith({SpringExtension.class}) +@WebMvcTest(ParticipantController.class) +@ActiveProfiles("testAPI") +@Import(GlobalExceptionHandler.class) +@Slf4j +class ParticipantControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + private ParticipantServiceImpl participantService; + + @MockBean + private UserRedisSessionRepository userRedisSessionRepository; + + @Autowired + private UserContextInterceptor userContextInterceptor; + + @BeforeEach + public void setUp() { + this.mockMvc = MockMvcBuilders + .standaloneSetup(new ParticipantController(participantService)) + .setControllerAdvice(new GlobalExceptionHandler()) + .addInterceptors(userContextInterceptor) + .build(); + } + + + @Test + @DisplayName("채팅방에 참여 시 참여 성공") + void whenValidParticipantAdd_thenSuccessShouldBeReturned() throws Exception { + // given + String refreshToken = "validToken"; + String userId = "userId"; + UserRedisSession userRedisSession = new UserRedisSession(userId, refreshToken); + when(userRedisSessionRepository.findById(refreshToken)).thenReturn(Optional.of(userRedisSession)); + when(participantService.addParticipant(1L,userId)).thenReturn("success"); + + // when + then + mockMvc.perform(post("/participant").param("roomId","1").cookie(new Cookie("refreshToken", refreshToken))) + .andExpect(status().isOk()).andExpect(jsonPath("$", is("success"))); + } + + @Test + @DisplayName("채팅방이 존재하지 않을 때 참여 시 에러 반환") + void addParticipant() throws Exception { + // given + String refreshToken = "validToken"; + String userId = "userId"; + UserRedisSession userRedisSession = new UserRedisSession(userId, refreshToken); + when(userRedisSessionRepository.findById(refreshToken)).thenReturn(Optional.of(userRedisSession)); + when(participantService.addParticipant(1L,userId)).thenThrow(new CustomException(CANNOT_FIND_ROOM)); + + // when + then + mockMvc.perform(post("/participant").param("roomId","1").cookie(new Cookie("refreshToken", refreshToken))) + .andExpect(status().isNotFound()); + } + + @Test + void getParticipants() { + } + + @Test + void getParticipant() { + } +} \ No newline at end of file diff --git a/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/service/ParticipantServiceImplTest.java b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/service/ParticipantServiceImplTest.java index 50999c6..d181a82 100644 --- a/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/service/ParticipantServiceImplTest.java +++ b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/service/ParticipantServiceImplTest.java @@ -42,6 +42,11 @@ class ParticipantServiceImplTest extends Initializer { .userName("friendName") .userStatus("").build(); + private final User testNewUser = User.builder() + .userId("newUserId") + .userName("newUserName") + .userStatus("").build(); + @BeforeEach void setUpRemove() { userRepository.deleteAll(); @@ -136,4 +141,171 @@ void whenParicipantUserIsNotValid_thenCustomExceptionShouldBeReturned() throws C assertThat(customException.getErrorCode()).isEqualTo(ErrorCode.CANNOT_FIND_FRIEND); } + @Test + @DisplayName("채팅방 참여 시 채팅방에 존재하지 않으면 에러 반환") + void whenRoomIsNotValid_thenCustomExceptionShouldBeReturned() throws CustomException{ + // given + userService.save(testUser.getUserId(), testUser.getUserName(), testUser.getUserStatus()); + userService.save(testFriendUser.getUserId(), testFriendUser.getUserName(), testFriendUser.getUserStatus()); + UserContext.setUserId(testUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 친구 추가 + friendService.save(testUser.getUserId(), testFriendUser.getUserId()); + + // when then + CustomException customException = assertThrows(CustomException.class, () -> { + participantService.addParticipant(1L, testUser.getUserId()); + }); + + assertThat(customException.getErrorCode()).isEqualTo(ErrorCode.CANNOT_FIND_ROOM); + } + + @Test + @DisplayName("채팅방에 참여 성공") + void whenValidParticipantAdd_thenSuccessShouldBeReturned() { + // given + // 유저 추가 + userService.save(testUser.getUserId(), testUser.getUserName(), testUser.getUserStatus()); + userService.save(testFriendUser.getUserId(), testFriendUser.getUserName(), testFriendUser.getUserStatus()); + UserContext.setUserId(testUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 친구 추가 + friendService.save(testUser.getUserId(), testFriendUser.getUserId()); + + // 채팅방 생성 + RoomDto roomDto = userService.makeRoomWithFriends(RequestAddChatRoomDTO.builder() + .userId(testUser.getUserId()) + .friendIds(Arrays.asList(testFriendUser.getUserId())) + .build()); + + userService.save(testNewUser.getUserId(), testNewUser.getUserName(), testNewUser.getUserStatus()); + UserContext.setUserId(testNewUser.getUserId()); // ThreadLocal 에 userId 저장 + + // when + String success = participantService.addParticipant(roomDto.getRoomId(), testNewUser.getUserId()); + + // then + List participants = participantService.findParticipantByRoomId(roomDto.getRoomId()); + + participants.forEach(participantDto -> log.info("participantDto: {}", participantDto)); + assertThat(participants).hasSize(3); + assertThat(participants.get(0).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(0).getUserDto().getUserId()).isEqualTo(testUser.getUserId()); + assertThat(participants.get(1).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(1).getUserDto().getUserId()).isEqualTo(testFriendUser.getUserId()); + assertThat(participants.get(2).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(2).getUserDto().getUserId()).isEqualTo(testNewUser.getUserId()); + } + + @Test + @DisplayName("채팅방에서 나가기 성공") + void whenValidParticipantRemove_thenSuccessShouldBeReturned() { + // given + // 유저 추가 + userService.save(testUser.getUserId(), testUser.getUserName(), testUser.getUserStatus()); + userService.save(testFriendUser.getUserId(), testFriendUser.getUserName(), testFriendUser.getUserStatus()); + UserContext.setUserId(testUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 친구 추가 + friendService.save(testUser.getUserId(), testFriendUser.getUserId()); + + // 채팅방 생성 + RoomDto roomDto = userService.makeRoomWithFriends(RequestAddChatRoomDTO.builder() + .userId(testUser.getUserId()) + .friendIds(Arrays.asList(testFriendUser.getUserId())) + .build()); + + userService.save(testNewUser.getUserId(), testNewUser.getUserName(), testNewUser.getUserStatus()); + UserContext.setUserId(testNewUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 채팅방 참여 + participantService.addParticipant(roomDto.getRoomId(), testNewUser.getUserId()); + + // when + String success = participantService.remove(roomDto.getRoomId(), testNewUser.getUserId()); + + // then + List participants = participantService.findParticipantByRoomId(roomDto.getRoomId()); + + participants.forEach(participantDto -> log.info("participantDto: {}", participantDto)); + assertThat(participants).hasSize(2); + assertThat(participants.get(0).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(0).getUserDto().getUserId()).isEqualTo(testUser.getUserId()); + assertThat(participants.get(1).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(1).getUserDto().getUserId()).isEqualTo(testFriendUser.getUserId()); + } + + @Test + @DisplayName("채팅방에 참여중인 유저 목록 조회 성공") + void whenValidParticipantGet_thenSuccessShouldBeReturned() { + // given + // 유저 추가 + userService.save(testUser.getUserId(), testUser.getUserName(), testUser.getUserStatus()); + userService.save(testFriendUser.getUserId(), testFriendUser.getUserName(), testFriendUser.getUserStatus()); + UserContext.setUserId(testUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 친구 추가 + friendService.save(testUser.getUserId(), testFriendUser.getUserId()); + + // 채팅방 생성 + RoomDto roomDto = userService.makeRoomWithFriends(RequestAddChatRoomDTO.builder() + .userId(testUser.getUserId()) + .friendIds(Arrays.asList(testFriendUser.getUserId())) + .build()); + + userService.save(testNewUser.getUserId(), testNewUser.getUserName(), testNewUser.getUserStatus()); + UserContext.setUserId(testNewUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 채팅방 참여 + participantService.addParticipant(roomDto.getRoomId(), testNewUser.getUserId()); + + // when + List participants = participantService.findParticipantByRoomId(roomDto.getRoomId()); + + // then + participants.forEach(participantDto -> log.info("participantDto: {}", participantDto)); + assertThat(participants).hasSize(3); + assertThat(participants.get(0).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(0).getUserDto().getUserId()).isEqualTo(testUser.getUserId()); + assertThat(participants.get(1).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(1).getUserDto().getUserId()).isEqualTo(testFriendUser.getUserId()); + assertThat(participants.get(2).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(2).getUserDto().getUserId()).isEqualTo(testNewUser.getUserId()); + } + + @Test + @DisplayName("기존 채팅방 참여 시 내 채팅방 목록 조회 성공") + void whenValidParticipantGetMyRoom_thenSuccessShouldBeReturned() { + // given + // 유저 추가 + userService.save(testUser.getUserId(), testUser.getUserName(), testUser.getUserStatus()); + userService.save(testFriendUser.getUserId(), testFriendUser.getUserName(), testFriendUser.getUserStatus()); + UserContext.setUserId(testUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 친구 추가 + friendService.save(testUser.getUserId(), testFriendUser.getUserId()); + + // 채팅방 생성 + RoomDto roomDto = userService.makeRoomWithFriends(RequestAddChatRoomDTO.builder() + .userId(testUser.getUserId()) + .friendIds(Arrays.asList(testFriendUser.getUserId())) + .build()); + + userService.save(testNewUser.getUserId(), testNewUser.getUserName(), testNewUser.getUserStatus()); + UserContext.setUserId(testNewUser.getUserId()); // ThreadLocal 에 userId 저장 + + // 채팅방 참여 + participantService.addParticipant(roomDto.getRoomId(), testNewUser.getUserId()); + + // when + List participants = participantService.findAllByUserId(testNewUser.getUserId()); + + // then + participants.forEach(participantDto -> log.info("participantDto: {}", participantDto)); + assertThat(participants).hasSize(1); + assertThat(participants.get(0).getRoomId()).isEqualTo(roomDto.getRoomId()); + assertThat(participants.get(0).getUserDto().getUserId()).isEqualTo(testNewUser.getUserId()); + } + + } \ No newline at end of file From 49e5876d5f9b1c166d3f30a8d3a76ae715bc1789 Mon Sep 17 00:00:00 2001 From: HwangboGyumin Date: Sun, 31 Dec 2023 18:16:03 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[chore]=20build=20=EB=94=94=EB=A0=89?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20ignore=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + spring-chatting-backend-server/build.gradle | 22 +++++++++++--- .../api/ParticipantControllerTest.java | 29 +++++++++++++++---- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index a9b041b..4a8b681 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ .Ds_store /redis .gradle +**/build/ diff --git a/spring-chatting-backend-server/build.gradle b/spring-chatting-backend-server/build.gradle index 7f80bb7..15a87f1 100644 --- a/spring-chatting-backend-server/build.gradle +++ b/spring-chatting-backend-server/build.gradle @@ -2,12 +2,30 @@ plugins { id 'java' id 'org.springframework.boot' version '3.0.5' id 'io.spring.dependency-management' version '1.1.0' + id 'jacoco' +} + +jacoco { + toolVersion = "0.8.8" } ext { set('springCloudVersion', "2022.0.1") } +jacocoTestReport { + dependsOn test // 리포트 생성을 위해서는 test가 먼저 완료되어야 함 + reports { + xml.enabled false + html.enabled true + } +} + +tasks.named('test') { + useJUnitPlatform() + finalizedBy jacocoTestReport // 테스트 종료후 항상 리포트 생성 +} + group = 'chattingBackend' version = project.rootProject.ext.projectVersion sourceCompatibility = '17' @@ -85,10 +103,6 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' } -tasks.named('test') { - useJUnitPlatform() -} - // find the latest jar file in the build/libs directory def findLatestJar() { def jarDir = file("${project.buildDir}/libs") diff --git a/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java index b3c12b7..496d759 100644 --- a/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java +++ b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java @@ -9,8 +9,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import chatting.chat.domain.participant.dto.ParticipantDto; import chatting.chat.domain.participant.service.ParticipantServiceImpl; import chatting.chat.domain.user.api.UserController; +import chatting.chat.domain.user.dto.UserDto; import chatting.chat.domain.user.entity.User; import chatting.chat.domain.user.service.UserService; import chatting.chat.web.error.GlobalExceptionHandler; @@ -19,6 +21,8 @@ import chatting.chat.web.sessionCluster.redis.UserRedisSessionRepository; import com.example.commondto.error.CustomException; import jakarta.servlet.http.Cookie; +import java.time.LocalDate; +import java.util.Arrays; import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -79,7 +83,7 @@ void whenValidParticipantAdd_thenSuccessShouldBeReturned() throws Exception { @Test @DisplayName("채팅방이 존재하지 않을 때 참여 시 에러 반환") - void addParticipant() throws Exception { + void whenRoomNotValid_then404ShouldBeReturned() throws Exception { // given String refreshToken = "validToken"; String userId = "userId"; @@ -93,10 +97,25 @@ void addParticipant() throws Exception { } @Test - void getParticipants() { - } + @DisplayName("내가 참여중인 채팅방 목록 조회 시 참여중인 채팅방 목록 반환 성공") + void whenValidUserGetHisParticipantList_thenValidParticipantListShouldBeReturned() + throws Exception { + // given + String refreshToken = "validToken"; + String userId = "userId"; + ParticipantDto participantDto = ParticipantDto.builder().userDto(UserDto.builder().userId(userId).userName("userName").userStatus("").build()) + .participantId(1L) + .createdAt(LocalDate.now()) + .updatedAt(LocalDate.now()) + .roomId(1L) + .roomName("roomName") + .build(); + UserRedisSession userRedisSession = new UserRedisSession(userId, refreshToken); + when(userRedisSessionRepository.findById(refreshToken)).thenReturn(Optional.of(userRedisSession)); + when(participantService.findAllByUserId(userId)).thenReturn(Arrays.asList(participantDto)); - @Test - void getParticipant() { + // when + then + mockMvc.perform(get("/participant").cookie(new Cookie("refreshToken", refreshToken))) + .andExpect(status().isOk()).andExpect(jsonPath("$[0].userDto.userId", is(userId))); } } \ No newline at end of file