X-Git-Url: https://juplo.de/gitweb/?a=blobdiff_plain;f=src%2Ftest%2Fjava%2Fde%2Fjuplo%2Fkafka%2Fchat%2Fbackend%2Fapi%2FChatBackendControllerTest.java;h=32b1e3578a02206b670e8d049231fee0aa92bad3;hb=e9a4bf3c31d504611fba0cc0be4a1e04812e2c65;hp=b3504d2e5f3e25945888a00d84cb77e096681608;hpb=9d61871563f4be4850cebca4fad0545d504522c3;p=demos%2Fkafka%2Fchat diff --git a/src/test/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerTest.java b/src/test/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerTest.java index b3504d2e..32b1e357 100644 --- a/src/test/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerTest.java +++ b/src/test/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerTest.java @@ -1,6 +1,9 @@ package de.juplo.kafka.chat.backend.api; +import de.juplo.kafka.chat.backend.ChatBackendProperties; import de.juplo.kafka.chat.backend.domain.*; +import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatHomeService; +import de.juplo.kafka.chat.backend.persistence.inmemory.ShardingStrategy; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -14,19 +17,32 @@ import reactor.core.publisher.Mono; import java.time.Clock; import java.time.LocalDateTime; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -@SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true") +@SpringBootTest(properties = { + "spring.main.allow-bean-definition-overriding=true", + "chat.backend.inmemory.sharding-strategy=kafkalike", + "chat.backend.inmemory.num-shards=10", + "chat.backend.inmemory.owned-shards=6", + }) @AutoConfigureWebTestClient @Slf4j public class ChatBackendControllerTest { + @Autowired + ChatBackendProperties properties; + @Autowired + ShardingStrategy shardingStrategy; + @MockBean - ChatHomeService chatHomeService; + InMemoryChatHomeService chatHomeService; @MockBean ChatRoomService chatRoomService; @@ -35,8 +51,9 @@ public class ChatBackendControllerTest void testUnknownChatroomExceptionForListChatroom(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + when(chatHomeService.getOwnedShards()).thenReturn(new int[] { 6 }); // When WebTestClient.ResponseSpec responseSpec = client @@ -55,8 +72,9 @@ public class ChatBackendControllerTest void testUnknownChatroomExceptionForGetChatroom(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + when(chatHomeService.getOwnedShards()).thenReturn(new int[] { 6 }); // When WebTestClient.ResponseSpec responseSpec = client @@ -74,10 +92,11 @@ public class ChatBackendControllerTest void testUnknownChatroomExceptionForPutMessage(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); String username = "foo"; Long messageId = 66l; when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + when(chatHomeService.getOwnedShards()).thenReturn(new int[] { 6 }); // When WebTestClient.ResponseSpec responseSpec = client @@ -100,10 +119,11 @@ public class ChatBackendControllerTest void testUnknownChatroomExceptionForGetMessage(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); String username = "foo"; Long messageId = 66l; when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + when(chatHomeService.getOwnedShards()).thenReturn(new int[] { 6 }); // When WebTestClient.ResponseSpec responseSpec = client @@ -125,8 +145,9 @@ public class ChatBackendControllerTest void testUnknownChatroomExceptionForListenChatroom(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + when(chatHomeService.getOwnedShards()).thenReturn(new int[] { 6 }); // When WebTestClient.ResponseSpec responseSpec = client @@ -152,10 +173,10 @@ public class ChatBackendControllerTest @Test @DisplayName("Assert expected problem-details for message mutation on PUT /put/{chatroomId}/{username}/{messageId}") - void testMessageMutationException(@Autowired WebTestClient client) throws Exception + void testMessageMutationException(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); String user = "foo"; Long messageId = 66l; Message.MessageKey key = Message.MessageKey.of(user, messageId); @@ -180,7 +201,7 @@ public class ChatBackendControllerTest .thenReturn(Mono.just(existingMessage)); // Needed for readable error-reports, in case of a bug that leads to according unwanted call when(chatRoomService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class))) - .thenReturn(mock(Message.class)); + .thenReturn(Mono.just(mock(Message.class))); // When client @@ -208,10 +229,10 @@ public class ChatBackendControllerTest @Test @DisplayName("Assert expected problem-details for invalid username on PUT /put/{chatroomId}/{username}/{messageId}") - void testInvalidUsernameException(@Autowired WebTestClient client) throws Exception + void testInvalidUsernameException(@Autowired WebTestClient client) { // Given - UUID chatroomId = UUID.randomUUID(); + UUID chatroomId = getRandomIdForOwnedShard(); String user = "Foo"; Long messageId = 66l; Message.MessageKey key = Message.MessageKey.of(user, messageId); @@ -228,7 +249,7 @@ public class ChatBackendControllerTest .thenReturn(Mono.empty()); // Needed for readable error-reports, in case of a bug that leads to according unwanted call when(chatRoomService.persistMessage(any(Message.MessageKey.class), any(LocalDateTime.class), any(String.class))) - .thenReturn(mock(Message.class)); + .thenReturn(Mono.just(mock(Message.class))); // When client @@ -248,4 +269,157 @@ public class ChatBackendControllerTest .jsonPath("$.username").isEqualTo(user); verify(chatRoomService, never()).persistMessage(eq(key), any(LocalDateTime.class), any(String.class)); } + + @Test + @DisplayName("Assert expected problem-details for not owned shard on GET /{chatroomId}") + void testShardNotOwnedExceptionForGetChatroom(@Autowired WebTestClient client) + { + // Given + UUID chatroomId = getRandomIdForForeignShard(); + + // When + WebTestClient.ResponseSpec responseSpec = client + .get() + .uri("/{chatroomId}", chatroomId) + .accept(MediaType.APPLICATION_JSON) + .exchange(); + + // Then + assertProblemDetailsForShardNotOwnedException(responseSpec, shardingStrategy.selectShard(chatroomId)); + } + + @Test + @DisplayName("Assert expected problem-details for not owned shard on GET /list/{chatroomId}") + void testShardNotOwnedExceptionForListChatroom(@Autowired WebTestClient client) + { + // Given + UUID chatroomId = getRandomIdForForeignShard(); + + // When + WebTestClient.ResponseSpec responseSpec = client + .get() + .uri("/{chatroomId}/list", chatroomId) + .accept(MediaType.APPLICATION_JSON) + .exchange(); + + // Then + assertProblemDetailsForShardNotOwnedException(responseSpec, shardingStrategy.selectShard(chatroomId)); + } + + @Test + @DisplayName("Assert expected problem-details for now owned shard on PUT /put/{chatroomId}/{username}/{messageId}") + void testShardNotOwnedExceptionForPutMessage(@Autowired WebTestClient client) + { + // Given + UUID chatroomId = getRandomIdForForeignShard(); + String username = "foo"; + Long messageId = 66l; + when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + + // When + WebTestClient.ResponseSpec responseSpec = client + .put() + .uri( + "/{chatroomId}/{username}/{messageId}", + chatroomId, + username, + messageId) + .bodyValue("bar") + .accept(MediaType.APPLICATION_JSON) + .exchange(); + + // Then + assertProblemDetailsForShardNotOwnedException(responseSpec, shardingStrategy.selectShard(chatroomId)); + } + + @Test + @DisplayName("Assert expected problem-details for not owned shard on GET /get/{chatroomId}/{username}/{messageId}") + void testShardNotOwnedExceptionForGetMessage(@Autowired WebTestClient client) + { + // Given + UUID chatroomId = getRandomIdForForeignShard(); + String username = "foo"; + Long messageId = 66l; + when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + + // When + WebTestClient.ResponseSpec responseSpec = client + .get() + .uri( + "/{chatroomId}/{username}/{messageId}", + chatroomId, + username, + messageId) + .accept(MediaType.APPLICATION_JSON) + .exchange(); + + // Then + assertProblemDetailsForShardNotOwnedException(responseSpec, shardingStrategy.selectShard(chatroomId)); + } + + @Test + @DisplayName("Assert expected problem-details for not owned shard on GET /listen/{chatroomId}") + void testShardNotOwnedExceptionForListenChatroom(@Autowired WebTestClient client) + { + // Given + UUID chatroomId = getRandomIdForForeignShard(); + when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty()); + + // When + WebTestClient.ResponseSpec responseSpec = client + .get() + .uri("/{chatroomId}/listen", chatroomId) + // .accept(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_JSON) << TODO: Does not work! + .exchange(); + + // Then + assertProblemDetailsForShardNotOwnedException(responseSpec, shardingStrategy.selectShard(chatroomId)); + } + + private void assertProblemDetailsForShardNotOwnedException( + WebTestClient.ResponseSpec responseSpec, + int shard) + { + responseSpec + .expectStatus().isNotFound() + .expectBody() + .jsonPath("$.type").isEqualTo("/problem/shard-not-owned") + .jsonPath("$.shard").isEqualTo(shard); + } + + private UUID getRandomIdForOwnedShard() + { + Set ownedShards = ownedShards(); + UUID randomId; + + do + { + randomId = UUID.randomUUID(); + } + while (!ownedShards.contains(shardingStrategy.selectShard(randomId))); + + return randomId; + } + + private UUID getRandomIdForForeignShard() + { + Set ownedShards = ownedShards(); + UUID randomId; + + do + { + randomId = UUID.randomUUID(); + } + while (ownedShards.contains(shardingStrategy.selectShard(randomId))); + + return randomId; + } + + private Set ownedShards() + { + return IntStream + .of(properties.getInmemory().getOwnedShards()) + .mapToObj(shard -> Integer.valueOf(shard)) + .collect(Collectors.toSet()); + } }