From 682925718dde4f9e778cf949fa8e4d850a082bf5 Mon Sep 17 00:00:00 2001 From: Kai Moritz Date: Mon, 18 Mar 2024 08:31:39 +0100 Subject: [PATCH] test: RED - Expectations for `HaproxyDataPlaneApiShardingPublischerStrategy` --- pom.xml | 12 ++ ...DataPlaneApiShardingPublisherStrategy.java | 31 ++++ ...PlaneApiShardingPublisherStrategyTest.java | 147 ++++++++++++++++++ .../implementation/haproxy/maps__get.json | 7 + .../haproxy/maps_entries__4__put.json | 4 + .../haproxy/maps_entries__4__put__error.json | 5 + 6 files changed, 206 insertions(+) create mode 100644 src/main/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategy.java create mode 100644 src/test/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategyTest.java create mode 100644 src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps__get.json create mode 100644 src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put.json create mode 100644 src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put__error.json diff --git a/pom.xml b/pom.xml index 13a0e7c6..50310cf3 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ 17 1.0.8 + 0.3.3 @@ -100,6 +101,17 @@ spring-kafka-test test + + com.squareup.okhttp3 + mockwebserver + test + + + io.hosuaby + inject-resources-junit-jupiter + ${inject-resources-junit-jupiter.version} + test + diff --git a/src/main/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategy.java b/src/main/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategy.java new file mode 100644 index 00000000..949104a6 --- /dev/null +++ b/src/main/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategy.java @@ -0,0 +1,31 @@ +package de.juplo.kafka.chat.backend.implementation.haproxy; + +import de.juplo.kafka.chat.backend.domain.ShardingPublisherStrategy; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + + +@Slf4j +public class HaproxyDataPlaneApiShardingPublisherStrategy implements ShardingPublisherStrategy +{ + @Getter + private final int mapId; + + + public HaproxyDataPlaneApiShardingPublisherStrategy( + WebClient webClient, + String mapPath, + String instanceId) + { + this.mapId = 0; + } + + + @Override + public Mono publishOwnership(int shard) + { + return Mono.empty(); + } +} diff --git a/src/test/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategyTest.java b/src/test/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategyTest.java new file mode 100644 index 00000000..87f707e5 --- /dev/null +++ b/src/test/java/de/juplo/kafka/chat/backend/implementation/haproxy/HaproxyDataPlaneApiShardingPublisherStrategyTest.java @@ -0,0 +1,147 @@ +package de.juplo.kafka.chat.backend.implementation.haproxy; + +import com.adelean.inject.resources.junit.jupiter.GivenTextResource; +import com.adelean.inject.resources.junit.jupiter.TestWithResources; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + + +@TestWithResources +public class HaproxyDataPlaneApiShardingPublisherStrategyTest +{ + final static String MAP_PATH = "/usr/local/etc/haproxy/sharding.map"; + final static String INSTANCE_ID = "backend_3"; + final static int SHARD = 4; + + + MockWebServer mockHaproxy; + WebClient webClient; + + @GivenTextResource("de/juplo/kafka/chat/backend/implementation/haproxy/maps__get.json") + String maps__get; + @GivenTextResource("de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put.json") + String maps_entries__4__put; + @GivenTextResource("de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put__error.json") + String maps_entries__4__put__error; + + + @BeforeEach + void setUp() throws IOException + { + mockHaproxy = new MockWebServer(); + mockHaproxy.start(); + webClient = WebClient + .builder() + .baseUrl(String.format("http://localhost:%s/v2", mockHaproxy.getPort())) + .build(); + } + + @AfterEach + void tearDown() throws IOException + { + mockHaproxy.shutdown(); + } + + + @DisplayName("Requests the available maps from HAProxy via the expected path on instanciation") + @Test + void testRequestsMapsFromHaproxyViaTheExpectedPathOnInstanciation() throws InterruptedException + { + // Given + mockHaproxy.enqueue(new MockResponse() + .setStatus("HTTP/1.1 200 OK") + .setBody(maps__get) + .addHeader("Content-Type", "application/json")); + + // When + HaproxyDataPlaneApiShardingPublisherStrategy shardingPublisherStrategy = + new HaproxyDataPlaneApiShardingPublisherStrategy(webClient, MAP_PATH, INSTANCE_ID); + + // Then + RecordedRequest recordedRequest = mockHaproxy.takeRequest(1l, TimeUnit.SECONDS); + assertThat(recordedRequest.getPath()) + .isEqualTo("/v2/services/haproxy/runtime/maps?include_unmanaged=true"); + } + + @DisplayName("Detects the expected map-ID on instanciation") + @Test + void testDetectsExpectedIdForMapOnInstanciation() + { + // Given + mockHaproxy.enqueue(new MockResponse() + .setStatus("HTTP/1.1 200 OK") + .setBody(maps__get) + .addHeader("Content-Type", "application/json")); + + // When + HaproxyDataPlaneApiShardingPublisherStrategy shardingPublisherStrategy = + new HaproxyDataPlaneApiShardingPublisherStrategy(webClient, MAP_PATH, INSTANCE_ID); + + // Then + assertThat(shardingPublisherStrategy.getMapId()) + .isEqualTo(4); + } + + @DisplayName("The expected result is yielded on successful publishing") + @Test + void testExpectedResultOnSuccessfulPublishing() + { + // Given + mockHaproxy.enqueue(new MockResponse() + .setStatus("HTTP/1.1 200 OK") + .setBody(maps__get) + .addHeader("Content-Type", "application/json")); + mockHaproxy.enqueue(new MockResponse() + .setStatus("HTTP/1.1 200 OK") + .setBody(maps_entries__4__put) + .addHeader("Content-Type", "application/json")); + + // When + HaproxyDataPlaneApiShardingPublisherStrategy shardingPublisherStrategy = + new HaproxyDataPlaneApiShardingPublisherStrategy(webClient, MAP_PATH, INSTANCE_ID); + Mono result = shardingPublisherStrategy.publishOwnership(SHARD); + + // Then + assertThat(result.block(Duration.ofSeconds(1))) + .isEqualTo(INSTANCE_ID); + } + + @DisplayName("The expected error is raised on failed publishing") + @Test + void testExpectedResultOnFailedPublishing() + { + // Given + mockHaproxy.enqueue(new MockResponse() + .setStatus("HTTP/1.1 200 OK") + .setBody(maps__get) + .addHeader("Content-Type", "application/json")); + mockHaproxy.enqueue(new MockResponse() + .setStatus("HTTP/1.1 400 Bad Request") + .setBody(maps_entries__4__put__error) + .addHeader("Content-Type", "application/json")); + + // When + HaproxyDataPlaneApiShardingPublisherStrategy shardingPublisherStrategy = + new HaproxyDataPlaneApiShardingPublisherStrategy(webClient, MAP_PATH, INSTANCE_ID); + Mono result = shardingPublisherStrategy + .publishOwnership(SHARD) + .onErrorResume(throwable -> Mono.just(throwable.getMessage())); + + // Then + assertThat(result.block(Duration.ofSeconds(1))) + .isEqualTo("Evil Error -- BOOM!"); + } +} diff --git a/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps__get.json b/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps__get.json new file mode 100644 index 00000000..a02728bd --- /dev/null +++ b/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps__get.json @@ -0,0 +1,7 @@ +[ + { + "description": "pattern loaded from file '/usr/local/etc/haproxy/sharding.map' used by map at file '/usr/local/etc/haproxy/haproxy.cfg' line 27. curr_ver=0 next_ver=0 entry_cnt=10", + "file": "/usr/local/etc/haproxy/sharding.map", + "id": "4" + } +] diff --git a/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put.json b/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put.json new file mode 100644 index 00000000..3409ea3c --- /dev/null +++ b/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put.json @@ -0,0 +1,4 @@ +{ + "key": "4", + "value": "backend_3" +} diff --git a/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put__error.json b/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put__error.json new file mode 100644 index 00000000..11a0e7f6 --- /dev/null +++ b/src/test/resources/de/juplo/kafka/chat/backend/implementation/haproxy/maps_entries__4__put__error.json @@ -0,0 +1,5 @@ +{ + "code": 666, + "message": "Evil Error -- BOOM!", + "any-key": "Some additional information" +} -- 2.20.1