3e0efd34d67ebe0e459fce8038ce48d604b8e9aa
[demos/kafka/chat] / src / test / java / de / juplo / kafka / chat / backend / AbstractConfigurationIT.java
1 package de.juplo.kafka.chat.backend;
2
3 import com.fasterxml.jackson.core.type.TypeReference;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5 import de.juplo.kafka.chat.backend.api.ChatRoomInfoTo;
6 import de.juplo.kafka.chat.backend.api.MessageTo;
7 import lombok.extern.slf4j.Slf4j;
8 import org.junit.jupiter.api.BeforeEach;
9 import org.junit.jupiter.api.DisplayName;
10 import org.junit.jupiter.api.Test;
11 import org.springframework.beans.factory.annotation.Autowired;
12 import org.springframework.beans.factory.annotation.Value;
13 import org.springframework.boot.test.web.server.LocalServerPort;
14 import org.springframework.core.io.Resource;
15 import org.springframework.http.MediaType;
16 import org.springframework.test.annotation.DirtiesContext;
17 import org.springframework.test.web.reactive.server.WebTestClient;
18 import org.testcontainers.shaded.org.awaitility.Awaitility;
19 import reactor.core.publisher.Flux;
20
21 import java.io.IOException;
22 import java.time.Duration;
23 import java.util.List;
24 import java.util.UUID;
25 import java.util.concurrent.atomic.AtomicBoolean;
26
27 import static org.assertj.core.api.Assertions.assertThat;
28 import static org.hamcrest.Matchers.endsWith;
29 import static pl.rzrz.assertj.reactor.Assertions.assertThat;
30
31
32 @Slf4j
33 @DirtiesContext
34 public abstract class AbstractConfigurationIT
35 {
36   final static String EXISTING_CHATROOM = "5c73531c-6fc4-426c-adcb-afc5c140a0f7";
37   String NONEXISTENT_CHATROOM = "7f59ec77-832e-4a17-8d22-55ef46242c17";
38
39
40   @LocalServerPort
41   int port;
42   @Autowired
43   WebTestClient webTestClient;
44   @Autowired
45   ObjectMapper objectMapper;
46
47   @Value("classpath:data/files/5c73531c-6fc4-426c-adcb-afc5c140a0f7.json")
48   Resource existingChatRoomRessource;
49   MessageTo[] expectedExistingMessages;
50
51
52   @BeforeEach
53   void waitForApp() throws IOException
54   {
55     expectedExistingMessages = objectMapper
56         .readValue(
57             existingChatRoomRessource.getInputStream(),
58             new TypeReference<List<MessageTo>>() {})
59         .toArray(size -> new MessageTo[size]);
60
61     Awaitility
62         .await()
63         .atMost(Duration.ofSeconds(15))
64         .untilAsserted(() ->
65         {
66           webTestClient
67               .get()
68               .uri(
69                   "http://localhost:{port}/actuator/health",
70                   port)
71               .exchange()
72               .expectStatus().isOk()
73               .expectBody().jsonPath("$.status").isEqualTo("UP");
74         });
75   }
76
77   @Test
78   @DisplayName("Restored chat-rooms can be listed")
79   void testRestoredChatRoomsCanBeListed()
80   {
81     Awaitility
82         .await()
83         .atMost(Duration.ofSeconds(15))
84         .untilAsserted(() ->
85         {
86           AtomicBoolean existingChatRoomFound = new AtomicBoolean(false);
87           webTestClient
88               .get()
89               .uri(
90                   "http://localhost:{port}/list",
91                   port)
92               .accept(MediaType.APPLICATION_JSON)
93               .exchange()
94               .expectStatus().isOk()
95               .returnResult(ChatRoomInfoTo.class)
96               .getResponseBody()
97               .toIterable()
98               .forEach(chatRoomInfoTo ->
99               {
100                 log.debug("Inspecting chat-room {}", chatRoomInfoTo);
101                 if (chatRoomInfoTo.getId().equals(UUID.fromString(EXISTING_CHATROOM)))
102                 {
103                   log.debug("Found existing chat-room {}", chatRoomInfoTo);
104                   existingChatRoomFound.set(true);
105                   assertThat(chatRoomInfoTo.getName().equals("FOO"));
106                 }
107               });
108           assertThat(existingChatRoomFound.get()).isTrue();
109         });
110   }
111
112   @Test
113   @DisplayName("Details as expected for restored chat-room")
114   void testRestoredChatRoomHasExpectedDetails()
115   {
116     Awaitility
117         .await()
118         .atMost(Duration.ofSeconds(15))
119         .untilAsserted(() ->
120         {
121           webTestClient
122               .get()
123               .uri(
124                   "http://localhost:{port}/{chatRoomId}",
125                   port,
126                   EXISTING_CHATROOM)
127               .accept(MediaType.APPLICATION_JSON)
128               .exchange()
129               .expectStatus().isOk()
130               .expectBody().jsonPath("$.name").isEqualTo("FOO");
131         });
132   }
133
134   @Test
135   @DisplayName("Restored message from Ute has expected Text")
136   void testRestoredMessageForUteHasExpectedText()
137   {
138     Awaitility
139         .await()
140         .atMost(Duration.ofSeconds(15))
141         .untilAsserted(() ->
142         {
143           webTestClient
144               .get()
145               .uri(
146                   "http://localhost:{port}/{chatRoomId}/ute/1",
147                   port,
148                   EXISTING_CHATROOM)
149               .accept(MediaType.APPLICATION_JSON)
150               .exchange()
151               .expectStatus().isOk()
152               .expectBody().jsonPath("$.text").isEqualTo("Ich bin Ute...");
153         });
154   }
155
156   @Test
157   @DisplayName("Restored message from Peter has expected Text")
158   void testRestoredMessageForPeterHasExpectedText()
159   {
160     Awaitility
161         .await()
162         .atMost(Duration.ofSeconds(15))
163         .untilAsserted(() ->
164         {
165           webTestClient
166               .get()
167               .uri(
168                   "http://localhost:{port}/{chatRoomId}/peter/1",
169                   port,
170                   EXISTING_CHATROOM)
171               .accept(MediaType.APPLICATION_JSON)
172               .exchange()
173               .expectStatus().isOk()
174               .expectBody().jsonPath("$.text").isEqualTo("Hallo, ich heiße Peter!");
175         });
176   }
177
178   @Test
179   @DisplayName("A PUT-message for a non-existent chat-room yields 404 NOT FOUND")
180   void testNotFoundForPutMessageToNonExistentChatRoom()
181   {
182     Awaitility
183         .await()
184         .atMost(Duration.ofSeconds(15))
185         .untilAsserted(() ->
186         {
187           webTestClient
188               .put()
189               .uri(
190                   "http://localhost:{port}/{chatRoomId}/otto/66",
191                   port,
192                   NONEXISTENT_CHATROOM)
193               .contentType(MediaType.TEXT_PLAIN)
194               .accept(MediaType.APPLICATION_JSON)
195               .bodyValue("The devil rules route 66")
196               .exchange()
197               .expectStatus().isNotFound()
198               .expectBody()
199                 .jsonPath("$.type").value(endsWith("/problem/unknown-chatroom"))
200                 .jsonPath("$.chatroomId").isEqualTo(NONEXISTENT_CHATROOM);
201         });
202   }
203
204   @Test
205   @DisplayName("A message can be put into a newly created chat-room")
206   void testPutMessageInNewChatRoom() throws IOException
207   {
208     ChatRoomInfoTo chatRoomInfo;
209     do
210     {
211       // The first request creates a new chat-room
212       // It must be repeated, until a chat-room was created,
213       // that is owned by the instance
214       chatRoomInfo = webTestClient
215           .post()
216           .uri("http://localhost:{port}/create", port)
217           .contentType(MediaType.TEXT_PLAIN)
218           .bodyValue("bar")
219           .accept(MediaType.APPLICATION_JSON)
220           .exchange()
221           .returnResult(ChatRoomInfoTo.class)
222           .getResponseBody()
223           .retry(30)
224           .blockFirst();
225     }
226     while(!(chatRoomInfo.getShard() == null || chatRoomInfo.getShard().intValue() == 2));
227
228     UUID chatRoomId = chatRoomInfo.getId();
229
230     Awaitility
231         .await()
232         .atMost(Duration.ofSeconds(15))
233         .untilAsserted(() ->
234         {
235           webTestClient
236               .put()
237               .uri(
238                   "http://localhost:{port}/{chatRoomId}/nerd/7",
239                   port,
240                   chatRoomId)
241               .contentType(MediaType.TEXT_PLAIN)
242               .accept(MediaType.APPLICATION_JSON)
243               .bodyValue("Hello world!")
244               .exchange()
245               .expectStatus().isOk()
246               .expectBody()
247                 .jsonPath("$.id").isEqualTo(Integer.valueOf(7))
248                 .jsonPath("$.user").isEqualTo("nerd")
249                 .jsonPath("$.text").isEqualTo("Hello world!");
250         });
251   }
252
253   @Test
254   @DisplayName("Restored messages can be seen, when listening to restored chat-room")
255   void testListenToRestoredChatRoomYieldsRestoredMessages()
256   {
257     Awaitility
258         .await()
259         .atMost(Duration.ofSeconds(15))
260         .untilAsserted(() ->
261         {
262           Flux<MessageTo> result = webTestClient
263               .get()
264               .uri(
265                   "http://localhost:{port}/{chatRoomId}/listen",
266                   port,
267                   EXISTING_CHATROOM)
268               .accept(MediaType.TEXT_EVENT_STREAM)
269               .exchange()
270               .expectStatus().isOk()
271               .returnResult(MessageTo.class)
272               .getResponseBody();
273
274           List<MessageTo> messages = result
275               .take(expectedExistingMessages.length)
276               .collectList()
277               .block();
278           assertThat(messages).containsExactly(expectedExistingMessages);
279         });
280   }
281
282   @Test
283   @DisplayName("Newly send messages can be seen, when listening to restored chat-room")
284   void testListenToRestoredChatRoomYieldsAddedMessages()
285   {
286     MessageTo sentMessage = webTestClient
287         .put()
288         .uri(
289             "http://localhost:{port}/{chatRoomId}/nerd/7",
290             port,
291             EXISTING_CHATROOM)
292         .contentType(MediaType.TEXT_PLAIN)
293         .accept(MediaType.APPLICATION_JSON)
294         .bodyValue("Hello world!")
295         .exchange()
296         .expectStatus()
297         .isOk()
298         .returnResult(MessageTo.class)
299         .getResponseBody()
300         .next()
301         .block();
302
303     Flux<MessageTo> result = webTestClient
304         .get()
305         .uri(
306             "http://localhost:{port}/{chatRoomId}/listen",
307             port,
308             EXISTING_CHATROOM)
309         .accept(MediaType.TEXT_EVENT_STREAM)
310         .exchange()
311         .expectStatus().isOk()
312         .returnResult(MessageTo.class)
313         .getResponseBody();
314
315     assertThat(result.next().block()).isEqualTo(sentMessage);
316   }
317 }