/* * 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.persistence; import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.persistence.NodeDAO.ShortNodeDescriptor; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.ArrayList; import java.util.Arrays; import java.util.Set; import javax.sql.DataSource; 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.View; import static org.junit.jupiter.api.Assertions.assertEquals; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.util.ReflectionTestUtils; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {DataSourceConfig.class}) @TestPropertySource(locations = "classpath:test.properties") public class NodeDAOTest { private static final String AUTHORITY = "example.com!vospace"; @Autowired private DataSource dataSource; private NodeDAO dao; @BeforeEach public void init() { dao = new NodeDAO(dataSource); ReflectionTestUtils.setField(dao, "authority", AUTHORITY); } @Test public void testCreateNode() { DataNode dataNode = new DataNode(); dataNode.setUri("vos://example.com!vospace/mydata1"); dataNode.setAccepts(getViews()); dataNode.setProvides(getViews()); dataNode.setBusy(true); dao.createNode(dataNode); DataNode retrievedNode = (DataNode) dao.listNode("/mydata1").get(); assertEquals(retrievedNode.getAccepts().get(0).getUri(), dataNode.getAccepts().get(0).getUri()); assertEquals(retrievedNode.getProvides().get(0).getUri(), dataNode.getProvides().get(0).getUri()); } @Test public void testCreateLinkNode() { LinkNode linkNode = new LinkNode(); String target = "vos://example.com!vospace/myData1"; linkNode.setUri("vos://example.com!vospace/myLink1"); linkNode.setTarget(target); dao.createNode(linkNode); Node retrievedNode = dao.listNode("/myLink1").get(); assertTrue(retrievedNode instanceof LinkNode); assertEquals(target, ((LinkNode) retrievedNode).getTarget()); } @Test public void testListNode() { ContainerNode root = (ContainerNode) dao.listNode("/").get(); assertEquals(5, root.getNodes().size()); assertEquals("true", NodeProperties.getNodePropertyByURI(root, NodeProperties.PUBLIC_READ_URI)); assertEquals("0", NodeProperties.getNodePropertyByURI(root, NodeProperties.LENGTH_URI)); assertEquals("group1", NodeProperties.getNodePropertyByURI(root.getNodes().get(0), NodeProperties.GROUP_READ_URI)); String bTime = NodeProperties.getNodePropertyByURI(root.getNodes().get(0), NodeProperties.INITIAL_CREATION_TIME_URI); assertTrue(bTime.contains("T")); assertEquals(bTime, NodeProperties.getNodePropertyByURI(root.getNodes().get(0), NodeProperties.DATE_URI)); } @Test public void testListNodeChildren() { assertTrue(dao.listNodeChildren("/test4").isEmpty()); List children = dao.listNodeChildren("/test2"); assertFalse(children.isEmpty()); assertTrue(children.size() == 2); assertTrue(children.containsAll(List.of("f4", "f5"))); } @Test public void testGetQuotaAndMD5() { ContainerNode node = (ContainerNode) dao.listNode("/test1/f1/f2_renamed").get(); assertEquals("50000", NodeProperties.getNodePropertyByURI(node, NodeProperties.QUOTA_URI)); DataNode child = (DataNode) node.getNodes().get(0); assertEquals("4000", NodeProperties.getNodePropertyByURI(child, NodeProperties.LENGTH_URI)); assertEquals("", NodeProperties.getNodePropertyByURI(child, NodeProperties.MD5_URI)); } @Test public void testGetNodeId() { Optional id1 = dao.getNodeId("/test1"); assertTrue(id1.isPresent()); assertEquals(2, id1.get()); Optional id2 = dao.getNodeId("/test1/f1"); assertTrue(id2.isPresent()); assertEquals(3, id2.get()); Optional id3 = dao.getNodeId("/pippo123123"); assertTrue(id3.isEmpty()); } @Test public void testGetShortNodeDescriptor() { String userName = "user3"; List userGroups = List.of(); Optional snd1Opt = dao.getShortNodeDescriptor("/test3/mstick", userName, userGroups); assertTrue(snd1Opt.isPresent()); ShortNodeDescriptor snd1 = snd1Opt.get(); assertTrue(snd1.isContainer()); assertFalse(snd1.isPermissionDenied()); assertTrue(snd1.isWritable()); assertFalse(snd1.isBusy()); assertTrue(snd1.isSticky()); assertEquals("9.13", snd1.getDestinationNodeLtreePath()); snd1Opt = dao.getShortNodeDescriptor("/test3/mbusy", userName, userGroups); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertTrue(snd1.isWritable()); assertFalse(snd1.isPermissionDenied()); assertTrue(snd1.isBusy()); assertFalse(snd1.isSticky()); snd1Opt = dao.getShortNodeDescriptor("/test3/masynctrans", userName, userGroups); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertFalse(snd1.isWritable()); assertFalse(snd1.isBusy()); snd1Opt = dao.getShortNodeDescriptor("/test3/asyncloc", userName, userGroups); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertFalse(snd1.isWritable()); assertFalse(snd1.isBusy()); snd1Opt = dao.getShortNodeDescriptor("/test1/f1/f2_renamed/f3", "user1", userGroups); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertFalse(snd1.isContainer()); assertFalse(snd1.isWritable()); assertFalse(snd1.isPermissionDenied()); assertFalse(snd1.isBusy()); snd1Opt = dao.getShortNodeDescriptor("/test3/group1", "user1", userGroups); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertTrue(snd1.isWritable()); assertTrue(snd1.isPermissionDenied()); snd1Opt = dao.getShortNodeDescriptor("/test3/group1", "user3", List.of("group99")); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertTrue(snd1.isWritable()); assertFalse(snd1.isPermissionDenied()); snd1Opt = dao.getShortNodeDescriptor("/test3/group1", "user1", List.of("group1", "group2")); assertTrue(snd1Opt.isPresent()); snd1 = snd1Opt.get(); assertTrue(snd1.isWritable()); assertFalse(snd1.isPermissionDenied()); } @Test public void testIsBranchBusy() { Optional optId = dao.getNodeId("/test3/m1"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchBusy(optId.get())); optId = dao.getNodeId("/test3"); assertTrue(optId.isPresent()); assertTrue(dao.isBranchBusy(optId.get())); } @Test public void testIsBranchWritable() { List userGroups = List.of("group1"); Optional optId = dao.getNodeId("/test3/m1"); assertTrue(optId.isPresent()); assertTrue(dao.isBranchWritable(optId.get(), "user3", userGroups)); optId = dao.getNodeId("/test3"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchWritable(optId.get(), "user3", userGroups)); optId = dao.getNodeId("/test3/group1"); assertTrue(optId.isPresent()); assertTrue(dao.isBranchWritable(optId.get(), "user3", userGroups)); optId = dao.getNodeId("/test3/group1"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchWritable(optId.get(), "user1", List.of("group99"))); } @Test public void testIsBranchReadable() { List userGroups = List.of("group1"); Optional optId = dao.getNodeId("/test3/m1"); assertTrue(optId.isPresent()); assertTrue(dao.isBranchReadable(optId.get(), "user3", userGroups)); optId = dao.getNodeId("/test3"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchReadable(optId.get(), "user2", userGroups)); optId = dao.getNodeId("/test3/group1"); assertTrue(optId.isPresent()); assertTrue(dao.isBranchReadable(optId.get(), "user2", userGroups)); optId = dao.getNodeId("/test3/group1"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchReadable(optId.get(), "user1", List.of("group99"))); } @Test public void testSetJobId() { Optional optId = dao.getNodeId("/test3/m1"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchBusy(optId.get())); dao.setBranchJobId(optId.get(), "pippo1"); assertTrue(dao.isBranchBusy(optId.get())); Optional childId = dao.getNodeId("/test3/m1/m2"); assertTrue(childId.isPresent()); assertTrue(dao.isBranchBusy(childId.get())); dao.setBranchJobId(optId.get(), null); assertFalse(dao.isBranchBusy(optId.get())); assertFalse(dao.isBranchBusy((childId.get()))); } @Test public void testMoveNodeBranch() { // Let's move /test3/m1 to /test3/group1 Optional optSourceId = dao.getNodeId("/test3/m1"); assertTrue(optSourceId.isPresent()); Optional optSnd = dao.getShortNodeDescriptor("/test3/group1", "user3", List.of("group1")); assertTrue(optSnd.isPresent()); ShortNodeDescriptor snd = optSnd.get(); assertEquals("9.17", snd.getDestinationNodeLtreePath()); dao.moveNodeBranch(optSourceId.get(), snd.getDestinationNodeLtreePath()); Optional optResultId = dao.getNodeId("/test3/group1/m1"); assertTrue(optResultId.isPresent()); optSnd = dao.getShortNodeDescriptor("/test3/group1/m1", "user3", List.of("group1")); assertEquals("9.17.10", optSnd.get().getDestinationNodeLtreePath()); Optional optResultIdChild = dao.getNodeId("/test3/group1/m1/m2"); optSnd = dao.getShortNodeDescriptor("/test3/group1/m1/m2", "user3", List.of("group1")); assertEquals("9.17.10.11", optSnd.get().getDestinationNodeLtreePath()); assertTrue(optResultIdChild.isPresent()); } @Test public void testCopyNodeBranch() { // Let's copy /test3/m1 to /test3/group1 Optional optSourceId = dao.getNodeId("/test3/m1"); assertTrue(optSourceId.isPresent()); Optional optSourceChildId = dao.getNodeId("/test3/m1/m2"); assertTrue(optSourceChildId.isPresent()); Optional optSourceChildLinkId = dao.getNodeId("/test3/m1/link1"); assertTrue(optSourceChildLinkId.isPresent()); Optional optDestParentId = dao.getNodeId("/test3/group1"); assertTrue(optDestParentId.isPresent()); dao.copyBranch("/test3/m1", "/test3/group1/copy_of_m1"); Optional resultId = dao.getNodeId("/test3/group1/copy_of_m1"); assertTrue(resultId.isPresent()); Optional recheckSource = dao.getNodeId("/test3/m1"); assertTrue(recheckSource.isPresent()); Optional resultIdChild = dao.getNodeId("/test3/group1/copy_of_m1/m2"); assertTrue(resultIdChild.isPresent()); Optional recheckSourceChild = dao.getNodeId("/test3/m1/m2"); assertTrue(recheckSourceChild.isPresent()); Optional resultIdChildLink = dao.getNodeId("/test3/group1/copy_of_m1/link1"); assertTrue(resultIdChildLink.isPresent()); Optional recheckSourceChildLink = dao.getNodeId("/test3/m1/link1"); assertTrue(recheckSourceChildLink.isPresent()); } @Test public void testMoveAndCopyIntegrated() { assertTrue(dao.getNodeId("/mycontainer").isPresent()); assertTrue(dao.getNodeId("/mycontainer/destination2").isPresent()); assertTrue(dao.getNodeId("/mycontainer/destination2/control").isPresent()); dao.copyBranch("/mycontainer/destination2/control", "/mycontainer/control"); assertTrue(dao.getNodeId("/mycontainer/container1").isPresent()); Optional optSnd = dao.getShortNodeDescriptor("/mycontainer/destination2", "user3", List.of("group1")); dao.moveNodeBranch(dao.getNodeId("/mycontainer/container1").get(), optSnd.get().getDestinationNodeLtreePath()); assertTrue(dao.getNodeId("/mycontainer/destination2/container1").isPresent()); assertTrue(dao.getNodeId("/mycontainer/container1").isEmpty()); dao.copyBranch("/mycontainer/destination2/container1", "/mycontainer/container1"); assertTrue(dao.getNodeId("/mycontainer/container1").isPresent()); } @Test public void testRenameNode() { String oldPath = "/test1/f1"; String newPath = "/test1/f_pippo"; String child = "/f2_renamed"; String oldPathChild = oldPath + child; String newPathChild = newPath + child; assertTrue(dao.listNode(oldPath).isPresent()); assertTrue(dao.listNode(oldPathChild).isPresent()); Optional rootId = dao.getNodeId(oldPath); assertTrue(rootId.isPresent()); assertEquals("f1", dao.getNodeOsName(oldPath)); dao.renameNode(rootId.get(), "f_pippo"); assertTrue(dao.listNode(oldPath).isEmpty()); assertTrue(dao.listNode(oldPathChild).isEmpty()); // After the first rename the os_name column has to be equal to the old name // to avoid issues with renaming folders where some files have been uploaded assertEquals("f1", dao.getNodeOsName(newPath)); assertTrue(dao.listNode(newPath).isPresent()); assertTrue(dao.listNode(newPathChild).isPresent()); // The second rename mustn't change the os_name column dao.renameNode(rootId.get(), "f_pippo_second_rename"); assertEquals("f1", dao.getNodeOsName("/test1/f_pippo_second_rename")); } @Test public void testCountNodeWithPath() { assertEquals(1, dao.countNodesWithPath("/")); assertEquals(1, dao.countNodesWithPath("/test1"), "Test db has been changed"); assertEquals(1, dao.countNodesWithPath("/test1/f1"), "Test db has been changed"); assertEquals(1, dao.countNodesWithPath("/test1/f1/f2_renamed"), "Test db has been changed"); assertEquals(1, dao.countNodesWithPath("/test1/f1/f2_renamed/f3"), "Test db has been changed"); assertEquals(1, dao.countNodesWithPath("/test2"), "Test db has been changed"); assertEquals(1, dao.countNodesWithPath("/test2/f4"), "Test db has been changed"); assertEquals(1, dao.countNodesWithPath("/test2/f5"), "Test db has been changed"); assertEquals(0, dao.countNodesWithPath("/pippooo"), "Test db has been changed"); } @Test public void testDeleteNode() { assertEquals(1, dao.countNodesWithPath("/test1/f1/f2_renamed/f3"), "Test db has been changed"); dao.deleteNode("/test1"); assertEquals(0, dao.countNodesWithPath("/test1")); assertEquals(0, dao.countNodesWithPath("/test1/f1")); assertEquals(0, dao.countNodesWithPath("/test1/f1/f2_renamed")); assertEquals(0, dao.countNodesWithPath("/test1/f1/f2_renamed/f3")); } @Test public void testSetNodeLocation() { DataNode dataNode = new DataNode(); dataNode.setUri("vos://example.com!vospace/mydata2"); dao.createNode(dataNode); dao.setNodeLocation("/mydata2", 1, "mydata2"); } @Test public void testSetNodeLocationFailure() { boolean exception = false; try { dao.setNodeLocation("/foo", 1, "foo"); } catch (InternalFaultException ex) { exception = true; } assertTrue(exception); } @Test public void testSetNode() { Property publicReadProperty = getProperty(NodeProperties.PUBLIC_READ_URI, String.valueOf(false)); Node node = new DataNode(); node.setUri("vos://example.com!vospace/mydata3"); node.getProperties().add(publicReadProperty); dao.createNode(node); node = dao.listNode("/mydata3").get(); assertEquals("false", NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI)); node.getProperties().clear(); publicReadProperty.setValue(String.valueOf(true)); node.getProperties().add(publicReadProperty); dao.setNode(node); node = dao.listNode("/mydata3").get(); assertEquals("true", NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI)); } @Test public void testSetLinkNodeTarget() { Property publicReadProperty = getProperty(NodeProperties.PUBLIC_READ_URI, String.valueOf(false)); LinkNode node = new LinkNode(); node.setUri("vos://example.com!vospace/mylink1"); node.getProperties().add(publicReadProperty); node.setTarget("vos://example.com!vospace/mydummytarget1"); dao.createNode(node); node = (LinkNode) dao.listNode("/mylink1").get(); assertEquals("false", NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI)); assertEquals("vos://example.com!vospace/mydummytarget1", node.getTarget()); node.getProperties().clear(); publicReadProperty.setValue(String.valueOf(true)); node.getProperties().add(publicReadProperty); node.setTarget("vos://example.com!vospace/mydummytarget1_modded"); dao.setNode(node); node = (LinkNode) dao.listNode("/mylink1").get(); assertEquals("true", NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI)); assertEquals("vos://example.com!vospace/mydummytarget1_modded", node.getTarget()); } @Test public void testSetNodeRecursiveGroup() { Property parentGroupRead = getProperty(NodeProperties.GROUP_READ_URI, "group1 group2"); Property parentGroupWrite = getProperty(NodeProperties.GROUP_WRITE_URI, "group2 group3"); Node node = new DataNode(); node.setUri("vos://example.com!vospace/mydata4"); node.getProperties().add(parentGroupRead); node.getProperties().add(parentGroupWrite); dao.createNode(node); Node child1 = new DataNode(); child1.setUri("vos://example.com!vospace/mydata4/child1"); child1.getProperties().add(getProperty(NodeProperties.GROUP_READ_URI, "group3")); child1.getProperties().add(getProperty(NodeProperties.GROUP_WRITE_URI, "group3 group4")); dao.createNode(child1); Node child2 = new DataNode(); child2.setUri("vos://example.com!vospace/mydata4/child1/child2"); child2.getProperties().add(getProperty(NodeProperties.GROUP_READ_URI, "group2 group5")); child2.getProperties().add(getProperty(NodeProperties.GROUP_WRITE_URI, "group6")); dao.createNode(child2); parentGroupRead.setValue("group1 group5"); // remove group2; add group5 parentGroupWrite.setValue("group2 group6"); // remove group3; add group6 // Recursively set node dao.setNode(node, true); node = dao.listNode("/mydata4").get(); child1 = dao.listNode("/mydata4/child1").get(); child2 = dao.listNode("/mydata4/child1/child2").get(); checkGroups(NodeProperties.getNodePropertyAsListByURI(node, NodeProperties.GROUP_READ_URI), "group1", "group5"); checkGroups(NodeProperties.getNodePropertyAsListByURI(node, NodeProperties.GROUP_WRITE_URI), "group2", "group6"); checkGroups(NodeProperties.getNodePropertyAsListByURI(child1, NodeProperties.GROUP_READ_URI), "group3", "group5"); checkGroups(NodeProperties.getNodePropertyAsListByURI(child1, NodeProperties.GROUP_WRITE_URI), "group4", "group6"); checkGroups(NodeProperties.getNodePropertyAsListByURI(child2, NodeProperties.GROUP_READ_URI), "group5"); checkGroups(NodeProperties.getNodePropertyAsListByURI(child2, NodeProperties.GROUP_WRITE_URI), "group6"); } @Test public void testGetNodeOsName() { assertEquals("f2", dao.getNodeOsName("/test1/f1/f2_renamed")); assertEquals("f4", dao.getNodeOsName("/test2/f4")); } @Test public void testReleaseNodesByJobId() { Optional optId = dao.getNodeId("/test3/m1"); assertTrue(optId.isPresent()); assertFalse(dao.isBranchBusy(optId.get())); dao.setBranchJobId(optId.get(), "pippo1"); assertTrue(dao.isBranchBusy(optId.get())); Optional childId = dao.getNodeId("/test3/m1/m2"); assertTrue(childId.isPresent()); assertTrue(dao.isBranchBusy(childId.get())); dao.releaseBusyNodesByJobId("pippo1"); assertFalse(dao.isBranchBusy(optId.get())); assertFalse(dao.isBranchBusy((childId.get()))); } private Property getProperty(String uri, String value) { Property property = new Property(); property.setUri(uri); property.setValue(value); return property; } private void checkGroups(List groups, String... expectedGroups) { Set set1 = new HashSet<>(Arrays.asList(expectedGroups)); Set set2 = new HashSet<>(groups); assertEquals(set1, set2); } private List getViews() { View view = new View(); view.setUri("urn:myview"); List views = new ArrayList<>(); views.add(view); return views; } }