info.magnolia.cms.core.DefaultContentTest.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.cms.core.DefaultContentTest.java

Source

/**
 * This file Copyright (c) 2003-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;

import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import info.magnolia.cms.beans.config.ContentRepository;
import info.magnolia.cms.beans.runtime.FileProperties;
import info.magnolia.cms.core.version.VersionManager;
import info.magnolia.cms.util.NodeDataUtil;
import info.magnolia.cms.util.Rule;
import info.magnolia.context.MgnlContext;
import info.magnolia.importexport.PropertiesImportExport;
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.jcr.MockNode;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionIterator;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.easymock.IAnswer;
import org.junit.Test;

/**
 * @version $Id$
 */
public class DefaultContentTest extends RepositoryTestCase {

    public interface ExceptionThrowingCallback {
        void call() throws Exception;
    }

    @Test
    public void testAddMixin() throws IOException, RepositoryException {
        final Content content = getTestContent();
        final String repoName = content.getWorkspace().getName();
        final String mixDeleted = "mgnl:deleted";
        final Provider repoProvider = ContentRepository.getRepositoryProvider(repoName);
        final 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=\"" + mixDeleted
                + "\" isMixin=\"true\" hasOrderableChildNodes=\"true\" primaryItemName=\"\">" + "<supertypes>"
                + "<supertype>nt:base</supertype>" + "</supertypes>" + "</nodeType>" + "</nodeTypes>";

        try {
            repoProvider.registerNodeTypes(new ByteArrayInputStream(mgnlMixDeleted.getBytes()));
        } catch (RepositoryException e) {
            // ignore, either it's already registered and test will pass, or type can't be registered and test should fail
        }

        assertTrue(content.getJCRNode().canAddMixin(mixDeleted));
        content.addMixin(mixDeleted);
    }

