]> juplo.de Git - demos/kafka/chat/commitdiff
test: RED - Added IT for application-startup, if no data is available
authorKai Moritz <kai@juplo.de>
Sun, 24 Mar 2024 10:35:07 +0000 (11:35 +0100)
committerKai Moritz <kai@juplo.de>
Sun, 24 Mar 2024 19:28:48 +0000 (20:28 +0100)
src/test/java/de/juplo/kafka/chat/backend/AbstractApplicationStartupIT.java [new file with mode: 0644]
src/test/java/de/juplo/kafka/chat/backend/InMemoryWithFilesAndShardingApplicationStartupIT.java [new file with mode: 0644]
src/test/java/de/juplo/kafka/chat/backend/InMemoryWithFilesApplicationStartupIT.java [new file with mode: 0644]
src/test/java/de/juplo/kafka/chat/backend/InMemoryWithMongoDbApplicationStartupIT.java [new file with mode: 0644]
src/test/java/de/juplo/kafka/chat/backend/InMemoryWithNoStorageAndShardingApplicationStartupIT.java [new file with mode: 0644]
src/test/java/de/juplo/kafka/chat/backend/KafkaApplicationStartupIT.java [new file with mode: 0644]
src/test/java/de/juplo/kafka/chat/backend/implementation/kafka/InfoChannelTest.java [new file with mode: 0644]

