a2870284b4e89f2166027830e73d6eed7910ebd9
[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         Clock.systemDefaultZone(),
174         chatRoomService, 8);
175     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.just(chatRoom));
176     Message existingMessage = new Message(
177         key,
178         serialNumberExistingMessage,
179         timeExistingMessage,
180         textExistingMessage);
181     when(chatRoomService.getMessage(any(Message.MessageKey.class)))
182         .thenReturn(Mono.just(existingMessage));
183     // Needed for readable error-reports, in case of a bug that leads to according unwanted call
184     when(chatRoomService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
185         .thenReturn(mock(Message.class));
186
187     // When
188     client
189         .put()
190         .uri(
191             "/{chatroomId}/{username}/{messageId}",
192             chatroomId,
193             user,
194             messageId)
195         .bodyValue(textMutatedMessage)
196         .accept(MediaType.APPLICATION_JSON)
197         .exchange()
198         // Then
199         .expectStatus().is4xxClientError()
200         .expectBody()
201         .jsonPath("$.type").isEqualTo("/problem/message-mutation")
202         .jsonPath("$.existingMessage.id").isEqualTo(messageId)
203         .jsonPath("$.existingMessage.serial").isEqualTo(serialNumberExistingMessage)
204         .jsonPath("$.existingMessage.time").isEqualTo(timeExistingMessageAsString)
205         .jsonPath("$.existingMessage.user").isEqualTo(user)
206         .jsonPath("$.existingMessage.text").isEqualTo(textExistingMessage)
207         .jsonPath("$.mutatedText").isEqualTo(textMutatedMessage);
208     verify(chatRoomService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class));
209   }
210
211   @Test
212   @DisplayName("Assert expected problem-details for invalid username on PUT /put/{chatroomId}/{username}/{messageId}")
213   void testInvalidUsernameException(@Autowired WebTestClient client) throws Exception
214   {
215     // Given
216     UUID chatroomId = UUID.randomUUID();
217     String user = "Foo";
218     Long messageId = 66l;
219     Message.MessageKey key = Message.MessageKey.of(user, messageId);
220     String textMessage = "Hallo Welt";
221     ChatRoom chatRoom = new ChatRoom(
222         chatroomId,
223         "Test-ChatRoom",
224         Clock.systemDefaultZone(),
225         chatRoomService, 8);
226     when(chatHomeService.getChatRoom(anyInt(), any(UUID.class)))
227         .thenReturn(Mono.just(chatRoom));
228     when(chatRoomService.getMessage(any(Message.MessageKey.class)))
229         .thenReturn(Mono.empty());
230     // Needed for readable error-reports, in case of a bug that leads to according unwanted call
231     when(chatRoomService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class)))
232         .thenReturn(mock(Message.class));
233
234     // When
235     client
236         .put()
237         .uri(
238             "/{chatroomId}/{username}/{messageId}",
239             chatroomId,
240             user,
241             messageId)
242         .bodyValue(textMessage)
243         .accept(MediaType.APPLICATION_JSON)
244         .exchange()
245         // Then
246         .expectStatus().is4xxClientError()
247         .expectBody()
248         .jsonPath("$.type").isEqualTo("/problem/invalid-username")
249         .jsonPath("$.username").isEqualTo(user);
250     verify(chatRoomService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class));
251   }
252 }