Package org.jboss.dna.connector.store.jpa.model.basic

Source Code of org.jboss.dna.connector.store.jpa.model.basic.SubgraphQueryTest

/*
* JBoss DNA (http://www.jboss.org/dna)
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
* See the AUTHORS.txt file in the distribution for a full listing of
* individual contributors.
*
* JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
* is licensed to you under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* JBoss DNA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.dna.connector.store.jpa.model.basic;

import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.IsCollectionContaining.hasItems;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import org.hibernate.ejb.Ejb3Configuration;
import org.jboss.dna.common.util.IoUtil;
import org.jboss.dna.common.util.SecureHash;
import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.connector.store.jpa.model.common.NamespaceEntity;
import org.jboss.dna.connector.store.jpa.util.Namespaces;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PropertyType;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* @author Randall Hauch
*/
public class SubgraphQueryTest {

    private EntityManagerFactory factory;
    private EntityManager manager;
    private BasicModel model;
    private ExecutionContext context;
    private Long workspaceId;
    private Map<Long, Map<Path, UUID>> uuidByPathByWorkspace;
    private Namespaces namespaces;
    private List<Location> locations;
    private String[] validLargeValues;
    private SubgraphQuery query;

    @BeforeClass
    public static void beforeAll() throws Exception {
    }

    @Before
    public void beforeEach() throws Exception {
        model = new BasicModel();
        context = new ExecutionContext();

        // Load in the large value ...
        validLargeValues = new String[] {IoUtil.read(getClass().getClassLoader().getResourceAsStream("LoremIpsum1.txt")),
            IoUtil.read(getClass().getClassLoader().getResourceAsStream("LoremIpsum2.txt")),
            IoUtil.read(getClass().getClassLoader().getResourceAsStream("LoremIpsum3.txt"))};

        // Connect to the database ...
        Ejb3Configuration configurator = new Ejb3Configuration();
        model.configure(configurator);
        configurator.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        configurator.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");
        configurator.setProperty("hibernate.connection.username", "sa");
        configurator.setProperty("hibernate.connection.password", "");
        configurator.setProperty("hibernate.connection.url", "jdbc:hsqldb:.");
        configurator.setProperty("hibernate.show_sql", "false");
        configurator.setProperty("hibernate.format_sql", "true");
        configurator.setProperty("hibernate.use_sql_comments", "true");
        configurator.setProperty("hibernate.hbm2ddl.auto", "create");
        factory = configurator.buildEntityManagerFactory();
        manager = factory.createEntityManager();
        namespaces = new Namespaces(manager);

        uuidByPathByWorkspace = new HashMap<Long, Map<Path, UUID>>();

        manager.getTransaction().begin();

        // Determine the UUID for all root nodes ...
        UUID rootUuid = UUID.randomUUID();

        // Now populate a graph of nodes ...
        workspaceId = 10L;
        uuidByPath(workspaceId).put(path("/"), rootUuid);
        create(workspaceId, "/a");
        create(workspaceId, "/a/a1");
        create(workspaceId, "/a/a1/a1");
        create(workspaceId, "/a/a1/a2");
        create(workspaceId, "/a/a1/a3");
        create(workspaceId, "/a/a2");
        create(workspaceId, "/a/a2/a1");
        create(workspaceId, "/a/a2/a1/a1");
        create(workspaceId, "/a/a2/a1/a1/a1");
        create(workspaceId, "/a/a2/a1/a1/a2");
        create(workspaceId, "/a/a2/a1/a2");
        create(workspaceId, "/a/a2/a2");
        create(workspaceId, "/a/a2/a3");
        create(workspaceId, "/a/a2/a4");
        setLargeValue(workspaceId, "/a/a1", "prop1", validLargeValues[0]);
        setLargeValue(workspaceId, "/a/a1", "prop1", validLargeValues[1]); // the only node that uses #1
        setLargeValue(workspaceId, "/a/a2", "prop1", validLargeValues[0]);
        setLargeValue(workspaceId, "/a/a2", "prop2", validLargeValues[2]);
        setLargeValue(workspaceId, "/a/a2/a1", "prop2", validLargeValues[0]);
        setLargeValue(workspaceId, "/a/a2/a1", "prop3", validLargeValues[2]);
        manager.getTransaction().commit();
        manager.getTransaction().begin();

        // Create some content in other workspaces ...
        Long otherWorkspace = 3254L;
        uuidByPath(otherWorkspace).put(path("/"), rootUuid);
        create(otherWorkspace, "/a");
        create(otherWorkspace, "/a/a1");
        create(otherWorkspace, "/a/a1/a1");
        create(otherWorkspace, "/a/a1/a2");
        create(otherWorkspace, "/a/a1/a3");
        create(otherWorkspace, "/a/a2");
        create(otherWorkspace, "/a/a2/a1");
        create(otherWorkspace, "/a/a2/a1/a1");
        create(otherWorkspace, "/a/a2/a1/a1/a1");
        create(otherWorkspace, "/a/a2/a1/a1/a2");
        create(otherWorkspace, "/a/a2/a1/a2");
        create(otherWorkspace, "/a/a2/a2");
        create(otherWorkspace, "/a/a2/a3");
        create(otherWorkspace, "/a/a2/a4");
        // Add some large values that were already used in the other workspace
        setLargeValue(workspaceId, "/a/a2/a1", "prop2", validLargeValues[0]);
        setLargeValue(workspaceId, "/a/a2/a1", "prop2", validLargeValues[2]);
        manager.getTransaction().commit();
        manager.getTransaction().begin();
    }

