diff --git a/src/test/java/it/inaf/oats/vospace/SetNodeControllerTest.java b/src/test/java/it/inaf/oats/vospace/SetNodeControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a7b490c245878a3e4d3279a021e499af2fbaf6f6 --- /dev/null +++ b/src/test/java/it/inaf/oats/vospace/SetNodeControllerTest.java @@ -0,0 +1,221 @@ +package it.inaf.oats.vospace; + +import it.inaf.oats.vospace.datamodel.NodeProperties; +import it.inaf.oats.vospace.persistence.NodeDAO; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import net.ivoa.xml.vospace.v2.ContainerNode; +import net.ivoa.xml.vospace.v2.DataNode; +import net.ivoa.xml.vospace.v2.LinkNode; +import net.ivoa.xml.vospace.v2.Node; +import net.ivoa.xml.vospace.v2.Property; +import org.junit.jupiter.api.Test; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +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.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +@ContextConfiguration(classes = {TokenFilterConfig.class}) +@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true") +public class SetNodeControllerTest { + + private static final String URI_PREFIX = "vos://example.com!vospace"; + + @MockBean + private NodeDAO nodeDao; + + @Autowired + private MockMvc mockMvc; + + protected static String getResourceFileContent(String fileName) throws Exception { + try ( InputStream in = CreateNodeControllerTest.class.getClassLoader().getResourceAsStream(fileName)) { + return new String(in.readAllBytes(), StandardCharsets.UTF_8); + } + } + + private ContainerNode getContainerParentNode(String path) { + ContainerNode parentNode = new ContainerNode(); + // Set parent node address at / + parentNode.setUri("vos://example.com!vospace" + path); + // Set groupwrite property + Property groups = new Property(); + groups.setUri("ivo://ivoa.net/vospace/core#groupwrite"); + groups.setValue("group1 group2"); + parentNode.setProperties(List.of(groups)); + return parentNode; + } + + private Node getWritableDataNode(String path) { + DataNode node = new DataNode(); + List nodeProperties = node.getProperties(); + Property groupWriteProp = new Property(); + groupWriteProp.setUri(NodeProperties.GROUP_WRITE_URI); + groupWriteProp.setValue("group1"); + nodeProperties.add(groupWriteProp); + node.setUri(URI_PREFIX + path); + return node; + } + + private Node getWritableDataNodeWithAcceptsAndProvides(String path) { + DataNode node = new DataNode(); + List nodeProperties = node.getProperties(); + Property groupWriteProp = new Property(); + groupWriteProp.setUri(NodeProperties.GROUP_WRITE_URI); + groupWriteProp.setValue("group1"); + Property groupReadProp = new Property(); + groupReadProp.setUri(NodeProperties.GROUP_READ_URI); + groupReadProp.setValue("group1 group2"); + Property descriptionProp = new Property(); + descriptionProp.setUri(NodeProperties.DESCRIPTION_URI); + descriptionProp.setValue("Modified description"); + nodeProperties.add(groupWriteProp); + nodeProperties.add(groupReadProp); + nodeProperties.add(descriptionProp); + List accepts = new ArrayList(); + accepts.add("ivo://ivoa.net/vospace/core#httpput"); + accepts.add("ivo://ivoa.net/vospace/core#defaultview"); + node.setAccepts(accepts); + List provides = new ArrayList(); + provides.add("ivo://ivoa.net/vospace/core#httpput"); + provides.add("ivo://ivoa.net/vospace/core#defaultview"); + node.setAccepts(provides); + node.setUri(URI_PREFIX + path); + return node; + } + + /* Test case: + try to modify node type. + Forbidden. + */ + @Test + public void testUpdateType() throws Exception { + + String requestBody = getResourceFileContent("modify-data-node-1_type.xml"); + + // Create node + when(nodeDao.listNode(eq("/"))) + .thenReturn(Optional.of(getContainerParentNode("/"))); + when(nodeDao.listNode(eq("/mydata1"))).thenReturn(Optional.of(getWritableDataNode("/mydata1"))); + + mockMvc.perform(post("/nodes/mydata1") + .header("Authorization", "Bearer user2_token") + .content(requestBody) + .contentType(MediaType.APPLICATION_XML) + .accept(MediaType.APPLICATION_XML)) + .andDo(print()) + .andExpect(status().isForbidden()); + + } + + /* Test case: + try to add accepted views to a node without views. + Forbidden + */ + @Test + public void testModifyAccepts() throws Exception { + + String requestBody = getResourceFileContent("modify-data-node-1-views.xml"); + + // Create node + when(nodeDao.listNode(eq("/"))) + .thenReturn(Optional.of(getContainerParentNode("/"))); + when(nodeDao.listNode(eq("/mydata1"))).thenReturn(Optional.of(getWritableDataNode("/mydata1"))); + + mockMvc.perform(post("/nodes/mydata1") + .header("Authorization", "Bearer user2_token") + .content(requestBody) + .contentType(MediaType.APPLICATION_XML) + .accept(MediaType.APPLICATION_XML)) + .andDo(print()) + .andExpect(status().isForbidden()); + + } + + /* Test case: + try to modify accepted and provides views and protocols of a node already having. + Forbidden + */ + @Test + public void testModifyAcceptsAndProvides() throws Exception { + + String requestBody = getResourceFileContent("modify-data-node-1-views_and_protocols.xml"); + + // Create node + when(nodeDao.listNode(eq("/"))) + .thenReturn(Optional.of(getContainerParentNode("/"))); + when(nodeDao.listNode(eq("/mydata1"))).thenReturn(Optional.of(getWritableDataNodeWithAcceptsAndProvides("/mydata1"))); + + mockMvc.perform(post("/nodes/mydata1") + .header("Authorization", "Bearer user2_token") + .content(requestBody) + .contentType(MediaType.APPLICATION_XML) + .accept(MediaType.APPLICATION_XML)) + .andDo(print()) + .andExpect(status().isForbidden()); + + } + + /* Test case: + try to modify node having accepted and provides views and protocols + Forbidden + */ + @Test + public void testModifyNodeHavingAcceptsAndProvides() throws Exception { + + String requestBody = getResourceFileContent("modify-data-node-having-views_and_protocols.xml"); + + // Create node + when(nodeDao.listNode(eq("/"))) + .thenReturn(Optional.of(getContainerParentNode("/"))); + when(nodeDao.listNode(eq("/mydata1"))).thenReturn(Optional.of(getWritableDataNodeWithAcceptsAndProvides("/mydata1"))); + + mockMvc.perform(post("/nodes/mydata1") + .header("Authorization", "Bearer user2_token") + .content(requestBody) + .contentType(MediaType.APPLICATION_XML) + .accept(MediaType.APPLICATION_XML)) + .andDo(print()) + .andExpect(status().isForbidden()); + + } + + /* Test case: + try to modify node not modifying accepted and provides views and protocols + Expect OK + */ + @Test + public void testModifyNodeLeavingAcceptsAndProvides() throws Exception { + String requestBody = getResourceFileContent("modify-data-node_description-leaving-views_and_protocols.xml"); + + // Create node + when(nodeDao.listNode(eq("/"))) + .thenReturn(Optional.of(getContainerParentNode("/"))); + when(nodeDao.listNode(eq("/mydata1"))).thenReturn(Optional.of(getWritableDataNodeWithAcceptsAndProvides("/mydata1"))); + when(nodeDao.setNode(any())).thenReturn(Optional.of(getWritableDataNodeWithAcceptsAndProvides("/mydata1"))); + + mockMvc.perform(post("/nodes/mydata1") + .header("Authorization", "Bearer user2_token") + .content(requestBody) + .contentType(MediaType.APPLICATION_XML) + .accept(MediaType.APPLICATION_XML)) + .andDo(print()) + .andExpect(status().isOk()); + + } + +} diff --git a/src/test/java/it/inaf/oats/vospace/UpdateNodeController.java b/src/test/java/it/inaf/oats/vospace/UpdateNodeController.java deleted file mode 100644 index 889b39dc8baa2d0a0cd6cd58f272add677bd7e57..0000000000000000000000000000000000000000 --- a/src/test/java/it/inaf/oats/vospace/UpdateNodeController.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package it.inaf.oats.vospace; - -/** - * - * @author bertocco - */ -public class UpdateNodeController { - -} diff --git a/src/test/resources/modify-data-node-1-views.xml b/src/test/resources/modify-data-node-1-views.xml new file mode 100644 index 0000000000000000000000000000000000000000..04eba6f9bf13a034b74d67612d0c17561f1bf9af --- /dev/null +++ b/src/test/resources/modify-data-node-1-views.xml @@ -0,0 +1,12 @@ +<vos:node xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" xsi:type="vos:DataNode" uri="vos://example.com!vospace/mydata1"> + <vos:properties> + <vos:property uri="ivo://ivoa.net/vospace/core#description">Data node 1, no views or protocols</vos:property> + </vos:properties> + <vos:accepts> + <vos:view uri="ivo://ivoa.net/vospace/core#anyview"/> + </vos:accepts> + <vos:provides/> + <vos:capabilities/> +</vos:node> diff --git a/src/test/resources/modify-data-node-1_type.xml b/src/test/resources/modify-data-node-1_type.xml new file mode 100644 index 0000000000000000000000000000000000000000..730d8fd210a3bcbea55d1bf8add904e7cbd9c80a --- /dev/null +++ b/src/test/resources/modify-data-node-1_type.xml @@ -0,0 +1,10 @@ +<vos:node xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" xsi:type="vos:LinkNode" uri="vos://example.com!vospace/mydata1"> + <vos:properties> + <vos:property uri="ivo://ivoa.net/vospace/core#description">Data node 1, no views or protocols</vos:property> + </vos:properties> + <vos:accepts/> + <vos:provides/> + <vos:capabilities/> +</vos:node> diff --git a/src/test/resources/modify-data-node-having-views_and_protocols.xml b/src/test/resources/modify-data-node-having-views_and_protocols.xml new file mode 100644 index 0000000000000000000000000000000000000000..c7e4e1d5105ad70d5771f4abd627a4c2ad852baf --- /dev/null +++ b/src/test/resources/modify-data-node-having-views_and_protocols.xml @@ -0,0 +1,18 @@ +<vos:node xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" xsi:type="vos:DataNode" uri="vos://example.com!vospace/mydata1"> + <vos:properties> + <vos:property uri="ivo://ivoa.net/vospace/core#description">Data node 1, views and protocols</vos:property> + <vos:property uri="ivo://ivoa.net/vospace/core#groupread">group1</vos:property> + <vos:property uri="ivo://ivoa.net/vospace/core#publicread">true</vos:property> + </vos:properties> + <vos:accepts> + <vos:property uri="ivo://ivoa.net/vospace/core#httpget"/> + <vos:view uri="ivo://ivoa.net/vospace/core#defaultview"/> + </vos:accepts> + <vos:provides> + <vos:property uri="ivo://ivoa.net/vospace/core#httpget"/> + <vos:view uri="ivo://ivoa.net/vospace/core#defaultview"/> + </vos:provides> + <vos:capabilities/> +</vos:node> diff --git a/src/test/resources/modify-data-node_description-leaving-views_and_protocols.xml b/src/test/resources/modify-data-node_description-leaving-views_and_protocols.xml new file mode 100644 index 0000000000000000000000000000000000000000..8d0c5930be7123bc48ac7eb6d1a05ec799af6337 --- /dev/null +++ b/src/test/resources/modify-data-node_description-leaving-views_and_protocols.xml @@ -0,0 +1,19 @@ +<vos:node xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" xsi:type="vos:DataNode" uri="vos://example.com!vospace/mydata1"> + <vos:properties> + <vos:property uri="ivo://ivoa.net/vospace/core#description">Data node 1, views and protocols</vos:property> + <vos:property uri="ivo://ivoa.net/vospace/core#groupread">group1 group2</vos:property> + <vos:property uri="ivo://ivoa.net/vospace/core#groupwrite">group1</vos:property> + <vos:property uri="ivo://ivoa.net/vospace/core#publicread">true</vos:property> + </vos:properties> + <vos:accepts> + <vos:property uri="ivo://ivoa.net/vospace/core#httpput"/> + <vos:view uri="ivo://ivoa.net/vospace/core#defaultview"/> + </vos:accepts> + <vos:provides> + <vos:property uri="ivo://ivoa.net/vospace/core#httpput"/> + <vos:view uri="ivo://ivoa.net/vospace/core#defaultview"/> + </vos:provides> + <vos:capabilities/> +</vos:node>