Package org.structr.common

Source Code of org.structr.common.DeleteGraphObjectsTest

/**
* Copyright (C) 2010-2014 Morgner UG (haftungsbeschränkt)
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Structr.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.common;

import org.structr.core.property.PropertyMap;
import org.structr.common.error.FrameworkException;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.AbstractRelationship;
import org.structr.core.entity.Relation;
import org.structr.core.entity.TestFour;
import org.structr.core.entity.TestOne;
import org.structr.core.entity.TestThree;
import org.structr.core.entity.TestTwo;

//~--- JDK imports ------------------------------------------------------------

import java.util.logging.Level;
import java.util.logging.Logger;
import org.structr.core.Result;
import org.structr.core.entity.SixOneOneToOne;
import org.structr.core.entity.TestSix;
import org.structr.core.entity.relationship.NodeHasLocation;
import org.structr.core.graph.NodeInterface;
import org.structr.core.graph.Tx;

//~--- classes ----------------------------------------------------------------

/**
* Test basic delete operations with graph objects (nodes, relationships)
*
* All tests are executed in superuser context
*
* @author Axel Morgner
*/
public class DeleteGraphObjectsTest extends StructrTest {

  private static final Logger logger = Logger.getLogger(DeleteGraphObjectsTest.class.getName());

  //~--- methods --------------------------------------------------------

  @Override
  public void test00DbAvailable() {

    super.test00DbAvailable();

  }

  /**
   * Test successful deletion of a node.
   *
   * The node shouldn't be found afterwards.
   * Creation and deletion are executed in two different transactions.
   *
   */
  public void test01DeleteNode() {

    try {

      final PropertyMap props = new PropertyMap();
      final String type       = "UnknownTestType";
      final String name       = "GenericNode-name";
      NodeInterface node      = null;
      String uuid             = null;

      props.put(AbstractNode.type, type);
      props.put(AbstractNode.name, name);

      try (final Tx tx = app.tx()) {

        node = app.create(NodeInterface.class, props);
        tx.success();
      }

      assertTrue(node != null);

      try (final Tx tx = app.tx()) {
        uuid = node.getUuid();
      }

      try (final Tx tx = app.tx()) {

        app.delete(node);
        tx.success();
      }

      try (final Tx tx = app.tx()) {

        Result result = app.nodeQuery(NodeInterface.class).uuid(uuid).getResult();

        assertEquals("Node should have been deleted", 0, result.size());

      } catch (FrameworkException fe) {}

    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }

  }

  public void test01DeleteRelationship() {

    try {

      final TestOne testOne  = createTestNode(TestOne.class);
      final TestSix testSix  = createTestNode(TestSix.class);
      SixOneOneToOne rel     = null;

      assertNotNull(testOne);
      assertNotNull(testSix);

      try (final Tx tx = app.tx()) {

        rel = app.create(testSix, testOne, SixOneOneToOne.class);
        tx.success();
      }

      assertNotNull(rel);

      try {
        // try to delete relationship
        rel.getRelationship().delete();

        fail("Should have raised an org.neo4j.graphdb.NotInTransactionException");
      } catch (org.neo4j.graphdb.NotInTransactionException e) {}

      // Relationship still there
      assertNotNull(rel);

      try (final Tx tx = app.tx()) {

        app.delete(rel);
        tx.success();
      }

      try (final Tx tx = app.tx()) {

        String uuid = rel.getUuid();
        fail("Deleted entity should have thrown an exception on access.");

      } catch (IllegalStateException iex) {
      }


    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }


  }

  /**
   * DELETE_NONE should not trigger any delete cascade
   */
  public void test03CascadeDeleteNone() {

    /* this test is flawed in that it expects the cascading
     * not to take place but expects to run without an
     * exception, but deleting one node of the two will leave
     * the other (TestTwo) in an invalid state according
     * to its isValid() method!
    try {

      // Create a relationship with DELETE_NONE
      AbstractRelationship rel = cascadeRel(TestOne.class, TestTwo.class, Relation.DELETE_NONE);
      AbstractNode startNode   = rel.getStartNode();
      AbstractNode endNode     = rel.getEndNode();
      final String startNodeId = startNode.getUuid();
      final String endNodeId   = endNode.getUuid();
      boolean exception        = false;

      deleteCascade(startNode);
      assertNodeNotFound(startNodeId);
      assertNodeExists(endNodeId);

      // Create another relationship with DELETE_NONE
      rel = cascadeRel(TestOne.class, TestTwo.class, Relation.DELETE_NONE);

      try {
        deleteCascade(rel.getEndNode());

      } catch (FrameworkException fex) {

        assertEquals(422, fex.getStatus());
        exception = true;
      }

      assertTrue("Exception should be raised", exception);

    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }
     */
  }

  /**
   * DELETE_INCOMING should not trigger delete cascade from start to end node,
   * but from end to start node
   */
  public void test04CascadeDeleteIncoming() {

    /* this test is flawed in that it expects the cascading
     * not to take place but expectes to run without an
     * exception, but deleting one node of the two will leave
     * the other (TestTwo) in an invalid state according
     * to its isValid() method!
    try {

      // Create a relationship with DELETE_INCOMING
      AbstractRelationship rel = cascadeRel(TestOne.class, TestTwo.class, Relation.DELETE_INCOMING);
      final String startNodeId = rel.getStartNode().getUuid();
      final String endNodeId   = rel.getEndNode().getUuid();
      boolean exception        = false;

      deleteCascade(rel.getStartNode());

      // Start node should not be found after deletion
      assertNodeNotFound(startNodeId);

      // End node should be found after deletion of start node
      assertNodeExists(endNodeId);

      // Create another relationship with DELETE_INCOMING
      rel = cascadeRel(TestOne.class, TestTwo.class, Relation.DELETE_INCOMING);

      try {
        deleteCascade(rel.getEndNode());

      } catch (FrameworkException fex) {

        assertEquals(422, fex.getStatus());
        exception = true;
      }

      assertTrue("Exception should be raised", exception);

    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }
    */
  }

