diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java index 540234630a..95d3d2637a 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import lombok.RequiredArgsConstructor; -import org.finos.vuu.layoutserver.dto.ApplicationLayoutDto; +import org.finos.vuu.layoutserver.dto.response.ApplicationLayoutDto; import org.finos.vuu.layoutserver.service.ApplicationLayoutService; import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; @@ -42,7 +42,7 @@ public ApplicationLayoutDto getApplicationLayout(@RequestHeader("user") String u */ @ResponseStatus(HttpStatus.CREATED) @PostMapping - public void createLayout(@RequestHeader("user") String username, @RequestBody JsonNode layoutDefinition) { + public void createApplicationLayout(@RequestHeader("user") String username, @RequestBody JsonNode layoutDefinition) { service.createApplicationLayout(username, layoutDefinition); } @@ -54,7 +54,7 @@ public void createLayout(@RequestHeader("user") String username, @RequestBody Js */ @ResponseStatus(HttpStatus.NO_CONTENT) @PutMapping - public void updateLayout(@RequestHeader("user") String username, @RequestBody JsonNode layoutDefinition) { + public void updateApplicationLayout(@RequestHeader("user") String username, @RequestBody JsonNode layoutDefinition) { service.updateApplicationLayout(username, layoutDefinition); } @@ -65,7 +65,7 @@ public void updateLayout(@RequestHeader("user") String username, @RequestBody Js */ @ResponseStatus(HttpStatus.NO_CONTENT) @DeleteMapping - public void deleteLayout(@RequestHeader("user") String username) { + public void deleteApplicationLayout(@RequestHeader("user") String username) { service.deleteApplicationLayout(username); } } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/ApplicationLayoutDto.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ApplicationLayoutDto.java similarity index 94% rename from layout-server/src/main/java/org/finos/vuu/layoutserver/dto/ApplicationLayoutDto.java rename to layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ApplicationLayoutDto.java index 52e9455f12..929781ee49 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/ApplicationLayoutDto.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ApplicationLayoutDto.java @@ -1,4 +1,4 @@ -package org.finos.vuu.layoutserver.dto; +package org.finos.vuu.layoutserver.dto.response; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java index f20833a321..d76e618063 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; -import org.finos.vuu.layoutserver.dto.ApplicationLayoutDto; +import org.finos.vuu.layoutserver.dto.response.ApplicationLayoutDto; import org.finos.vuu.layoutserver.model.ApplicationLayout; import org.finos.vuu.layoutserver.repository.ApplicationLayoutRepository; import org.slf4j.Logger; diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/ApplicationLayoutIntegrationTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/ApplicationLayoutIntegrationTest.java new file mode 100644 index 0000000000..9143649cbd --- /dev/null +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/ApplicationLayoutIntegrationTest.java @@ -0,0 +1,184 @@ +package org.finos.vuu.layoutserver.integration; + +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.finos.vuu.layoutserver.repository.ApplicationLayoutRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +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") +public class ApplicationLayoutIntegrationTest { + @Autowired + private MockMvc mockMvc; + @Autowired + private ApplicationLayoutRepository repository; + + @Test + public void getApplicationLayout_noLayoutExists_returns200WithDefaultLayout() throws Exception { + mockMvc.perform(get("/application-layouts").header("user", "new user")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.user", nullValue())) + // Expecting application layout as defined in /test/resources/defaultLayout.json + .andExpect(jsonPath("$.definition.defaultLayoutKey", is("default-layout-value"))); + } + + @Test + public void getApplicationLayout_layoutExists_returns200WithPersistedLayout() throws Exception { + String user = "user"; + + Map definition = new HashMap<>(); + definition.put("defKey", "defVal"); + + persistApplicationLayout(user, definition); + + mockMvc.perform(get("/application-layouts").header("user", user)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.user", is(user))) + .andExpect(jsonPath("$.definition", is(definition))); + } + + @Test + public void createApplicationLayout_noLayoutExists_returns201AndPersistsLayout() throws Exception { + String user = "user"; + String definition = "{\"key\":\"value\"}"; + + mockMvc.perform(post("/application-layouts") + .header("user", user) + .content(definition) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$").doesNotExist()); + + ApplicationLayout persistedLayout = repository.findById(user).orElseThrow(); + + assertThat(persistedLayout.getUsername()).isEqualTo(user); + assertThat(persistedLayout.extractDefinition()).isEqualTo(definition); + } + + @Test + public void createApplicationLayout_layoutExists_returns201AndOverwritesLayout() throws Exception { + String user = "user"; + + Map initialDefinition = new HashMap<>(); + initialDefinition.put("initial-key", "initial-value"); + + persistApplicationLayout(user, initialDefinition); + + String newDefinition = "{\"new-key\":\"new-value\"}"; + + mockMvc.perform(post("/application-layouts") + .header("user", user) + .content(newDefinition) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$").doesNotExist()); + + assertThat(repository.findAll()).hasSize(1); + + ApplicationLayout retrievedLayout = repository.findById(user).orElseThrow(); + + assertThat(retrievedLayout.getUsername()).isEqualTo(user); + assertThat(retrievedLayout.extractDefinition()).isEqualTo(newDefinition); + } + + @Test + public void updateApplicationLayout_noLayoutExists_returns204AndPersistsLayout() throws Exception { + String user = "user"; + String definition = "{\"key\":\"value\"}"; + + mockMvc.perform(put("/application-layouts") + .header("user", user) + .content(definition) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$").doesNotExist()); + + ApplicationLayout persistedLayout = repository.findById(user).orElseThrow(); + + assertThat(persistedLayout.getUsername()).isEqualTo(user); + assertThat(persistedLayout.extractDefinition()).isEqualTo(definition); + } + + @Test + public void updateApplicationLayout_layoutExists_returns204AndOverwritesLayout() throws Exception { + String user = "user"; + + Map initialDefinition = new HashMap<>(); + initialDefinition.put("initial-key", "initial-value"); + + persistApplicationLayout(user, initialDefinition); + + String newDefinition = "{\"new-key\":\"new-value\"}"; + + mockMvc.perform(put("/application-layouts") + .header("user", user) + .content(newDefinition) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$").doesNotExist()); + + assertThat(repository.findAll()).hasSize(1); + + ApplicationLayout retrievedLayout = repository.findById(user).orElseThrow(); + + assertThat(retrievedLayout.getUsername()).isEqualTo(user); + assertThat(retrievedLayout.extractDefinition()).isEqualTo(newDefinition); + } + + @Test + public void deleteApplicationLayout_noLayoutExists_returns404() throws Exception { + String user = "user"; + + String response = mockMvc.perform(delete("/application-layouts") + .header("user", user)) + .andExpect(status().isNotFound()) + .andReturn().getResponse().getContentAsString(); + + assertThat(response).isEqualTo("No layout found for user: " + user); + } + + @Test + public void deleteApplicationLayout_layoutExists_returns204AndDeletesLayout() throws Exception { + String user = "user"; + + Map initialDefinition = new HashMap<>(); + initialDefinition.put("initial-key", "initial-value"); + + persistApplicationLayout(user, initialDefinition); + + mockMvc.perform(delete("/application-layouts") + .header("user", user)) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$").doesNotExist()); + + assertThat(repository.findAll()).hasSize(0); + } + + private void persistApplicationLayout(String user, Map definition) { + StringBuilder defBuilder = new StringBuilder("{"); + definition.forEach((k, v) -> defBuilder.append("\"").append(k).append("\":\"").append(v).append("\"")); + defBuilder.append("}"); + + ApplicationLayout appLayout = new ApplicationLayout(user, defBuilder.toString()); + repository.save(appLayout); + } +} diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java index b3fe52f5a1..3dbc397064 100644 --- a/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.finos.vuu.layoutserver.dto.ApplicationLayoutDto; +import org.finos.vuu.layoutserver.dto.response.ApplicationLayoutDto; import org.finos.vuu.layoutserver.model.ApplicationLayout; import org.finos.vuu.layoutserver.repository.ApplicationLayoutRepository; import org.junit.jupiter.api.BeforeEach; diff --git a/layout-server/src/test/resources/defaultLayout.json b/layout-server/src/test/resources/defaultLayout.json new file mode 100644 index 0000000000..87a79e544c --- /dev/null +++ b/layout-server/src/test/resources/defaultLayout.json @@ -0,0 +1,3 @@ +{ + "defaultLayoutKey": "default-layout-value" +}