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/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/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/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, 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..496d759 --- /dev/null +++ b/spring-chatting-backend-server/src/test/java/chatting/chat/domain/participant/api/ParticipantControllerTest.java @@ -0,0 +1,121 @@ +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.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; +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.time.LocalDate; +import java.util.Arrays; +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 whenRoomNotValid_then404ShouldBeReturned() 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 + @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)); + + // 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 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