/** * This file Copyright (c) 2008-2012 Magnolia International * Ltd. (http://www.magnolia-cms.com). All rights reserved. * * * This file is dual-licensed under both the Magnolia * Network Agreement and the GNU General Public License. * You may elect to use one or the other of these licenses. * * This file is distributed in the hope that it will be * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. * Redistribution, except as permitted by whichever of the GPL * or MNA you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or * modify this file under the terms of the GNU General * Public License, Version 3, as published by the Free Software * Foundation. You should have received a copy of the GNU * General Public License, Version 3 along with this program; * if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 2. For the Magnolia Network Agreement (MNA), this file * and the accompanying materials are made available under the * terms of the MNA which accompanies this distribution, and * is available at http://www.magnolia-cms.com/mna.html * * Any modifications to this file must keep this entire header * intact. * */ package info.magnolia.cms.core.version; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import info.magnolia.cms.beans.config.ContentRepository; import info.magnolia.cms.core.MgnlNodeType; import info.magnolia.cms.core.SystemProperty; import info.magnolia.cms.security.MgnlUser; import info.magnolia.cms.util.Rule; import info.magnolia.context.MgnlContext; import info.magnolia.jcr.util.NodeTypes; import info.magnolia.repository.Provider; import info.magnolia.repository.RepositoryConstants; import info.magnolia.test.RepositoryTestCase; import info.magnolia.test.mock.MockContext; import java.io.ByteArrayInputStream; import java.util.Collections; import javax.jcr.LoginException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.version.Version; import org.apache.jackrabbit.JcrConstants; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Tests. */ public class BaseVersionManagerTest extends RepositoryTestCase { private static String mgnlMixDeleted = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<nodeTypes" + " xmlns:rep=\"internal\"" + " xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\"" + " xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\"" + " xmlns:mgnl=\"http://www.magnolia.info/jcr/mgnl\"" + " xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" + "<nodeType name=\"" + NodeTypes.Deleted.NAME + "\" isMixin=\"true\" hasOrderableChildNodes=\"true\" primaryItemName=\"\">" + "<supertypes>" + "<supertype>nt:base</supertype>" + "</supertypes>" + "</nodeType>" + "</nodeTypes>"; @Override @Before public void setUp() throws Exception { super.setUp(); // context is then cleared automatically on teardown by RepoTestCase(MgnlTestCase) MockContext ctx = (MockContext) MgnlContext.getInstance(); ctx.setUser(new MgnlUser("toto","admin",Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_MAP, null, null)); MgnlContext.setInstance(ctx); } @Test public void testCreateAndRestoreVersion() throws RepositoryException{ Session session = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE); VersionManager versionMan = VersionManager.getInstance(); Node node = session.getRootNode().addNode( "page", NodeTypes.Content.NAME); node.addNode("paragraph", NodeTypes.ContentNode.NAME); session.save(); Version version = versionMan.addVersion(node); assertFalse("Original node should not have mixin", node.isNodeType(JcrConstants.MIX_VERSIONABLE)); Node nodeInVersionWS =versionMan.getVersionedNode(node); assertTrue("Node in mgnlVersion workspace must have mixin", nodeInVersionWS.isNodeType(JcrConstants.MIX_VERSIONABLE)); // assert that the the paragraph was versioned Node versionedNode = versionMan.getVersion(node, version.getName()); assertTrue("Versioned content must include the paragraph", versionedNode.hasNode("paragraph")); // now delete the paragraph node.getNode("paragraph").remove(); node.save(); assertFalse("Paragraph should be deleted", node.hasNode("paragraph")); // restore //FIXME: wrap all nodes returned by the session (except for mgnlVersion) in the wrapper that delegates restore call to the version manager ... node.restore(version.getName(), true); assertTrue("Paragraph should be restored", node.hasNode("paragraph")); } @Test public void testCreateAndRestoreDeletedVersion() throws RepositoryException { Provider repoProvider = ContentRepository.getRepositoryProvider(RepositoryConstants.WEBSITE); repoProvider.registerNodeTypes(new ByteArrayInputStream(mgnlMixDeleted.getBytes())); Session session = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE); VersionManager versionMan = VersionManager.getInstance(); Node node = session.getRootNode().addNode( "page", NodeTypes.Content.NAME); // add deleted mixin node.addMixin(NodeTypes.Deleted.NAME); session.save(); versionMan.addVersion(node); Node nodeInVersionWS = versionMan.getVersionedNode(node); assertTrue("Node in mgnlVersion workspace must have mixin", nodeInVersionWS.isNodeType(NodeTypes.Deleted.NAME)); node.removeMixin(NodeTypes.Deleted.NAME); session.save(); assertFalse("Node in website workspace should not have mixin", node.isNodeType(NodeTypes.Deleted.NAME)); // add version w/o mixin versionMan.addVersion(node); nodeInVersionWS = versionMan.getVersionedNode(node); assertFalse("Node in mgnlVersion workspace should not have mixin", nodeInVersionWS.isNodeType(NodeTypes.Deleted.NAME)); } @Test public void testUseSystemSessionToRetrieveVersions() throws RepositoryException { Session session = MgnlContext.getSystemContext().getJCRSession(RepositoryConstants.VERSION_STORE); VersionManager versionMan = VersionManager.getInstance(); assertSame(session, versionMan.getSession()); } @Test public void testNumberOfCreatedVersions() throws LoginException, RepositoryException{ Session session = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE); Node root = session.getRootNode(); Node firstPage = root.addNode("firstPage", NodeTypes.Page.NAME); session.save(); VersionManager versionManager = VersionManager.getInstance(); final Rule rule = new Rule(); rule.addAllowType(NodeTypes.Page.NAME); rule.addAllowType(NodeTypes.ContentNode.NAME); rule.addAllowType(NodeTypes.Resource.NAME); firstPage.setProperty("title", "v1title"); firstPage.addNode("v1child", "mgnl:area"); firstPage.save(); Version v1 = versionManager.addVersion(firstPage, rule); assertEquals(versionManager.getAllVersions(firstPage).getSize(), 2); Node versionedNode = versionManager.getVersion(firstPage, v1.getName()); assertEquals("v1title", versionedNode.getProperty("title").getString()); assertTrue(versionedNode.hasNode("v1child")); assertEquals("toto", versionManager.getSystemNode(versionedNode).getProperty(ContentVersion.VERSION_USER).getString()); firstPage.setProperty("title", "v2title"); firstPage.addNode("v2child", "mgnl:area"); firstPage.save(); Version v2 = versionManager.addVersion(firstPage, rule); versionedNode = versionManager.getVersion(firstPage, v2.getName()); assertEquals(versionManager.getAllVersions(firstPage).getSize(), 3); assertEquals("v2title", versionedNode.getProperty("title").getString()); assertTrue(versionedNode.hasNode("v2child")); assertEquals("toto", versionManager.getSystemNode(versionedNode).getProperty(ContentVersion.VERSION_USER).getString()); //test when user wasn't set into MgnlContext MockContext ctx = (MockContext) MgnlContext.getInstance(); ctx.setUser(null); MgnlContext.setInstance(ctx); firstPage.setProperty("title", "v3title"); firstPage.addNode("v3child", "mgnl:area"); firstPage.save(); Version v3 = versionManager.addVersion(firstPage, rule); versionedNode = versionManager.getVersion(firstPage, v3.getName()); assertEquals(versionManager.getAllVersions(firstPage).getSize(), 4); assertEquals("v3title", versionedNode.getProperty("title").getString()); assertTrue(versionedNode.hasNode("v3child")); assertEquals("", versionManager.getSystemNode(versionedNode).getProperty(ContentVersion.VERSION_USER).getString()); } @Test public void testCreateAndRestoreVersionAndCheckOrder() throws RepositoryException { // GIVEN Session session = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE); VersionManager versionMan = VersionManager.getInstance(); Node node = session.getRootNode().addNode("page", MgnlNodeType.NT_PAGE); node.addNode("component0", MgnlNodeType.NT_COMPONENT); node.addNode("component1", MgnlNodeType.NT_COMPONENT); node.addNode("component2", MgnlNodeType.NT_COMPONENT); node.addNode("component3", MgnlNodeType.NT_COMPONENT); Node area = node.addNode("area", MgnlNodeType.NT_AREA); area.addNode("sub0", MgnlNodeType.NT_COMPONENT); area.addNode("sub1", MgnlNodeType.NT_COMPONENT); session.save(); Version version = versionMan.addVersion(node); Node nodeInVersionWS = versionMan.getVersionedNode(node); // sanity check NodeIterator iterator = nodeInVersionWS.getNodes("compo*"); assertEquals("component0", iterator.nextNode().getName()); assertEquals("component1", iterator.nextNode().getName()); assertEquals("component2", iterator.nextNode().getName()); assertEquals("component3", iterator.nextNode().getName()); iterator = area.getNodes("sub*"); assertEquals("sub0", iterator.nextNode().getName()); assertEquals("sub1", iterator.nextNode().getName()); // WHEN // swap subnodes - put first at the end node.orderBefore("component0", null); // and second before the fourth node.orderBefore("component1", "component3"); area.orderBefore("sub0", null); session.save(); // sanity check again iterator = node.getNodes("compo*"); assertEquals("component2", iterator.nextNode().getName()); assertEquals("component1", iterator.nextNode().getName()); assertEquals("component3", iterator.nextNode().getName()); assertEquals("component0", iterator.nextNode().getName()); iterator = area.getNodes("sub*"); assertEquals("sub1", iterator.nextNode().getName()); assertEquals("sub0", iterator.nextNode().getName()); // restore node.restore(version.getName(), true); // THEN // http://www.day.com/specs/jcr/2.0/23_Orderable_Child_Nodes.html // If a node has orderable child nodes then at any time its child node set has a current order, reflected in the iterator returned by Node.getNodes()(see ยง5.2.2 Iterating Over Child Items). If a node does not have orderable child nodes then the order of nodes returned by Node.getNodes is not guaranteed and may change at any time. iterator = node.getNodes("compo*"); assertEquals("component0", iterator.nextNode().getName()); assertEquals("component1", iterator.nextNode().getName()); iterator = node.getNode("area").getNodes("sub*"); assertEquals("sub0", iterator.nextNode().getName()); assertEquals("sub1", iterator.nextNode().getName()); } @Test public void testCreateAndRestoreVersionAndCheckOrderBetweenTwoVersions() throws RepositoryException { // GIVEN Session session = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE); VersionManager versionMan = VersionManager.getInstance(); Node node = session.getRootNode().addNode("page", MgnlNodeType.NT_PAGE); node.addNode("component0", MgnlNodeType.NT_COMPONENT); node.addNode("component1", MgnlNodeType.NT_COMPONENT); session.save(); Version version1 = versionMan.addVersion(node); // add 3rd and order on top node.addNode("component2", MgnlNodeType.NT_COMPONENT); node.orderBefore("component2", "component0"); session.save(); // version again Version version2 = versionMan.addVersion(node); // WHEN // restore 1st node.restore(version1.getName(), true); // THEN NodeIterator iterator = node.getNodes("compo*"); assertEquals("component0", iterator.nextNode().getName()); assertEquals("component1", iterator.nextNode().getName()); // comp2 is gone assertFalse(iterator.hasNext()); // WHEN // restore 2ndt node.restore(version2.getName(), true); // THEN iterator = node.getNodes("compo*"); assertEquals("component2", iterator.nextNode().getName()); assertEquals("component0", iterator.nextNode().getName()); assertEquals("component1", iterator.nextNode().getName()); } @Override @After public void tearDown(){ MgnlContext.setInstance(null); SystemProperty.clear(); } }