diff --git a/src/test/java/de/juplo/kafka/chat/backend/AbstractApplicationStartupIT.java b/src/test/java/de/juplo/kafka/chat/backend/AbstractApplicationStartupIT.java
new file mode 100644 (file)
index 0000000..e9d78f8
--- /dev/null
@@ -0,0 +1,66 @@
+package de.juplo.kafka.chat.backend;
+
+import de.juplo.kafka.chat.backend.api.ChatRoomInfoTo;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.testcontainers.shaded.org.awaitility.Awaitility;
+import reactor.core.publisher.Flux;
+
+import java.io.IOException;
+import java.time.Duration;
+
+import static pl.rzrz.assertj.reactor.Assertions.assertThat;
+
+
+@Slf4j
+public abstract class AbstractApplicationStartupIT
+{
+  @Autowired
+  WebTestClient webTestClient;
+
+
+  @Test
+  @DisplayName("Applications starts when no data is available (fresh install)")
+  void testStartup() throws IOException
+  {
+    Awaitility
+        .await()
+        .atMost(Duration.ofSeconds(15))
+        .untilAsserted(() -> webTestClient
+            .get()
+            .uri("/actuator/health")
+            .exchange()
+            .expectStatus().isOk()
+            .expectBody().jsonPath("$.status").isEqualTo("UP"));
+  }
+
+  @Test
+  @DisplayName("Chat-rooms can be listed and returns an empty list")
+  void testListChatRooms() throws IOException
+  {
+    Awaitility
+        .await()
+        .atMost(Duration.ofSeconds(15))
+        .untilAsserted(() ->
+        {
+          Flux<ChatRoomInfoTo> result = webTestClient
+              .get()
+              .uri("/list")
+              .accept(MediaType.APPLICATION_JSON)
+              .exchange()
+              .expectStatus().isOk()
+              .returnResult(ChatRoomInfoTo.class)
+              .getResponseBody()
+              .doOnNext(chatRoomInfoTo ->
+              {
+                log.debug("Found chat-room {}", chatRoomInfoTo);
+              });
+
+          assertThat(result).emitsExactly();
+        });
+  }
+}
diff --git a/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithFilesAndShardingApplicationStartupIT.java b/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithFilesAndShardingApplicationStartupIT.java
new file mode 100644 (file)
index 0000000..3b8b091
--- /dev/null
@@ -0,0 +1,15 @@
+package de.juplo.kafka.chat.backend;
+
+import org.springframework.boot.test.context.SpringBootTest;
+
+
+@SpringBootTest(
+    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+    properties = {
+        "chat.backend.inmemory.storage-strategy=files",
+        "chat.backend.inmemory.sharding-strategy=kafkalike",
+        "chat.backend.inmemory.num-shards=10",
+        "chat.backend.inmemory.owned-shards=2" })
+class InMemoryWithFilesAndShardingApplicationStartupIT extends AbstractApplicationStartupIT
+{
+}
diff --git a/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithFilesApplicationStartupIT.java b/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithFilesApplicationStartupIT.java
new file mode 100644 (file)
index 0000000..8c88292
--- /dev/null
@@ -0,0 +1,13 @@
+package de.juplo.kafka.chat.backend;
+
+import org.springframework.boot.test.context.SpringBootTest;
+
+
+@SpringBootTest(
+               webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+               properties = {
+                               "chat.backend.inmemory.sharding-strategy=none",
+                               "chat.backend.inmemory.storage-strategy=files" })
+class InMemoryWithFilesApplicationStartupIT extends AbstractApplicationStartupIT
+{
+}
diff --git a/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithMongoDbApplicationStartupIT.java b/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithMongoDbApplicationStartupIT.java
new file mode 100644 (file)
index 0000000..234cb3f
--- /dev/null
@@ -0,0 +1,44 @@
+package de.juplo.kafka.chat.backend;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.BeforeEach;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.BindMode;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+
+@SpringBootTest(
+               webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+               properties = {
+                               "spring.data.mongodb.host=localhost",
+                               "spring.data.mongodb.database=test",
+                               "chat.backend.inmemory.sharding-strategy=none",
+                               "chat.backend.inmemory.storage-strategy=mongodb" })
+@Testcontainers
+@Slf4j
+class InMemoryWithMongoDbApplicationStartupIT extends AbstractApplicationStartupIT
+{
+       private static final int MONGODB_PORT = 27017;
+
+       @Container
+       private static final GenericContainer CONTAINER =
+                       new GenericContainer("mongo:6").withExposedPorts(MONGODB_PORT);
+
+       @DynamicPropertySource
+       static void addMongoPortProperty(DynamicPropertyRegistry registry)
+       {
+               registry.add("spring.data.mongodb.port", () -> CONTAINER.getMappedPort(MONGODB_PORT));
+       }
+
+       @BeforeEach
+       void setUpLogging()
+       {
+               Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log);
+               CONTAINER.followOutput(logConsumer);
+       }
+}
diff --git a/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithNoStorageAndShardingApplicationStartupIT.java b/src/test/java/de/juplo/kafka/chat/backend/InMemoryWithNoStorageAndShardingApplicationStartupIT.java
new file mode 100644 (file)
index 0000000..9832c28
--- /dev/null
@@ -0,0 +1,15 @@
+package de.juplo.kafka.chat.backend;
+
+import org.springframework.boot.test.context.SpringBootTest;
+
+
+@SpringBootTest(
+    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+    properties = {
+        "chat.backend.inmemory.storage-strategy=none",
+        "chat.backend.inmemory.sharding-strategy=kafkalike",
+        "chat.backend.inmemory.num-shards=10",
+        "chat.backend.inmemory.owned-shards=2" })
+class InMemoryWithNoStorageAndShardingApplicationStartupIT extends AbstractApplicationStartupIT
+{
+}
diff --git a/src/test/java/de/juplo/kafka/chat/backend/KafkaApplicationStartupIT.java b/src/test/java/de/juplo/kafka/chat/backend/KafkaApplicationStartupIT.java
new file mode 100644 (file)
index 0000000..27fcd11
--- /dev/null
@@ -0,0 +1,31 @@
+package de.juplo.kafka.chat.backend;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+
+import static de.juplo.kafka.chat.backend.KafkaApplicationStartupIT.DATA_TOPIC;
+import static de.juplo.kafka.chat.backend.KafkaApplicationStartupIT.INFO_TOPIC;
+
+
+@SpringBootTest(
+    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+    properties = {
+        "spring.main.allow-bean-definition-overriding=true",
+        "chat.backend.services=kafka",
+        "chat.backend.kafka.client-id-PREFIX=TEST",
+        "chat.backend.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}",
+        "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}",
+        "chat.backend.kafka.info-channel-topic=" + INFO_TOPIC,
+        "chat.backend.kafka.data-channel-topic=" + DATA_TOPIC,
+        "chat.backend.kafka.num-partitions=10",
+        })
+@EmbeddedKafka(
+    topics = { INFO_TOPIC, DATA_TOPIC },
+    partitions = 10)
+@Slf4j
+class KafkaApplicationStartupIT extends AbstractApplicationStartupIT
+{
+  final static String INFO_TOPIC = "KAFKA_APPLICATION_STARTUP_IT_INFO_CHANNEL";
+  final static String DATA_TOPIC = "KAFKA_APPLICATION_STARTUP_IT_DATA_CHANNEL";
+}
diff --git a/src/test/java/de/juplo/kafka/chat/backend/implementation/kafka/InfoChannelTest.java b/src/test/java/de/juplo/kafka/chat/backend/implementation/kafka/InfoChannelTest.java
new file mode 100644 (file)
index 0000000..c651a5b
--- /dev/null
@@ -0,0 +1,109 @@
+package de.juplo.kafka.chat.backend.implementation.kafka;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import de.juplo.kafka.chat.backend.ChatBackendProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.common.TopicPartition;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
+import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.util.List;
+
+import static de.juplo.kafka.chat.backend.domain.ChatHomeServiceWithShardsTest.NUM_SHARDS;
+import static de.juplo.kafka.chat.backend.implementation.kafka.InfoChannelTest.DATA_TOPIC;
+import static de.juplo.kafka.chat.backend.implementation.kafka.InfoChannelTest.INFO_TOPIC;
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+@SpringJUnitConfig(classes = {
+    KafkaAutoConfiguration.class,
+    TaskExecutionAutoConfiguration.class,
+    KafkaServicesConfiguration.class,
+    InfoChannelTest.InfoChannelTestConfiguration.class
+})
+@EnableConfigurationProperties(ChatBackendProperties.class)
+@TestPropertySource(properties = {
+    "chat.backend.services=kafka",
+    "chat.backend.kafka.client-id-PREFIX=TEST",
+    "chat.backend.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}",
+    "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}",
+    "chat.backend.kafka.info-channel-topic=" + INFO_TOPIC,
+    "chat.backend.kafka.data-channel-topic=" + DATA_TOPIC,
+    "chat.backend.kafka.num-partitions=" + NUM_SHARDS,
+})
+@EmbeddedKafka(
+    topics = { INFO_TOPIC, DATA_TOPIC },
+    partitions = NUM_SHARDS)
+@Slf4j
+public class InfoChannelTest
+{
+  final static String INFO_TOPIC = "INFO_CHANNEL_TEST_INFO";
+  final static String DATA_TOPIC = "INFO_CHANNEL_TEST_DATA";
+
+
+  @Autowired
+  InfoChannel infoChannel;
+
+
+  @Test
+  @DisplayName("The loading completes, if the topic is empty")
+  void testLoadingCompletesIfTopicEmpty()
+  {
+    Awaitility
+        .await()
+        .atMost(Duration.ofSeconds(15))
+        .untilAsserted(() -> assertThat(infoChannel.getChannelState()).isEqualTo(ChannelState.READY));
+  }
+
+
+  static class InfoChannelTestConfiguration
+  {
+    @Bean
+    WorkAssignor infoChannelWorkAssignor()
+    {
+      return consumer ->
+      {
+        List<TopicPartition> partitions = consumer
+            .partitionsFor(INFO_TOPIC)
+            .stream()
+            .map(partitionInfo -> new TopicPartition(INFO_TOPIC, partitionInfo.partition()))
+            .toList();
+        consumer.assign(partitions);
+      };
+    }
+
+    @Bean
+    WorkAssignor dataChannelWorkAssignor()
+    {
+      return consumer -> log.info("No work is assigned to the DataChannel!");
+    }
+
+    @Bean
+    ObjectMapper objectMapper()
+    {
+      ObjectMapper objectMapper = new ObjectMapper();
+      objectMapper.registerModule(new JavaTimeModule());
+      return objectMapper;
+    }
+
+    @Bean
+    Clock clock()
+    {
+      return Clock.systemDefaultZone();
+    }
+  }
+}