/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.core.portal.instruction; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.List; import org.apache.commons.lang.StringUtils; import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.mock.web.MockHttpServletRequest; import com.enonic.cms.framework.util.UrlPathEncoder; import com.enonic.cms.core.MockSitePropertiesService; import com.enonic.cms.core.SiteURLResolver; import com.enonic.cms.core.content.ContentEntity; import com.enonic.cms.core.content.ContentKey; import com.enonic.cms.core.content.ContentVersionEntity; import com.enonic.cms.core.content.binary.BinaryDataEntity; import com.enonic.cms.core.content.binary.ContentBinaryDataEntity; import com.enonic.cms.core.image.ImageRequest; import com.enonic.cms.core.portal.image.ImageService; import com.enonic.cms.core.portal.rendering.WindowRendererContext; import com.enonic.cms.core.preview.PreviewContext; import com.enonic.cms.core.resource.FileResource; import com.enonic.cms.core.resource.FileResourceName; import com.enonic.cms.core.resource.FileResourceService; import com.enonic.cms.core.resource.ResourceKey; import com.enonic.cms.core.servlet.ServletRequestAccessor; import com.enonic.cms.core.structure.SiteEntity; import com.enonic.cms.core.structure.SiteKey; import com.enonic.cms.core.structure.SitePropertyNames; import com.enonic.cms.core.structure.menuitem.MenuItemEntity; import com.enonic.cms.core.structure.menuitem.MenuItemKey; import com.enonic.cms.core.vhost.VirtualHostHelper; import com.enonic.cms.store.dao.ContentDao; import com.enonic.cms.store.dao.MenuItemDao; import static org.junit.Assert.*; /** * Created by IntelliJ IDEA. * User: rmh * Date: Nov 20, 2009 * Time: 10:03:44 AM */ public class PostProcessInstructionExecutorImplTest { private static final Logger LOG = LoggerFactory.getLogger( PostProcessInstructionExecutorImplTest.class.getName() ); private PostProcessInstructionExecutorImpl executor; private static final String HOME_DIR = "/_public/mysite"; private String timeStamp; private String serverName; private Calendar now; private MockHttpServletRequest request; private PostProcessInstructionContext context; private static final String MOCK_PATH_TO_REQUESTED_MENUITEM = "path/to/menuitem"; @Before public void setUp() { executor = new PostProcessInstructionExecutorImpl(); serverName = "test.com"; now = Calendar.getInstance(); timeStamp = Long.toHexString( now.getTimeInMillis() ); executor.setFileResourceService( setUpResourceServiceMock( now ) ); executor.setMenuItemDao( setUpMenuItemDaoMock() ); request = setUpMockRequest( serverName ); ServletRequestAccessor.setRequest( request ); context = setUpContext( request ); // make sure site-path isn't applied in the final path VirtualHostHelper.setBasePath( request, "" ); context.setSiteURLResolverEnableHtmlEscaping( setUpSiteResolverMock( true ) ); context.setSiteURLResolverDisableHtmlEscaping( setUpSiteResolverMock( false ) ); } @Test public void testCreateResourceUrl() throws Exception { String resolvedPath = "_public/test/path/test.css"; CreateResourceUrlInstruction instruction = doCreateResourceUrlInstruction( resolvedPath, null, true ); String result = executor.execute( instruction, context ); assertEquals( "http://" + serverName + "/" + resolvedPath + "?_ts=" + timeStamp, result ); resolvedPath = "_public/test/path/test.css"; String[] params = {"a", "1", "b", "2"}; instruction = doCreateResourceUrlInstruction( resolvedPath, params, true ); result = executor.execute( instruction, context ); LOG.info( result ); verifyPath( result, resolvedPath, new String[]{"a", "b"}, null, true ); } @Test public void testCreateResourceUrl_nested_function() throws Exception { ContentDao contentDao = setUpSingleContentData(); executor.setContentDao( contentDao ); String resolvedPath = "_public/test/path/test.css"; CreateAttachmentUrlInstruction attachmentUrlInstruction = createCreateAttachmentUrlInstruction( "1/binary/1", true ); String attachmentUrlResult = executor.execute( attachmentUrlInstruction, context ); String[] params = {"a", PostProcessInstructionSerializer.serialize( attachmentUrlInstruction )}; CreateResourceUrlInstruction instruction = doCreateResourceUrlInstruction( resolvedPath, params, true ); String result = executor.execute( instruction, context ); verifyPath( result, resolvedPath, new String[]{"a"}, null, true ); assertTrue( "Should contain result of nested function", result.contains( UrlPathEncoder.encode( attachmentUrlResult ) ) ); } @Test public void testCreateResourceUrl_outputEscaping() throws Exception { String resolvedPath = "_public/test/path/test.css"; CreateResourceUrlInstruction instruction = doCreateResourceUrlInstruction( resolvedPath, null, false ); String result = executor.execute( instruction, context ); assertEquals( "http://" + serverName + "/" + resolvedPath + "?_ts=" + timeStamp, result ); resolvedPath = "_public/test/path/test.css"; String[] params = {"a", "1", "b", "2"}; instruction = doCreateResourceUrlInstruction( resolvedPath, params, false ); result = executor.execute( instruction, context ); verifyPath( result, resolvedPath, new String[]{"a", "b"}, null, false ); } private CreateResourceUrlInstruction doCreateResourceUrlInstruction( String resolvedPath, String[] params, boolean disableOutputEscaping ) { CreateResourceUrlInstruction instruction = new CreateResourceUrlInstruction(); instruction.setResolvedPath( resolvedPath ); instruction.setParams( params ); instruction.setDisableOutputEscaping( disableOutputEscaping ); return instruction; } @Test public void testCreateContentUrl_noHome() throws Exception { ContentDao contentDao = setUpSingleContentData(); executor.setContentDao( contentDao ); CreateContentUrlInstruction instruction = new CreateContentUrlInstruction(); instruction.setContentKey( "123" ); String result = executor.execute( instruction, context ); assertEquals( "http://" + serverName + "/" + "123" + "/contentName", result ); } @Test public void testCreateAttachmentUrl_contentkey_binary_binarykey() { ContentDao contentDao = setUpSingleContentData(); executor.setContentDao( contentDao ); CreateAttachmentUrlInstruction instruction = createCreateAttachmentUrlInstruction( "1/binary/1", true ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_attachment/1/binary/1", null, null, true ); } @Test public void testCreateAttachmentUrl_contentkey() { ContentDao contentDao = setUpSingleContentData(); executor.setContentDao( contentDao ); CreateAttachmentUrlInstruction instruction = createCreateAttachmentUrlInstruction( "1", true ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_attachment/1", null, null, true ); } @Test public void testCreateAttachmentUrl_contentkey_label() { ContentDao contentDao = setUpContentData( new String[]{"small", "large"} ); executor.setContentDao( contentDao ); CreateAttachmentUrlInstruction instruction = createCreateAttachmentUrlInstruction( "1/label/large", true ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_attachment/1/label/large", null, null, true ); } @Test public void testCreateAttachmentUrl_contentkey_label_not_found() { ContentDao contentDao = setUpContentData( new String[]{"dummy1", "dummy2"} ); executor.setContentDao( contentDao ); CreateAttachmentUrlInstruction instruction = createCreateAttachmentUrlInstruction( "1/label/large", true ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_attachment/1/label/large", null, new String[]{"_ts"}, true ); } @Test public void testCreateAttachmentUrl_nested_function() throws Exception { String resolvedPath = "_public/test/path/test.css"; CreateResourceUrlInstruction createResourceUrlInstruction = doCreateResourceUrlInstruction( resolvedPath, null, true ); String createResourceResult = executor.execute( createResourceUrlInstruction, context ); ContentDao contentDao = setUpSingleContentData(); executor.setContentDao( contentDao ); CreateAttachmentUrlInstruction instruction = createCreateAttachmentUrlInstruction( "1/binary/1", true ); instruction.setParams( new String[]{"a", PostProcessInstructionSerializer.serialize( createResourceUrlInstruction )} ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_attachment/1/binary/1", null, null, true ); assertTrue( "Should contain result of nested function", result.contains( UrlPathEncoder.encode( createResourceResult ) ) ); } @Test public void testCreateImageUrl() { ImageService imageService = Mockito.mock( ImageService.class ); Mockito.when( imageService.getImageTimestamp( Mockito.<ImageRequest>any() ) ).thenReturn( now.getTimeInMillis() ); executor.setImagesService( imageService ); CreateImageUrlInstruction instruction = new CreateImageUrlInstruction(); instruction.setDisableOutputEscaping( true ); String background = "0x00000"; String type = "png"; String filter = "rounded(10);"; String key = "1"; instruction.setBackground( background ); instruction.setFilter( filter ); instruction.setFormat( type ); instruction.setKey( key ); instruction.setRequestedMenuItemKey( "1" ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_image/1.png", new String[]{"_ts", "_background", "_filter", "_quality"}, null, true ); } @Test public void testCreateImageUrl_invalidImage() { ImageService imageService = Mockito.mock( ImageService.class ); Mockito.when( imageService.getImageTimestamp( Mockito.<ImageRequest>any() ) ).thenReturn( null ); executor.setImagesService( imageService ); CreateImageUrlInstruction instruction = new CreateImageUrlInstruction(); String background = "0x00000"; String type = "png"; String filter = "rounded(10);"; String key = "1"; instruction.setBackground( background ); instruction.setFilter( filter ); instruction.setFormat( type ); instruction.setKey( key ); instruction.setRequestedMenuItemKey( "1" ); String result = executor.execute( instruction, context ); verifyPath( result, MOCK_PATH_TO_REQUESTED_MENUITEM + "/" + "_image/1.png", null, new String[]{"_ts"}, true ); } private ContentDao setUpSingleContentData() { ContentVersionEntity contentVersion = new ContentVersionEntity(); BinaryDataEntity binaryData = new BinaryDataEntity(); binaryData.setKey( 1 ); binaryData.setCreatedAt( now.getTime() ); ContentBinaryDataEntity contentBinaryDataEntity = new ContentBinaryDataEntity(); contentBinaryDataEntity.setBinaryData( binaryData ); contentVersion.addContentBinaryData( contentBinaryDataEntity ); ContentEntity content = new ContentEntity(); content.setKey( new ContentKey( "123" ) ); content.setName( "contentName" ); content.setMainVersion( contentVersion ); ContentDao contentDao = createContentDaoMock( content ); return contentDao; } private ContentDao setUpContentData( String[] labels ) { ContentVersionEntity contentVersion = new ContentVersionEntity(); if ( labels != null && labels.length > 0 ) { for ( int i = 0; i < labels.length; i++ ) { BinaryDataEntity binaryData = new BinaryDataEntity(); binaryData.setKey( i ); binaryData.setCreatedAt( now.getTime() ); ContentBinaryDataEntity contentBinaryDataEntity = new ContentBinaryDataEntity(); contentBinaryDataEntity.setBinaryData( binaryData ); contentBinaryDataEntity.setLabel( labels[i] ); contentVersion.addContentBinaryData( contentBinaryDataEntity ); } } ContentEntity content = new ContentEntity(); content.setMainVersion( contentVersion ); ContentDao contentDao = createContentDaoMock( content ); return contentDao; } private ContentDao createContentDaoMock( ContentEntity content ) { ContentDao contentDao = Mockito.mock( ContentDao.class ); Mockito.when( contentDao.findByKey( Mockito.<ContentKey>any() ) ).thenReturn( content ); return contentDao; } private CreateAttachmentUrlInstruction createCreateAttachmentUrlInstruction( String nativeLinkKey, boolean disableOutputEscaping ) { CreateAttachmentUrlInstruction instruction = new CreateAttachmentUrlInstruction(); instruction.setNativeLinkKey( nativeLinkKey ); instruction.setDisableOutputEscaping( disableOutputEscaping ); instruction.setRequestedMenuItemKey( "1" ); return instruction; } private PostProcessInstructionContext setUpContext( MockHttpServletRequest request ) { PostProcessInstructionContext context = new PostProcessInstructionContext(); WindowRendererContext windowRendererContext = new WindowRendererContext(); context.setHttpRequest( request ); windowRendererContext.setHttpRequest( request ); SiteEntity site = new SiteEntity(); site.setKey( 1 ); site.setPathToPublicResources( ResourceKey.from( HOME_DIR ) ); context.setSite( site ); windowRendererContext.setSite( site ); context.setWindowRendererContext( windowRendererContext ); context.setPreviewContext( PreviewContext.NO_PREVIEW ); return context; } private SiteURLResolver setUpSiteResolverMock( boolean htmlEscapeParameterAmps ) { MockSitePropertiesService sitePropertiesService = new MockSitePropertiesService(); SiteURLResolver siteURLResolver = new SiteURLResolver(); siteURLResolver.setCharacterEncoding( "UTF-8" ); siteURLResolver.setSitePropertiesService( sitePropertiesService ); siteURLResolver.setHtmlEscapeParameterAmps( htmlEscapeParameterAmps ); return siteURLResolver; } private MockHttpServletRequest setUpMockRequest( String serverName ) { MockHttpServletRequest request = new MockHttpServletRequest(); request.setServerName( serverName ); request.setRequestURI( "/site/0/" ); return request; } private FileResourceService setUpResourceServiceMock( Calendar now ) { FileResourceService resourceService = Mockito.mock( FileResourceService.class ); FileResource fileResource = new FileResource( new FileResourceName( "test" ) ); fileResource.setLastModified( new DateTime( now.getTimeInMillis() ) ); Mockito.when( resourceService.getResource( Mockito.<FileResourceName>any() ) ).thenReturn( fileResource ); return resourceService; } private MenuItemDao setUpMenuItemDaoMock() { MenuItemEntity mockMenuItemEntity = Mockito.mock( MenuItemEntity.class ); Mockito.when( mockMenuItemEntity.getPathAsString() ).thenReturn( MOCK_PATH_TO_REQUESTED_MENUITEM ); MenuItemDao menuItemDao = Mockito.mock( MenuItemDao.class ); Mockito.when( menuItemDao.findByKey( Mockito.any( MenuItemKey.class ) ) ).thenReturn( mockMenuItemEntity ); return menuItemDao; } private void verifyPath( String matchUrl, String expectedLocalPath, String[] expectedParams, String[] notExpectedParams, boolean disableOutputEscaping ) { String url; if ( matchUrl.contains( "?" ) ) { url = matchUrl.substring( 0, matchUrl.indexOf( "?" ) ); } else { url = matchUrl; } assertEquals( getServerPath( expectedLocalPath ), url ); List<String> paramList = getParamList( matchUrl, disableOutputEscaping ); if ( expectedParams != null ) { for ( String expectedParam : expectedParams ) { assertTrue( "Parameter '" + expectedParam + "' expected", paramList.contains( expectedParam ) ); } } if ( notExpectedParams != null ) { for ( String notExpectedParam : notExpectedParams ) { assertFalse( "Parameter '" + notExpectedParam + "' not expected", paramList.contains( notExpectedParam ) ); } } } private List<String> getParamList( String result, boolean disableOutputEscaping ) { if ( !result.contains( "?" ) ) { return new ArrayList<String>(); } if ( !disableOutputEscaping ) { result = StringUtils.replace( result, "&", "&" ); } List<String> paramsList = Arrays.asList( StringUtils.split( result.substring( result.indexOf( "?" ) + 1 ), "&" ) ); List<String> normalizedParams = new ArrayList<String>(); for ( String param : paramsList ) { normalizedParams.add( param.substring( 0, param.indexOf( "=" ) ) ); } return normalizedParams; } private String getServerPath( String localPath ) { StringBuffer buffer = new StringBuffer(); buffer.append( "http://" ); buffer.append( serverName ); buffer.append( "/" ); buffer.append( localPath ); return buffer.toString(); } }