From 11eb0b6030d2cd4e6537310420c7aebe075524c4 Mon Sep 17 00:00:00 2001 From: Cara Fisher Date: Tue, 21 Nov 2023 11:53:24 +0000 Subject: [PATCH] SLVUU-90: Add not blank constraints to name, group, and user in BaseMetadata --- .../dto/request/LayoutRequestDto.java | 8 +- .../dto/request/MetadataRequestDto.java | 2 + .../vuu/layoutserver/model/BaseMetadata.java | 8 +- .../integration/LayoutIntegrationTest.java | 471 +++++++++++------- 4 files changed, 315 insertions(+), 174 deletions(-) diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java index d1aa93157..fa85a6a98 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java @@ -1,19 +1,21 @@ package org.finos.vuu.layoutserver.dto.request; import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.Data; - +import javax.validation.Valid; import javax.validation.constraints.NotNull; +import lombok.Data; @Data public class LayoutRequestDto { /** - * The definition of the layout as an arbitrary JSON structure, describing all required components + * The definition of the layout as an arbitrary JSON structure, describing all required + * components */ @NotNull(message = "Definition must not be null") private ObjectNode definition; @NotNull(message = "Metadata must not be null") + @Valid private MetadataRequestDto metadata; } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java index abbf99430..e3528e6fe 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java @@ -1,6 +1,7 @@ package org.finos.vuu.layoutserver.dto.request; import com.fasterxml.jackson.annotation.JsonUnwrapped; +import javax.validation.Valid; import lombok.Data; import org.finos.vuu.layoutserver.model.BaseMetadata; @@ -8,5 +9,6 @@ public class MetadataRequestDto { @JsonUnwrapped + @Valid BaseMetadata baseMetadata; } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java index 2500eb247..a4f134856 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java @@ -1,19 +1,23 @@ package org.finos.vuu.layoutserver.model; -import lombok.Data; - import javax.persistence.Embeddable; import javax.persistence.Lob; +import javax.validation.constraints.NotBlank; +import lombok.Data; @Data @Embeddable public class BaseMetadata { + @NotBlank(message = "Name is required") private String name; + + @NotBlank(message = "Group is required") private String group; @Lob private String screenshot; + @NotBlank(message = "User is required") private String user; } diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java index 94eedc8e3..9e68f2707 100644 --- a/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java @@ -1,7 +1,20 @@ package org.finos.vuu.layoutserver.integration; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.iterableWithSize; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; +import java.util.Map; +import java.util.UUID; import org.finos.vuu.layoutserver.dto.request.LayoutRequestDto; import org.finos.vuu.layoutserver.dto.request.MetadataRequestDto; import org.finos.vuu.layoutserver.model.BaseMetadata; @@ -12,6 +25,9 @@ import org.finos.vuu.layoutserver.utils.ObjectNodeConverter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -20,20 +36,6 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; -import java.util.Map; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.iterableWithSize; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @ActiveProfiles("test") @@ -45,7 +47,8 @@ public class LayoutIntegrationTest { private static final String DEFAULT_LAYOUT_GROUP = "Default layout group"; private static final String DEFAULT_LAYOUT_SCREENSHOT = "Default layout screenshot"; private static final String DEFAULT_LAYOUT_USER = "Default layout user"; - private static final UUID DEFAULT_LAYOUT_ID = UUID.fromString("00000000-0000-0000-0000-000000000000"); + private static final UUID DEFAULT_LAYOUT_ID = UUID.fromString( + "00000000-0000-0000-0000-000000000000"); private final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectNodeConverter objectNodeConverter = new ObjectNodeConverter(); @@ -68,20 +71,21 @@ void getLayout_validIDAndLayoutExists_returns200WithLayout() throws Exception { Layout layout = createDefaultLayoutInDatabase(); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); - Map definition = objectMapper.convertValue(layout.getDefinition(), Map.class); + Map definition = objectMapper.convertValue(layout.getDefinition(), + Map.class); mockMvc.perform(get("/layouts/{id}", layout.getId())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.definition", - is(definition))) - .andExpect(jsonPath("$.metadata.name", - is(layout.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$.metadata.group", - is(layout.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$.metadata.screenshot", - is(layout.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$.metadata.user", - is(layout.getMetadata().getBaseMetadata().getUser()))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.definition", + is(definition))) + .andExpect(jsonPath("$.metadata.name", + is(layout.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$.metadata.group", + is(layout.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$.metadata.screenshot", + is(layout.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$.metadata.user", + is(layout.getMetadata().getBaseMetadata().getUser()))); } @Test @@ -96,12 +100,13 @@ void getLayout_invalidId_returns400() throws Exception { String layoutID = "invalidUUID"; mockMvc.perform(get("/layouts/{id}", layoutID)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", - contains("Failed to convert value of type 'java.lang.String' to required type 'java.util" - + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " - + "UUID string: invalidUUID"))); + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", + contains( + "Failed to convert value of type 'java.lang.String' to required type 'java.util" + + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " + + "UUID string: invalidUUID"))); } @Test @@ -110,15 +115,15 @@ void getMetadata_singleMetadataExists_returnsMetadata() throws Exception { assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); mockMvc.perform(get("/layouts/metadata")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].name", - is(layout.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$[0].group", - is(layout.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$[0].screenshot", - is(layout.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$[0].user", - is(layout.getMetadata().getBaseMetadata().getUser()))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].name", + is(layout.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$[0].group", + is(layout.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$[0].screenshot", + is(layout.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$[0].user", + is(layout.getMetadata().getBaseMetadata().getUser()))); } @Test @@ -127,7 +132,8 @@ void getMetadata_multipleMetadataExists_returnsAllMetadata() throws Exception { UUID layout2Id = UUID.randomUUID(); Layout layout1 = createLayoutWithIdInDatabase(layout1Id); Layout layout2 = createLayoutWithIdInDatabase(layout2Id); - layout2.setDefinition(objectNodeConverter.convertToEntityAttribute(UPDATED_LAYOUT_DEFINITION_STRING)); + layout2.setDefinition( + objectNodeConverter.convertToEntityAttribute(UPDATED_LAYOUT_DEFINITION_STRING)); layout2.getMetadata().getBaseMetadata().setName("Different name"); layout2.getMetadata().getBaseMetadata().setGroup("Different group"); layout2.getMetadata().getBaseMetadata().setScreenshot("Different screenshot"); @@ -138,60 +144,61 @@ void getMetadata_multipleMetadataExists_returnsAllMetadata() throws Exception { assertThat(layoutRepository.findById(layout2.getId()).orElseThrow()).isEqualTo(layout2); mockMvc.perform(get("/layouts/metadata")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].name", - is(layout1.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$[0].group", - is(layout1.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$[0].screenshot", - is(layout1.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$[0].user", - is(layout1.getMetadata().getBaseMetadata().getUser()))) - .andExpect(jsonPath("$[1].name", - is(layout2.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$[1].group", - is(layout2.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$[1].screenshot", - is(layout2.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$[1].user", - is(layout2.getMetadata().getBaseMetadata().getUser()))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].name", + is(layout1.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$[0].group", + is(layout1.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$[0].screenshot", + is(layout1.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$[0].user", + is(layout1.getMetadata().getBaseMetadata().getUser()))) + .andExpect(jsonPath("$[1].name", + is(layout2.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$[1].group", + is(layout2.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$[1].screenshot", + is(layout2.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$[1].user", + is(layout2.getMetadata().getBaseMetadata().getUser()))); } @Test void getMetadata_metadataDoesNotExist_returnsEmptyList() throws Exception { mockMvc.perform(get("/layouts/metadata")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$").isEmpty()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isEmpty()); } @Test void createLayout_validRequest_returnsCreatedLayoutAndLayoutIsPersisted() - throws Exception { + throws Exception { LayoutRequestDto layoutRequest = createValidLayoutRequest(); - Map definition = objectMapper.convertValue(layoutRequest.getDefinition(), Map.class); + Map definition = objectMapper.convertValue(layoutRequest.getDefinition(), + Map.class); MvcResult result = mockMvc.perform(post("/layouts") - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isCreated()) - .andExpect(jsonPath("$.id").isNotEmpty()) - .andExpect(jsonPath("$.definition", is(definition))) - .andExpect(jsonPath("$.metadata.name", - is(layoutRequest.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$.metadata.group", - is(layoutRequest.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$.metadata.screenshot", - is(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$.metadata.user", - is(layoutRequest.getMetadata().getBaseMetadata().getUser()))) - .andReturn(); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").isNotEmpty()) + .andExpect(jsonPath("$.definition", is(definition))) + .andExpect(jsonPath("$.metadata.name", + is(layoutRequest.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$.metadata.group", + is(layoutRequest.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$.metadata.screenshot", + is(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$.metadata.user", + is(layoutRequest.getMetadata().getBaseMetadata().getUser()))) + .andReturn(); UUID createdLayoutId = UUID.fromString( - JsonPath.read(result.getResponse().getContentAsString(), "$.id")); + JsonPath.read(result.getResponse().getContentAsString(), "$.id")); Layout createdLayout = layoutRepository.findById(createdLayoutId).orElseThrow(); Metadata createdMetadata = metadataRepository.findById(createdLayout.getMetadata().getId()) - .orElseThrow(); + .orElseThrow(); // Check that the one-to-one relationship isn't causing duplicate/unexpected entries in // the DB @@ -199,29 +206,29 @@ void createLayout_validRequest_returnsCreatedLayoutAndLayoutIsPersisted() assertThat(metadataRepository.findAll()).containsExactly(createdMetadata); assertThat(createdLayout.getDefinition()) - .isEqualTo(layoutRequest.getDefinition()); + .isEqualTo(layoutRequest.getDefinition()); assertThat(createdMetadata.getBaseMetadata().getName()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); assertThat(createdMetadata.getBaseMetadata().getGroup()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); assertThat(createdMetadata.getBaseMetadata().getScreenshot()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); assertThat(createdMetadata.getBaseMetadata().getUser()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); } @Test void createLayout_invalidRequestBodyDefinitionsIsNull_returns400AndDoesNotCreateLayout() - throws Exception { + throws Exception { LayoutRequestDto layoutRequest = createValidLayoutRequest(); layoutRequest.setDefinition(null); mockMvc.perform(post("/layouts") - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains("definition: Definition must not be null"))); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("definition: Definition must not be null"))); assertThat(layoutRepository.findAll()).isEmpty(); assertThat(metadataRepository.findAll()).isEmpty(); @@ -229,79 +236,136 @@ void createLayout_invalidRequestBodyDefinitionsIsNull_returns400AndDoesNotCreate @Test void createLayout_invalidRequestBodyMetadataIsNull_returns400AndDoesNotCreateLayout() - throws Exception { + throws Exception { LayoutRequestDto layoutRequest = createValidLayoutRequest(); layoutRequest.setMetadata(null); mockMvc.perform(post("/layouts") - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains("metadata: Metadata must not be null"))); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("metadata: Metadata must not be null"))); assertThat(layoutRepository.findAll()).isEmpty(); assertThat(metadataRepository.findAll()).isEmpty(); } + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void createLayout_invalidRequestBodyMetadataNameIsInvalid_returns400AndDoesNotCreateLayout( + String name) throws Exception { + LayoutRequestDto layoutRequest = createValidLayoutRequest(); + layoutRequest.getMetadata().getBaseMetadata().setName(name); + + mockMvc.perform(post("/layouts") + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect( + jsonPath("$.messages", contains("metadata.baseMetadata.name: Name is required"))); + + assertThat(layoutRepository.findAll()).isEmpty(); + assertThat(metadataRepository.findAll()).isEmpty(); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void createLayout_invalidRequestBodyMetadataGroupIsInvalid_returns400AndDoesNotCreateLayout( + String group) throws Exception { + LayoutRequestDto layoutRequest = createValidLayoutRequest(); + layoutRequest.getMetadata().getBaseMetadata().setGroup(group); + + mockMvc.perform(post("/layouts") + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect( + jsonPath("$.messages", contains("metadata.baseMetadata.group: Group is required"))); + + assertThat(layoutRepository.findAll()).isEmpty(); + assertThat(metadataRepository.findAll()).isEmpty(); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void createLayout_invalidRequestBodyUserIsInvalid_returns400AndDoesNotCreateLayout(String user) + throws Exception { + LayoutRequestDto layoutRequest = createValidLayoutRequest(); + layoutRequest.getMetadata().getBaseMetadata().setUser(user); + + mockMvc.perform(post("/layouts") + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect( + jsonPath("$.messages", contains("metadata.baseMetadata.user: User is required"))); + } @Test void createLayout_invalidRequestBodyUnexpectedFormat_returns400() throws Exception { String invalidLayout = "invalidLayout"; mockMvc.perform(post("/layouts") - .content(invalidLayout) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains( - "JSON parse error: Unrecognized token 'invalidLayout': was expecting (JSON " - + "String, Number, Array, Object or token 'null', 'true' or 'false'); nested " - + "exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized " - + "token 'invalidLayout': was expecting (JSON String, Number, Array, Object " - + "or token 'null', 'true' or 'false')\n" - + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" - + " line: 1, column: 14]"))); + .content(invalidLayout) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "JSON parse error: Unrecognized token 'invalidLayout': was expecting (JSON " + + "String, Number, Array, Object or token 'null', 'true' or 'false'); nested " + + "exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized " + + "token 'invalidLayout': was expecting (JSON String, Number, Array, Object " + + "or token 'null', 'true' or 'false')\n" + + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" + + " line: 1, column: 14]"))); } @Test void updateLayout_validIdAndValidRequest_returns204AndLayoutHasChanged() throws Exception { Layout initialLayout = createDefaultLayoutInDatabase(); assertThat(layoutRepository.findById(initialLayout.getId()).orElseThrow()).isEqualTo( - initialLayout); + initialLayout); LayoutRequestDto layoutRequest = createValidLayoutRequest(); - layoutRequest.setDefinition(objectNodeConverter.convertToEntityAttribute(UPDATED_LAYOUT_DEFINITION_STRING)); + layoutRequest.setDefinition( + objectNodeConverter.convertToEntityAttribute(UPDATED_LAYOUT_DEFINITION_STRING)); layoutRequest.getMetadata().getBaseMetadata().setName("Updated name"); layoutRequest.getMetadata().getBaseMetadata().setGroup("Updated group"); layoutRequest.getMetadata().getBaseMetadata().setScreenshot("Updated screenshot"); layoutRequest.getMetadata().getBaseMetadata().setUser("Updated user"); mockMvc.perform(put("/layouts/{id}", initialLayout.getId()) - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isNoContent()) - .andExpect(jsonPath("$").doesNotExist()); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$").doesNotExist()); Layout updatedLayout = layoutRepository.findById(initialLayout.getId()).orElseThrow(); assertThat(updatedLayout.getDefinition()) - .isEqualTo(layoutRequest.getDefinition()); + .isEqualTo(layoutRequest.getDefinition()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getName()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getGroup()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getScreenshot()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getUser()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); assertThat(updatedLayout).isNotEqualTo(initialLayout); } @Test void updateLayout_invalidRequestBodyDefinitionIsNull_returns400AndLayoutDoesNotChange() - throws Exception { + throws Exception { Layout layout = createDefaultLayoutInDatabase(); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); @@ -309,18 +373,18 @@ void updateLayout_invalidRequestBodyDefinitionIsNull_returns400AndLayoutDoesNotC request.setDefinition(null); mockMvc.perform(put("/layouts/{id}", layout.getId()) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains("definition: Definition must not be null"))); + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("definition: Definition must not be null"))); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); } @Test void updateLayout_invalidRequestBodyMetadataIsNull_returns400AndLayoutDoesNotChange() - throws Exception { + throws Exception { Layout layout = createDefaultLayoutInDatabase(); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); @@ -328,42 +392,108 @@ void updateLayout_invalidRequestBodyMetadataIsNull_returns400AndLayoutDoesNotCha request.setMetadata(null); mockMvc.perform(put("/layouts/{id}", layout.getId()) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains("metadata: Metadata must not be null"))); + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("metadata: Metadata must not be null"))); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); } @Test void updateLayout_invalidRequestBodyUnexpectedFormat_returns400AndLayoutDoesNotChange() - throws Exception { + throws Exception { Layout layout = createDefaultLayoutInDatabase(); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); String request = "invalidRequest"; mockMvc.perform(put("/layouts/{id}", layout.getId()) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains( - "JSON parse error: Cannot construct instance of `org.finos.vuu.layoutserver.dto" - + ".request.LayoutRequestDto` (although at least one Creator exists): no " - + "String-argument constructor/factory method to deserialize from String " - + "value ('invalidRequest'); nested exception is com.fasterxml.jackson" - + ".databind.exc.MismatchedInputException: Cannot construct instance of `org" - + ".finos.vuu.layoutserver.dto.request.LayoutRequestDto` (although at least " - + "one Creator exists): no String-argument constructor/factory method to " - + "deserialize from String value ('invalidRequest')\n" - + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" - + " line: 1, column: 1]"))); + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "JSON parse error: Cannot construct instance of `org.finos.vuu.layoutserver.dto" + + ".request.LayoutRequestDto` (although at least one Creator exists): no " + + "String-argument constructor/factory method to deserialize from String " + + "value ('invalidRequest'); nested exception is com.fasterxml.jackson" + + ".databind.exc.MismatchedInputException: Cannot construct instance of `org" + + ".finos.vuu.layoutserver.dto.request.LayoutRequestDto` (although at least " + + "one Creator exists): no String-argument constructor/factory method to " + + "deserialize from String value ('invalidRequest')\n" + + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" + + " line: 1, column: 1]"))); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo( - layout); + layout); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void updateLayout_invalidRequestBodyMetadataNameIsInvalid_returns400AndLayoutDoesNotChange( + String name) throws Exception { + Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + + LayoutRequestDto request = createValidLayoutRequest(); + request.getMetadata().getBaseMetadata().setName(name); + + mockMvc.perform(put("/layouts/{id}", layout.getId()) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect( + jsonPath("$.messages", contains("metadata.baseMetadata.name: Name is required"))); + + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void updateLayout_invalidRequestBodyMetadataGroupIsInvalid_returns400AndDoesNotUpdateLayout( + String group) throws Exception { + Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + + LayoutRequestDto request = createValidLayoutRequest(); + request.getMetadata().getBaseMetadata().setGroup(group); + + mockMvc.perform(put("/layouts/{id}", layout.getId()) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect( + jsonPath("$.messages", contains("metadata.baseMetadata.group: Group is required"))); + + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void updateLayout_invalidRequestBodyMetadataUserIsNullOrEmpty_returns400AndDoesNotUpdateLayout( + String user) throws Exception { + Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + + LayoutRequestDto request = createValidLayoutRequest(); + request.getMetadata().getBaseMetadata().setUser(user); + + mockMvc.perform(put("/layouts/{id}", layout.getId()) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect( + jsonPath("$.messages", contains("metadata.baseMetadata.user: User is required"))); + + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); } @Test @@ -372,9 +502,9 @@ void updateLayout_validIdButLayoutDoesNotExist_returnsNotFound() throws Exceptio LayoutRequestDto layoutRequest = createValidLayoutRequest(); mockMvc.perform(put("/layouts/{id}", layoutID) - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); } @Test @@ -383,14 +513,14 @@ void updateLayout_invalidId_returns400() throws Exception { LayoutRequestDto layoutRequest = createValidLayoutRequest(); mockMvc.perform(put("/layouts/{id}", layoutID) - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains( - "Failed to convert value of type 'java.lang.String' to required type 'java.util" - + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " - + "UUID string: invalidUUID"))); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "Failed to convert value of type 'java.lang.String' to required type 'java.util" + + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " + + "UUID string: invalidUUID"))); } @Test @@ -415,12 +545,12 @@ void deleteLayout_invalidId_returns400() throws Exception { String layoutID = "invalidUUID"; mockMvc.perform(delete("/layouts/{id}", layoutID)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.messages", iterableWithSize(1))) - .andExpect(jsonPath("$.messages", contains( - "Failed to convert value of type 'java.lang.String' to required type 'java.util" - + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " - + "UUID string: invalidUUID"))); + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "Failed to convert value of type 'java.lang.String' to required type 'java.util" + + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " + + "UUID string: invalidUUID"))); } private Layout createDefaultLayoutInDatabase() { @@ -435,7 +565,8 @@ private Layout createDefaultLayoutInDatabase() { metadata.setBaseMetadata(baseMetadata); - layout.setDefinition(objectNodeConverter.convertToEntityAttribute(DEFAULT_LAYOUT_DEFINITION_STRING)); + layout.setDefinition( + objectNodeConverter.convertToEntityAttribute(DEFAULT_LAYOUT_DEFINITION_STRING)); layout.setMetadata(metadata); layout.setId(DEFAULT_LAYOUT_ID); @@ -454,7 +585,8 @@ private Layout createLayoutWithIdInDatabase(UUID id) { metadata.setBaseMetadata(baseMetadata); - layout.setDefinition(objectNodeConverter.convertToEntityAttribute(DEFAULT_LAYOUT_DEFINITION_STRING)); + layout.setDefinition( + objectNodeConverter.convertToEntityAttribute(DEFAULT_LAYOUT_DEFINITION_STRING)); layout.setMetadata(metadata); layout.setId(id); @@ -472,7 +604,8 @@ private LayoutRequestDto createValidLayoutRequest() { metadataRequest.setBaseMetadata(baseMetadata); LayoutRequestDto layoutRequest = new LayoutRequestDto(); - layoutRequest.setDefinition(objectNodeConverter.convertToEntityAttribute(DEFAULT_LAYOUT_DEFINITION_STRING)); + layoutRequest.setDefinition( + objectNodeConverter.convertToEntityAttribute(DEFAULT_LAYOUT_DEFINITION_STRING)); layoutRequest.setMetadata(metadataRequest); return layoutRequest;