  /**
   * DELETE_OUTGOING should trigger delete cascade from start to end node,
   * but not from end to start node.
   */
  public void test05CascadeDeleteOutgoing() {

    try {

      // Create a relationship with DELETE_OUTGOING
      AbstractRelationship rel = cascadeRel(TestOne.class, TestTwo.class, Relation.SOURCE_TO_TARGET);
      NodeInterface sourceNode;
      NodeInterface targetNode;
      String startNodeId;
      String endNodeId;

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        sourceNode  = rel.getSourceNode();
      }

      deleteCascade(sourceNode);

      try (final Tx tx = app.tx()) {

        // Start node should not be found after deletion
        assertNodeNotFound(startNodeId);

        // End node should not be found after deletion
        assertNodeNotFound(endNodeId);
      }

      // Create another relationship with DELETE_OUTGOING
      rel = cascadeRel(TestOne.class, TestTwo.class, Relation.SOURCE_TO_TARGET);

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        targetNode  = rel.getTargetNode();
      }

      deleteCascade(targetNode);

      try (final Tx tx = app.tx()) {

        // End node should not be found after deletion
        assertNodeNotFound(endNodeId);

        // Start node should still exist deletion of end node
        assertNodeExists(startNodeId);
      }

    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }

  }

  /**
   * DELETE_INCOMING + DELETE_OUTGOING should trigger delete cascade from start to end node
   * and from end node to start node
   */
  public void test06CascadeDeleteBidirectional() {

    try {

      // Create a relationship with DELETE_INCOMING
      AbstractRelationship rel = cascadeRel(TestOne.class, TestTwo.class, Relation.TARGET_TO_SOURCE | Relation.SOURCE_TO_TARGET);
      NodeInterface sourceNode;
      NodeInterface targetNode;
      String startNodeId;
      String endNodeId;

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        sourceNode  = rel.getSourceNode();
      }

      deleteCascade(sourceNode);

      try (final Tx tx = app.tx()) {

        // Start node should not be found after deletion
        assertNodeNotFound(startNodeId);

        // End node should not be found after deletion of start node
        assertNodeNotFound(endNodeId);
      }

      // Create a relationship with DELETE_INCOMING
      rel = cascadeRel(TestOne.class, TestTwo.class, Relation.TARGET_TO_SOURCE | Relation.SOURCE_TO_TARGET);

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        targetNode  = rel.getTargetNode();
      }

      deleteCascade(targetNode);

      try (final Tx tx = app.tx()) {

        // End node should not be found after deletion
        assertNodeNotFound(endNodeId);

        // Start node should not be found after deletion of end node
        assertNodeNotFound(startNodeId);
      }

    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }

  }

  /**
   * DELETE_IF_CONSTRAINT_WOULD_BE_VIOLATED should
   * trigger delete cascade from start to end node only
   * if the remote node would not be valid afterwards
   */
  public void test07CascadeDeleteConditional() {

    try {

      AbstractRelationship rel = cascadeRel(TestOne.class, TestTwo.class, Relation.CONSTRAINT_BASED);
      NodeInterface sourceNode;
      String startNodeId;
      String endNodeId;

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        sourceNode  = rel.getSourceNode();
      }

      deleteCascade(sourceNode);

      try (final Tx tx = app.tx()) {

        // Start node should be deleted
        assertNodeNotFound(startNodeId);

        // End node should be deleted
        assertNodeNotFound(endNodeId);
      }

      rel = cascadeRel(TestOne.class, TestThree.class, Relation.CONSTRAINT_BASED);

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        sourceNode   = rel.getSourceNode();
      }

      deleteCascade(sourceNode);

      try (final Tx tx = app.tx()) {

        // Start node should be deleted
        assertNodeNotFound(startNodeId);

        // End node should still be there
        assertNodeExists(endNodeId);
      }

      rel = cascadeRel(TestOne.class, TestFour.class, Relation.CONSTRAINT_BASED);

      try (final Tx tx = app.tx()) {

        startNodeId = rel.getSourceNode().getUuid();
        endNodeId   = rel.getTargetNode().getUuid();
        sourceNode   = rel.getSourceNode();
      }

      deleteCascade(sourceNode);

      try (final Tx tx = app.tx()) {

        // Start node should be deleted
        assertNodeNotFound(startNodeId);

        // End node should still be there
        assertNodeExists(endNodeId);
      }

    } catch (FrameworkException ex) {

      ex.printStackTrace();

      logger.log(Level.SEVERE, ex.toString());
      fail("Unexpected exception");

    }

  }

  private AbstractRelationship cascadeRel(final Class type1, final Class type2, final int cascadeDeleteFlag) throws FrameworkException {

    try (final Tx tx = app.tx()) {

      AbstractNode start       = createTestNode(type1);
      AbstractNode end         = createTestNode(type2);
      AbstractRelationship rel = createTestRelationship(start, end, NodeHasLocation.class);

      rel.setProperty(AbstractRelationship.cascadeDelete, cascadeDeleteFlag);

      tx.success();

      return rel;
    }
  }

  private void deleteCascade(final NodeInterface node) throws FrameworkException {

    try (final Tx tx = app.tx()) {

      app.delete(node);
      tx.success();
    }
  }
}
TOP

Related Classes of org.structr.common.DeleteGraphObjectsTest

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.