/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.itest.content; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.Set; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockHttpServletRequest; import com.enonic.cms.framework.util.JDOMUtil; import com.enonic.cms.framework.xml.XMLDocumentFactory; import com.enonic.cms.core.content.ContentEntity; import com.enonic.cms.core.content.ContentKey; import com.enonic.cms.core.content.ContentService; import com.enonic.cms.core.content.ContentStatus; import com.enonic.cms.core.content.ContentVersionEntity; import com.enonic.cms.core.content.ContentVersionKey; import com.enonic.cms.core.content.SnapshotContentException; import com.enonic.cms.core.content.SnapshotContentResult; import com.enonic.cms.core.content.UpdateContentResult; import com.enonic.cms.core.content.command.CreateContentCommand; import com.enonic.cms.core.content.command.SnapshotContentCommand; import com.enonic.cms.core.content.command.UpdateContentCommand; import com.enonic.cms.core.content.contentdata.custom.CustomContentData; import com.enonic.cms.core.content.contentdata.custom.stringbased.TextDataEntry; import com.enonic.cms.core.content.contenttype.ContentHandlerName; import com.enonic.cms.core.content.contenttype.ContentTypeEntity; import com.enonic.cms.core.content.contenttype.dataentryconfig.TextDataEntryConfig; import com.enonic.cms.core.security.user.UserEntity; import com.enonic.cms.core.security.user.UserType; import com.enonic.cms.core.servlet.ServletRequestAccessor; import com.enonic.cms.itest.AbstractSpringTest; import com.enonic.cms.itest.util.DomainFactory; import com.enonic.cms.itest.util.DomainFixture; import com.enonic.cms.store.dao.ContentDao; import com.enonic.cms.store.dao.ContentVersionDao; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.*; public class ContentServiceImpl_snapshotContentTest extends AbstractSpringTest { @Autowired private ContentDao contentDao; @Autowired private ContentService contentService; @Autowired private ContentVersionDao contentVersionDao; private DomainFactory factory; @Autowired private DomainFixture fixture; private Element standardConfigEl; private Document standardConfig; @Before public void setUp() throws IOException, JDOMException { factory = fixture.getFactory(); fixture.initSystemData(); fixture.createAndStoreUserAndUserGroup( "testuser", "testuser fullname", UserType.NORMAL, "testuserstore" ); StringBuffer standardConfigXml = new StringBuffer(); standardConfigXml.append( "<config name=\"MyContentType\" version=\"1.0\">" ); standardConfigXml.append( " <form>" ); standardConfigXml.append( " <title name=\"myTitle\"/>" ); standardConfigXml.append( " <block name=\"TestBlock1\">" ); standardConfigXml.append( " <input name=\"myTitle\" required=\"true\" type=\"text\">" ); standardConfigXml.append( " <display>My title</display>" ); standardConfigXml.append( " <xpath>contentdata/mytitle</xpath>" ); standardConfigXml.append( " </input>" ); standardConfigXml.append( " <input name=\"myTitleInSubElement\" required=\"false\" type=\"text\">" ); standardConfigXml.append( " <display>My title in sub element</display>" ); standardConfigXml.append( " <xpath>contentdata/subelement/mytitle</xpath>" ); standardConfigXml.append( " </input>" ); standardConfigXml.append( " </block>" ); standardConfigXml.append( " </form>" ); standardConfigXml.append( "</config>" ); standardConfigEl = JDOMUtil.parseDocument( standardConfigXml.toString() ).getRootElement(); standardConfig = XMLDocumentFactory.create( standardConfigXml.toString() ).getAsJDOMDocument(); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRemoteAddr( "127.0.0.1" ); ServletRequestAccessor.setRequest( request ); fixture.save( factory.createContentHandler( "Custom content", ContentHandlerName.CUSTOM.getHandlerClassShortName() ) ); fixture.save( factory.createContentType( "MyContentType", ContentHandlerName.CUSTOM.getHandlerClassShortName(), standardConfig ) ); fixture.save( factory.createUnit( "MyUnit" ) ); fixture.save( factory.createCategory( "MyCategory", null, "MyContentType", "MyUnit", "testuser", "testuser" ) ); fixture.save( factory.createCategoryAccessForUser( "MyCategory", "testuser", "read, create, approve" ) ); setupReadCreateAndApproveUsers(); fixture.flushAndClearHibernateSession(); } private void setupReadCreateAndApproveUsers() { fixture.createAndStoreNormalUserWithUserGroup( "userWithRead", "userWithRead", "testuserstore" ); fixture.createAndStoreNormalUserWithUserGroup( "userWithCreate", "userWithCreate", "testuserstore" ); fixture.createAndStoreNormalUserWithUserGroup( "userWithApprove", "userWithApprove", "testuserstore" ); fixture.save( factory.createCategoryAccessForUser( "MyCategory", "userWithRead", "read" ) ); fixture.save( factory.createCategoryAccessForUser( "MyCategory", "userWithCreate", "read, create" ) ); fixture.save( factory.createCategoryAccessForUser( "MyCategory", "userWithApprove", "read, create, approve" ) ); } private ContentKey createContent( Integer status ) { CreateContentCommand createContentCommand = createCreateContentCommand( status ); return contentService.createContent( createContentCommand ); } private CreateContentCommand createCreateContentCommand( Integer status ) { UserEntity runningUser = fixture.findUserByName( "testuser" ); ContentTypeEntity contentType = fixture.findContentTypeByName( "MyContentType" ); CustomContentData contentData = new CustomContentData( contentType.getContentTypeConfig() ); TextDataEntryConfig titleConfig = new TextDataEntryConfig( "myTitle", true, "Tittel", "contentdata/mytitle" ); TextDataEntryConfig subElementConfig = new TextDataEntryConfig( "myTitleInSubElement", false, "My title in sub element", "contentdata/subelement/mytitle" ); contentData.add( new TextDataEntry( titleConfig, "test title" ) ); contentData.add( new TextDataEntry( subElementConfig, "test subtitle" ) ); CreateContentCommand createContentCommand = new CreateContentCommand(); createContentCommand.setCreator( runningUser ); createContentCommand.setLanguage( fixture.findLanguageByCode( "en" ) ); createContentCommand.setCategory( fixture.findCategoryByName( "MyCategory" ) ); createContentCommand.setPriority( 0 ); createContentCommand.setStatus( ContentStatus.get( status ) ); createContentCommand.setContentData( contentData ); createContentCommand.setContentName( "testcontent_" + status ); return createContentCommand; } private UpdateContentResult updateContent( ContentKey contentKey, ContentVersionKey versionKey, Integer status, boolean asMainVersion, boolean asNewVersion ) { UpdateContentCommand command; if ( asNewVersion ) { command = UpdateContentCommand.storeNewVersionEvenIfUnchanged( versionKey ); } else { command = UpdateContentCommand.updateExistingVersion2( versionKey ); } command.setModifier( fixture.findUserByName( "testuser" ) ); command.setUpdateAsMainVersion( asMainVersion ); // Populate command with contentEntity data command.setLanguage( fixture.findLanguageByCode( "en" ) ); command.setStatus( ContentStatus.get( status ) ); command.setContentKey( contentKey ); return contentService.updateContent( command ); } private SnapshotContentResult createContentVersionSnapshot( ContentEntity content ) { SnapshotContentCommand command = new SnapshotContentCommand(); command.setContentKey( content.getKey() ); command.setSnapshotterKey( fixture.findUserByName( "testuser" ).getKey() ); return contentService.snapshotContent( command ); } @Test(expected = SnapshotContentException.class) public void testSnapshotContentAccessRights_NotAllowedForReadOnlyUser() { UserEntity readUser = fixture.findUserByName( "userWithRead" ); UserEntity createUser = fixture.findUserByName( "userWithCreate" ); CreateContentCommand createCommand = createCreateContentCommand( ContentStatus.DRAFT.getKey() ); createCommand.setCreator( createUser ); ContentKey contentKey = contentService.createContent( createCommand ); fixture.flushAndClearHibernateSession(); ContentEntity persistedContent = contentDao.findByKey( contentKey ); SnapshotContentCommand snapshotCommand = new SnapshotContentCommand(); snapshotCommand.setContentKey( persistedContent.getKey() ); snapshotCommand.setSnapshotterKey( readUser.getKey() ); contentService.snapshotContent( snapshotCommand ); } @Test public void testSnapshotContentAccessRights_AllowedForCreateAccessUser() { UserEntity createUser = fixture.findUserByName( "userWithCreate" ); CreateContentCommand createCommand = createCreateContentCommand( ContentStatus.DRAFT.getKey() ); createCommand.setCreator( createUser ); ContentKey contentKey = contentService.createContent( createCommand ); fixture.flushAndClearHibernateSession(); ContentEntity persistedContent = contentDao.findByKey( contentKey ); SnapshotContentCommand snapshotCommand = new SnapshotContentCommand(); snapshotCommand.setContentKey( persistedContent.getKey() ); snapshotCommand.setSnapshotterKey( createUser.getKey() ); contentService.snapshotContent( snapshotCommand ); } @Test public void testSnapshotContentAccessRights_AllowedForApproveAccessUser() { UserEntity createUser = fixture.findUserByName( "userWithCreate" ); UserEntity approveUser = fixture.findUserByName( "userWithApprove" ); CreateContentCommand createCommand = createCreateContentCommand( ContentStatus.DRAFT.getKey() ); createCommand.setCreator( createUser ); ContentKey contentKey = contentService.createContent( createCommand ); fixture.flushAndClearHibernateSession(); ContentEntity persistedContent = contentDao.findByKey( contentKey ); SnapshotContentCommand snapshotCommand = new SnapshotContentCommand(); snapshotCommand.setContentKey( persistedContent.getKey() ); snapshotCommand.setSnapshotterKey( approveUser.getKey() ); contentService.snapshotContent( snapshotCommand ); } @Test public void testContentTimestampUpdatedOnSnapshot() { ContentKey contentKey = createContent( ContentStatus.DRAFT.getKey() ); fixture.flushAndClearHibernateSession(); Date startTime = Calendar.getInstance().getTime(); ContentEntity originalContent = contentDao.findByKey( contentKey ); SnapshotContentResult result = createContentVersionSnapshot( originalContent ); fixture.flushAndClearHibernateSession(); ContentEntity snapshottedContent = contentDao.findByKey( contentKey ); assertNotNull( snapshottedContent.getTimestamp() ); Assert.assertTrue( snapshottedContent.getTimestamp().compareTo( startTime ) > 0 ); } @Test public void testCreateSnapshot() { // setup ContentKey contentKey = createContent( ContentStatus.DRAFT.getKey() ); fixture.flushAndClearHibernateSession(); ContentEntity originalContent = contentDao.findByKey( contentKey ); assertNotNull( originalContent.getDraftVersion() ); SnapshotContentResult result = createContentVersionSnapshot( originalContent ); fixture.flushAndClearHibernateSession(); ContentEntity snapshottedContent = contentDao.findByKey( contentKey ); assertNotNull( snapshottedContent ); assertEquals( "Should have 2 versions", 2, snapshottedContent.getVersionCount() ); ContentVersionEntity draftVersion = snapshottedContent.getDraftVersion(); assertNotNull( "Draft should exist", draftVersion ); Set<ContentVersionEntity> snapshots = draftVersion.getSnapshots(); assertNotNull( "Draft should have snapshot", snapshots ); assertTrue( "Draft should have 1 snapshot", snapshots.size() == 1 ); assertTrue( "Draft should be in snapshot-list of draft", snapshots.contains( result.getStoredSnapshotContentVersion() ) ); ContentVersionEntity persistedSnapshot = contentVersionDao.findByKey( result.getStoredSnapshotContentVersion().getKey() ); assertNotNull( "Snapshot should be persisted", persistedSnapshot ); assertTrue( "Snapshot should point to draft as source", persistedSnapshot.getSnapshotSource().equals( draftVersion ) ); assertNotSame( originalContent, snapshottedContent ); assertEquals( originalContent.getAvailableFrom(), snapshottedContent.getAvailableFrom() ); assertEquals( originalContent.getAvailableTo(), snapshottedContent.getAvailableTo() ); assertEquals( originalContent.getAssignee(), snapshottedContent.getAssignee() ); assertEquals( originalContent.getLanguage().getCode(), snapshottedContent.getLanguage().getCode() ); assertEquals( originalContent.getCategory(), snapshottedContent.getCategory() ); assertEquals( originalContent.getCreatedAt(), snapshottedContent.getCreatedAt() ); assertEquals( originalContent.getAssignmentDueDate(), snapshottedContent.getAssignmentDueDate() ); assertEquals( originalContent.getOwner(), snapshottedContent.getOwner() ); assertEquals( originalContent.getName(), snapshottedContent.getName() ); } @Test public void testApproveVersionWithSnapshot() { // setup ContentKey contentKey = createContent( ContentStatus.DRAFT.getKey() ); fixture.flushAndClearHibernateSession(); ContentEntity persistedContent = contentDao.findByKey( contentKey ); assertNotNull( persistedContent.getDraftVersion() ); SnapshotContentResult result = createContentVersionSnapshot( persistedContent ); ContentVersionEntity snapshot = result.getStoredSnapshotContentVersion(); ContentVersionKey snapshotVersionKey = snapshot.getKey(); fixture.flushAndClearHibernateSession(); persistedContent = contentDao.findByKey( contentKey ); assertNotNull( persistedContent ); assertEquals( "Should have 2 versions", 2, persistedContent.getVersionCount() ); UpdateContentResult updateResult = updateContent( contentKey, persistedContent.getDraftVersion().getKey(), ContentStatus.APPROVED.getKey(), true, false ); fixture.flushAndClearHibernateSession(); persistedContent = contentDao.findByKey( contentKey ); ContentVersionEntity persistedSnapshot = contentVersionDao.findByKey( snapshotVersionKey ); assertNotNull( "Snapshot should exist", persistedSnapshot ); assertEquals( "Status should be 'SNAPSHOT' for the snapshotter version", persistedSnapshot.getStatus(), ContentStatus.SNAPSHOT ); assertNotNull( "Snapshot should have relation to parent", persistedSnapshot.getSnapshotSource() ); assertTrue( "Content should be maked as changed", updateResult.isAnyChangesMade() ); } @Test public void testDeleteDraftAndSnapshots() { ContentKey contentKey = createContent( ContentStatus.APPROVED.getKey() ); fixture.flushAndClearHibernateSession(); ContentEntity persistedContent = contentDao.findByKey( contentKey ); UpdateContentResult updateResult = updateContent( contentKey, persistedContent.getMainVersion().getKey(), ContentStatus.DRAFT.getKey(), false, true ); persistedContent = contentDao.findByKey( contentKey ); assertNotNull( persistedContent.getDraftVersion() ); createContentVersionSnapshot( persistedContent ); createContentVersionSnapshot( persistedContent ); createContentVersionSnapshot( persistedContent ); persistedContent = contentDao.findByKey( contentKey ); assertNotNull( persistedContent.getDraftVersion() ); assertEquals( 5, persistedContent.getVersionCount() ); assertNotNull( "Draft should not be null", persistedContent.getDraftVersion() ); assertNotNull( "Snapshots should not be null", persistedContent.getDraftVersion().getSnapshots() ); assertEquals( "Draft should have 3 snapshots", 3, persistedContent.getDraftVersion().getSnapshots().size() ); assertEquals( "Should have 5 versions", 5, fixture.countContentVersionsByTitle( "test title" ) ); contentService.deleteVersion( fixture.findUserByName( "admin" ), updateResult.getTargetedVersionKey() ); persistedContent = contentDao.findByKey( contentKey ); assertNotNull( persistedContent ); assertEquals( 1, persistedContent.getVersionCount() ); assertEquals( 1, fixture.countContentVersionsByTitle( "test title" ) ); assertEquals( ContentStatus.APPROVED, persistedContent.getMainVersion().getStatus() ); } @Test public void testCommentFlow() { CreateContentCommand createContentCommand = createCreateContentCommand( ContentStatus.DRAFT.getKey() ); createContentCommand.setChangeComment( "Initial comment" ); ContentKey contentKey = contentService.createContent( createContentCommand ); ContentEntity persistedContent = contentDao.findByKey( contentKey ); ContentVersionEntity persistedVersion = persistedContent.getDraftVersion(); assertEquals( "Initial comment", persistedVersion.getChangeComment() ); SnapshotContentCommand snapshotCommand = new SnapshotContentCommand(); snapshotCommand.setContentKey( persistedContent.getKey() ); snapshotCommand.setClearCommentInDraft( false ); snapshotCommand.setSnapshotterKey( fixture.findUserByName( "testuser" ).getKey() ); persistedVersion = persistedContent.getDraftVersion(); assertEquals( "Comment should not be cleared from draft when clearCommentInDraftIsFalse", "Initial comment", persistedVersion.getChangeComment() ); snapshotCommand = new SnapshotContentCommand(); snapshotCommand.setContentKey( persistedContent.getKey() ); snapshotCommand.setClearCommentInDraft( true ); snapshotCommand.setSnapshotterKey( fixture.findUserByName( "testuser" ).getKey() ); snapshotCommand.setSnapshotComment( "Snapshot comment" ); SnapshotContentResult snapshotResult = contentService.snapshotContent( snapshotCommand ); ContentVersionEntity storedSnapshotVersion = snapshotResult.getStoredSnapshotContentVersion(); persistedContent = contentDao.findByKey( contentKey ); assertNull( "Comment should be cleared from draft", persistedContent.getDraftVersion().getChangeComment() ); boolean found = false; for ( ContentVersionEntity contentVersion : persistedContent.getVersions() ) { if ( contentVersion.equals( storedSnapshotVersion ) ) { found = true; assertEquals( "Snapshot comment", contentVersion.getChangeComment() ); break; } } assertTrue( found ); } }