    @After
    public void afterEach() throws Exception {
        if (query != null) {
            try {
                query.close();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        try {
            manager.close();
        } finally {
            factory.close();
        }
    }

    protected Map<Path, UUID> uuidByPath( Long workspaceId ) {
        Map<Path, UUID> map = uuidByPathByWorkspace.get(workspaceId);
        if (map == null) {
            map = new HashMap<Path, UUID>();
            uuidByPathByWorkspace.put(workspaceId, map);
        }
        return map;
    }

    protected Path path( String path ) {
        return context.getValueFactories().getPathFactory().create(path);
    }

    protected void create( Long workspaceId,
                           String pathStr ) {
        Path path = path(pathStr);
        if (uuidByPath(workspaceId).containsKey(path)) return;
        if (path.isRoot()) return;
        Path parent = path.getParent();
        // Look up the parent ...
        UUID parentUuid = uuidByPath(workspaceId).get(parent);
        assert parentUuid != null;
        // Calculate the child index by walking the existing nodes ...
        int numChildren = 0;
        for (Path existing : uuidByPath(workspaceId).keySet()) {
            if (parent.equals(existing.getParent())) {
                ++numChildren;
            }
        }

        // Create the child entity ...
        Name childName = path.getLastSegment().getName();
        int snsIndex = path.getLastSegment().getIndex();
        NamespaceEntity namespace = namespaces.get(childName.getNamespaceUri(), true);
        UUID childUuid = UUID.randomUUID();
        ChildId id = new ChildId(workspaceId, parentUuid.toString(), childUuid.toString());
        ChildEntity entity = new ChildEntity(id, ++numChildren, namespace, childName.getLocalName(), snsIndex);
        manager.persist(entity);

        // Create the properties ...
        NodeId nodeId = new NodeId(workspaceId, childUuid.toString());
        PropertiesEntity props = new PropertiesEntity(nodeId);
        props.setData("bogus data".getBytes());
        props.setPropertyCount(1);
        props.setCompressed(false);
        manager.persist(props);

        uuidByPath(workspaceId).put(path, childUuid);
    }

    protected ReferenceEntity createReferenceBetween( Long workspaceId,
                                                      String fromPathStr,
                                                      String toPathStr ) {
        Path fromPath = path(fromPathStr);
        Path toPath = path(toPathStr);

        // Look up the UUIDs ...
        UUID fromUuid = uuidByPath(workspaceId).get(fromPath);
        UUID toUuid = uuidByPath(workspaceId).get(toPath);
        assert fromUuid != null;
        assert toUuid != null;

        // Now create a reference entity ...
        ReferenceEntity entity = new ReferenceEntity(new ReferenceId(workspaceId, fromUuid.toString(), toUuid.toString()));
        manager.persist(entity);
        return entity;
    }

    protected UUID uuidForPath( Long workspaceId,
                                String pathStr ) {
        Path path = path(pathStr);
        return uuidByPath(workspaceId).get(path);
    }

    protected void setLargeValue( Long workspaceId,
                                  String pathStr,
                                  String propertyName,
                                  String largeValue ) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        Path path = path(pathStr);
        UUID nodeUuid = uuidByPath(workspaceId).get(path);
        assertThat(nodeUuid, is(notNullValue()));

        // Find or create the large value object ...
        LargeValueId id = largeValueId(largeValue);
        LargeValueEntity entity = manager.find(LargeValueEntity.class, id);
        if (entity == null) {
            entity = new LargeValueEntity();
            entity.setId(id);
            entity.setLength(largeValue.length());
            entity.setCompressed(false);
            entity.setData(largeValue.getBytes());
            entity.setType(PropertyType.STRING);
            manager.persist(entity);
        }

        // Load the PropertiesEntity ...
        NodeId nodeId = new NodeId(workspaceId, nodeUuid.toString());
        PropertiesEntity props = manager.find(PropertiesEntity.class, nodeId);
        assertThat(props, is(notNullValue()));

        // Add the large value ...
        props.getLargeValues().add(id);
    }

    protected LargeValueId largeValueId( String value ) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        return new LargeValueId(StringUtil.getHexString(SecureHash.getHash(SecureHash.Algorithm.SHA_1, value.getBytes())));
    }

