refactor: `ChatRoomService.persistMessage(..)` returns a `Mono<Message>`
[demos/kafka/chat] / src / test / java / de / juplo / kafka / chat / backend / api / ChatBackendControllerTest.java
1 package de.juplo.kafka.chat.backend.api;
2
3 import de.juplo.kafka.chat.backend.domain.*;
4 import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatHomeService;
5 import lombok.extern.slf4j.Slf4j;
6 import org.junit.jupiter.api.DisplayName;
7 import org.junit.jupiter.api.Test;
8 import org.springframework.beans.factory.annotation.Autowired;
9 import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
10 import org.springframework.boot.test.context.SpringBootTest;
11 import org.springframework.boot.test.mock.mockito.MockBean;
12 import org.springframework.http.MediaType;
13 import org.springframework.test.web.reactive.server.WebTestClient;
14 import reactor.core.publisher.Mono;
15
16 import java.time.Clock;
17 import java.time.LocalDateTime;
18 import java.util.UUID;
19
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.*;
22
23
24 @SpringBootTest(properties = {
25     "spring.main.allow-bean-definition-overriding=true",
26     "chat.backend.inmemory.sharding-strategy=none" })
27 @AutoConfigureWebTestClient
28 @Slf4j
29 public class ChatBackendControllerTest
30 {
31   @MockBean
32   InMemoryChatHomeService chatHomeService;
33   @MockBean
34   ChatRoomService chatRoomService;
35
36   @Test
37   @DisplayName("Assert expected problem-details for unknown chatroom on GET /list/{chatroomId}")
38   void testUnknownChatroomExceptionForListChatroom(@Autowired WebTestClient client)
39   {
40     // Given
41     UUID chatroomId = UUID.randomUUID();
42     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
43
44     // When
45     WebTestClient.ResponseSpec responseSpec = client
46         .get()
47         .uri("/{chatroomId}/list", chatroomId)
48         .accept(MediaType.APPLICATION_JSON)
49         .exchange();
50
51     // Then
52     assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
53   }
54
55
56   @Test
57   @DisplayName("Assert expected problem-details for unknown chatroom on GET /get/{chatroomId}")
58   void testUnknownChatroomExceptionForGetChatroom(@Autowired WebTestClient client)
59   {
60     // Given
61     UUID chatroomId = UUID.randomUUID();
62     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
63
64     // When
65     WebTestClient.ResponseSpec responseSpec = client
66         .get()
67         .uri("/{chatroomId}", chatroomId)
68         .accept(MediaType.APPLICATION_JSON)
69         .exchange();
70
71     // Then
72     assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
73   }
74
75   @Test
76   @DisplayName("Assert expected problem-details for unknown chatroom on PUT /put/{chatroomId}/{username}/{messageId}")
77   void testUnknownChatroomExceptionForPutMessage(@Autowired WebTestClient client)
78   {
79     // Given
80     UUID chatroomId = UUID.randomUUID();
81     String username = "foo";
82     Long messageId = 66l;
83     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
84
85     // When
86     WebTestClient.ResponseSpec responseSpec = client
87         .put()
88         .uri(
89             "/{chatroomId}/{username}/{messageId}",
90             chatroomId,
91             username,
92             messageId)
93         .bodyValue("bar")
94         .accept(MediaType.APPLICATION_JSON)
95         .exchange();
96
97     // Then
98     assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
99   }
100
101   @Test
102   @DisplayName("Assert expected problem-details for unknown chatroom on GET /get/{chatroomId}/{username}/{messageId}")
103   void testUnknownChatroomExceptionForGetMessage(@Autowired WebTestClient client)
104   {
105     // Given
106     UUID chatroomId = UUID.randomUUID();
107     String username = "foo";
108     Long messageId = 66l;
109     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
110
111     // When
112     WebTestClient.ResponseSpec responseSpec = client
113         .get()
114         .uri(
115             "/{chatroomId}/{username}/{messageId}",
116             chatroomId,
117             username,
118             messageId)
119         .accept(MediaType.APPLICATION_JSON)
120         .exchange();
121
122     // Then
123     assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
124   }
125
126   @Test
127   @DisplayName("Assert expected problem-details for unknown chatroom on GET /listen/{chatroomId}")
128   void testUnknownChatroomExceptionForListenChatroom(@Autowired WebTestClient client)
129   {
130     // Given
131     UUID chatroomId = UUID.randomUUID();
132     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
133
134     // When
135     WebTestClient.ResponseSpec responseSpec = client
136         .get()
137         .uri("/{chatroomId}/listen", chatroomId)
138         // .accept(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_JSON) << TODO: Does not work!
139         .exchange();
140
141     // Then
142     assertProblemDetailsForUnknownChatroomException(responseSpec, chatroomId);
143   }
144
145   private void assertProblemDetailsForUnknownChatroomException(
146       WebTestClient.ResponseSpec responseSpec,
147       UUID chatroomId)
148   {
149     responseSpec
150         .expectStatus().isNotFound()
151         .expectBody()
152         .jsonPath("$.type").isEqualTo("/problem/unknown-chatroom")
153         .jsonPath("$.chatroomId").isEqualTo(chatroomId.toString());
154   }
155
156   @Test
157   @DisplayName("Assert expected problem-details for message mutation on PUT /put/{chatroomId}/{username}/{messageId}")
158   void testMessageMutationException(@Autowired WebTestClient client) throws Exception
159   {
160     // Given
161     UUID chatroomId = UUID.randomUUID();
162     String user = "foo";
163     Long messageId = 66l;
164     Message.MessageKey key = Message.MessageKey.of(user, messageId);
165     Long serialNumberExistingMessage = 0l;
166     String timeExistingMessageAsString = "2023-01-09T20:44:57.389665447";
167     LocalDateTime timeExistingMessage = LocalDateTime.parse(timeExistingMessageAsString);
168     String textExistingMessage = "Existing";
169     String textMutatedMessage = "Mutated!";
170     ChatRoom chatRoom = new ChatRoom(
171         chatroomId,
172         "Test-ChatRoom",
173         0,
174         Clock.systemDefaultZone(),
175         chatRoomService, 8);
176     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.just(chatRoom));
177     Message existingMessage = new Message(
178         key,
179         serialNumberExistingMessage,
180         timeExistingMessage,
181         textExistingMessage);
182     when(chatRoomService.getMessage(any(Message.MessageKey.class)))
183         .thenReturn(Mono.just(existingMessage));
184     // Needed for readable error-reports, in case of a bug that leads to according unwanted call
185     when(chatRoomService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
186         .thenReturn(Mono.just(mock(Message.class)));
187
188     // When
189     client
190         .put()
191         .uri(
192             "/{chatroomId}/{username}/{messageId}",
193             chatroomId,
194             user,
195             messageId)
196         .bodyValue(textMutatedMessage)
197         .accept(MediaType.APPLICATION_JSON)
198         .exchange()
199         // Then
200         .expectStatus().is4xxClientError()
201         .expectBody()
202         .jsonPath("$.type").isEqualTo("/problem/message-mutation")
203         .jsonPath("$.existingMessage.id").isEqualTo(messageId)
204         .jsonPath("$.existingMessage.serial").isEqualTo(serialNumberExistingMessage)
205         .jsonPath("$.existingMessage.time").isEqualTo(timeExistingMessageAsString)
206         .jsonPath("$.existingMessage.user").isEqualTo(user)
207         .jsonPath("$.existingMessage.text").isEqualTo(textExistingMessage)
208         .jsonPath("$.mutatedText").isEqualTo(textMutatedMessage);
209     verify(chatRoomService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class));
210   }
211
212   @Test
213   @DisplayName("Assert expected problem-details for invalid username on PUT /put/{chatroomId}/{username}/{messageId}")
214   void testInvalidUsernameException(@Autowired WebTestClient client) throws Exception
215   {
216     // Given
217     UUID chatroomId = UUID.randomUUID();
218     String user = "Foo";
219     Long messageId = 66l;
220     Message.MessageKey key = Message.MessageKey.of(user, messageId);
221     String textMessage = "Hallo Welt";
222     ChatRoom chatRoom = new ChatRoom(
223         chatroomId,
224         "Test-ChatRoom",
225         0,
226         Clock.systemDefaultZone(),
227         chatRoomService, 8);
228     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class)))
229         .thenReturn(Mono.just(chatRoom));
230     when(chatRoomService.getMessage(any(Message.MessageKey.class)))
231         .thenReturn(Mono.empty());
232     // Needed for readable error-reports, in case of a bug that leads to according unwanted call
233     when(chatRoomService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
234         .thenReturn(Mono.just(mock(Message.class)));
235
236     // When
237     client
238         .put()
239         .uri(
240             "/{chatroomId}/{username}/{messageId}",
241             chatroomId,
242             user,
243             messageId)
244         .bodyValue(textMessage)
245         .accept(MediaType.APPLICATION_JSON)
246         .exchange()
247         // Then
248         .expectStatus().is4xxClientError()
249         .expectBody()
250         .jsonPath("$.type").isEqualTo("/problem/invalid-username")
251         .jsonPath("$.username").isEqualTo(user);
252     verify(chatRoomService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class));
253   }
254 }