Commit 2df69c87 authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

refactored delete service tests

parent c7ae8d2e
Loading
Loading
Loading
Loading
+9 −27
Original line number Diff line number Diff line
@@ -6,14 +6,7 @@
package it.inaf.oats.vospace;

import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.LinkFoundException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.vospace.v2.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -23,7 +16,6 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class DeleteNodeController extends BaseNodeController {

@@ -39,20 +31,10 @@ public class DeleteNodeController extends BaseNodeController {
        String path = getPath();
        LOG.debug("deleteNode called for path {}", path);

        
        try {
        deleteNodeService.doPreliminaryChecks(path);
        deleteNodeService.deleteNode(path, principal);
        return ResponseEntity.ok("Node deleted");
        } catch(Exception ex) {
            return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
        }       

    }

}


    
    
+5 −7
Original line number Diff line number Diff line
@@ -14,8 +14,6 @@ import java.util.List;
import net.ivoa.xml.vospace.v2.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Isolation;
@@ -63,7 +61,7 @@ public class DeleteNodeService {

    }

    public void doPreliminaryChecks(String path) throws Exception {
    public void doPreliminaryChecks(String path) {
        // Check if the node is present, 
        // if the node does not exist the service SHALL throw a HTTP 404 status code 
        // including a NodeNotFound fault in the entity-body 
@@ -76,13 +74,13 @@ public class DeleteNodeService {
        // For example, given the URI path /a/b/c, the service must throw a HTTP 400 
        // status code including a LinkFound fault in the entity-body if either /a 
        // or /a/b are LinkNodes.        
        List<String> pathComponents = NodeUtils.subPathComponents(path);
        if (pathComponents.isEmpty()) {
        if (path.equals("/")) {
            
            // Manage root node
            throw PermissionDeniedException.forPath("/");

        } else {
            List<String> pathComponents = NodeUtils.subPathComponents(path);

            // Manage all precursors in full path
            for (int i = 0; i < pathComponents.size(); i++) {
+0 −201
Original line number Diff line number Diff line
/*
 * This file is part of vospace-rest
 * Copyright (C) 2021 Istituto Nazionale di Astrofisica
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package it.inaf.oats.vospace;

import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.persistence.NodeDAO;
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.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.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@ContextConfiguration(classes = {TokenFilterConfig.class})
@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true")
@AutoConfigureMockMvc 
public class DeleteNodeControllerTest {    
    
    private static final String URI_PREFIX = "vos://example.com!vospace";
    
    @MockBean
    private NodeDAO nodeDao;

    @Autowired
    private MockMvc mockMvc;

    
    @Test
    public void testDeleteRootNode() throws Exception {
        
        when(nodeDao.listNode(eq("/"))).thenReturn(getRootNode());

        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isForbidden());
        
    }
   
    
    @Test
    public void testDeleteFirstLevelNode() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode()));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes/mynode")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isOk());
        
    }
       

    
    @Test
    public void testDeleteMoreLevelNode() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));        
        when(nodeDao.listNode(eq("/mynode/middlenode"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode")));        
        when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes/mynode/middlenode/myfile.txt")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isOk());
        
    }

    
    @Test
    public void testLeafNodeNotFound() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes/mynode/notexisting")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isNotFound());
        
    }

    
    @Test
    public void testMiddleLevelNodeNotFound() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));     
        when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/mynode/middlenode/myfile.txt")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isNotFound());
        
    }

    
    @Test
    public void testLinkNodeLeafDelete() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableLinkNode("/mynode")));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes/mynode")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isOk());
        
    }

    
    @Test
    public void testMiddleLevelLinkNodeDelete() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));        
        when(nodeDao.listNode(eq("/mynode/middlenode"))).thenReturn(Optional.of(getWritableLinkNode("/mynode/middlenode")));        
        when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes/mynode/middlenode/myfile.txt")
                        .header("Authorization", "Bearer user2_token"))
                        .andExpect(status().isBadRequest());
        
    }
    

    @Test
    public void testDeleteMoreLevelNodeNotAllowed() throws Exception {
        
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(getWritableDataNode("/mynode")));        
        when(nodeDao.listNode(eq("/mynode/middlenode"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode")));        
        when(nodeDao.listNode(eq("/mynode/middlenode/myfile.txt"))).thenReturn(Optional.of(getWritableDataNode("/mynode/middlenode/myfile.txt")));
        
        mockMvc.perform(MockMvcRequestBuilders
                        .delete("/nodes/mynode/middlenode/myfile.txt"))
                        .andExpect(status().isForbidden());
        
    }
    
    
    private Optional<Node> getRootNode() {
        ContainerNode root = new ContainerNode();
        root.setUri(URI_PREFIX + "/");
        root.getNodes().add(getWritableDataNode());
        return Optional.of(root);
    }
    
    

    private Node getWritableDataNode() {
        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 + "/mynode");
        return node;
    }
    
    
    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 LinkNode getWritableLinkNode(String path) {
        LinkNode myNode = new LinkNode();
        // Set parent node address at /
        myNode.setUri("vos://example.com!vospace" + path);
        // Set groupwrite property
        Property groups = new Property();
        groups.setUri("ivo://ivoa.net/vospace/core#groupwrite");
        groups.setValue("group1");
        myNode.setProperties(List.of(groups));
        return myNode;
    }

}
+147 −0
Original line number Diff line number Diff line
/*
 * This file is part of vospace-rest
 * Copyright (C) 2021 Istituto Nazionale di Astrofisica
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package it.inaf.oats.vospace;

import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.DataSourceConfigSingleton;
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
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.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.annotation.DirtiesContext;

@SpringBootTest
@AutoConfigureMockMvc
@ContextConfiguration(classes = DataSourceConfigSingleton.class)
@TestPropertySource(locations = "classpath:test.properties", properties = {"vospace-authority=example.com!vospace", "file-service-url=http://file-service"})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class DeleteNodeServiceTest {    
 
    @Autowired
    private DeleteNodeService deleteNodeService;
    
    @Autowired
    private NodeDAO nodeDao;
    
    
    @Test
    public void testPreliminaryCheckOnRoot() {
        assertThrows(PermissionDeniedException.class, ()->{
            deleteNodeService.doPreliminaryChecks("/");
        });
    }
    
    @Test
    public void testPreliminaryNodeNotFound() {
        assertThrows(NodeNotFoundException.class, ()->{
            deleteNodeService.doPreliminaryChecks("/nonexistent/node");
        });
    }
    
    @Test
    public void deleteBranchTest() {
        User user = mock(User.class);
        when(user.getName()).thenReturn("user3");

        Optional<Long> sourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(sourceId.isPresent());
        Optional<Long> childId = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(childId.isPresent());
        // Delete
        deleteNodeService.deleteNode("/test3/m1", user);

        Optional<Long> checkSourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(checkSourceId.isEmpty());
        
        Optional<Long> checkSourceIdChild = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(checkSourceIdChild.isEmpty());        
        
    }
    
    @Test
    public void deleteStopOnImmutableTest() {
        User user = mock(User.class);
        when(user.getName()).thenReturn("user3");

        Optional<Long> sourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(sourceId.isPresent());
        Optional<Long> childId = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(childId.isPresent());
        
        nodeDao.setBranchImmutable(childId.get(), true);
        
        // Delete
        assertThrows(InternalFaultException.class, 
                ()->{ deleteNodeService.deleteNode("/test3/m1", user);}
        );

        Optional<Long> checkSourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(checkSourceId.isPresent());
        
        Optional<Long> checkSourceIdChild = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(checkSourceIdChild.isPresent());        
    }
    
    @Test
    public void deleteStopOnBusyTest() {
        User user = mock(User.class);
        when(user.getName()).thenReturn("user3");

        Optional<Long> sourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(sourceId.isPresent());
        Optional<Long> childId = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(childId.isPresent());
        
        nodeDao.setBranchJobId(childId.get(), "pippo");
        
        // Delete
        assertThrows(NodeBusyException.class, 
                ()->{ deleteNodeService.deleteNode("/test3/m1", user);}
        );

        Optional<Long> checkSourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(checkSourceId.isPresent());
        
        Optional<Long> checkSourceIdChild = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(checkSourceIdChild.isPresent());        
    }
    
    
    @Test
    public void deleteStopOnPermissionDeniedTest() {
        User user = mock(User.class);
        when(user.getName()).thenReturn("user-pippo");

        Optional<Long> sourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(sourceId.isPresent());
        Optional<Long> childId = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(childId.isPresent());
      
        // Delete
        assertThrows(PermissionDeniedException.class, 
                ()->{ deleteNodeService.deleteNode("/test3/m1", user);}
        );

        Optional<Long> checkSourceId = nodeDao.getNodeId("/test3/m1");
        assertTrue(checkSourceId.isPresent());
        
        Optional<Long> checkSourceIdChild = nodeDao.getNodeId("/test3/m1/m2");
        assertTrue(checkSourceIdChild.isPresent());        
    }

}