/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jackrabbit.test.api; import org.apache.jackrabbit.test.AbstractJCRTest; import org.apache.jackrabbit.test.NotExecutableException; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.Session; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.NoSuchWorkspaceException; import javax.jcr.ItemNotFoundException; import javax.jcr.InvalidItemStateException; import javax.jcr.ItemExistsException; import javax.jcr.PathNotFoundException; import javax.jcr.Repository; import javax.jcr.Value; import javax.jcr.PropertyType; import javax.jcr.lock.LockException; /** * <code>NodeTest</code> contains all test cases for the * <code>javax.jcr.Node</code> that are related to writing, modifying or deleting * nodes (level 2 of the specification). * */ public class NodeTest extends AbstractJCRTest { private Session superuserW2; /** * to be able to test the update(String) and getCorrespondingNodePath(String) * methods we need an additional workspace */ public void setUp() throws Exception { super.setUp(); // login to second workspace superuserW2 = getHelper().getSuperuserSession(workspaceName); } /** * remove all nodes in second workspace and log out */ public void tearDown() throws Exception { try { cleanUpTestRoot(superuserW2); } catch (RepositoryException e) { log.println("Exception in tearDown: " + e.toString()); } finally { // log out superuserW2.logout(); superuserW2 = null; } super.tearDown(); } /** * Calls {@link javax.jcr.Node#getCorrespondingNodePath(String )} with a non * existing workspace. * <p> * This should throw an {@link javax.jcr.NoSuchWorkspaceException }. */ public void testGetCorrespondingNodePathNoSuchWorkspaceException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create testNode in default workspace Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // save changes superuser.save(); try { defaultTestNode.getCorrespondingNodePath(getNonExistingWorkspaceName(superuser)); fail("Calling Node.getCorrespondingNodePath(workspace) with invalid workspace should throw NoSuchWorkspaceException"); } catch (NoSuchWorkspaceException e) { // ok, works as expected } } /** * Calls {@link javax.jcr.Node#getCorrespondingNodePath(String)} on a node * that has no corresponding node in second workspace */ public void testGetCorrespondingNodePathItemNotFoundException() throws RepositoryException, NotExecutableException { // make sure the repository supports multiple workspaces super.ensureMultipleWorkspacesSupported(); // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create testNode in default workspace Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // save changes superuser.save(); try { // call the update method on test node in default workspace defaultTestNode.getCorrespondingNodePath(workspaceName); fail("Calling Node.getCorrespondingNodePath() on node that has no correspondend node should throw ItemNotFoundException"); } catch (ItemNotFoundException e) { // ok, works as expected } } /** * Creates a node with same path in both workspaces to check if {@link * javax.jcr.Node#getCorrespondingNodePath(String)} works properly. */ public void testGetCorrespondingNodePath() throws RepositoryException, NotExecutableException { // make sure the repository supports multiple workspaces super.ensureMultipleWorkspacesSupported(); // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create test node in default workspace Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // save changes superuser.save(); // get the root node in the second workspace Node rootNodeW2 = (Node) superuserW2.getItem(testRootNode.getPath()); // create test node in second workspace rootNodeW2.addNode(nodeName1, testNodeType); // save changes superuserW2.save(); // call the update method on test node in default workspace defaultTestNode.getCorrespondingNodePath(workspaceName); // ok, works as expected } /** * Tries calling {@link javax.jcr.Node#update(String)} after node has * changed in first workspace but not been saved yet. * <p> * This should throw an {@link javax.jcr.InvalidItemStateException}. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.propertyname1</code> name of * a String property that can be modified in <code>javax.jcr.tck.nodetype</code> * for testing</li> </ul> */ public void testUpdateInvalidItemStateException() throws RepositoryException, NotExecutableException { // make sure the repository supports multiple workspaces super.ensureMultipleWorkspacesSupported(); // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a test node in default workspace Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // save changes superuser.save(); // get the root node in the second workspace Node rootNodeW2 = (Node) superuserW2.getItem(testRootNode.getPath()); // create test node in second workspace rootNodeW2.addNode(nodeName1); // save changes superuserW2.save(); // modify the node testNode.setProperty(propertyName1, "test"); try { // try calling update testNode.update(workspaceName); fail("Calling Node.update() on modified node should throw InvalidItemStateException"); } catch (InvalidItemStateException e) { // ok, works as expected } } /** * Tries to use {@link javax.jcr.Node#update(String)} with an invalid * workspace. * <p> * This should throw an {@link javax.jcr.NoSuchWorkspaceException}. */ public void testUpdateNoSuchWorkspaceException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a test node in default workspace Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // save changes superuser.save(); try { testNode.update(getNonExistingWorkspaceName(superuser)); fail("Calling Node.update() on a non existing workspace should throw NoSuchWorkspaceException"); } catch (NoSuchWorkspaceException e) { // ok, works as expected } } /** * Calls {@link javax.jcr.Node#update(String)} for a node that only exists * in current workspace. <br><br> In that case nothing should happen. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.propertyname1</code> * name of a String property that can be modified in * <code>javax.jcr.tck.nodetype</code> for testing</li> </ul> */ public void testUpdateNoClone() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a test node in default workspace Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // modify the node testNode.setProperty(propertyName1, "test"); superuser.save(); // call the update method on test node in default workspace testNode.update(workspaceName); // check if property is still there assertTrue("Node got property removed after Node.update() eventhough node has no clone", testNode.hasProperty(propertyName1)); // check if node did not get children suddenly assertFalse("Node has children assigned after Node.update() eventhough node has no clone", testNode.hasNodes()); } /** * Checks if {@link javax.jcr.Node#update(String)} works properly by * creating the same node in two workspaces one with a child node the other * with a property set. * <p> * Calling <code>update()</code> on the node * with properties, should remove the properties and add the child node. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.nodetype</code> * must allow children of same nodetype. <li><code>javax.jcr.tck.propertyname1</code> * name of a String property that can be modified in * <code>javax.jcr.tck.nodetype</code> for testing</li> </ul> */ public void testUpdate() throws RepositoryException, NotExecutableException { // make sure the repository supports multiple workspaces super.ensureMultipleWorkspacesSupported(); // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create test node in default workspace Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); defaultTestNode.setProperty(propertyName1, "test"); // save changes superuser.save(); // get the root node in the second workspace Node rootNodeW2 = (Node) superuserW2.getItem(testRootNode.getPath()); // create test node in second workspace Node testNodeW2 = rootNodeW2.addNode(nodeName1, testNodeType); // add a child node testNodeW2.addNode(nodeName2, testNodeType); // save changes superuserW2.save(); // call the update method on test node in default workspace defaultTestNode.update(workspaceName); // ok first check if node has no longer properties assertFalse("Node updated with Node.update() should have property removed", defaultTestNode.hasProperty(propertyName1)); // ok check if the child has been added assertTrue("Node updated with Node.update() should have received childrens", defaultTestNode.hasNode(nodeName2)); } /** * Tries to add a node using {@link javax.jcr.Node#addNode(String)} where * node type can not be determined by parent (<code>nt:base</code> is used * as parent nodetype). * <p>This should throw a {@link javax.jcr.nodetype.ConstraintViolationException}. */ public void testAddNodeConstraintViolationExceptionUndefinedNodeType() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); String nodetype = testNodeTypeNoChildren == null ? ntBase : testNodeTypeNoChildren; Node defaultTestNode = defaultRootNode.addNode(nodeName1, nodetype); try { defaultTestNode.addNode(nodeName2); fail("Adding a node with node.addNode(node) where nodetype can not be determined from parent should" + " throw ConstraintViolationException"); } catch (ConstraintViolationException e) { // ok, works as expected } } /** * Tries to add a node using {@link javax.jcr.Node#addNode(String)} as a * child of a property. * <p> * This should throw an {@link javax.jcr.nodetype.ConstraintViolationException}. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.propertyname1</code> * name of a String property that can be set in <code>javax.jcr.tck.nodetype</code> * for testing</li> </ul> */ public void testAddNodeConstraintViolationExceptionProperty() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // add a node Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // set a property defaultTestNode.setProperty(propertyName1, "test"); try { // try to add a node as a child of a property defaultTestNode.addNode(propertyName1 + "/" + nodeName2); fail("Adding a node as a child of a property should throw ConstraintViolationException"); } catch (ConstraintViolationException e) { // ok, works as expected } } /** * Tries to create a node using {@link javax.jcr.Node#addNode(String, * String)} at a location where there is already a node with same name and * the parent does not allow same name siblings. * <p> * This should throw an {@link javax.jcr.ItemExistsException}. * <p> * Prerequisites: * <ul> <li><code>javax.jcr.tck.NodeTest.testAddNodeItemExistsException.nodetype</code> * node type that does not allow same name siblings and allows to add child * nodes of the same type.</li> </ul> */ public void testAddNodeItemExistsException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // add a node Node defaultTestNode = defaultRootNode.addNode(nodeName2, testNodeType); // add a child defaultTestNode.addNode(nodeName3, testNodeType); // save the new node defaultRootNode.save(); try { // try to add a node with same name again defaultTestNode.addNode(nodeName3, testNodeType); defaultRootNode.save(); fail("Adding a node to a location where same name siblings are not allowed, but a node with same name" + " already exists should throw ItemExistsException "); } catch (ItemExistsException e) { //ok, works as expected } } /** * Tries to add a node using {@link javax.jcr.Node#addNode(String)} to a non * existing destination node. * <p> * This should throw an {@link javax.jcr.PathNotFoundException}. */ public void testAddNodePathNotFoundException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); try { // use invalid parent path defaultRootNode.addNode(nodeName1 + "/" + nodeName2); fail("Creating a node at a non existent destination should throw PathNotFoundException"); } catch (PathNotFoundException e) { // ok, works as expected } } /** * Adds a new node using {@link javax.jcr.Node#addNode(String)} with an * index for the new name. * <p>This should throw an {@link RepositoryException}. */ public void testAddNodeRepositoryExceptionRelPathIndex() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); try { // use invalid relPath defaultRootNode.addNode(nodeName1 + "[1]", testNodeType); fail("Creating a node with index as postfix for new name should throw RepositoryException"); } catch (RepositoryException e) { // ok, works as expected } } /** * Creates a new node using {@link Node#addNode(String)}, then tries to call * {@link javax.jcr.Node#save()} on the newly node. * <p> * This should throw an {@link RepositoryException}. */ public void testAddNodeRepositoryExceptionSaveOnNewNode() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // add a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); try { // try to call save on newly created node testNode.save(); fail("Calling Node.save() on a newly created node should throw RepositoryException"); } catch (RepositoryException e) { // ok, works as expected. } } /** * Creates a new node using {@link Node#addNode(String)} , saves using * {@link javax.jcr.Node#save()} on parent node. Uses a second session to * verify if the node has been saved. */ public void testAddNodeParentSave() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // add a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // save new nodes defaultRootNode.save(); // use a different session to verify if the node is there Session session = getHelper().getReadOnlySession(); try { testNode = (Node) session.getItem(testNode.getPath()); } finally { session.logout(); } } /** * Creates a new node using {@link Node#addNode(String)} , saves using * {@link javax.jcr.Session#save()}. Uses a second session to verify if the * node has been saved. */ public void testAddNodeSessionSave() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // add a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // save new nodes superuser.save(); // use a different session to verify if the node is there Session session = getHelper().getReadOnlySession(); try { testNode = (Node) session.getItem(testNode.getPath()); } finally { session.logout(); } } /** * Creates a node with a mandatory child node using {@link * Node#addNode(String, String)}, saves on parent node then tries to delete * the mandatory child node. * <p> * This should throw a {@link ConstraintViolationException}. * <p> * Prerequisites: <ul> * <li><code>javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodetype2</code> * a node type that has a mandatory child node</li> <li><code>javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodetype3</code> * nodetype of the mandatory child node</li> <li><code>javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodename3</code> * name of the mandatory child node</li> </ul> */ public void testRemoveMandatoryNode() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create the node with the mandatory child node definition Node defaultTestNode = defaultRootNode.addNode(nodeName2, getProperty("nodetype2")); // add the mandatory child node Node defaultTestNodeChild = defaultTestNode.addNode(nodeName3, getProperty("nodetype3")); // save changes defaultRootNode.save(); try { // try to remove the mandatory node defaultTestNodeChild.remove(); defaultTestNode.save(); fail("Removing a mandatory node should throw a ConstraintViolationException"); } catch (ConstraintViolationException e) { // ok, works as expected } } /** * Removes a node using {@link javax.jcr.Node#remove()} with session 1, * afterwards it tries the same with session 2. * <p> * This should throw an {@link InvalidItemStateException}. */ public void testRemoveInvalidItemStateException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create the node Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // save the nodes superuser.save(); // get the node with session 2 Session testSession = getHelper().getReadWriteSession(); try { Node defaultTestNodeSession2 = (Node) testSession.getItem(defaultTestNode.getPath()); // remove node with session 1 defaultTestNode.remove(); superuser.save(); // try to remove already deleted node with session 2 try { defaultTestNodeSession2.remove(); testSession.save(); fail("Removing a node already deleted by other session should throw an InvalidItemStateException!"); } catch (InvalidItemStateException e) { //ok, works as expected } } finally { testSession.logout(); } } /** * Removes a node using {@link javax.jcr.Node#remove()}, then saves with * parent's nodes {@link javax.jcr.Node#save()} method. */ public void testRemoveNodeParentSave() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create the node Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // save the nodes defaultRootNode.save(); // remove them defaultTestNode.remove(); defaultRootNode.save(); // check if the node has been properly removed try { defaultRootNode.getNode(nodeName1); fail("Permanently removed node should no longer be adressable using Parent Node's getNode() method"); } catch (PathNotFoundException e) { // ok, works as expected } } /** * Removes a node using {@link javax.jcr.Node#remove()}, then saves using * {@link javax.jcr.Session#save()} method. */ public void testRemoveNodeSessionSave() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create the node Node defaultTestNode = defaultRootNode.addNode(nodeName1, testNodeType); // save the nodes superuser.save(); // remove them defaultTestNode.remove(); superuser.save(); // check if the node has been properly removed try { superuser.getItem(defaultRootNode.getPath() + "/" + nodeName1); fail("Permanently removed node should no longer be adressable using Session.getItem()"); } catch (PathNotFoundException e) { // ok, works as expected } } /** * Tests if <code>Node.remove()</code> does not throw a * <code>LockException</code> if <code>Node</code> is locked. * <p> * The test creates a node <code>nodeName1</code> of type * <code>testNodeType</code> under <code>testRoot</code> and locks the node * with the superuser session. Then the test removes * <code>nodeName1</code>. */ public void testRemoveNodeLockedItself() throws LockException, NotExecutableException, RepositoryException { if (!isSupported(Repository.OPTION_LOCKING_SUPPORTED)) { throw new NotExecutableException("Locking is not supported."); } // create a node that is lockable Node node = testRootNode.addNode(nodeName1, testNodeType); // or try to make it lockable if it is not ensureMixinType(node, mixLockable); testRootNode.getSession().save(); // remove first slash of path to get rel path to root String pathRelToRoot = node.getPath().substring(1); // access node through another session to lock it Session session2 = getHelper().getSuperuserSession(); try { Node node2 = session2.getRootNode().getNode(pathRelToRoot); node2.lock(true, true); // test fails if a LockException is thrown when removing the node // (remove must be possible since the parent is not locked) node.remove(); } finally { session2.logout(); } } /** * Tests if <code>Node.remove()</code> throws a <code>LockException</code> * if the parent node of <code>Node</code> is locked. * <p> * The test creates a node <code>nodeName1</code> of type * <code>testNodeType</code> under <code>testRoot</code>, adds a child node * <code>nodeName2</code> and locks it with the superuser session. Then the * test tries to remove the <code>nodeName2</code>. */ public void testRemoveNodeParentLocked() throws LockException, NotExecutableException, RepositoryException { Session session = testRootNode.getSession(); if (!isSupported(Repository.OPTION_LOCKING_SUPPORTED)) { throw new NotExecutableException("Locking is not supported."); } // create a node that is lockable Node node = testRootNode.addNode(nodeName1, testNodeType); // or try to make it lockable if it is not ensureMixinType(node, mixLockable); // create a child node Node subNode = node.addNode(nodeName2, testNodeType); testRootNode.getSession().save(); // lock the node // remove first slash of path to get rel path to root String pathRelToRoot = node.getPath().substring(1); // access node through another session to lock it Session session2 = getHelper().getSuperuserSession(); try { Node node2 = session2.getRootNode().getNode(pathRelToRoot); node2.lock(true, true); try { subNode.remove(); session.save(); fail("Removal of a Node must throw a LockException upon remove() " + "or upon save() if the parent of the node is locked"); } catch (LockException e) { // success } // unlock to remove node at tearDown() node2.unlock(); } finally { session2.logout(); } } /** * Tests object identity, meaning two nodes objects acquired through the * same session must have the same properties and states. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.nodetype</code> must allow * children of same node type</li> <li><code>javax.jcr.tck.propertyname1</code> * name of a String property that can be set in <code>javax.jcr.tck.nodetype</code> * for testing</li> </ul> */ public void testNodeIdentity() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode1 = defaultRootNode.addNode(nodeName1, testNodeType); // add a child node testNode1.addNode(nodeName1, testNodeType); // add a property testNode1.setProperty(propertyName1, "test"); // save the new node defaultRootNode.save(); // acquire the same node with session 2 Node testNode2 = (Node) superuser.getItem(testNode1.getPath()); // check if they have the same property assertTrue("Two references of same node have different properties", testNode1.getProperty(propertyName1).isSame(testNode2.getProperty(propertyName1))); // check if they have the same child assertTrue("Two references of same node have different children", testNode1.getNode(nodeName1).isSame(testNode2.getNode(nodeName1))); // check state methods assertEquals("Two references of same node have different State for Node.isCheckedOut()", testNode1.isCheckedOut(), testNode2.isCheckedOut()); assertEquals("Two references of same node have different State for Node.isLocked()", testNode1.isLocked(), testNode2.isLocked()); assertEquals("Two references of same node have different State for Node.isModified()", testNode1.isModified(), testNode2.isModified()); assertEquals("Two references of same node have different State for Node.isNew()", testNode1.isNew(), testNode2.isNew()); assertEquals("Two references of same node have different State for Node.isNode()", testNode1.isNode(), testNode2.isNode()); assertEquals("Two references of same node have different State for Node.isNodeType()", testNode1.isNodeType(testNodeType), testNode2.isNodeType(testNodeType)); assertTrue("Two references of same node should return true for Node1.isSame(Node2)", testNode1.isSame(testNode2)); assertEquals("Two references of same node have different Definitions", testNode1.getDefinition().getName(), testNode2.getDefinition().getName()); } /** * Tests if <code>Item.isSame(Item otherItem)</code> will return true when * two <code>Node</code> objects representing the same actual repository * item have been retrieved through two different sessions and one has been * modified. */ public void testIsSameMustNotCompareStates() throws RepositoryException { // create a node and save it Node testNode1 = testRootNode.addNode(nodeName1, testNodeType); testRootNode.getSession().save(); // acquire the same node with a different session Session session = getHelper().getReadOnlySession(); try { Node testNode2 = (Node) session.getItem(testNode1.getPath()); // add a property and do not save it so property is different in testNode2 testNode1.setProperty(propertyName1, "value1"); assertTrue("Two references of same node should return true for Node1.isSame(Node2)", testNode1.isSame(testNode2)); } finally { session.logout(); } } /** * Checks if {@link Node#isModified()} works correctly for unmodified and * modified nodes. */ public void testIsModified() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); defaultRootNode.save(); assertFalse("Unmodified node should return false on Node.isModified()", testNode.isModified()); // check if modified properties are recognized testNode.setProperty(propertyName1, "test"); assertTrue("Modified node should return true on Node.isModified()", testNode.isModified()); defaultRootNode.save(); // check if modified child nodes are recognized testNode.addNode(nodeName2, testNodeType); assertTrue("Modified node should return true on Node.isModified()", testNode.isModified()); } /** * Checks if {@link Node#isNew()} works correctly for new and existing, * unmodified nodes. */ public void testIsNew() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); assertTrue("Newly created node should return true on newNode.isNew()", testNode.isNew()); defaultRootNode.save(); assertFalse("Unmodified, exisiting node should return false on newNode.isNew()", testNode.isNew()); } /** * Tries to call {@link Node#refresh(boolean)} on a deleted node. * <p> * This should throw an {@link InvalidItemStateException}. */ public void testRefreshInvalidItemStateException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // save the new node defaultRootNode.save(); // remove the node defaultRootNode.remove(); try { testNode.refresh(true); fail("Calling Node.refresh() on deleted node should throw InvalidItemStateException!"); } catch (InvalidItemStateException e) { // ok, works as expected } } /** * Checks if {@link javax.jcr.Node#refresh(boolean refresh)} works properly * with <code>refresh</code> set to <code>false</code>. * <p> * Procedure: <ul> <li>Creates two nodes with session 1</li> <li>Modifies * node 1 with session 1 by adding a child node</li> <li>Get node 2 with * session 2</li> <li>Modifies node 2 with session 2 by adding a child * node</li> <li>saves session 2 changes using {@link * javax.jcr.Node#save()}</li> <li>calls <code>Node.refresh(false)</code> * on root node in session 1</li> </ul> Session 1 changes should be cleared * and session 2 changes should now be visible to session 1. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.nodetype</code> * must accept children of same nodetype</li> </ul> */ public void testRefreshBooleanFalse() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode1Session1 = defaultRootNode.addNode(nodeName1, testNodeType); // create a second node Node testNode2Session1 = defaultRootNode.addNode(nodeName2, testNodeType); // save the new nodes defaultRootNode.save(); // add child node to test node 1 using session 1 testNode1Session1.addNode(nodeName2, testNodeType); // get session 2 Session session2 = getHelper().getReadWriteSession(); try { // get the second node Node testNode2Session2 = (Node) session2.getItem(testNode2Session1.getPath()); // adds a child node testNode2Session2.addNode(nodeName3, testNodeType); // save the changes session2.save(); // call refresh on session 1 defaultRootNode.refresh(false); // check if session 1 flag has been cleared assertFalse("Session should have no pending changes recorded after Node.refresh(false)!", superuser.hasPendingChanges()); // check if added child node for node 1 by session 1 has been removed assertFalse("Node Modifications have not been flushed after Node.refresh(false)", testNode1Session1.hasNodes()); // check if added child node for node 2 by session 2 has become visible in session 1 assertTrue("Node modified by a different session has not been updated after Node.refresh(false)", testNode2Session1.hasNodes()); } finally { session2.logout(); } } /** * Checks if {@link javax.jcr.Node#refresh(boolean refresh)} works properly * with <code>refresh</code> set to <code>true</code>. * <p> * Procedure: <ul> <li>Creates two nodes with session 1</li> <li>Modifies * node 1 with session 1 by adding a child node</li> <li>Get node 2 with * session 2</li> <li>Modifies node 2 with session 2 by adding a child * node</li> <li>saves session 2 changes using {@link * javax.jcr.Node#save()}</li> <li>calls <code>Node.refresh(true)</code> on * root node in session 1</li> </ul> Session 1 changes and session 2 * changes now be visible to session 1. * <p> * Prerequisites: <ul> * <li><code>javax.jcr.tck.nodetype</code> must accept children of same * nodetype</li> </ul> */ public void testRefreshBooleanTrue() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode1Session1 = defaultRootNode.addNode(nodeName1, testNodeType); // create a second node Node testNode2Session1 = defaultRootNode.addNode(nodeName2, testNodeType); // save the new nodes defaultRootNode.save(); // add child node to test node 1 using session 1 testNode1Session1.addNode(nodeName2, testNodeType); // get session 2 Session session2 = getHelper().getReadWriteSession(); try { // get the second node Node testNode2Session2 = (Node) session2.getItem(testNode2Session1.getPath()); // adds a child node testNode2Session2.addNode(nodeName3, testNodeType); // save the changes session2.save(); // call refresh on session 1 defaultRootNode.refresh(true); // check if session 1 flag has been cleared assertTrue("Session should still have pending changes recorded after Node.refresh(true)!", superuser.hasPendingChanges()); // check if added child node for node 1 by session 1 is still there assertTrue("Node Modifications are lost after Node.refresh(true)", testNode1Session1.hasNodes()); // check if added child node for node 2 by session 2 has become visible in session 1 assertTrue("Node modified by a different session has not been updated after Node.refresh(true)", testNode2Session1.hasNodes()); } finally { session2.logout(); } } /** * Tries to save a node using {@link javax.jcr.Node#save()} that was already * deleted by an other session. * <p> * Procedure: <ul> <li>Creates a new * node with session 1, saves it, adds a child node.</li> <li>Access new * node with session 2,deletes the node, saves it.</li> <li>Session 1 tries * to save modifications using <code>Node.save()</code> on root node .</li> * </ul> This should throw an {@link javax.jcr.InvalidItemStateException}. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.nodetype</code> * must accept children of same nodetype</li> </ul> */ public void testSaveInvalidStateException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node nodeSession1 = defaultRootNode.addNode(nodeName1, testNodeType); // save new node superuser.save(); // make a modification nodeSession1.addNode(nodeName2, testNodeType); // get the new node with a different session Session testSession = getHelper().getReadWriteSession(); try { Node nodeSession2 = (Node) testSession.getItem(nodeSession1.getPath()); // delete the node with the new session nodeSession2.remove(); // make node removal persistent testSession.save(); // save changes made wit superuser session try { defaultRootNode.save(); fail("Saving a modified Node using Node.save() already deleted by an other session should throw InvalidItemStateException"); } catch (InvalidItemStateException e) { // ok, works as expected } } finally { testSession.logout(); } } /** * Tries to create and save a node using {@link javax.jcr.Node#save()} with * an mandatory property that is not set on saving time. * <p> * Prerequisites: <ul> <li><code>javax.jcr.tck.Node.testSaveConstraintViolationException.nodetype2</code> * must reference a nodetype that has at least one property that is * mandatory but not autocreated</li> </ul> */ public void testSaveConstraintViolationException() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node with at least one mandatory, not autocreated property defaultRootNode.addNode(nodeName1, this.getProperty("nodetype2")); // save changes try { superuser.save(); fail("Trying to use parent Node.save() with a node that has a mandatory property not set, should throw ConstraintViolationException"); } catch (ConstraintViolationException e) { // ok } } /** * Creates a new node, saves it uses second session to verify if node has * been added. */ public void testNodeSave() throws RepositoryException { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); // save new node defaultRootNode.save(); // get the new node with a different session Session testSession = getHelper().getReadOnlySession(); try { testSession.getItem(testNode.getPath()); } finally { testSession.logout(); } } /** * Tests if a {@link javax.jcr.RepositoryException} is thrown when calling * <code>Node.save()</code> on a newly added node */ public void testSaveOnNewNodeRepositoryException() throws Exception { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); // create a node Node newNode = defaultRootNode.addNode(nodeName1, testNodeType); try { newNode.save(); fail("Calling Node.save() on a newly added node should throw a RepositoryException"); } catch (RepositoryException success) { // ok } } /** * Tests if the primary node type is properly stored in jcr:primaryType */ public void testPrimaryType() throws Exception { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); assertEquals("The primary node type is not properly stored in jcr:primaryType",testNodeType,testNode.getProperty(jcrPrimaryType).getString()); } /** * Tests if jcr:primaryType is protected */ public void testPrimaryTypeProtected() throws Exception { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); try { testNode.setProperty(jcrPrimaryType,ntBase); fail("Manually setting jcr:primaryType should throw a ConstraintViolationException"); } catch (ConstraintViolationException success) { // ok } } /** * Tests if jcr:mixinTypes is protected */ public void testMixinTypesProtected() throws Exception { // get default workspace test root node using superuser session Node defaultRootNode = (Node) superuser.getItem(testRootNode.getPath()); Node testNode = defaultRootNode.addNode(nodeName1, testNodeType); Value mixinName = superuser.getValueFactory().createValue(mixLockable, PropertyType.NAME); try { testNode.setProperty(jcrMixinTypes, new Value[]{mixinName}); fail("Manually setting jcr:mixinTypes should throw a ConstraintViolationException"); } catch (ConstraintViolationException success) { // ok } } }