1 package de.juplo.kafka.chat.backend.domain;
3 import org.junit.jupiter.api.BeforeEach;
4 import org.awaitility.Awaitility;
5 import org.junit.jupiter.api.DisplayName;
6 import org.junit.jupiter.api.Test;
7 import reactor.core.publisher.Mono;
10 import java.util.LinkedList;
11 import java.util.List;
13 import static org.mockito.Mockito.*;
14 import static pl.rzrz.assertj.reactor.Assertions.assertThat;
17 public class ChatRoomDataTest
20 ChatMessageService chatMessageService;
21 ChatRoomData chatRoomData;
25 Message.MessageKey key;
26 LocalDateTime timestamp;
32 now = Clock.fixed(Instant.now(), ZoneId.systemDefault());
33 chatMessageService = mock(ChatMessageService.class);
34 chatRoomData = new ChatRoomData(
41 key = Message.MessageKey.of(user, messageId);
42 timestamp = LocalDateTime.now(now);
47 @DisplayName("Assert, that Mono emits expected message, if it exists")
48 void testGetExistingMessage()
51 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
52 .thenReturn(Mono.just(someMessage()));
55 Mono<Message> mono = chatRoomData.getMessage(user, messageId);
58 assertThat(mono).emitsExactly(someMessage());
62 @DisplayName("Assert, that Mono is empty, if message does not exists")
63 void testGetNonExistentMessage()
66 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
67 .thenReturn(Mono.empty());
70 Mono<Message> mono = chatRoomData.getMessage(user, messageId);
73 assertThat(mono).emitsCount(0);
77 @DisplayName("Assert, that Mono emits the persisted message, if a new message is added")
78 void testAddNewMessageEmitsPersistedMessage()
81 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
82 .thenReturn(Mono.empty());
83 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
84 .thenReturn(Mono.just(someMessage()));
87 Mono<Message> mono = chatRoomData.addMessage(messageId, user, "Some Text");
90 assertThat(mono).emitsExactly(someMessage());
94 @DisplayName("Assert, that ChatMessageService.persistMessage() is called correctly, if a new message is added")
95 void testAddNewMessageTriggersPersistence()
98 String messageText = "Bar";
99 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
100 .thenReturn(Mono.empty());
101 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
102 .thenReturn(Mono.just(someMessage()));
106 .addMessage(messageId, user, messageText)
110 verify(chatMessageService, times(1)).persistMessage(eq(key), eq(timestamp), eq(messageText));
114 @DisplayName("Assert, that Mono emits the already persisted message, if an unchanged message is added")
115 void testAddUnchangedMessageEmitsAlreadyPersistedMessage()
118 String messageText = "Bar";
119 Message existingMessage = new Message(key, 0l, timestamp, messageText);
120 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
121 .thenReturn(Mono.just(existingMessage));
124 Mono<Message> mono = chatRoomData.addMessage(messageId, user, messageText);
127 assertThat(mono).emitsExactly(existingMessage);
131 @DisplayName("Assert, that ChatMessageService.persistMessage() is not called, if an unchanged message is added")
132 void testAddUnchangedMessageDoesNotTriggerPersistence()
135 String messageText = "Bar";
136 Message existingMessage = new Message(key, 0l, timestamp, messageText);
137 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
138 .thenReturn(Mono.just(existingMessage));
142 .addMessage(messageId, user, messageText)
146 verify(chatMessageService, never()).persistMessage(any(), any(), any());
150 @DisplayName("Assert, that Mono sends an error, if a message is added again with mutated text")
151 void testAddMutatedMessageSendsError()
154 String messageText = "Bar";
155 String mutatedText = "Boom!";
156 Message existingMessage = new Message(key, 0l, timestamp, messageText);
157 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
158 .thenReturn(Mono.just(existingMessage));
161 Mono<Message> mono = chatRoomData.addMessage(messageId, user, mutatedText);
164 assertThat(mono).sendsError();
168 @DisplayName("Assert, that ChatMessageService.persistMessage() is not called, if a message is added again with mutated text")
169 void testAddMutatedDoesNotTriggerPersistence()
172 String messageText = "Bar";
173 String mutatedText = "Boom!";
174 Message existingMessage = new Message(key, 0l, timestamp, messageText);
175 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
176 .thenReturn(Mono.just(existingMessage));
180 .addMessage(messageId, user, mutatedText)
181 .onErrorResume((throwable) -> Mono.empty())
185 verify(chatMessageService, never()).persistMessage(any(), any(), any());
189 @DisplayName("Assert, that a listener receives a message, that was added after the listening had started")
190 void testListenerReceivesMessageAddedAfterListeningStarts()
193 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
194 .thenReturn(Mono.empty());
195 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
196 .thenReturn(Mono.just(someMessage()));
199 List<Message> receivedMessages = new LinkedList<>();
202 .subscribe(receivedMessage -> receivedMessages.add(receivedMessage));
203 Message sentMessage = chatRoomData
204 .addMessage(messageId, user, "Some Text")
210 .atMost(Duration.ofSeconds(1))
211 .untilAsserted(() -> assertThat(receivedMessages).contains(sentMessage));
215 @DisplayName("Assert, that a listener receives a message, that was added before the listening had started")
216 void testListenerReceivesMessageAddedBeforeListeningStarts()
219 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
220 .thenReturn(Mono.empty());
221 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
222 .thenReturn(Mono.just(someMessage()));
225 Message sentMessage = chatRoomData
226 .addMessage(messageId, user, "Some Text")
228 List<Message> receivedMessages = new LinkedList<>();
231 .subscribe(receivedMessage -> receivedMessages.add(receivedMessage));
236 .atMost(Duration.ofSeconds(1))
237 .untilAsserted(() -> assertThat(receivedMessages).contains(sentMessage));
241 @DisplayName("Assert, that a listener receives several messages, that were added before and after the listening had started, in correct order")
242 void testListenerReceivesMessagesFromBeforeAndAfterListeningHadStartedInCorrectOrder()
245 Message message1 = new Message(key, 1l, timestamp, "#1");
246 Message message2 = new Message(key, 2l, timestamp, "#2");
247 Message message3 = new Message(key, 3l, timestamp, "#3");
248 Message message4 = new Message(key, 4l, timestamp, "#4");
249 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
250 .thenReturn(Mono.empty());
251 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
252 .thenReturn(Mono.just(message1))
253 .thenReturn(Mono.just(message2))
254 .thenReturn(Mono.just(message3))
255 .thenReturn(Mono.just(message4));
258 Message[] sentMessages = new Message[4];
259 sentMessages[0] = chatRoomData.addMessage(messageId, user, "Some Text").block();
260 sentMessages[1] = chatRoomData.addMessage(messageId, user, "Some Text").block();
261 List<Message> receivedMessages = new LinkedList<>();
264 .subscribe(receivedMessage -> receivedMessages.add(receivedMessage));
265 sentMessages[2] = chatRoomData.addMessage(messageId, user, "Some Text").block();
266 sentMessages[3] = chatRoomData.addMessage(messageId, user, "Some Text").block();
271 .atMost(Duration.ofSeconds(1))
272 .untilAsserted(() -> assertThat(receivedMessages).contains(sentMessages));
276 @DisplayName("Assert, that multiple listeners can receive an added message")
277 void testMultipleListeners()
280 Message message1 = new Message(key, 1l, timestamp, "#1");
281 Message message2 = new Message(key, 2l, timestamp, "#2");
282 Message message3 = new Message(key, 3l, timestamp, "#3");
283 Message message4 = new Message(key, 4l, timestamp, "#4");
284 when(chatMessageService.getMessage(any(Message.MessageKey.class)))
285 .thenReturn(Mono.empty());
286 when(chatMessageService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
287 .thenReturn(Mono.just(message1))
288 .thenReturn(Mono.just(message2))
289 .thenReturn(Mono.just(message3))
290 .thenReturn(Mono.just(message4));
293 Message[] sentMessages = new Message[4];
294 List<Message> messagesReceivedByListener1 = new LinkedList<>();
297 .subscribe(receivedMessage -> messagesReceivedByListener1.add(receivedMessage));
298 sentMessages[0] = chatRoomData.addMessage(messageId, user, "Some Text").block();
299 sentMessages[1] = chatRoomData.addMessage(messageId, user, "Some Text").block();
300 List<Message> messagesReceivedByListener2 = new LinkedList<>();
303 .subscribe(receivedMessage -> messagesReceivedByListener2.add(receivedMessage));
304 sentMessages[2] = chatRoomData.addMessage(messageId, user, "Some Text").block();
305 List<Message> messagesReceivedByListener3 = new LinkedList<>();
308 .subscribe(receivedMessage -> messagesReceivedByListener3.add(receivedMessage));
309 sentMessages[3] = chatRoomData.addMessage(messageId, user, "Some Text").block();
310 List<Message> messagesReceivedByListener4 = new LinkedList<>();
313 .subscribe(receivedMessage -> messagesReceivedByListener4.add(receivedMessage));
318 .atMost(Duration.ofSeconds(1))
321 assertThat(messagesReceivedByListener1).contains(sentMessages);
322 assertThat(messagesReceivedByListener2).contains(sentMessages);
323 assertThat(messagesReceivedByListener3).contains(sentMessages);
324 assertThat(messagesReceivedByListener4).contains(sentMessages);
330 * This message is used, when methods of {@link ChatMessageService} are mocked,
331 * that return a {@link Message}.
332 * The contents of the message are set to arbitrary values, in order to underline
333 * the fact, that the test can only assert, that the message that was returned
334 * by {@link ChatMessageService} is handed on by {@link ChatRoomData} correctly.
337 private Message someMessage()
340 Message.MessageKey.of("FOO", 666l),
342 LocalDateTime.of(2024, 3, 8, 12, 13, 00),
343 "Just some message...");