1 package de.juplo.kafka.chat.backend.api;
3 import de.juplo.kafka.chat.backend.ChatBackendProperties;
4 import de.juplo.kafka.chat.backend.domain.*;
5 import de.juplo.kafka.chat.backend.domain.exceptions.ShardNotOwnedException;
6 import de.juplo.kafka.chat.backend.domain.exceptions.UnknownChatroomException;
7 import lombok.extern.slf4j.Slf4j;
8 import org.junit.jupiter.api.DisplayName;
9 import org.junit.jupiter.api.Test;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
12 import org.springframework.boot.test.context.SpringBootTest;
13 import org.springframework.boot.test.mock.mockito.MockBean;
14 import org.springframework.http.MediaType;
15 import org.springframework.test.web.reactive.server.WebTestClient;
16 import reactor.core.publisher.Mono;
18 import java.time.Clock;
19 import java.time.LocalDateTime;
20 import java.util.UUID;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Mockito.*;
26 @SpringBootTest(properties = {
27 "spring.main.allow-bean-definition-overriding=true",
29 @AutoConfigureWebTestClient
31 public class ChatBackendControllerTest
34 ChatBackendProperties properties;
37 ChatHomeService chatHomeService;
39 ChatMessageService chatMessageService;
42 @DisplayName("Assert expected problem-details for unknown chatroom on GET /list/{chatroomId}")
43 void testUnknownChatroomExceptionForListChatroom(@Autowired WebTestClient client)
46 UUID chatroomId = UUID.randomUUID();
47 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new UnknownChatroomException(chatroomId));
50 WebTestClient.ResponseSpec responseSpec = client
52 .uri("/{chatroomId}/list", chatroomId)
53 .accept(MediaType.APPLICATION_JSON)
57 assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
62 @DisplayName("Assert expected problem-details for unknown chatroom on GET /get/{chatroomId}")
63 void testUnknownChatroomExceptionForGetChatroom(@Autowired WebTestClient client)
66 UUID chatroomId = UUID.randomUUID();
67 when(chatHomeService.getChatRoomInfo(eq(chatroomId))).thenThrow(new UnknownChatroomException(chatroomId));
70 WebTestClient.ResponseSpec responseSpec = client
72 .uri("/{chatroomId}", chatroomId)
73 .accept(MediaType.APPLICATION_JSON)
77 assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
81 @DisplayName("Assert expected problem-details for unknown chatroom on PUT /put/{chatroomId}/{username}/{messageId}")
82 void testUnknownChatroomExceptionForPutMessage(@Autowired WebTestClient client)
85 UUID chatroomId = UUID.randomUUID();
86 String username = "foo";
88 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new UnknownChatroomException(chatroomId));
91 WebTestClient.ResponseSpec responseSpec = client
94 "/{chatroomId}/{username}/{messageId}",
99 .accept(MediaType.APPLICATION_JSON)
103 assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
107 @DisplayName("Assert expected problem-details for unknown chatroom on GET /get/{chatroomId}/{username}/{messageId}")
108 void testUnknownChatroomExceptionForGetMessage(@Autowired WebTestClient client)
111 UUID chatroomId = UUID.randomUUID();
112 String username = "foo";
113 Long messageId = 66l;
114 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new UnknownChatroomException(chatroomId));
117 WebTestClient.ResponseSpec responseSpec = client
120 "/{chatroomId}/{username}/{messageId}",
124 .accept(MediaType.APPLICATION_JSON)
128 assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
132 @DisplayName("Assert expected problem-details for unknown chatroom on GET /listen/{chatroomId}")
133 void testUnknownChatroomExceptionForListenChatroom(@Autowired WebTestClient client)
136 UUID chatroomId = UUID.randomUUID();
137 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new UnknownChatroomException(chatroomId));
140 WebTestClient.ResponseSpec responseSpec = client
142 .uri("/{chatroomId}/listen", chatroomId)
143 // .accept(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_JSON) << TODO: Does not work!
147 assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
150 private void assertProblemDetailsForUnknownChatroomException(
151 WebTestClient.ResponseSpec responseSpec,
155 .expectStatus().isNotFound()
157 .jsonPath("$.type").isEqualTo("/problem/unknown-chatroom")
158 .jsonPath("$.chatroomId").isEqualTo(chatroomId.toString());
162 @DisplayName("Assert expected problem-details for message mutation on PUT /put/{chatroomId}/{username}/{messageId}")
163 void testMessageMutationException(@Autowired WebTestClient client)
166 UUID chatroomId = UUID.randomUUID();
168 Long messageId = 66l;
169 Message.MessageKey key = Message.MessageKey.of(user, messageId);
170 Long serialNumberExistingMessage = 0l;
171 String timeExistingMessageAsString = "2023-01-09T20:44:57.389665447";
172 LocalDateTime timeExistingMessage = LocalDateTime.parse(timeExistingMessageAsString);
173 String textExistingMessage = "Existing";
174 String textMutatedMessage = "Mutated!";
175 ChatRoomData chatRoomData = new ChatRoomData(
176 Clock.systemDefaultZone(),
179 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenReturn(Mono.just(chatRoomData));
180 Message existingMessage = new Message(
182 serialNumberExistingMessage,
184 textExistingMessage);
185 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
186 .thenReturn(Mono.just(existingMessage));
187 // Needed for readable error-reports, in case of a bug that leads to according unwanted call
188 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
189 .thenReturn(Mono.just(mock(Message.class)));
195 "/{chatroomId}/{username}/{messageId}",
199 .bodyValue(textMutatedMessage)
200 .accept(MediaType.APPLICATION_JSON)
203 .expectStatus().is4xxClientError()
205 .jsonPath("$.type").isEqualTo("/problem/message-mutation")
206 .jsonPath("$.existingMessage.id").isEqualTo(messageId)
207 .jsonPath("$.existingMessage.serial").isEqualTo(serialNumberExistingMessage)
208 .jsonPath("$.existingMessage.time").isEqualTo(timeExistingMessageAsString)
209 .jsonPath("$.existingMessage.user").isEqualTo(user)
210 .jsonPath("$.existingMessage.text").isEqualTo(textExistingMessage)
211 .jsonPath("$.mutatedText").isEqualTo(textMutatedMessage);
212 verify(chatMessageService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class));
216 @DisplayName("Assert expected problem-details for invalid username on PUT /put/{chatroomId}/{username}/{messageId}")
217 void testInvalidUsernameException(@Autowired WebTestClient client)
220 UUID chatroomId = UUID.randomUUID();
222 Long messageId = 66l;
223 Message.MessageKey key = Message.MessageKey.of(user, messageId);
224 String textMessage = "Hallo Welt";
225 ChatRoomData chatRoomData = new ChatRoomData(
226 Clock.systemDefaultZone(),
229 when(chatHomeService.getChatRoomData(any(UUID.class)))
230 .thenReturn(Mono.just(chatRoomData));
231 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
232 .thenReturn(Mono.empty());
233 // Needed for readable error-reports, in case of a bug that leads to according unwanted call
234 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
235 .thenReturn(Mono.just(mock(Message.class)));
241 "/{chatroomId}/{username}/{messageId}",
245 .bodyValue(textMessage)
246 .accept(MediaType.APPLICATION_JSON)
249 .expectStatus().is4xxClientError()
251 .jsonPath("$.type").isEqualTo("/problem/invalid-username")
252 .jsonPath("$.username").isEqualTo(user);
253 verify(chatMessageService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class));
257 @DisplayName("Assert expected problem-details for not owned shard on GET /{chatroomId}")
258 void testShardNotOwnedExceptionForGetChatroom(@Autowired WebTestClient client)
261 UUID chatroomId = UUID.randomUUID();
263 when(chatHomeService.getChatRoomInfo(eq(chatroomId))).thenThrow(new ShardNotOwnedException(shard));
266 WebTestClient.ResponseSpec responseSpec = client
268 .uri("/{chatroomId}", chatroomId)
269 .accept(MediaType.APPLICATION_JSON)
273 assertProblemDetailsForShardNotOwnedException(responseSpec, shard);
277 @DisplayName("Assert expected problem-details for not owned shard on GET /list/{chatroomId}")
278 void testShardNotOwnedExceptionForListChatroom(@Autowired WebTestClient client)
281 UUID chatroomId = UUID.randomUUID();
283 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new ShardNotOwnedException(shard));
286 WebTestClient.ResponseSpec responseSpec = client
288 .uri("/{chatroomId}/list", chatroomId)
289 .accept(MediaType.APPLICATION_JSON)
293 assertProblemDetailsForShardNotOwnedException(responseSpec, shard);
297 @DisplayName("Assert expected problem-details for not owned shard on PUT /put/{chatroomId}/{username}/{messageId}")
298 void testShardNotOwnedExceptionForPutMessage(@Autowired WebTestClient client)
301 UUID chatroomId = UUID.randomUUID();
302 String username = "foo";
303 Long messageId = 66l;
305 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new ShardNotOwnedException(shard));
308 WebTestClient.ResponseSpec responseSpec = client
311 "/{chatroomId}/{username}/{messageId}",
316 .accept(MediaType.APPLICATION_JSON)
320 assertProblemDetailsForShardNotOwnedException(responseSpec, shard);
324 @DisplayName("Assert expected problem-details for not owned shard on GET /get/{chatroomId}/{username}/{messageId}")
325 void testShardNotOwnedExceptionForGetMessage(@Autowired WebTestClient client)
328 UUID chatroomId = UUID.randomUUID();
329 String username = "foo";
330 Long messageId = 66l;
332 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new ShardNotOwnedException(shard));
335 WebTestClient.ResponseSpec responseSpec = client
338 "/{chatroomId}/{username}/{messageId}",
342 .accept(MediaType.APPLICATION_JSON)
346 assertProblemDetailsForShardNotOwnedException(responseSpec, shard);
350 @DisplayName("Assert expected problem-details for not owned shard on GET /listen/{chatroomId}")
351 void testShardNotOwnedExceptionForListenChatroom(@Autowired WebTestClient client)
354 UUID chatroomId = UUID.randomUUID();
356 when(chatHomeService.getChatRoomData(eq(chatroomId))).thenThrow(new ShardNotOwnedException(shard));
359 WebTestClient.ResponseSpec responseSpec = client
361 .uri("/{chatroomId}/listen", chatroomId)
362 // .accept(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_JSON) << TODO: Does not work!
366 assertProblemDetailsForShardNotOwnedException(responseSpec, shard);
369 private void assertProblemDetailsForShardNotOwnedException(
370 WebTestClient.ResponseSpec responseSpec,
374 .expectStatus().isNotFound()
376 .jsonPath("$.type").isEqualTo("/problem/shard-not-owned")
377 .jsonPath("$.shard").isEqualTo(shard);