|
15 | 15 | import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom; |
16 | 16 | import kr.co.pennyway.domain.domains.chatroom.exception.ChatRoomErrorCode; |
17 | 17 | import kr.co.pennyway.domain.domains.chatroom.repository.ChatRoomRepository; |
| 18 | +import kr.co.pennyway.domain.domains.member.exception.ChatMemberErrorCode; |
18 | 19 | import kr.co.pennyway.domain.domains.member.repository.ChatMemberRepository; |
19 | 20 | import kr.co.pennyway.domain.domains.user.domain.User; |
20 | 21 | import kr.co.pennyway.domain.domains.user.repository.UserRepository; |
@@ -220,7 +221,44 @@ void successJoinPrivateRoomWithValidPassword() { |
220 | 221 |
|
221 | 222 | // then |
222 | 223 | assertEquals(HttpStatus.OK, response.getStatusCode()); |
| 224 | + } |
| 225 | + |
| 226 | + @Test |
| 227 | + @DisplayName("같은 사용자가 하나의 채팅방에 동시에 100개의 요청을 보내면, 100개의 가입 요청 중 1개만 성공한다") |
| 228 | + void concurrentJoinRequestsFromSameUser() throws InterruptedException { |
| 229 | + // given |
| 230 | + User admin = userRepository.save(UserFixture.GENERAL_USER.toUser()); |
| 231 | + ChatRoom chatRoom = chatRoomRepository.save(ChatRoomFixture.PUBLIC_CHAT_ROOM.toEntity(idGenerator.generate())); |
| 232 | + chatMemberRepository.save(ChatMemberFixture.ADMIN.toEntity(admin, chatRoom)); |
| 233 | + |
| 234 | + User user = userRepository.save(UserFixture.GENERAL_USER.toUser()); |
| 235 | + |
| 236 | + // when |
| 237 | + CountDownLatch latch = new CountDownLatch(100); |
| 238 | + List<CompletableFuture<JoinResult>> futures = IntStream.range(0, 100) |
| 239 | + .mapToObj(i -> CompletableFuture.supplyAsync(() -> { |
| 240 | + try { |
| 241 | + return JoinResult.from( |
| 242 | + postJoining(user, chatRoom.getId(), new ChatMemberReq.Join(null)) |
| 243 | + ); |
| 244 | + } finally { |
| 245 | + latch.countDown(); |
| 246 | + } |
| 247 | + })) |
| 248 | + .toList(); |
| 249 | + |
| 250 | + latch.await(); |
| 251 | + |
| 252 | + List<JoinResult> results = futures.stream() |
| 253 | + .map(CompletableFuture::join) |
| 254 | + .toList(); |
223 | 255 |
|
| 256 | + // then |
| 257 | + assertAll( |
| 258 | + () -> assertEquals(1, results.stream().filter(JoinResult::isSuccess).count()), |
| 259 | + () -> assertEquals(99, results.stream().filter(JoinResult::isAlreadyJoinedError).count()), |
| 260 | + () -> assertEquals(2, chatMemberRepository.countByChatRoomIdAndActive(chatRoom.getId())) |
| 261 | + ); |
224 | 262 | } |
225 | 263 |
|
226 | 264 | private ResponseEntity<?> postJoining(User user, Long chatRoomId, ChatMemberReq.Join request) { |
@@ -282,5 +320,12 @@ public boolean isFullRoomError() { |
282 | 320 | } |
283 | 321 | return false; |
284 | 322 | } |
| 323 | + |
| 324 | + public boolean isAlreadyJoinedError() { |
| 325 | + if (!isSuccess && body instanceof ErrorResponse errorResponse) { |
| 326 | + return errorResponse.getCode().equals(ChatMemberErrorCode.ALREADY_JOINED.causedBy().getCode()); |
| 327 | + } |
| 328 | + return false; |
| 329 | + } |
285 | 330 | } |
286 | 331 | } |
0 commit comments