From 73cea521ebd578e9a66db9cd6cab9bdcf49f614d Mon Sep 17 00:00:00 2001 From: Piotr Gawron <p.gawron@atcomp.pl> Date: Thu, 16 Jan 2025 16:46:55 +0100 Subject: [PATCH 1/2] basic GET endpoint for plugins --- .../persist/dao/plugin/PluginProperty.java | 8 + .../persist/dao/map/CommentDaoTest.java | 2 +- .../services/impl/PluginService.java | 32 +- .../services/interfaces/IPluginService.java | 9 +- .../web/api/plugin/NewPluginController.java | 134 +++++ .../web/api/plugin/NewPluginDTO.java | 90 ++++ .../web/ControllerIntegrationTest.java | 4 + .../web/PluginControllerIntegrationTest.java | 3 +- .../lcsb/mapviewer/web/api/NewApiDocs.java | 28 + .../api/plugin/NewPluginControllerTest.java | 486 ++++++++++++++++++ 10 files changed, 788 insertions(+), 8 deletions(-) create mode 100644 persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java create mode 100644 web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java create mode 100644 web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java create mode 100644 web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java diff --git a/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java b/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java new file mode 100644 index 0000000000..073fb582b8 --- /dev/null +++ b/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java @@ -0,0 +1,8 @@ +package lcsb.mapviewer.persist.dao.plugin; + +import lcsb.mapviewer.model.plugin.Plugin; +import lcsb.mapviewer.persist.dao.MinervaEntityProperty; + +public enum PluginProperty implements MinervaEntityProperty<Plugin> { + DEFAULT, +} diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java index a0453a3f9e..9eb17973ec 100644 --- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java +++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java @@ -55,7 +55,7 @@ public class CommentDaoTest extends PersistTestFunctions { } @Test - public void testGetById() throws Exception { + public void testGetById() { Project project = createProject(); int counter = (int) commentDao.getCount(); diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java b/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java index 58876fe37d..ed90d60d46 100644 --- a/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java +++ b/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java @@ -1,17 +1,22 @@ package lcsb.mapviewer.services.impl; +import lcsb.mapviewer.common.exception.NotImplementedException; import lcsb.mapviewer.model.plugin.Plugin; import lcsb.mapviewer.model.plugin.PluginDataEntry; import lcsb.mapviewer.model.user.User; import lcsb.mapviewer.persist.dao.plugin.PluginDao; import lcsb.mapviewer.persist.dao.plugin.PluginDataEntryDao; +import lcsb.mapviewer.persist.dao.plugin.PluginProperty; import lcsb.mapviewer.services.interfaces.IPluginService; import org.hibernate.Hibernate; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Map; @Transactional @Service @@ -44,6 +49,12 @@ public class PluginService implements IPluginService { return result; } + @Override + public Page<Plugin> getAll(final Map<PluginProperty, Object> filter, final Pageable pageable) { + throw new NotImplementedException(); + } + + @Override public PluginDataEntry getEntryByKey(final Plugin plugin, final String key, final User user) { PluginDataEntry result = pluginDataEntryDao.getByKey(plugin, key, user); @@ -68,8 +79,8 @@ public class PluginService implements IPluginService { } @Override - public Plugin add(final Plugin plugin) { - return pluginDao.add(plugin); + public void add(final Plugin plugin) { + pluginDao.add(plugin); } @Override @@ -94,4 +105,21 @@ public class PluginService implements IPluginService { pluginDao.update(plugin); } + + @Override + public Plugin getById(final int id) { + throw new NotImplementedException(); + } + + + @Override + public void remove(final Plugin object) { + throw new NotImplementedException(); + } + + @Override + public long getCount(final Map<PluginProperty, Object> filterOptions) { + throw new NotImplementedException(); + } + } diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java index afe8939be8..9c98718c79 100644 --- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java +++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java @@ -1,12 +1,13 @@ package lcsb.mapviewer.services.interfaces; -import java.util.List; - import lcsb.mapviewer.model.plugin.Plugin; import lcsb.mapviewer.model.plugin.PluginDataEntry; import lcsb.mapviewer.model.user.User; +import lcsb.mapviewer.persist.dao.plugin.PluginProperty; + +import java.util.List; -public interface IPluginService { +public interface IPluginService extends CrudService<Plugin, PluginProperty> { Plugin getByHash(final String hash); @@ -18,7 +19,7 @@ public interface IPluginService { void delete(final Plugin plugin); - Plugin add(final Plugin plugin); + void add(final Plugin plugin); void add(final PluginDataEntry entry); diff --git a/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java new file mode 100644 index 0000000000..4d6558bd47 --- /dev/null +++ b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java @@ -0,0 +1,134 @@ +package lcsb.mapviewer.web.api.plugin; + +import lcsb.mapviewer.api.QueryException; +import lcsb.mapviewer.model.plugin.Plugin; +import lcsb.mapviewer.model.security.PrivilegeType; +import lcsb.mapviewer.persist.dao.plugin.PluginProperty; +import lcsb.mapviewer.services.FailedDependencyException; +import lcsb.mapviewer.services.ObjectExistsException; +import lcsb.mapviewer.services.ObjectNotFoundException; +import lcsb.mapviewer.services.interfaces.IPluginService; +import lcsb.mapviewer.web.api.NewApiResponseSerializer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.hibernate.validator.constraints.NotBlank; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@RestController +@Validated +@RequestMapping( + value = { + "/minerva/new_api/plugins", + }, + produces = MediaType.APPLICATION_JSON_VALUE) +public class NewPluginController { + + private final Logger logger = LogManager.getLogger(); + + private final IPluginService pluginService; + private final NewApiResponseSerializer serializer; + + @Autowired + public NewPluginController( + final IPluginService pluginService, + final NewApiResponseSerializer serializer) { + this.serializer = serializer; + this.pluginService = pluginService; + } + + @GetMapping(value = "/{hash}") + public ResponseEntity<?> getPlugin(final @NotBlank @PathVariable(value = "hash") String hash) + throws ObjectNotFoundException, FailedDependencyException, IOException { + final lcsb.mapviewer.model.plugin.Plugin plugin = pluginService.getByHash(hash); + return serializer.prepareResponse(plugin); + } + + @PostMapping(value = "/") + public ResponseEntity<?> addPlugin( + final Authentication authentication, + final @Valid @RequestBody NewPluginDTO data) + throws QueryException, ObjectNotFoundException, ObjectExistsException { + + final boolean isAdmin = authentication.getAuthorities() + .contains(new SimpleGrantedAuthority(PrivilegeType.IS_ADMIN.name())); + + Plugin plugin = pluginService.getByHash(data.getHash()); + if (plugin != null) { + throw new ObjectExistsException("Plugin with given hash already exists"); + } + plugin = new Plugin(); + data.saveToPlugin(plugin, isAdmin); + pluginService.add(plugin); + + return serializer.prepareResponse(plugin, HttpStatus.CREATED); + } + + @PreAuthorize("hasAnyAuthority('IS_ADMIN')") + @PutMapping(value = "/{hash}") + public ResponseEntity<?> updatePlugin( + final Authentication authentication, + final @RequestHeader(name = "If-Match", required = false) String oldETag, + final @Valid @RequestBody NewPluginDTO data, + final @PathVariable(value = "hash") String hash) + throws IOException, QueryException, ObjectNotFoundException, FailedDependencyException { + final boolean isAdmin = authentication.getAuthorities() + .contains(new SimpleGrantedAuthority(PrivilegeType.IS_ADMIN.name())); + + Plugin plugin = pluginService.getByHash(hash); + if (plugin == null) { + throw new ObjectNotFoundException("Plugin with given hash does not exist"); + } + serializer.checkETag(oldETag, plugin); + data.saveToPlugin(plugin, isAdmin); + pluginService.update(plugin); + + return serializer.prepareResponse(plugin); + } + + @PreAuthorize("hasAnyAuthority('IS_ADMIN')") + @DeleteMapping(value = "/{hash}") + public void deletePlugin( + final @RequestHeader(name = "If-Match", required = false) String oldETag, + final @PathVariable(value = "hash") String hash) + throws QueryException, ObjectNotFoundException { + + final Plugin plugin = pluginService.getByHash(hash); + if (plugin == null) { + throw new ObjectNotFoundException("Plugin with given id doesn't exist"); + } + serializer.checkETag(oldETag, plugin); + + pluginService.delete(plugin); + } + + @GetMapping(value = "/") + public ResponseEntity<?> listPlugins(final Pageable pageable) { + final Map<PluginProperty, Object> pluginFilter = new HashMap<>(); + pluginFilter.put(PluginProperty.DEFAULT, true); + final Page<Plugin> plugins = pluginService.getAll(pluginFilter, pageable); + return serializer.prepareResponse(plugins); + } +} \ No newline at end of file diff --git a/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java new file mode 100644 index 0000000000..89c1db3551 --- /dev/null +++ b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java @@ -0,0 +1,90 @@ +package lcsb.mapviewer.web.api.plugin; + +import lcsb.mapviewer.api.QueryException; +import lcsb.mapviewer.model.plugin.Plugin; +import lcsb.mapviewer.web.api.AbstractDTO; +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +public class NewPluginDTO extends AbstractDTO { + + @NotBlank + @Size(max = 255) + private String hash; + + @NotNull + private String name; + + @NotNull + private String version; + + private boolean isPublic; + + private Boolean isDefault; + + @NotNull + private String url; + + public void saveToPlugin(final Plugin plugin, final boolean isAdmin) throws QueryException { + plugin.setHash(hash); + plugin.setPublic(isPublic); + if (isDefault != null && isAdmin) { + plugin.setDefault(isDefault); + } + plugin.setName(name); + plugin.setVersion(version); + if (!plugin.getUrls().contains(url)) { + plugin.addUrl(url); + } + } + + public String getHash() { + return hash; + } + + public void setHash(final String hash) { + this.hash = hash; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(final String version) { + this.version = version; + } + + public boolean isPublic() { + return isPublic; + } + + public void setPublic(final boolean aPublic) { + isPublic = aPublic; + } + + public Boolean getDefault() { + return isDefault; + } + + public void setDefault(final Boolean aDefault) { + isDefault = aDefault; + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } +} diff --git a/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java index d1426a44bb..4713155af4 100644 --- a/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java +++ b/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java @@ -909,6 +909,10 @@ public abstract class ControllerIntegrationTest extends TestUtils { return pathParameters(parameterWithName("projectId").description("project identifier")); } + protected PathParametersSnippet getPluginPathParameters() { + return pathParameters(parameterWithName("hash").description("plugin hash")); + } + protected PathParametersSnippet getMapPathParameters() { return getProjectPathParameters().and(parameterWithName("mapId").description("map identifier")); } diff --git a/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java index cdc7060fe6..6d5f2947b8 100644 --- a/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java +++ b/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java @@ -414,7 +414,8 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest { plugin.setName("starter-kit"); plugin.setVersion("0.0.1"); plugin.addUrl(PLUGIN_URL); - return pluginService.add(plugin); + pluginService.add(plugin); + return plugin; } @Test diff --git a/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java b/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java index c452810cdf..9903d19166 100644 --- a/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java +++ b/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java @@ -54,6 +54,10 @@ public class NewApiDocs { return new NewApiDocs().getProjectFields(prefix); } + public static List<FieldDescriptor> getPluginResponse(final String prefix) { + return new NewApiDocs().getPluginFields(prefix); + } + public static List<FieldDescriptor> getLayerResponse(final String prefix) { return new NewApiDocs().getLayerFields(prefix); } @@ -1029,6 +1033,30 @@ public class NewApiDocs { .optional()); } + public List<FieldDescriptor> getPluginFields(final String prefix) { + return Arrays.asList( + fieldWithPath(prefix + "hash") + .description("plugin hash (identifier)") + .type(JsonFieldType.STRING), + fieldWithPath(prefix + "name") + .description("name") + .type(JsonFieldType.STRING), + fieldWithPath(prefix + "version") + .description("version") + .type(JsonFieldType.STRING), + fieldWithPath(prefix + "isPublic") + .description("is the plugin visible in the list of plugins") + .type(JsonFieldType.BOOLEAN), + fieldWithPath(prefix + "isDefault") + .description("is the plugin automatically loaded when opening map") + .type(JsonFieldType.BOOLEAN), + subsectionWithPath(prefix + "urls") + .description("list of urls where plugin is accessible") + .type(JsonFieldType.ARRAY) + .optional() + ); + } + private static <T extends Enum<T>> String getOptionsAsString(final Class<T> enumType) { final List<String> options = new ArrayList<>(); for (final T c : enumType.getEnumConstants()) { diff --git a/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java b/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java new file mode 100644 index 0000000000..32757059b5 --- /dev/null +++ b/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java @@ -0,0 +1,486 @@ +package lcsb.mapviewer.web.api.plugin; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lcsb.mapviewer.model.plugin.Plugin; +import lcsb.mapviewer.services.interfaces.IPluginService; +import lcsb.mapviewer.web.ControllerIntegrationTest; +import lcsb.mapviewer.web.api.NewApiDocs; +import lcsb.mapviewer.web.api.NewApiResponseSerializer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.RequestBuilder; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles("webCtdTestProfile") +public class NewPluginControllerTest extends ControllerIntegrationTest { + + @Autowired + private IPluginService pluginService; + + @Autowired + private NewApiResponseSerializer newApiResponseSerializer; + + private ObjectMapper objectMapper; + + @Before + public void setUp() throws Exception { + objectMapper = newApiResponseSerializer.getObjectMapper(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetPlugin() throws Exception { + Plugin plugin = createPlugin(); + pluginService.add(plugin); + + final RequestBuilder request = get("/minerva/new_api/plugins/{hash}", plugin.getHash()); + + final MockHttpServletResponse response = mockMvc.perform(request) + .andExpect(status().isOk()) + .andDo(document("new_api/plugins/get_by_hash", + getPluginPathParameters(), + responseFields(NewApiDocs.getPluginResponse("")))) + .andExpect(status().is2xxSuccessful()) + .andReturn().getResponse(); + logger.debug(response.getContentAsString()); + } + + private static Plugin createPlugin() { + Plugin plugin = new Plugin(); + plugin.setHash("x"); + plugin.setName("plugin"); + plugin.setVersion("1.0.0"); + return plugin; + } +// +// @Test +// public void testGetProjectContainsInfoAboutMinervaNet() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", BUILT_IN_PROJECT) +// .session(session); +// +// final MockHttpServletResponse response = mockMvc.perform(request) +// .andExpect(status().isOk()) +// .andReturn().getResponse(); +// +// final Map<String, Object> object = objectMapper.readValue(response.getContentAsString(), new TypeReference<Map<String, Object>>() { +// }); +// +// assertTrue(object.containsKey("sharedInMinervaNet")); +// +// } +// +// @Test +// public void testGetNonExisting() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", "unknown") +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isNotFound()); +// } +// +// @Test +// public void testGetProjectWithoutPermission() throws Exception { +// createAndPersistProject(TEST_PROJECT); +// +// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", TEST_PROJECT); +// +// mockMvc.perform(request) +// .andExpect(status().isForbidden()); +// } +// +// @Test +// public void testCreateProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); +// +// final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// final MockHttpServletResponse response = mockMvc.perform(request) +// .andExpect(status().isCreated()) +// .andReturn().getResponse(); +// assertNotNull(response.getHeader("ETag")); +// +// assertNotNull(projectService.getProjectByProjectId(TEST_PROJECT)); +// } +// +// @Test +// public void testCreateProjectWithProjectIdMismatch() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); +// +// final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/", TEST_PROJECT_2) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// public void testCreateProjectExisting() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final NewProjectDTO data = createProjectDTO(BUILT_IN_PROJECT); +// +// final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/", BUILT_IN_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isConflict()); +// } +// +// @Test +// public void testUpdateProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// createAndPersistProject(TEST_PROJECT); +// +// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); +// +// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// final HttpServletResponse response = mockMvc.perform(request) +// .andExpect(status().isOk()) +// .andReturn().getResponse(); +// assertNotNull(response.getHeader("ETag")); +// +// final Project project = projectService.getProjectByProjectId(TEST_PROJECT); +// assertEquals(data.getVersion(), project.getVersion()); +// } +// +// @Test +// public void testUpdateProjectWithMissingData() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// createAndPersistProject(TEST_PROJECT); +// +// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); +// data.setName(null); +// +// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// public void testUpdateProjectWithOldVersion() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// createAndPersistProject(TEST_PROJECT); +// +// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); +// +// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .header("If-Match", "-1") +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isPreconditionFailed()); +// } +// +// @Test +// public void testUpdateProjectWithGoodVersion() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// Project project = createAndPersistProject(TEST_PROJECT); +// +// final String originalVersion = project.getEntityVersion() + ""; +// +// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); +// +// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .header("If-Match", originalVersion) +// .session(session); +// +// final HttpServletResponse response = mockMvc.perform(request) +// .andExpect(status().isOk()) +// .andReturn().getResponse(); +// assertNotNull(response.getHeader("ETag")); +// +// project = projectService.getProjectByProjectId(TEST_PROJECT); +// assertNotEquals(originalVersion, project.getEntityVersion() + ""); +// } +// +// private NewProjectDTO createProjectDTO(final String projectId) { +// final NewProjectDTO data = new NewProjectDTO(); +// data.setName("my name"); +// data.setNotifyEmail("minerva@uni.lu"); +// data.setProjectId(projectId); +// data.setSbgnFormat(false); +// data.setVersion("0.0.1"); +// return data; +// } +// +// @Test +// public void testDeleteProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// createAndPersistProject(TEST_PROJECT); +// +// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .session(session); +// +// final String response = mockMvc.perform(request) +// .andExpect(status().isAccepted()) +// .andReturn().getResponse() +// .getContentAsString(); +// +// final MinervaJob job = objectMapper.readValue(response, MinervaJob.class); +// assertEquals(MinervaJobType.DELETE_PROJECT, job.getJobType()); +// +// minervaJobService.waitForTasksToFinish(); +// +// assertNull(projectService.getProjectByProjectId(TEST_PROJECT)); +// } +// +// @Test +// public void testDeleteNotExistingProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isNotFound()); +// } +// +// @Test +// public void testDeleteNoAccessProject() throws Exception { +// createAndPersistProject(TEST_PROJECT); +// +// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT); +// +// mockMvc.perform(request) +// .andExpect(status().isForbidden()); +// } +// +// @Test +// public void testDeleteDefaultProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", BUILT_IN_PROJECT) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isForbidden()); +// } +// +// @Test +// public void testDeleteProjectDropsPrivileges() throws Exception { +// createAndPersistProject(TEST_PROJECT); +// User curator = createCurator(CURATOR_LOGIN, CURATOR_PASSWORD); +// +// userService.grantUserPrivilege(curator, PrivilegeType.WRITE_PROJECT, TEST_PROJECT); +// +// final RequestBuilder request = delete("/minerva/api/projects/" + TEST_PROJECT) +// .session(createSession(CURATOR_LOGIN, CURATOR_PASSWORD)); +// +// mockMvc.perform(request) +// .andExpect(status().is2xxSuccessful()); +// +// minervaJobService.waitForTasksToFinish(); +// +// curator = userService.getUserByLogin(CURATOR_LOGIN, true); +// +// assertFalse("Curator privileges weren't updated after project was removed", +// curator.getPrivileges().contains(new Privilege(PrivilegeType.WRITE_PROJECT, TEST_PROJECT))); +// } +// +// @Test +// public void testDeleteProjectWithGoodVersion() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final Project project = createAndPersistProject(TEST_PROJECT); +// +// final String originalVersion = project.getEntityVersion() + ""; +// +// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .header("If-Match", originalVersion) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isAccepted()); +// } +// +// @Test +// public void testDeleteProjectWithWrongVersion() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// createAndPersistProject(TEST_PROJECT); +// +// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .header("If-Match", "-1") +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isPreconditionFailed()); +// } +// +// @Test +// public void testListProjects() throws Exception { +// final RequestBuilder request = get("/minerva/new_api/projects/"); +// +// mockMvc.perform(request) +// .andExpect(status().isOk()); +// } +// +// @Test +// public void testListProjectsWithoutAccess() throws Exception { +// final RequestBuilder request = get("/minerva/new_api/projects/"); +// +// createAndPersistProject(TEST_PROJECT); +// +// final String response = mockMvc.perform(request) +// .andExpect(status().isOk()) +// .andReturn().getResponse() +// .getContentAsString(); +// +// final Page<Object> page = objectMapper.readValue(response, new TypeReference<Page<Object>>() { +// }); +// assertEquals(1, page.getTotalElements()); +// assertEquals(1, page.getNumberOfElements()); +// } +// +// @Test +// public void testListProjectsWithoutAdminAccess() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// final RequestBuilder request = get("/minerva/new_api/projects/") +// .session(session); +// +// createAndPersistProject(TEST_PROJECT); +// +// final String response = mockMvc.perform(request) +// .andExpect(status().isOk()) +// .andReturn().getResponse() +// .getContentAsString(); +// +// final Page<Object> page = objectMapper.readValue(response, new TypeReference<Page<Object>>() { +// }); +// assertEquals(2, page.getTotalElements()); +// assertEquals(2, page.getNumberOfElements()); +// } +// +// @Test +// public void testUpdateOwnerInProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// createAndPersistProject(TEST_PROJECT); +// +// final NewUserLoginDTO data = new NewUserLoginDTO(); +// data.setLogin(Configuration.ANONYMOUS_LOGIN); +// +// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/owner/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// final HttpServletResponse response = mockMvc.perform(request) +// .andExpect(status().isOk()) +// .andReturn().getResponse(); +// assertNotNull(response.getHeader("ETag")); +// +// final Project project = projectService.getProjectByProjectId(TEST_PROJECT); +// assertEquals(Configuration.ANONYMOUS_LOGIN, project.getOwner().getLogin()); +// } +// +// @Test +// public void testUpdateInvalidOwnerInProject() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// createAndPersistProject(TEST_PROJECT); +// +// final NewUserLoginDTO data = new NewUserLoginDTO(); +// data.setLogin("blah"); +// +// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/owner/", TEST_PROJECT) +// .contentType(MediaType.APPLICATION_JSON) +// .content(objectMapper.writeValueAsString(data)) +// .session(session); +// +// mockMvc.perform(request) +// .andExpect(status().isNotFound()); +// } +// +// @Test +// public void testGetProjects() throws Exception { +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final RequestBuilder request = get("/minerva/new_api/projects/") +// .session(session); +// +// mockMvc.perform(request) +// .andDo(document("new_api/projects/get_projects", +// getProjectsSearchResult())) +// .andExpect(status().is2xxSuccessful()) +// .andReturn().getResponse().getContentAsString(); +// } +// +// private Snippet getProjectsSearchResult() { +// final String prefix = "content[]."; +// final List<FieldDescriptor> fields = new ArrayList<>(); +// fields.add( +// fieldWithPath("content") +// .description("list of projects on the page") +// .type(JsonFieldType.ARRAY)); +// fields.addAll(NewApiDocs.getProjectResponse(prefix)); +// fields.addAll(NewApiDocs.getPageableFields()); +// return responseFields(fields); +// } +// +// @Test +// public void testGetProjectWithError() throws Exception { +// Project project = new Project(TEST_PROJECT); +// projectService.add(project); +// +// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); +// +// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) +// .session(session); +// +// final MockHttpServletResponse response = mockMvc.perform(request) +// .andExpect(status().isInternalServerError()) +// .andReturn().getResponse(); +// +// Map<String, String> data = objectMapper.readValue(response.getContentAsString(), new TypeReference<Map<String, String>>() { +// }); +// +// assertNotNull(data.get("error-id")); +// assertNotNull(stacktraceService.getById(data.get("error-id"))); +// } +// +} -- GitLab From 67bd0e75636c28546107ea6f3f171e8539c42eec Mon Sep 17 00:00:00 2001 From: Piotr Gawron <p.gawron@atcomp.pl> Date: Fri, 17 Jan 2025 09:41:40 +0100 Subject: [PATCH 2/2] new api endpoints for plugins --- .../persist/dao/plugin/PluginDao.java | 36 +- .../persist/dao/plugin/PluginProperty.java | 2 +- .../api/plugins/PluginController.java | 14 +- .../services/impl/PluginService.java | 14 +- .../services/interfaces/IPluginService.java | 1 + .../web/api/plugin/NewPluginController.java | 6 +- .../web/api/plugin/NewPluginDTO.java | 23 +- .../api/plugin/NewPluginControllerTest.java | 680 +++++++----------- 8 files changed, 325 insertions(+), 451 deletions(-) diff --git a/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginDao.java b/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginDao.java index 2ca006601a..0369e9f960 100644 --- a/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginDao.java +++ b/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginDao.java @@ -1,22 +1,25 @@ package lcsb.mapviewer.persist.dao.plugin; -import org.springframework.stereotype.Repository; - +import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.model.plugin.Plugin; import lcsb.mapviewer.persist.dao.BaseDao; -import lcsb.mapviewer.persist.dao.MinervaEntityProperty; +import org.springframework.stereotype.Repository; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * Data access object class for {@link Plugin} objects. - * + * * @author Piotr Gawron - * */ @Repository -public class PluginDao extends BaseDao<Plugin, MinervaEntityProperty<Plugin>> { - /** - * Default constructor. - */ +public class PluginDao extends BaseDao<Plugin, PluginProperty> { + public PluginDao() { super(Plugin.class); } @@ -25,4 +28,19 @@ public class PluginDao extends BaseDao<Plugin, MinervaEntityProperty<Plugin>> { return getByParameter("hash", hash); } + @Override + protected Predicate createPredicate(final Map<PluginProperty, Object> filterOptions, final Root<Plugin> root) { + final CriteriaBuilder builder = getSession().getCriteriaBuilder(); + final List<Predicate> predicates = new ArrayList<>(); + + for (final PluginProperty key : filterOptions.keySet()) { + if (key.equals(PluginProperty.DEFAULT_VALUE)) { + final Predicate predicate = builder.and(root.get("isDefault").in(filterOptions.get(key))); + predicates.add(predicate); + } else { + throw new InvalidArgumentException("Unknown property: " + key); + } + } + return builder.and(predicates.toArray(new Predicate[0])); + } } diff --git a/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java b/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java index 073fb582b8..79b1ba0c9d 100644 --- a/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java +++ b/persist/src/main/java/lcsb/mapviewer/persist/dao/plugin/PluginProperty.java @@ -4,5 +4,5 @@ import lcsb.mapviewer.model.plugin.Plugin; import lcsb.mapviewer.persist.dao.MinervaEntityProperty; public enum PluginProperty implements MinervaEntityProperty<Plugin> { - DEFAULT, + DEFAULT_VALUE, } diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/plugins/PluginController.java b/rest-api/src/main/java/lcsb/mapviewer/api/plugins/PluginController.java index f12b1eb7ca..ec095be816 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/plugins/PluginController.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/plugins/PluginController.java @@ -1,9 +1,7 @@ package lcsb.mapviewer.api.plugins; -import lcsb.mapviewer.annotation.cache.WebPageDownloader; import lcsb.mapviewer.api.BaseController; import lcsb.mapviewer.api.QueryException; -import lcsb.mapviewer.common.Md5; import lcsb.mapviewer.model.plugin.Plugin; import lcsb.mapviewer.model.plugin.PluginDataEntry; import lcsb.mapviewer.model.user.User; @@ -29,7 +27,6 @@ import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import javax.validation.constraints.NotNull; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -82,14 +79,15 @@ public class PluginController extends BaseController { if (!url.isEmpty()) { plugin.addUrl(url); if (!url.startsWith("http://localhost")) { + String md5; try { - String md5 = Md5.compute(new WebPageDownloader().getFromNetwork(url)); - if (!Objects.equals(md5, hash)) { - throw new QueryException(String.format("Invalid hash. Expected %s, but %s found", md5, hash)); - } - } catch (IOException e) { + md5 = pluginService.getExpectedHash(url); + } catch (Exception e) { throw new QueryException("Problem with fetching url", e); } + if (!Objects.equals(md5, hash)) { + throw new QueryException(String.format("Invalid hash. Expected %s, but %s found", md5, hash)); + } } } pluginService.add(plugin); diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java b/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java index ed90d60d46..699e67d1ca 100644 --- a/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java +++ b/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java @@ -1,5 +1,7 @@ package lcsb.mapviewer.services.impl; +import lcsb.mapviewer.annotation.cache.WebPageDownloader; +import lcsb.mapviewer.common.Md5; import lcsb.mapviewer.common.exception.NotImplementedException; import lcsb.mapviewer.model.plugin.Plugin; import lcsb.mapviewer.model.plugin.PluginDataEntry; @@ -15,6 +17,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.util.List; import java.util.Map; @@ -51,7 +54,7 @@ public class PluginService implements IPluginService { @Override public Page<Plugin> getAll(final Map<PluginProperty, Object> filter, final Pageable pageable) { - throw new NotImplementedException(); + return pluginDao.getAll(filter, pageable); } @@ -105,6 +108,15 @@ public class PluginService implements IPluginService { pluginDao.update(plugin); } + @Override + public String getExpectedHash(final String url) { + try { + return Md5.compute(new WebPageDownloader().getFromNetwork(url)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override public Plugin getById(final int id) { diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java index 9c98718c79..e71f4ef849 100644 --- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java +++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IPluginService.java @@ -27,4 +27,5 @@ public interface IPluginService extends CrudService<Plugin, PluginProperty> { void update(final Plugin plugin); + String getExpectedHash(String url); } diff --git a/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java index 4d6558bd47..1803cbd3b9 100644 --- a/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java +++ b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginController.java @@ -80,7 +80,7 @@ public class NewPluginController { throw new ObjectExistsException("Plugin with given hash already exists"); } plugin = new Plugin(); - data.saveToPlugin(plugin, isAdmin); + data.saveToPlugin(plugin, isAdmin, pluginService::getExpectedHash); pluginService.add(plugin); return serializer.prepareResponse(plugin, HttpStatus.CREATED); @@ -102,7 +102,7 @@ public class NewPluginController { throw new ObjectNotFoundException("Plugin with given hash does not exist"); } serializer.checkETag(oldETag, plugin); - data.saveToPlugin(plugin, isAdmin); + data.saveToPlugin(plugin, isAdmin, pluginService::getExpectedHash); pluginService.update(plugin); return serializer.prepareResponse(plugin); @@ -127,7 +127,7 @@ public class NewPluginController { @GetMapping(value = "/") public ResponseEntity<?> listPlugins(final Pageable pageable) { final Map<PluginProperty, Object> pluginFilter = new HashMap<>(); - pluginFilter.put(PluginProperty.DEFAULT, true); + pluginFilter.put(PluginProperty.DEFAULT_VALUE, true); final Page<Plugin> plugins = pluginService.getAll(pluginFilter, pageable); return serializer.prepareResponse(plugins); } diff --git a/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java index 89c1db3551..35212a980f 100644 --- a/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java +++ b/web/src/main/java/lcsb/mapviewer/web/api/plugin/NewPluginDTO.java @@ -7,6 +7,8 @@ import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import java.util.Objects; +import java.util.function.Function; public class NewPluginDTO extends AbstractDTO { @@ -27,7 +29,7 @@ public class NewPluginDTO extends AbstractDTO { @NotNull private String url; - public void saveToPlugin(final Plugin plugin, final boolean isAdmin) throws QueryException { + public void saveToPlugin(final Plugin plugin, final boolean isAdmin, final Function<String, String> urlToHash) throws QueryException { plugin.setHash(hash); plugin.setPublic(isPublic); if (isDefault != null && isAdmin) { @@ -36,6 +38,17 @@ public class NewPluginDTO extends AbstractDTO { plugin.setName(name); plugin.setVersion(version); if (!plugin.getUrls().contains(url)) { + if (!url.startsWith("http://localhost")) { + String md5; + try { + md5 = urlToHash.apply(url); + } catch (Exception e) { + throw new QueryException("Problem with fetching source file: " + url, e); + } + if (!Objects.equals(md5, hash)) { + throw new QueryException(String.format("Invalid hash. Expected %s, but %s found", md5, hash)); + } + } plugin.addUrl(url); } } @@ -68,16 +81,16 @@ public class NewPluginDTO extends AbstractDTO { return isPublic; } - public void setPublic(final boolean aPublic) { - isPublic = aPublic; + public void setPublic(final boolean isPublic) { + this.isPublic = isPublic; } public Boolean getDefault() { return isDefault; } - public void setDefault(final Boolean aDefault) { - isDefault = aDefault; + public void setDefault(final Boolean isDefault) { + this.isDefault = isDefault; } public String getUrl() { diff --git a/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java b/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java index 32757059b5..2fefda636c 100644 --- a/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java +++ b/web/src/test/java/lcsb/mapviewer/web/api/plugin/NewPluginControllerTest.java @@ -11,13 +11,24 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.RequestBuilder; +import javax.servlet.http.HttpServletResponse; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -25,6 +36,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ActiveProfiles("webCtdTestProfile") public class NewPluginControllerTest extends ControllerIntegrationTest { + private static final String PLUGIN_URL = "https://minerva-dev.lcsb.uni.lu/plugins/starter-kit/plugin.js"; + + private static final String PLUGIN_HASH = "b7a875a0536949d4d8a2f834dc54489e"; + @Autowired private IPluginService pluginService; @@ -40,447 +55,264 @@ public class NewPluginControllerTest extends ControllerIntegrationTest { @After public void tearDown() throws Exception { + Plugin plugin = pluginService.getByHash(PLUGIN_HASH); + if (plugin != null) { + pluginService.delete(plugin); + } } @Test public void testGetPlugin() throws Exception { - Plugin plugin = createPlugin(); + Plugin plugin = createPlugin(PLUGIN_HASH); pluginService.add(plugin); final RequestBuilder request = get("/minerva/new_api/plugins/{hash}", plugin.getHash()); - final MockHttpServletResponse response = mockMvc.perform(request) + mockMvc.perform(request) .andExpect(status().isOk()) .andDo(document("new_api/plugins/get_by_hash", getPluginPathParameters(), responseFields(NewApiDocs.getPluginResponse("")))) - .andExpect(status().is2xxSuccessful()) - .andReturn().getResponse(); - logger.debug(response.getContentAsString()); + .andExpect(status().is2xxSuccessful()); } - private static Plugin createPlugin() { + private static Plugin createPlugin(final String hash) { Plugin plugin = new Plugin(); - plugin.setHash("x"); + plugin.setHash(hash); plugin.setName("plugin"); plugin.setVersion("1.0.0"); return plugin; } -// -// @Test -// public void testGetProjectContainsInfoAboutMinervaNet() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", BUILT_IN_PROJECT) -// .session(session); -// -// final MockHttpServletResponse response = mockMvc.perform(request) -// .andExpect(status().isOk()) -// .andReturn().getResponse(); -// -// final Map<String, Object> object = objectMapper.readValue(response.getContentAsString(), new TypeReference<Map<String, Object>>() { -// }); -// -// assertTrue(object.containsKey("sharedInMinervaNet")); -// -// } -// -// @Test -// public void testGetNonExisting() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", "unknown") -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isNotFound()); -// } -// -// @Test -// public void testGetProjectWithoutPermission() throws Exception { -// createAndPersistProject(TEST_PROJECT); -// -// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", TEST_PROJECT); -// -// mockMvc.perform(request) -// .andExpect(status().isForbidden()); -// } -// -// @Test -// public void testCreateProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); -// -// final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// final MockHttpServletResponse response = mockMvc.perform(request) -// .andExpect(status().isCreated()) -// .andReturn().getResponse(); -// assertNotNull(response.getHeader("ETag")); -// -// assertNotNull(projectService.getProjectByProjectId(TEST_PROJECT)); -// } -// -// @Test -// public void testCreateProjectWithProjectIdMismatch() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); -// -// final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/", TEST_PROJECT_2) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isBadRequest()); -// } -// -// @Test -// public void testCreateProjectExisting() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final NewProjectDTO data = createProjectDTO(BUILT_IN_PROJECT); -// -// final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/", BUILT_IN_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isConflict()); -// } -// -// @Test -// public void testUpdateProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// createAndPersistProject(TEST_PROJECT); -// -// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); -// -// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// final HttpServletResponse response = mockMvc.perform(request) -// .andExpect(status().isOk()) -// .andReturn().getResponse(); -// assertNotNull(response.getHeader("ETag")); -// -// final Project project = projectService.getProjectByProjectId(TEST_PROJECT); -// assertEquals(data.getVersion(), project.getVersion()); -// } -// -// @Test -// public void testUpdateProjectWithMissingData() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// createAndPersistProject(TEST_PROJECT); -// -// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); -// data.setName(null); -// -// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isBadRequest()); -// } -// -// @Test -// public void testUpdateProjectWithOldVersion() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// createAndPersistProject(TEST_PROJECT); -// -// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); -// -// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .header("If-Match", "-1") -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isPreconditionFailed()); -// } -// -// @Test -// public void testUpdateProjectWithGoodVersion() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// Project project = createAndPersistProject(TEST_PROJECT); -// -// final String originalVersion = project.getEntityVersion() + ""; -// -// final NewProjectDTO data = createProjectDTO(TEST_PROJECT); -// -// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .header("If-Match", originalVersion) -// .session(session); -// -// final HttpServletResponse response = mockMvc.perform(request) -// .andExpect(status().isOk()) -// .andReturn().getResponse(); -// assertNotNull(response.getHeader("ETag")); -// -// project = projectService.getProjectByProjectId(TEST_PROJECT); -// assertNotEquals(originalVersion, project.getEntityVersion() + ""); -// } -// -// private NewProjectDTO createProjectDTO(final String projectId) { -// final NewProjectDTO data = new NewProjectDTO(); -// data.setName("my name"); -// data.setNotifyEmail("minerva@uni.lu"); -// data.setProjectId(projectId); -// data.setSbgnFormat(false); -// data.setVersion("0.0.1"); -// return data; -// } -// -// @Test -// public void testDeleteProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// createAndPersistProject(TEST_PROJECT); -// -// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .session(session); -// -// final String response = mockMvc.perform(request) -// .andExpect(status().isAccepted()) -// .andReturn().getResponse() -// .getContentAsString(); -// -// final MinervaJob job = objectMapper.readValue(response, MinervaJob.class); -// assertEquals(MinervaJobType.DELETE_PROJECT, job.getJobType()); -// -// minervaJobService.waitForTasksToFinish(); -// -// assertNull(projectService.getProjectByProjectId(TEST_PROJECT)); -// } -// -// @Test -// public void testDeleteNotExistingProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isNotFound()); -// } -// -// @Test -// public void testDeleteNoAccessProject() throws Exception { -// createAndPersistProject(TEST_PROJECT); -// -// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT); -// -// mockMvc.perform(request) -// .andExpect(status().isForbidden()); -// } -// -// @Test -// public void testDeleteDefaultProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", BUILT_IN_PROJECT) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isForbidden()); -// } -// -// @Test -// public void testDeleteProjectDropsPrivileges() throws Exception { -// createAndPersistProject(TEST_PROJECT); -// User curator = createCurator(CURATOR_LOGIN, CURATOR_PASSWORD); -// -// userService.grantUserPrivilege(curator, PrivilegeType.WRITE_PROJECT, TEST_PROJECT); -// -// final RequestBuilder request = delete("/minerva/api/projects/" + TEST_PROJECT) -// .session(createSession(CURATOR_LOGIN, CURATOR_PASSWORD)); -// -// mockMvc.perform(request) -// .andExpect(status().is2xxSuccessful()); -// -// minervaJobService.waitForTasksToFinish(); -// -// curator = userService.getUserByLogin(CURATOR_LOGIN, true); -// -// assertFalse("Curator privileges weren't updated after project was removed", -// curator.getPrivileges().contains(new Privilege(PrivilegeType.WRITE_PROJECT, TEST_PROJECT))); -// } -// -// @Test -// public void testDeleteProjectWithGoodVersion() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final Project project = createAndPersistProject(TEST_PROJECT); -// -// final String originalVersion = project.getEntityVersion() + ""; -// -// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .header("If-Match", originalVersion) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isAccepted()); -// } -// -// @Test -// public void testDeleteProjectWithWrongVersion() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// createAndPersistProject(TEST_PROJECT); -// -// final RequestBuilder request = delete("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .header("If-Match", "-1") -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isPreconditionFailed()); -// } -// -// @Test -// public void testListProjects() throws Exception { -// final RequestBuilder request = get("/minerva/new_api/projects/"); -// -// mockMvc.perform(request) -// .andExpect(status().isOk()); -// } -// -// @Test -// public void testListProjectsWithoutAccess() throws Exception { -// final RequestBuilder request = get("/minerva/new_api/projects/"); -// -// createAndPersistProject(TEST_PROJECT); -// -// final String response = mockMvc.perform(request) -// .andExpect(status().isOk()) -// .andReturn().getResponse() -// .getContentAsString(); -// -// final Page<Object> page = objectMapper.readValue(response, new TypeReference<Page<Object>>() { -// }); -// assertEquals(1, page.getTotalElements()); -// assertEquals(1, page.getNumberOfElements()); -// } -// -// @Test -// public void testListProjectsWithoutAdminAccess() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// final RequestBuilder request = get("/minerva/new_api/projects/") -// .session(session); -// -// createAndPersistProject(TEST_PROJECT); -// -// final String response = mockMvc.perform(request) -// .andExpect(status().isOk()) -// .andReturn().getResponse() -// .getContentAsString(); -// -// final Page<Object> page = objectMapper.readValue(response, new TypeReference<Page<Object>>() { -// }); -// assertEquals(2, page.getTotalElements()); -// assertEquals(2, page.getNumberOfElements()); -// } -// -// @Test -// public void testUpdateOwnerInProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// createAndPersistProject(TEST_PROJECT); -// -// final NewUserLoginDTO data = new NewUserLoginDTO(); -// data.setLogin(Configuration.ANONYMOUS_LOGIN); -// -// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/owner/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// final HttpServletResponse response = mockMvc.perform(request) -// .andExpect(status().isOk()) -// .andReturn().getResponse(); -// assertNotNull(response.getHeader("ETag")); -// -// final Project project = projectService.getProjectByProjectId(TEST_PROJECT); -// assertEquals(Configuration.ANONYMOUS_LOGIN, project.getOwner().getLogin()); -// } -// -// @Test -// public void testUpdateInvalidOwnerInProject() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// createAndPersistProject(TEST_PROJECT); -// -// final NewUserLoginDTO data = new NewUserLoginDTO(); -// data.setLogin("blah"); -// -// final RequestBuilder request = put("/minerva/new_api/projects/{projectId}/owner/", TEST_PROJECT) -// .contentType(MediaType.APPLICATION_JSON) -// .content(objectMapper.writeValueAsString(data)) -// .session(session); -// -// mockMvc.perform(request) -// .andExpect(status().isNotFound()); -// } -// -// @Test -// public void testGetProjects() throws Exception { -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final RequestBuilder request = get("/minerva/new_api/projects/") -// .session(session); -// -// mockMvc.perform(request) -// .andDo(document("new_api/projects/get_projects", -// getProjectsSearchResult())) -// .andExpect(status().is2xxSuccessful()) -// .andReturn().getResponse().getContentAsString(); -// } -// -// private Snippet getProjectsSearchResult() { -// final String prefix = "content[]."; -// final List<FieldDescriptor> fields = new ArrayList<>(); -// fields.add( -// fieldWithPath("content") -// .description("list of projects on the page") -// .type(JsonFieldType.ARRAY)); -// fields.addAll(NewApiDocs.getProjectResponse(prefix)); -// fields.addAll(NewApiDocs.getPageableFields()); -// return responseFields(fields); -// } -// -// @Test -// public void testGetProjectWithError() throws Exception { -// Project project = new Project(TEST_PROJECT); -// projectService.add(project); -// -// final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); -// -// final RequestBuilder request = get("/minerva/new_api/projects/{projectId}/", TEST_PROJECT) -// .session(session); -// -// final MockHttpServletResponse response = mockMvc.perform(request) -// .andExpect(status().isInternalServerError()) -// .andReturn().getResponse(); -// -// Map<String, String> data = objectMapper.readValue(response.getContentAsString(), new TypeReference<Map<String, String>>() { -// }); -// -// assertNotNull(data.get("error-id")); -// assertNotNull(stacktraceService.getById(data.get("error-id"))); -// } -// + + @Test + public void testGetNonExisting() throws Exception { + final RequestBuilder request = get("/minerva/new_api/plugins/{pluginId}/", "unknown"); + + mockMvc.perform(request) + .andExpect(status().isNotFound()); + } + + @Test + public void testCreatePlugin() throws Exception { + final NewPluginDTO data = createPluginDTO(PLUGIN_HASH); + + final RequestBuilder request = post("/minerva/new_api/plugins/") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)); + + final MockHttpServletResponse response = mockMvc.perform(request) + .andExpect(status().isCreated()) + .andReturn().getResponse(); + assertNotNull(response.getHeader("ETag")); + + assertNotNull(pluginService.getByHash(PLUGIN_HASH)); + } + + @Test + public void testCreatePluginWithHashMismatch() throws Exception { + final NewPluginDTO data = createPluginDTO(TEST_PROJECT); + + final RequestBuilder request = post("/minerva/new_api/plugins/") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)); + + mockMvc.perform(request) + .andExpect(status().isBadRequest()); + } + + @Test + public void testCreatePluginExisting() throws Exception { + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final NewPluginDTO data = createPluginDTO(PLUGIN_HASH); + + final RequestBuilder request = post("/minerva/new_api/plugins/") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)); + + mockMvc.perform(request) + .andExpect(status().isConflict()); + } + + @Test + public void testUpdatePlugin() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final NewPluginDTO data = createPluginDTO(PLUGIN_HASH); + + final RequestBuilder request = put("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)) + .session(session); + + final HttpServletResponse response = mockMvc.perform(request) + .andExpect(status().isOk()) + .andReturn().getResponse(); + assertNotNull(response.getHeader("ETag")); + + plugin = pluginService.getByHash(PLUGIN_HASH); + assertEquals(data.getVersion(), plugin.getVersion()); + } + + + @Test + public void testUpdatePluginWithMissingData() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final NewPluginDTO data = createPluginDTO(PLUGIN_HASH); + data.setName(null); + + final RequestBuilder request = put("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)) + .session(session); + + mockMvc.perform(request) + .andExpect(status().isBadRequest()); + } + + @Test + public void testUpdatePluginWithOldVersion() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final NewPluginDTO data = createPluginDTO(PLUGIN_HASH); + + final RequestBuilder request = put("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)) + .header("If-Match", "-1") + .session(session); + + mockMvc.perform(request) + .andExpect(status().isPreconditionFailed()); + } + + @Test + public void testUpdatePluginWithGoodVersion() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + String originalVersion = plugin.getEntityVersion() + ""; + + final NewPluginDTO data = createPluginDTO(PLUGIN_HASH); + + final RequestBuilder request = put("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(data)) + .header("If-Match", originalVersion) + .session(session); + + final HttpServletResponse response = mockMvc.perform(request) + .andExpect(status().isOk()) + .andReturn().getResponse(); + assertNotNull(response.getHeader("ETag")); + + plugin = pluginService.getByHash(PLUGIN_HASH); + assertEquals(data.getVersion(), plugin.getVersion()); + + assertNotEquals(originalVersion, plugin.getEntityVersion() + ""); + } + + private NewPluginDTO createPluginDTO(final String hash) { + final NewPluginDTO data = new NewPluginDTO(); + data.setName("my name"); + data.setHash(hash); + data.setName("starter-kit"); + data.setVersion("0.0.1"); + data.setUrl(PLUGIN_URL); + return data; + } + + + @Test + public void testDeletePlugin() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final RequestBuilder request = delete("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .session(session); + + mockMvc.perform(request) + .andExpect(status().isOk()); + + assertNull(pluginService.getByHash(PLUGIN_HASH)); + } + + + @Test + public void testDeleteNotExistingPlugin() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + final RequestBuilder request = delete("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .session(session); + + mockMvc.perform(request) + .andExpect(status().isNotFound()); + } + + @Test + public void testDeleteNoAccessPlugin() throws Exception { + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final RequestBuilder request = delete("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH); + + mockMvc.perform(request) + .andExpect(status().isForbidden()); + } + + @Test + public void testDeletePluginWithGoodVersion() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final String originalVersion = plugin.getEntityVersion() + ""; + + final RequestBuilder request = delete("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .header("If-Match", originalVersion) + .session(session); + + mockMvc.perform(request) + .andExpect(status().isOk()); + } + + @Test + public void testDeletePluginWithWrongVersion() throws Exception { + final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD); + + Plugin plugin = createPlugin(PLUGIN_HASH); + pluginService.add(plugin); + + final RequestBuilder request = delete("/minerva/new_api/plugins/{pluginId}/", PLUGIN_HASH) + .header("If-Match", "-1") + .session(session); + + mockMvc.perform(request) + .andExpect(status().isPreconditionFailed()); + } + + @Test + public void testListPlugins() throws Exception { + final RequestBuilder request = get("/minerva/new_api/plugins/"); + + mockMvc.perform(request) + .andExpect(status().isOk()); + } } -- GitLab