1 package de.juplo.kafka.chat.backend;
3 import com.fasterxml.jackson.databind.ObjectMapper;
4 import de.juplo.kafka.chat.backend.api.ChatRoomInfoTo;
5 import lombok.extern.slf4j.Slf4j;
6 import org.hamcrest.BaseMatcher;
7 import org.hamcrest.Description;
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.boot.test.web.server.LocalServerPort;
13 import org.springframework.http.MediaType;
14 import org.springframework.test.annotation.DirtiesContext;
15 import org.springframework.test.web.reactive.server.WebTestClient;
16 import org.testcontainers.shaded.org.awaitility.Awaitility;
18 import java.io.IOException;
19 import java.time.Duration;
20 import java.util.UUID;
21 import java.util.concurrent.atomic.AtomicBoolean;
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.hamcrest.Matchers.endsWith;
29 public abstract class AbstractConfigurationIT
31 final static String EXISTING_CHATROOM = "5c73531c-6fc4-426c-adcb-afc5c140a0f7";
32 String NONEXISTENT_CHATROOM = "7f59ec77-832e-4a17-8d22-55ef46242c17";
38 WebTestClient webTestClient;
40 ObjectMapper objectMapper;
48 .atMost(Duration.ofSeconds(15))
54 "http://localhost:{port}/actuator/health",
57 .expectStatus().isOk()
58 .expectBody().jsonPath("$.status").isEqualTo("UP");
63 @DisplayName("Restored chat-rooms can be listed")
64 void testRestoredChatRoomsCanBeListed()
68 .atMost(Duration.ofSeconds(15))
71 AtomicBoolean existingChatRoomFound = new AtomicBoolean(false);
75 "http://localhost:{port}/list",
77 .accept(MediaType.APPLICATION_JSON)
79 .expectStatus().isOk()
80 .returnResult(ChatRoomInfoTo.class)
83 .forEach(chatRoomInfoTo ->
85 log.debug("Inspecting chat-room {}", chatRoomInfoTo);
86 if (chatRoomInfoTo.getId().equals(UUID.fromString(EXISTING_CHATROOM)))
88 log.debug("Found existing chat-room {}", chatRoomInfoTo);
89 existingChatRoomFound.set(true);
90 assertThat(chatRoomInfoTo.getName().equals("FOO"));
93 assertThat(existingChatRoomFound.get()).isTrue();
98 @DisplayName("Details as expected for restored chat-room")
99 void testRestoredChatRoomHasExpectedDetails()
103 .atMost(Duration.ofSeconds(15))
109 "http://localhost:{port}/{chatRoomId}",
112 .accept(MediaType.APPLICATION_JSON)
114 .expectStatus().isOk()
115 .expectBody().jsonPath("$.name").isEqualTo("FOO");
120 @DisplayName("Restored message from Ute has expected Text")
121 void testRestoredMessageForUteHasExpectedText()
125 .atMost(Duration.ofSeconds(15))
131 "http://localhost:{port}/{chatRoomId}/ute/1",
134 .accept(MediaType.APPLICATION_JSON)
136 .expectStatus().isOk()
137 .expectBody().jsonPath("$.text").isEqualTo("Ich bin Ute...");
142 @DisplayName("Restored message from Peter has expected Text")
143 void testRestoredMessageForPeterHasExpectedText()
147 .atMost(Duration.ofSeconds(15))
153 "http://localhost:{port}/{chatRoomId}/peter/1",
156 .accept(MediaType.APPLICATION_JSON)
158 .expectStatus().isOk()
159 .expectBody().jsonPath("$.text").isEqualTo("Hallo, ich heiße Peter!");
164 @DisplayName("A PUT-message for a non-existent chat-room yields 404 NOT FOUND")
165 void testNotFoundForPutMessageToNonExistentChatRoom()
169 .atMost(Duration.ofSeconds(15))
175 "http://localhost:{port}/{chatRoomId}/otto/66",
177 NONEXISTENT_CHATROOM)
178 .contentType(MediaType.TEXT_PLAIN)
179 .accept(MediaType.APPLICATION_JSON)
180 .bodyValue("The devil rules route 66")
182 .expectStatus().isNotFound()
184 .jsonPath("$.type").value(endsWith("/problem/unknown-chatroom"))
185 .jsonPath("$.chatroomId").isEqualTo(NONEXISTENT_CHATROOM);
190 @DisplayName("A message can be put into a newly created chat-room")
191 void testPutMessageInNewChatRoom() throws IOException
195 .atMost(Duration.ofSeconds(15))
198 // The first request creates a new chat-room
199 // It must be repeated, until a chat-room was created,
200 // that is owned by the instance
201 byte[] result = webTestClient
203 .uri("http://localhost:{port}/create", port)
204 .contentType(MediaType.TEXT_PLAIN)
206 .accept(MediaType.APPLICATION_JSON)
208 .expectStatus().isOk()
210 .jsonPath("$.id").exists()
211 .jsonPath("$.name").isEqualTo("bar")
212 .jsonPath("$.shard").value(new BaseMatcher<Integer>() {
214 public boolean matches(Object actual)
216 return actual == null
218 : actual.equals(Integer.valueOf(2));
222 public void describeTo(Description description)
224 description.appendText("shard has expected value 2, or is empty");
229 ChatRoomInfoTo chatRoomInfo = objectMapper.readValue(result, ChatRoomInfoTo.class);
230 UUID chatRoomId = chatRoomInfo.getId();
234 "http://localhost:{port}/{chatRoomId}/nerd/7",
237 .contentType(MediaType.TEXT_PLAIN)
238 .accept(MediaType.APPLICATION_JSON)
239 .bodyValue("Hello world!")
241 .expectStatus().isOk()
243 .jsonPath("$.id").isEqualTo(Integer.valueOf(7))
244 .jsonPath("$.user").isEqualTo("nerd")
245 .jsonPath("$.text").isEqualTo("Hello world!");