    protected PropertiesEntity getProperties( Long workspaceId,
                                              String pathStr ) {
        Path path = path(pathStr);
        UUID nodeUuid = uuidByPath(workspaceId).get(path);
        assertThat(nodeUuid, is(notNullValue()));

        NodeId nodeId = new NodeId(workspaceId, nodeUuid.toString());
        return manager.find(PropertiesEntity.class, nodeId);
    }

    protected void verifyNextLocationIs( Long workspaceId,
                                         String path ) {
        Path pathObj = path(path);
        UUID uuid = uuidByPath(workspaceId).get(pathObj);
        Location next = locations.remove(0);
        assertThat(next, is(notNullValue()));
        assertThat(next.getPath(), is(pathObj));
        assertThat(next.getUuid(), is(uuid));
    }

    protected void verifyNoMoreLocations() {
        assertThat(locations.isEmpty(), is(true));
    }

    @SuppressWarnings( "unchecked" )
    protected void verifyNodesHaveLargeValues( String... paths ) {
        if (paths == null || paths.length == 0) return;
        // Build the set of UUIDs for the nodes that should have large values ...
        String[] expectedNodeUuids = new String[paths.length];
        for (int i = 0; i != paths.length; ++i) {
            String pathStr = paths[i];
            expectedNodeUuids[i] = uuidForPath(workspaceId, pathStr).toString();
        }
        // Load the PropertiesEntity for the nodes that have large properties ...
        Query queryProps = manager.createQuery("select prop from PropertiesEntity as prop where size(prop.largeValues) > 0");
        Set<String> actualNodeUuids = new HashSet<String>();
        List<PropertiesEntity> propsWithLargeValues = queryProps.getResultList();
        for (PropertiesEntity entity : propsWithLargeValues) {
            String uuidStr = entity.getId().getUuidString();
            actualNodeUuids.add(uuidStr);
        }
        assertThat(actualNodeUuids, hasItems(expectedNodeUuids));
    }

    protected void assertNumberOfLargeValueEntities( long count ) throws Exception {
        Query query = manager.createQuery("select count(*) from LargeValueEntity");
        assertThat((Long)query.getSingleResult(), is(count));
    }

