X-Git-Url: http://juplo.de/gitweb/?a=blobdiff_plain;f=src%2Ftest%2Fjava%2Fde%2Fjuplo%2Fkafka%2Fchat%2Fbackend%2Fapi%2FChatBackendControllerTest.java;h=f66be45912b792b2664919849e079eff9f46404b;hb=8837fa6b1caed563ef8fb1929e8d66609477153c;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..f66be459 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,8 @@ 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 lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -14,19 +16,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,7 +50,7 @@ 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 @@ -55,7 +70,7 @@ 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 @@ -74,7 +89,7 @@ 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()); @@ -100,7 +115,7 @@ 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()); @@ -125,7 +140,7 @@ 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 @@ -152,10 +167,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 +195,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 +223,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 +243,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 +263,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()); + } }