    @Test
    public void testReadingANodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        NodeData nodeData = content.getNodeData("nd1");
        assertEquals("hello", nodeData.getString());
        assertEquals(true, nodeData.isExist());
    }

    @Test
    public void testThatReadingANonExistingNodeDataDoesNotFail() throws IOException, RepositoryException {
        Content content = getTestContent();
        // this should not fail
        NodeData nodeData = content.getNodeData("nd2");
        assertEquals(false, nodeData.isExist());
    }

    @Test
    public void testSettingAnExistingNodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        // this should not fail
        Value value = createValue("test");
        NodeData nodeData = content.setNodeData("nd1", value);
        assertEquals("test", nodeData.getString());
    }

    @Test
    public void testSettingANonExistingNodeDataCreatesANewNodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        Value value = createValue("test");
        // does not exist yet
        NodeData nodeData = content.setNodeData("nd2", value);
        assertEquals("test", nodeData.getString());
    }

    @Test
    public void testCreatingAnEmptyNodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        // this should not fail
        NodeData nodeData = content.createNodeData("nd2");
        assertEquals("", nodeData.getString());
        assertEquals(true, nodeData.isExist());
    }

    @Test
    public void testCreatingAnEmptyNodeDataSetsADefaultValueIfPossible() throws IOException, RepositoryException {
        Content content = getTestContent();
        NodeData nodeData = content.createNodeData("nd2", PropertyType.BOOLEAN);
        assertEquals(true, nodeData.isExist());
        assertEquals(PropertyType.BOOLEAN, nodeData.getType());
    }

    @Test
    public void testCreatingAndSettingANodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        // this should not fail
        NodeData nodeData = content.createNodeData("nd2", "test");
        assertEquals("test", nodeData.getString());
    }

    @Test
    public void testCreatingAndSettingABooleanNodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        // this actually creates a string property having an empty string value
        NodeData nodeData = content.createNodeData("nd2");
        // now setting a boolean value
        nodeData.setValue(true);
        assertEquals(true, nodeData.getBoolean());

        nodeData = content.createNodeData("nd3", true);
        assertEquals(true, nodeData.getBoolean());
    }

    @Test
    public void testCreatingAnExistingNodeDataDoesNotFail() throws IOException, RepositoryException {
        Content content = getTestContent();
        NodeData nodeData = content.createNodeData("nd1", "other");
        assertEquals("other", nodeData.getString());
    }

    @Test
    public void testCreatingAndReadingABinaryNodeData() throws IOException, RepositoryException {
        Content content = getTestContent();
        String binaryContent = "the content";
        NodeData nodeData = content.createNodeData("nd2", PropertyType.BINARY);
        nodeData.setValue(IOUtils.toInputStream(binaryContent));
        //        nodeData.setAttribute(FileProperties.PROPERTY_FILENAME, "filename");
        nodeData.setAttribute(FileProperties.PROPERTY_CONTENTTYPE, "text/plain");
        nodeData.setAttribute(FileProperties.PROPERTY_LASTMODIFIED, Calendar.getInstance());

        content.save();
        nodeData = content.getNodeData("nd2");
        assertEquals(binaryContent, IOUtils.toString(nodeData.getStream()));
        //assertEquals("filename", nodeData.getAttribute(FileProperties.PROPERTY_FILENAME));
    }

    @Test
    public void testThatReadingANonExistingNodeDataReturnsAnEmptyNodeData()
            throws IOException, RepositoryException {
        Content content = getTestContent();
        NodeData nd = content.getNodeData("nirvana");
        assertEquals("nirvana", nd.getName());
        assertEquals("", nd.getString());
        assertEquals(false, nd.getBoolean());
        assertEquals(0, nd.getLong());
        assertEquals("", nd.getAttribute("other"));
    }

    @Test
    public void testThatReadingANonExistingNodeDataReturnsAnEmptyNodeDataWhichIsUnmutable()
            throws IOException, RepositoryException {
        Content content = getTestContent();
        NodeData nd = content.getNodeData("nirvana");
        try {
            nd.setValue("value");
        } catch (ItemNotFoundException e) {
            return;
        }
        fail("should throw an exception");
    }

    private Content getTestContent() throws IOException, RepositoryException {
        String contentProperties = "/mycontent.@type=mgnl:content\n" + "/mycontent.nd1=hello";

        HierarchyManager hm = MgnlContext.getHierarchyManager(RepositoryConstants.WEBSITE);
        new PropertiesImportExport().createContent(hm.getRoot(), IOUtils.toInputStream(contentProperties));
        hm.save();
        Content content = hm.getContent("/mycontent");
        return content;
    }

    //    public void testPermissionCheckedOnDeleteNodeData() throws Exception {
    //        HierarchyManager hm = MgnlContext.getHierarchyManager(RepositoryConstants.WEBSITE);
    //        // create the content while we have full permissions
    //        final Content node = hm.createContent("/", "foo", ItemType.CONTENTNODE.getSystemName());
    //        node.createNodeData("bar").setValue("test");
    //
    //        AccessManager am = new AccessManagerImpl();
    //        setPermission(am, "/*", Permission.READ);
    //
    //        // test that we can read
    //        assertTrue(node.hasNodeData("bar"));
    //        assertEquals("test", node.getNodeData("bar").getString());
    //
    //        mustFailWithAccessDeniedException(new ExceptionThrowingCallback() {
    //            public void call() throws Exception {
    //                node.setNodeData("bar", "other");
    //            }
    //
    //        }, "should not be allowed to set a value");
    //
    //        mustFailWithAccessDeniedException(new ExceptionThrowingCallback() {
    //            public void call() throws Exception {
    //                node.delete("bar");
    //            }
    //
    //        }, "should not be allowed to delete a nodedata");
    //
    //        mustFailWithAccessDeniedException(new ExceptionThrowingCallback() {
    //            public void call() throws Exception {
    //                node.deleteNodeData("bar");
    //            }
    //
    //        }, "should not be allowed to delete a nodedata");
    //    }
    //
    //    private void mustFailWithAccessDeniedException(ExceptionThrowingCallback callback, String msg) throws Exception {
    //        try{
    //            callback.call();
    //        }
    //        catch (AccessDeniedException e) {
    //            // this expected
    //            return;
    //        }
    //        fail(msg);
    //
    //    }
    //
    //    private void setPermission(AccessManager am, String path, long permissionValue) {
    //        List<Permission> permissions = am.getPermissionList();
    //        if(permissions == null){
    //            permissions = new ArrayList<Permission>();
    //        }
    //
    //        PermissionImpl permission = new PermissionImpl();
    //        permission.setPattern(new SimpleUrlPattern(path));
    //        permission.setPermissions(permissionValue);
    //        permissions.add(permission);
    //        am.setPermissionList(permissions);
    //    }

    @Test
    public void testIsNodeTypeForNodeChecksPrimaryType() throws RepositoryException {
        final Node node = createMock(Node.class);
        final Property nodeTypeProp = createStrictMock(Property.class);
        expect(node.getProperty(ItemType.JCR_PRIMARY_TYPE)).andReturn(nodeTypeProp).times(2);
        expect(node.isNodeType((String) anyObject())).andAnswer(new IAnswer<Boolean>() {
            @Override
            public Boolean answer() throws Throwable {
                return getCurrentArguments()[0].equals("foo");
            }
        }).times(2);
        expect(nodeTypeProp.getString()).andReturn("foo").times(2);
        replay(node, nodeTypeProp);

        final DefaultContent c = new DefaultContent();
        c.setNode(node);
        assertTrue(c.isNodeType(node, "foo"));
        assertFalse(c.isNodeType(node, "bar"));
        verify(node, nodeTypeProp);
    }

    @Test
    public void testIsNodeTypeForNodeCheckFrozenTypeIfWereNotLookingForFrozenNodes() throws Exception {
        // GIVEN
        final Node node = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE).getRootNode().addNode("testPage",
                NodeTypes.ContentNode.NAME);
        node.addMixin(NodeTypes.Versionable.NAME);
        node.getSession().save();
        final Node version = VersionManager.getInstance()
                .addVersion(node, new Rule(NodeTypes.ContentNode.NAME, ",")).getFrozenNode();
        final DefaultContent content = new DefaultContent();

        // WHEN-THEN
        assertTrue(content.isNodeType(version, NodeTypes.ContentNode.NAME));
    }

    @Test
    public void testIsNodeTypeForNodeCheckFrozenTypeForSupertypesIfWereNotLookingForFrozenNodes() throws Exception {
        // GIVEN
        final Node node = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE).getRootNode().addNode("testPage",
                NodeTypes.Area.NAME);
        node.addMixin(NodeTypes.Versionable.NAME);
        node.getSession().save();
        final Node version = VersionManager.getInstance()
                .addVersion(node, new Rule(NodeTypes.ContentNode.NAME, ",")).getFrozenNode();
        final DefaultContent content = new DefaultContent();

        // WHEN-THEN
        assertTrue(content.isNodeType(version, NodeTypes.ContentNode.NAME));
    }

    @Test
    public void testIsNotNodeTypeForNodeCheckFrozenTypeIfWereNotLookingForFrozenNodes() throws Exception {
        // GIVEN
        final Node node = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE).getRootNode().addNode("testPage",
                NodeTypes.Content.NAME);
        node.addMixin(NodeTypes.Versionable.NAME);
        node.getSession().save();
        final Node version = VersionManager.getInstance()
                .addVersion(node, new Rule(NodeTypes.ContentNode.NAME, ",")).getFrozenNode();
        final DefaultContent content = new DefaultContent();

        // WHEN-THEN
        assertFalse(content.isNodeType(version, NodeTypes.ContentNode.NAME));
    }

    @Test
    public void testIsNodeTypeForNodeDoesNotCheckFrozenTypeIfTheRequestedTypeIsFrozenType()
            throws RepositoryException {
        final Node node = createStrictMock(Node.class);
        final Property nodeTypeProp = createStrictMock(Property.class);
        expect(node.getProperty(ItemType.JCR_PRIMARY_TYPE)).andReturn(nodeTypeProp);
        expect(nodeTypeProp.getString()).andReturn(ItemType.NT_FROZENNODE);
        expect(node.isNodeType(ItemType.NT_FROZENNODE)).andReturn(true);

        replay(node, nodeTypeProp);
        final DefaultContent c = new DefaultContent();
        c.setNode(node);
        assertTrue(c.isNodeType(node, ItemType.NT_FROZENNODE));
        verify(node, nodeTypeProp);
    }

    @Test
    public void testNameFilteringWorksForBothBinaryAndNonBinaryProperties() throws Exception {
        String contentProperties = StringUtils.join(Arrays.asList("/somepage/mypage@type=mgnl:content",
                "/somepage/mypage/paragraphs@type=mgnl:contentNode",
                "/somepage/mypage/paragraphs/0@type=mgnl:contentNode",
                "/somepage/mypage/paragraphs/0@type=mgnl:contentNode",

                // 2 regular props
                "/somepage/mypage/paragraphs/0/attention=booyah",
                "/somepage/mypage/paragraphs/0/imaginary=date:2009-10-14T08:59:01.227-04:00",

                // 3 binaries
                "/somepage/mypage/paragraphs/0/attachment1@type=mgnl:resource",
                "/somepage/mypage/paragraphs/0/attachment1.fileName=hello",
                "/somepage/mypage/paragraphs/0/attachment1.extension=gif",
                // being a binary node, magnolia knows to store data as jcr:data w/o need to be explicitly told so
                "/somepage/mypage/paragraphs/0/attachment1=binary:X",
                "/somepage/mypage/paragraphs/0/attachment1.jcr\\:mimeType=image/gif",
                "/somepage/mypage/paragraphs/0/attachment1.jcr\\:lastModified=date:2009-10-14T08:59:01.227-04:00",

                "/somepage/mypage/paragraphs/0/attachment2@type=mgnl:resource",
                "/somepage/mypage/paragraphs/0/attachment2.fileName=test",
                "/somepage/mypage/paragraphs/0/attachment2.extension=jpeg",
                "/somepage/mypage/paragraphs/0/attachment2=binary:X",
                "/somepage/mypage/paragraphs/0/attachment2.jcr\\:mimeType=image/jpeg",
                "/somepage/mypage/paragraphs/0/attachment2.jcr\\:lastModified=date:2009-10-14T08:59:01.227-04:00",

                "/somepage/mypage/paragraphs/0/image3@type=mgnl:resource",
                "/somepage/mypage/paragraphs/0/image3.fileName=third",
                "/somepage/mypage/paragraphs/0/image3.extension=png",
                "/somepage/mypage/paragraphs/0/image3=binary:X",
                "/somepage/mypage/paragraphs/0/image3.jcr\\:mimeType=image/png",
                "/somepage/mypage/paragraphs/0/image3.jcr\\:lastModified=date:2009-10-14T08:59:01.227-04:00",

                // and more which should not match
                "/somepage/mypage/paragraphs/0/foo=bar", "/somepage/mypage/paragraphs/0/mybool=boolean:true",
                "/somepage/mypage/paragraphs/0/rand@type=mgnl:resource",
                "/somepage/mypage/paragraphs/0/rand.fileName=randdddd",
                "/somepage/mypage/paragraphs/0/rand.extension=png", "/somepage/mypage/paragraphs/0/rand=binary:X",
                "/somepage/mypage/paragraphs/0/rand.jcr\\:mimeType=image/png",
                "/somepage/mypage/paragraphs/0/rand.jcr\\:lastModified=date:2009-10-14T08:59:01.227-04:00"), "\n");
        final HierarchyManager hm = MgnlContext.getHierarchyManager(RepositoryConstants.WEBSITE);
        new PropertiesImportExport().createContent(hm.getRoot(), IOUtils.toInputStream(contentProperties));
        hm.save();

        final Content content = hm.getContent("/somepage/mypage/paragraphs/0");
        final Collection<NodeData> props = content.getNodeDataCollection("att*|ima*");
        assertEquals(5, props.size());

        // sort by name
        final TreeSet<NodeData> sorted = new TreeSet<NodeData>(new Comparator<NodeData>() {
            @Override
            public int compare(NodeData o1, NodeData o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        sorted.addAll(props);
        // sanity check - just recheck we still have 5 elements
        assertEquals(5, sorted.size());
        final Iterator<NodeData> it = sorted.iterator();
        final NodeData a = it.next();
        final NodeData b = it.next();
        final NodeData c = it.next();
        final NodeData d = it.next();
        final NodeData e = it.next();
        assertEquals("attachment1", a.getName());
        assertEquals(PropertyType.BINARY, a.getType());
        assertEquals("attachment2", b.getName());
        assertEquals(PropertyType.BINARY, b.getType());
        assertEquals("image3", d.getName());
        assertEquals(PropertyType.BINARY, d.getType());
        assertEquals("image3", d.getName());
        assertEquals(PropertyType.BINARY, d.getType());

        assertEquals("attention", c.getName());
        assertEquals(PropertyType.STRING, c.getType());
        assertEquals("booyah", c.getString());
        assertEquals("imaginary", e.getName());
        assertEquals(PropertyType.DATE, e.getType());
        assertEquals(true, e.getDate().before(Calendar.getInstance()));
    }

    @Test
    public void testStringPropertiesCanBeRetrievedByStreamAndViceVersa() throws Exception {
        String contentProperties = StringUtils.join(Arrays.asList("/hello/foo=bar",
                // a binary
                "/hello/bin@type=mgnl:resource", "/hello/bin.fileName=hello", "/hello/bin.extension=gif",
                "/hello/bin=binary:some-data", "/hello/bin.jcr\\:mimeType=image/gif",
                "/hello/bin.jcr\\:lastModified=date:2009-10-14T08:59:01.227-04:00"), "\n");
        final HierarchyManager hm = MgnlContext.getHierarchyManager(RepositoryConstants.WEBSITE);
        new PropertiesImportExport().createContent(hm.getRoot(), IOUtils.toInputStream(contentProperties));
        hm.save();

        final Content content = hm.getContent("/hello");
        final NodeData st = content.getNodeData("foo");
        assertEquals(PropertyType.STRING, st.getType());
        assertEquals("bar", st.getString());
        assertEquals("bar", IOUtils.toString(st.getStream()));

        final NodeData bin = content.getNodeData("bin");
        assertEquals(PropertyType.BINARY, bin.getType());
        assertEquals("some-data", IOUtils.toString(bin.getStream()));
        assertEquals("some-data", bin.getString());
    }

    @Test
    public void testModDate() throws IOException, RepositoryException {
        Content content = getTestContent();
        Calendar modDate = content.getMetaData().getModificationDate();
        Calendar creationDate = content.getMetaData().getCreationDate();
        assertNotNull(modDate);
        assertEquals(creationDate, modDate);
        content.setNodeData("test", false);
        content.save();
        modDate = content.getMetaData().getModificationDate();
        assertNotNull(modDate);
        assertNotSame(creationDate, modDate);
    }

    @Test
    public void testDelete() throws Exception {
        // GIVEN content node with version history
        final Content content = getTestContent();
        final String uuid = content.getUUID();
        final Content parent = content.getParent();
        content.addVersion();
        // parent.save();
        Content versionedContent = MgnlContext.getHierarchyManager("mgnlVersion").getContentByUUID(uuid);
        assertNotNull(versionedContent);
        VersionHistory history = versionedContent.getJCRNode().getVersionHistory();
        // root and current
        VersionIterator versions = content.getAllVersions();
        // root version
        assertNotNull(versions.nextVersion());
        // previously created version
        assertNotNull(versions.nextVersion());

        // WHEN we delete the content
        content.delete();
        parent.save();

        // THEN versioned node and all versions should be deleted as well
        // make sure versioned node is deleted
        try {
            MgnlContext.getHierarchyManager("mgnlVersion").getContentByUUID(uuid);
            fail("versioned copy should have been deleted but was not.");
        } catch (ItemNotFoundException e) {
            // expected
        }

        // make sure history has no label => all versions incl. root are gone
        try {
            history.getVersionLabels();
            fail("version history should have been invalidated by JR after manually deleting all versions except root and referencing content");
        } catch (RepositoryException e) {
            // no versions exist anymore.
        }
    }

    @Test
    public void testEquals() {
        // GIVEN
        Node node = new MockNode("test");
        DefaultContent first = new DefaultContent(node);
        DefaultContent second = new DefaultContent(node);

        // WHEN
        boolean result = first.equals(second);

        // THEN
        assertTrue(result);
    }

    @Test
    public void testEqualsWithNull() {
        // GIVEN
        Node node = new MockNode("test");
        DefaultContent first = new DefaultContent(node);

        // WHEN
        boolean result = first.equals(null);

        // THEN
        assertFalse(result);
    }

    @Test
    public void testEqualsWithWrongType() {
        // GIVEN
        Node node = new MockNode("test");
        DefaultContent first = new DefaultContent(node);
        Object second = "second";

        // WHEN
        boolean result = first.equals(second);

        // THEN
        assertFalse(result);
    }

    private Value createValue(Object valueObj) throws RepositoryException, UnsupportedRepositoryOperationException {
        ValueFactory valueFactory = MgnlContext.getHierarchyManager("website").getWorkspace().getSession()
                .getValueFactory();
        return NodeDataUtil.createValue(valueObj, valueFactory);
    }

}