    protected void assertNumberOfPropertyEntitiesInWorkspace( Long workspaceId,
                                                              long count ) throws Exception {
        Query query = manager.createQuery("select count(*) from PropertiesEntity as prop where prop.id.workspaceId = :workspaceId");
        query.setParameter("workspaceId", workspaceId);
        assertThat((Long)query.getSingleResult(), is(count));
    }

    protected void assertNumberOfChildEntitiesInWorkspace( Long workspaceId,
                                                           long count ) throws Exception {
        Query query = manager.createQuery("select count(*) from ChildEntity as child where child.id.workspaceId = :workspaceId");
        query.setParameter("workspaceId", workspaceId);
        assertThat((Long)query.getSingleResult(), is(count));
    }

    @Test
    public void shouldFindLargeValueContentFromFile() {
        for (int i = 0; i != validLargeValues.length; ++i) {
            assertThat(validLargeValues[i].startsWith((i + 1) + ". Lorem ipsum dolor sit amet"), is(true));
        }
    }

    @Test
    public void shouldPerformSubgraphQueryOfNodeWithChildrenAndNoGrandchildren() {
        Path path = path("/a/a1");
        UUID uuid = uuidByPath(workspaceId).get(path);
        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNoMoreLocations();
        query.close();
    }

    @Test
    public void shouldPerformSubgraphQueryOfNodeWithChildrenAndGrandchildren() {
        Path path = path("/a/a2");
        UUID uuid = uuidByPath(workspaceId).get(path);
        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a2");
        verifyNoMoreLocations();
        query.close();
    }

    @Test
    public void shouldPerformSubgraphQueryOfNodeWithChildrenAndGrandchildrenAndGreatGranchildren() {
        Path path = path("/a");
        UUID uuid = uuidByPath(workspaceId).get(path);
        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a2");
        verifyNoMoreLocations();
        query.close();
    }

    @Test
    public void shouldPerformMaxDepthSubgraphQueryOfNodeWithChildrenAndGrandchildrenAndGreatGranchildren() {
        Path path = path("/a");
        UUID uuid = uuidByPath(workspaceId).get(path);
        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, 4);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a2");
        verifyNoMoreLocations();

