/* * Copyright (C) 2005-2011 Alfresco Software Limited. * * This file is part of Alfresco * * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco 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 Alfresco. If not, see . */ package org.alfresco.repo.publishing; import static org.alfresco.model.ContentModel.ASPECT_GEOGRAPHIC; import static org.alfresco.model.ContentModel.ASPECT_TEMPORARY; import static org.alfresco.model.ContentModel.PROP_CONTENT; import static org.alfresco.model.ContentModel.PROP_LATITUDE; import static org.alfresco.model.ContentModel.PROP_LONGITUDE; import static org.alfresco.model.ContentModel.PROP_NAME; import static org.alfresco.model.ContentModel.TYPE_CONTENT; import static org.alfresco.repo.publishing.PublishingModel.ASSOC_LAST_PUBLISHING_EVENT; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.publishing.NodeSnapshot; import org.alfresco.service.cmr.publishing.PublishingDetails; import org.alfresco.service.cmr.publishing.PublishingEvent; import org.alfresco.service.cmr.publishing.PublishingPackage; import org.alfresco.service.cmr.publishing.PublishingPackageEntry; import org.alfresco.service.cmr.publishing.PublishingService; import org.alfresco.service.cmr.publishing.Status; import org.alfresco.service.cmr.publishing.channels.Channel; import org.alfresco.service.cmr.publishing.channels.ChannelType; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; /** * @author Nick Smith * @since 4.0 */ public class PublishEventActionTest extends AbstractPublishingIntegrationTest { private static final String contentNodeName = "TheName"; private static final String content = "The quick brown fox jumped over the lazy dog"; @Resource(name="publishingService") private PublishingService publishingService; @Resource(name="contentService") private ContentService contentService; @Autowired private ChannelHelper channelHelper; @Autowired private PublishEventAction action; private Channel channel; private NodeRef channelNode; private AbstractChannelType channelType; @Test public void testPublishNodes() throws Exception { // Create content node with appropriate aspects added. NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); double lattitude = 0.25; double longtitude = 0.75; addGeographicAspect(source, lattitude, longtitude); nodeService.addAspect(source, ASPECT_TEMPORARY, null); NodeRef publishEventNode = publishNode(source); // Check published node exists and is in correct place. NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertNotNull(publishedNode); assertTrue(nodeService.exists(publishedNode)); assertEquals(channelNode, nodeService.getPrimaryParent(publishedNode).getParentRef()); // Check published node type and aspects assertEquals(TYPE_CONTENT, nodeService.getType(publishedNode)); Set sourceAspects = nodeService.getAspects(source); Set publishedAspects = nodeService.getAspects(publishedNode); assertTrue(publishedAspects.containsAll(sourceAspects)); assertTrue(publishedAspects.contains(ASPECT_GEOGRAPHIC)); assertTrue(publishedAspects.contains(ASPECT_TEMPORARY)); // Check published node properties Map publishedProps = nodeService.getProperties(publishedNode); assertEquals(lattitude, publishedProps.get(PROP_LATITUDE)); assertEquals(longtitude, publishedProps.get(PROP_LONGITUDE)); assertEquals(contentNodeName, publishedProps.get(PROP_NAME)); assertEquals(content, readContent(source)); // Check lastPublishingEvent association is created. List assocs = nodeService.getTargetAssocs(publishedNode, ASSOC_LAST_PUBLISHING_EVENT); assertEquals(1, assocs.size()); assertEquals(publishEventNode, assocs.get(0).getTargetRef()); } public void testUpdatePublishedNode() throws Exception { // Create content node without aspects NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); NodeRef publishEventNode = publishNode(source); // Check published node exists NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertNotNull(publishedNode); assertTrue(nodeService.exists(publishedNode)); // Verify properties set correctly. Map publishedProps = nodeService.getProperties(publishedNode); assertFalse(publishedProps.containsKey(PROP_LATITUDE)); assertFalse(publishedProps.containsKey(PROP_LONGITUDE)); assertEquals(contentNodeName, publishedProps.get(PROP_NAME)); assertEquals(content, readContent(source)); Set aspects = nodeService.getAspects(source); assertFalse(aspects.contains(ASPECT_GEOGRAPHIC)); // Check lastPublishingEvent association is created. List assocs = nodeService.getTargetAssocs(publishedNode, ASSOC_LAST_PUBLISHING_EVENT); assertEquals(1, assocs.size()); assertEquals(publishEventNode, assocs.get(0).getTargetRef()); // Modify source node double lattitude = 0.25; double longtitude = 0.75; addGeographicAspect(source, lattitude, longtitude); String newName = "NewName"; nodeService.setProperty(source, PROP_NAME, newName); String newContent = "The new content"; testHelper.writeContent(source, newContent, MimetypeMap.MIMETYPE_TEXT_PLAIN); // Update published node. publishEventNode = publishNode(source); NodeRef newPublishNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertEquals(publishedNode, newPublishNode); // Published node shoudl still exist. assertNotNull(publishedNode); assertTrue(nodeService.exists(publishedNode)); // Check aspects modified aspects = nodeService.getAspects(publishedNode); assertTrue(aspects.contains(ASPECT_GEOGRAPHIC)); assertTrue(aspects.containsAll(nodeService.getAspects(source))); // Check properties modified publishedProps = nodeService.getProperties(publishedNode); assertEquals(lattitude, publishedProps.get(PROP_LATITUDE)); assertEquals(longtitude, publishedProps.get(PROP_LONGITUDE)); assertEquals(newName, publishedProps.get(PROP_NAME)); assertEquals(newContent, readContent(source)); // Check lastPublishingEvent association has changed. assocs = nodeService.getTargetAssocs(publishedNode, ASSOC_LAST_PUBLISHING_EVENT); assertEquals(1, assocs.size()); assertEquals(publishEventNode, assocs.get(0).getTargetRef()); // Remove aspect from source node. nodeService.removeAspect(source, ASPECT_GEOGRAPHIC); // Update publish node publishNode(source); newPublishNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertEquals(publishedNode, newPublishNode); aspects = nodeService.getAspects(source); assertFalse(aspects.contains(ASPECT_GEOGRAPHIC)); publishedProps = nodeService.getProperties(publishedNode); assertFalse(publishedProps.containsKey(PROP_LATITUDE)); assertFalse(publishedProps.containsKey(PROP_LONGITUDE)); } public void testUnpublishNode() throws Exception { // Create content node and publish. NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); publishNode(source); // Check published node exists NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertNotNull(publishedNode); assertTrue(nodeService.exists(publishedNode)); // Unpublish source node. NodeRef eventNode = publishNode(source, null, false); // Check the published node no longer exists. assertFalse(nodeService.exists(publishedNode)); publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertNull(publishedNode); // Check can generate a valid snapshot for the unpublish entry. PublishingEvent event = publishingService.getPublishingEvent(eventNode.toString()); PublishingPackage packg = event.getPackage(); Set toUnpublish = packg.getNodesToUnpublish(); assertEquals(1, toUnpublish.size()); assertTrue(toUnpublish.contains(source)); PublishingPackageEntry entry = packg.getEntryMap().get(source); assertEquals(false, entry.isPublish()); NodeSnapshot snapshot = entry.getSnapshot(); assertEquals(source, snapshot.getNodeRef()); assertEquals(ContentModel.TYPE_CONTENT, snapshot.getType()); Serializable name = nodeService.getProperty(source, ContentModel.PROP_NAME); assertEquals(name, snapshot.getProperties().get(ContentModel.PROP_NAME)); } @SuppressWarnings("unchecked") @Test public void testChannelTypePublishIsCalledOnPublish() throws Exception { // Create content node with appropriate aspects added. NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); // Enable publishing on ChannelType. when(channelType.canPublish()).thenReturn(true); publishNode(source); NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); // Check publish was called verify(channelType, times(1)).publish(eq(publishedNode), anyMap()); } @SuppressWarnings("unchecked") public void testChannelTypePublishIsCalledOnUpdate() throws Exception { // Create content node with appropriate aspects added. NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); // Publish source node but dont' call ChannelType.publish(). publishNode(source); NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); // Check publish was not called. verify(channelType, never()).publish(eq(publishedNode), anyMap()); // Enable publishing on ChannelType. when(channelType.canPublish()).thenReturn(true); // Update publish node publishNode(source); // Check publish was called on update verify(channelType, times(1)).publish(eq(publishedNode), anyMap()); // Unpublish node. publishNode(source, null, false); // Check unpublish was not called, since ChannelType doesn't support it. verify(channelType, never()).unpublish(eq(publishedNode), anyMap()); // Enable unpublishing on ChannelType. when(channelType.canUnpublish()).thenReturn(true); // Re-publish the node. publishNode(source); // Get the newly published node. publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); assertNotNull(publishedNode); // Unpublish the node publishNode(source, null, false); // Check unpublish was called on update verify(channelType, times(1)).unpublish(eq(publishedNode), anyMap()); } @Test @SuppressWarnings("unchecked") public void testSupportedContentTypes() throws Exception { // Create content node with appropriate aspects added. NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); // Enable publishing on ChannelType. when(channelType.canPublish()).thenReturn(true); // Set supported type to cm:folder Set contentTypes = Collections.singleton(ContentModel.TYPE_FOLDER); when(channelType.getSupportedContentTypes()).thenReturn(contentTypes); // Publish source node but don't call ChannelType.publish(). publishNode(source); NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); verify(channelType, never()).publish(eq(publishedNode), anyMap()); // Change supported type to cm:content contentTypes = Collections.singleton(ContentModel.TYPE_CONTENT); when(channelType.getSupportedContentTypes()).thenReturn(contentTypes); // Publish source node publishNode(source); verify(channelType, times(1)).publish(eq(publishedNode), anyMap()); // Change supported type to cm:cmobject contentTypes = Collections.singleton(ContentModel.TYPE_CMOBJECT); when(channelType.getSupportedContentTypes()).thenReturn(contentTypes); // Publish source node publishNode(source); verify(channelType, times(2)).publish(eq(publishedNode), anyMap()); } @Test @SuppressWarnings("unchecked") public void testSupportedMimeTypes() throws Exception { // Create content node with appropriate aspects added. NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); // Enable publishing on ChannelType. when(channelType.canPublish()).thenReturn(true); // Set supported type to XML Set mimeTypes = Collections.singleton(MimetypeMap.MIMETYPE_XML); when(channelType.getSupportedMimeTypes()).thenReturn(mimeTypes); // Publish source node but don't call ChannelType.publish(). publishNode(source); NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channelNode); verify(channelType, never()).publish(eq(publishedNode), anyMap()); // Change supported type to plain text. mimeTypes = Collections.singleton(MimetypeMap.MIMETYPE_TEXT_PLAIN); when(channelType.getSupportedMimeTypes()).thenReturn(mimeTypes); // Publish source node publishNode(source); verify(channelType, times(1)).publish(eq(publishedNode), anyMap()); } @SuppressWarnings("unchecked") public void testStatusUpdate() throws Exception { NodeRef source = testHelper.createContentNode(contentNodeName, content, MimetypeMap.MIMETYPE_TEXT_PLAIN); // Create Status Update String message = "Here is the message "; String url = "http://test/url"; when(channelType.getNodeUrl(any(NodeRef.class))).thenReturn(url); when(channelType.canPublishStatusUpdates()).thenReturn(true); publishNode(source, message); String expMessage = message + " " + url; verify(channelType, times(1)).sendStatusUpdate(any(Channel.class), eq(expMessage)); } private NodeRef publishNode(NodeRef source) { return publishNode(source, null); } private NodeRef publishNode(NodeRef source, String message) { return publishNode(source, message, true); } private NodeRef publishNode(NodeRef source, String message, boolean publish) { PublishingDetails details = publishingService.createPublishingDetails(); details.setPublishChannelId(channel.getId()); if (publish) { details.addNodesToPublish(source); } else { details.addNodesToUnpublish(source); } if (message != null) { details.setStatusMessage(message) .setStatusNodeToLinkTo(source) .addStatusUpdateChannels(channel.getId()); } String eventId = testHelper.scheduleEvent1Year(details); assertNotNull(eventId); NodeRef eventNode = new NodeRef(eventId); assertTrue(nodeService.exists(eventNode)); Serializable eventStatus = nodeService.getProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS); assertEquals(Status.SCHEDULED.name(), eventStatus); action.executeImpl(null, eventNode); // Check Status has changed to COMPLETE eventStatus = nodeService.getProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS); assertEquals(Status.COMPLETED.name(), eventStatus); return eventNode; } private void addGeographicAspect(NodeRef source, double lattitude, double longtitude) { Map props = new HashMap(); props.put(PROP_LATITUDE, lattitude); props.put(PROP_LONGITUDE, longtitude); serviceRegistry.getNodeService().addAspect(source, ASPECT_GEOGRAPHIC, props); } private String readContent(NodeRef source) { ContentReader reader = contentService.getReader(source, PROP_CONTENT); return reader.getContentString(); } @Override public void onSetUp() throws Exception { super.onSetUp(); this.publishingService = (PublishingService) getApplicationContext().getBean("publishingService"); this.contentService = (ContentService) getApplicationContext().getBean("ContentService"); this.channelHelper = (ChannelHelper) getApplicationContext().getBean("channelHelper"); this.action = (PublishEventAction) getApplicationContext().getBean("pub_publishEvent"); this.channelType = testHelper.mockChannelType(channelTypeId); this.channel = testHelper.createChannel(channelTypeId); this.channelNode = new NodeRef(channel.getId()); } }