        locations = query.getNodeLocations(true, false);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNoMoreLocations();
        query.close();

        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, 2);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNoMoreLocations();

        locations = query.getNodeLocations(true, false);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNoMoreLocations();

        query.close();

        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, 3);
        locations = query.getNodeLocations(true, false);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNoMoreLocations();

        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNoMoreLocations();
        query.close();
    }

    @Test
    public void shouldDeleteSubgraph() throws Exception {
        // Verify that all the nodes with large values do indeed have them ...
        verifyNodesHaveLargeValues("/a/a1", "/a/a2", "/a/a2/a1");

        // Count the number of objects ...
        assertNumberOfLargeValueEntities(3L);
        assertNumberOfPropertyEntitiesInWorkspace(workspaceId, 14L);
        assertNumberOfChildEntitiesInWorkspace(workspaceId, 14L);

        // Delete "/a/a1". Note that "/a/a1" has a large value that is shared by "/a/a2", but it's also the only
        // user of large value #1.
        Path path = path("/a/a1");
        UUID uuid = uuidByPath(workspaceId).get(path);

        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNoMoreLocations();
        query.deleteSubgraph(true);
        assertThat(query.getInwardReferences().isEmpty(), is(true));
        query.close();

        // Commit the transaction, and start another ...
        manager.getTransaction().commit();
        manager.getTransaction().begin();
        manager.flush();

        // Count the number of objects ...
        assertNumberOfLargeValueEntities(2L);
        assertNumberOfPropertyEntitiesInWorkspace(workspaceId, 10L);
        assertNumberOfChildEntitiesInWorkspace(workspaceId, 10L);

        // Verify the graph structure is correct ...
        path = path("/a");
        uuid = uuidByPath(workspaceId).get(path);
        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, 4);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1/a2");
        verifyNoMoreLocations();

        locations = query.getNodeLocations(true, false);
        verifyNextLocationIs(workspaceId, "/a");
        verifyNextLocationIs(workspaceId, "/a/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a2");
        verifyNextLocationIs(workspaceId, "/a/a2/a3");
        verifyNextLocationIs(workspaceId, "/a/a2/a4");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a2/a1/a2");
        verifyNoMoreLocations();
        query.close();

        // Verify that all the nodes with large values do indeed have them ...
        verifyNodesHaveLargeValues("/a/a2", "/a/a2/a1"); // "/a/a1" was deleted

        // Now, load the one node remaining with
    }

    @Test
    public void shouldNotDeleteSubgraphThatHasNodesReferencedByOtherNodesNotBeingDeleted() throws Exception {
        // Verify that all the nodes with large values do indeed have them ...
        verifyNodesHaveLargeValues("/a/a1", "/a/a2", "/a/a2/a1");

        // Count the number of objects ...
        assertNumberOfLargeValueEntities(3L);
        assertNumberOfPropertyEntitiesInWorkspace(workspaceId, 14L);
        assertNumberOfChildEntitiesInWorkspace(workspaceId, 14L);

        // Create references from the "/a/a2" (not being deleted) branch, to the branch being deleted...
        List<ReferenceEntity> expectedInvalidRefs = new ArrayList<ReferenceEntity>();
        expectedInvalidRefs.add(createReferenceBetween(workspaceId, "/a/a2", "/a/a1"));
        expectedInvalidRefs.add(createReferenceBetween(workspaceId, "/a/a2/a1", "/a/a1/a1"));
        expectedInvalidRefs.add(createReferenceBetween(workspaceId, "/a/a2/a2", "/a/a1/a2"));

        // Create references between nodes in the branch being deleted (these shouldn't matter) ...
        createReferenceBetween(workspaceId, "/a/a1", "/a/a1/a1");
        createReferenceBetween(workspaceId, "/a/a1/a2", "/a/a1/a3");

        // Delete "/a/a1". Note that "/a/a1" has a large value that is shared by "/a/a2", but it's also the only
        // user of large value #1.
        Path path = path("/a/a1");
        UUID uuid = uuidByPath(workspaceId).get(path);

        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNoMoreLocations();
        query.deleteSubgraph(true);

        // Now there should be invalid references ...
        List<ReferenceEntity> invalidReferences = query.getInwardReferences();
        assertThat(invalidReferences.size(), is(3));
        invalidReferences.removeAll(invalidReferences);
        assertThat(invalidReferences.size(), is(0));
        query.close();
    }

    @SuppressWarnings( "unchecked" )
    @Test
    public void shouldDeleteSubgraphThatHasInternalReferences() throws Exception {
        // Verify that all the nodes with large values do indeed have them ...
        verifyNodesHaveLargeValues("/a/a1", "/a/a2", "/a/a2/a1");

        // Count the number of objects ...
        assertNumberOfLargeValueEntities(3L);
        assertNumberOfPropertyEntitiesInWorkspace(workspaceId, 14L);
        assertNumberOfChildEntitiesInWorkspace(workspaceId, 14L);

        // Create references from the nodes that aren't being deleted (these won't matter, but will remain)...
        List<ReferenceEntity> expectedValidRefs = new ArrayList<ReferenceEntity>();
        expectedValidRefs.add(createReferenceBetween(workspaceId, "/a/a2", "/a/a2/a1"));

        // Create references between nodes in the branch being deleted (these shouldn't matter) ...
        createReferenceBetween(workspaceId, "/a/a1", "/a/a1/a1");
        createReferenceBetween(workspaceId, "/a/a1/a2", "/a/a1/a3");

        // Delete "/a/a1". Note that "/a/a1" has a large value that is shared by "/a/a2", but it's also the only
        // user of large value #1.
        Path path = path("/a/a1");
        UUID uuid = uuidByPath(workspaceId).get(path);

        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);
        locations = query.getNodeLocations(true, true);
        verifyNextLocationIs(workspaceId, "/a/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a1");
        verifyNextLocationIs(workspaceId, "/a/a1/a2");
        verifyNextLocationIs(workspaceId, "/a/a1/a3");
        verifyNoMoreLocations();
        query.deleteSubgraph(true);

        // Now there should be invalid references ...
        List<ReferenceEntity> invalidReferences = query.getInwardReferences();
        assertThat(invalidReferences.size(), is(0));
        query.close();

        // There should be no references any more ...
        Query refQuery = manager.createQuery("select ref from ReferenceEntity as ref");
        List<ReferenceEntity> remainingReferences = refQuery.getResultList();
        assertThat(remainingReferences.size(), is(1));
        remainingReferences.removeAll(expectedValidRefs);
        assertThat(remainingReferences.size(), is(0));
    }

    @Test
    public void shouldGetVariousReferencesRelatedToSubgraph() throws Exception {
        // Verify that all the nodes with large values do indeed have them ...
        verifyNodesHaveLargeValues("/a/a1", "/a/a2", "/a/a2/a1");

        // Count the number of objects ...
        assertNumberOfLargeValueEntities(3L);
        assertNumberOfPropertyEntitiesInWorkspace(workspaceId, 14L);
        assertNumberOfChildEntitiesInWorkspace(workspaceId, 14L);

        // Create references from the nodes that aren't even part of the subgraph ...
        List<ReferenceEntity> otherRefs = new ArrayList<ReferenceEntity>();
        otherRefs.add(createReferenceBetween(workspaceId, "/a/a2", "/a/a2/a1"));
        otherRefs.add(createReferenceBetween(workspaceId, "/a/a2/a1", "/a/a2/a2"));

        // Create references between nodes in the subgraph ...
        List<ReferenceEntity> internalRefs = new ArrayList<ReferenceEntity>();
        internalRefs.add(createReferenceBetween(workspaceId, "/a/a1", "/a/a1/a1"));
        internalRefs.add(createReferenceBetween(workspaceId, "/a/a1/a2", "/a/a1/a3"));

        // Create references from nodes outside of the subgraph to nodes inside of the subgraph ...
        List<ReferenceEntity> inwardRefs = new ArrayList<ReferenceEntity>();
        inwardRefs.add(createReferenceBetween(workspaceId, "/a/a2", "/a/a1/a1"));
        inwardRefs.add(createReferenceBetween(workspaceId, "/a/a2/a1", "/a/a1/a3"));

        // Create references from nodes inside of the subgraph to nodes outside of the subgraph ...
        List<ReferenceEntity> outwardRefs = new ArrayList<ReferenceEntity>();
        outwardRefs.add(createReferenceBetween(workspaceId, "/a/a1", "/a/a2"));
        outwardRefs.add(createReferenceBetween(workspaceId, "/a/a1/a1", "/a/a2/a1"));

        // Create the query ...
        Path path = path("/a/a1");
        UUID uuid = uuidByPath(workspaceId).get(path);
        query = SubgraphQuery.create(context, manager, workspaceId, uuid, path, Integer.MAX_VALUE);

        // Check the various kinds of references ...
        List<ReferenceEntity> actualInternal = query.getInternalReferences();
        List<ReferenceEntity> actualInward = query.getInwardReferences();
        List<ReferenceEntity> actualOutward = query.getOutwardReferences();

        assertThat(actualInternal.size(), is(internalRefs.size()));
        actualInternal.removeAll(internalRefs);
        assertThat(actualInternal.size(), is(0));

        assertThat(actualInward.size(), is(inwardRefs.size()));
        actualInward.removeAll(inwardRefs);
        assertThat(actualInward.size(), is(0));

        assertThat(actualOutward.size(), is(outwardRefs.size()));
        actualOutward.removeAll(outwardRefs);
        assertThat(actualOutward.size(), is(0));

        query.close();
    }

}
TOP

Related Classes of org.jboss.dna.connector.store.jpa.model.basic.SubgraphQueryTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.