/* * Copyright (C) 2005-2015 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.model.filefolder; import java.util.List; import java.util.Locale; import junit.framework.TestCase; import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.node.MLPropertyInterceptor; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.transaction.TransactionService; import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.util.ApplicationContextHelper; import org.junit.Test; import org.junit.experimental.categories.Category; import org.springframework.context.ApplicationContext; import static org.junit.Assert.assertNotEquals; /** * @see org.alfresco.repo.model.filefolder.FileFolderLoader * @author Derek Hulley * @since 5.1 */ @Category(OwnJVMTestsCategory.class) public class FileFolderLoaderTest extends TestCase { private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); private FileFolderLoader fileFolderLoader; private FileFolderService fileFolderService; private PermissionService permissionService; private TransactionService transactionService; private NodeService nodeService; private String sharedHomePath; private NodeRef hiddenFolderNodeRef; private String hiddenFolderPath; private NodeRef readOnlyFolderNodeRef; private String readOnlyFolderPath; private NodeRef writeFolderNodeRef; private String writeFolderPath; @Override public void setUp() throws Exception { AuthenticationUtil.pushAuthentication(); RunAsWork setUpWork = new RunAsWork() { @Override public Void doWork() throws Exception { fileFolderLoader = (FileFolderLoader) ctx.getBean("FileFolderLoader"); fileFolderService = (FileFolderService) ctx.getBean("FileFolderService"); permissionService = (PermissionService) ctx.getBean("PermissionService"); transactionService = (TransactionService) ctx.getBean("TransactionService"); nodeService = (NodeService) ctx.getBean("nodeService"); NodeRef companyHomeNodeRef = fileFolderLoader.getRepository().getCompanyHome(); NodeRef sharedHomeNodeRef = fileFolderLoader.getRepository().getSharedHome(); List sharedHomeFileInfos = fileFolderService.getNamePath(companyHomeNodeRef, sharedHomeNodeRef); sharedHomePath = "/" + sharedHomeFileInfos.get(0).getName(); // Create a folder that will be invisible to all normal users FileInfo hiddenFolderInfo = fileFolderService.create(sharedHomeNodeRef, "HideThis", ContentModel.TYPE_FOLDER); hiddenFolderNodeRef = hiddenFolderInfo.getNodeRef(); hiddenFolderPath = sharedHomePath + "/HideThis"; permissionService.setInheritParentPermissions(hiddenFolderNodeRef, false); // Create a folder that will be read-only FileInfo readOnlyFolderInfo = fileFolderService.create(sharedHomeNodeRef, "ReadOnlyThis", ContentModel.TYPE_FOLDER); readOnlyFolderNodeRef = readOnlyFolderInfo.getNodeRef(); readOnlyFolderPath = sharedHomePath + "/ReadOnlyThis"; permissionService.setInheritParentPermissions(readOnlyFolderNodeRef, false); permissionService.setPermission(readOnlyFolderNodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true); // Create a folder to write to FileInfo writeFolderInfo = fileFolderService.create(sharedHomeNodeRef, "WriteThis", ContentModel.TYPE_FOLDER); writeFolderNodeRef = writeFolderInfo.getNodeRef(); writeFolderPath = sharedHomePath + "/WriteThis"; // Done return null; } }; AuthenticationUtil.runAsSystem(setUpWork); } @Override public void tearDown() throws Exception { RunAsWork setUpWork = new RunAsWork() { @Override public Void doWork() throws Exception { fileFolderService.delete(hiddenFolderNodeRef); fileFolderService.delete(readOnlyFolderNodeRef); fileFolderService.delete(writeFolderNodeRef); // Done return null; } }; AuthenticationUtil.runAsSystem(setUpWork); AuthenticationUtil.popAuthentication(); } @Test public void testBasic() { assertNotNull(fileFolderLoader); assertNotNull(sharedHomePath); } @Test public void testIllegalArgs_MinMax() throws Exception { try { fileFolderLoader.createFiles( sharedHomePath, 1, 256, 100L, 10L, Long.MAX_VALUE, false, 10, 256); fail("Should detect min/max size issue."); } catch (IllegalArgumentException e) { // Expected } } @Test public void testIllegalArgs_DescriptionCount() throws Exception { try { fileFolderLoader.createFiles( sharedHomePath, 1, 256, 1024L, 10L, Long.MAX_VALUE, false, Integer.MAX_VALUE, 256); fail("Should detect description count issue."); } catch (IllegalArgumentException e) { // Expected } } @Test public void testIllegalArgs_DescriptionSize() throws Exception { try { fileFolderLoader.createFiles( sharedHomePath, 1, 256, 1024L, 10L, Long.MAX_VALUE, false, 10, Long.MAX_VALUE); fail("Should detect description size issue."); } catch (IllegalArgumentException e) { // Expected } } @Test public void testNoPermissionsAtAll() throws Exception { try { fileFolderLoader.createFiles( sharedHomePath, 0, 256, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); fail("No permissions to see folder."); } catch (AuthenticationCredentialsNotFoundException e) { // Expected } } @Test public void testNoPermissionsToFindFolder() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser("BOB-1"); fileFolderLoader.createFiles( hiddenFolderPath, 0, 256, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); fail("No permissions to see folder."); } catch (AccessDeniedException e) { // Expected } finally { AuthenticationUtil.popAuthentication(); } } @Test public void testFolderMissing() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); fileFolderLoader.createFiles( sharedHomePath + "/Missing", 0, 256, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); fail("Folder does not exist"); } catch (AlfrescoRuntimeException e) { // Expected assertTrue(e.getCause() instanceof FileNotFoundException); } finally { AuthenticationUtil.popAuthentication(); } } @Test public void testNoPermissionsToWriteToFolder() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser("BOB-1"); fileFolderLoader.createFiles( readOnlyFolderPath, 1, 256, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); fail("Folder is read only. Should not be able to write to it."); } catch (AccessDeniedException e) { // Expected } finally { AuthenticationUtil.popAuthentication(); } } /** * Zero files */ @Test public void testLoad_ZeroFiles() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); int created = fileFolderLoader.createFiles( writeFolderPath, 0, 256, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); assertEquals("Incorrect number of files generated.", 0, created); // Count assertEquals(0, nodeService.countChildAssocs(writeFolderNodeRef, true)); } finally { AuthenticationUtil.popAuthentication(); } } /** * One file */ @Test public void testLoad_OneFile() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); int created = fileFolderLoader.createFiles( writeFolderPath, 1, 256, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); assertEquals("Incorrect number of files generated.", 1, created); // Check the descriptions RetryingTransactionCallback checkCallback = new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { MLPropertyInterceptor.setMLAware(true); List childAssocs = nodeService.getChildAssocs(writeFolderNodeRef); // Count assertEquals(1, childAssocs.size()); NodeRef fileNodeRef = childAssocs.get(0).getChildRef(); MLText descriptions = (MLText) nodeService.getProperty(fileNodeRef, ContentModel.PROP_DESCRIPTION); assertNotNull("No descriptions added", descriptions); assertEquals("Incorrect number of unique descriptions added: ", 10, descriptions.size()); assertTrue("Expect the default language to be present. ", descriptions.containsKey(new Locale(Locale.getDefault().getLanguage()))); return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(checkCallback, true); } finally { AuthenticationUtil.popAuthentication(); } } /** * 100 files; 10 per txn */ @Test public void testLoad_02() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); int created = fileFolderLoader.createFiles( writeFolderPath, 100, 10, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); assertEquals("Incorrect number of files generated.", 100, created); // Count assertEquals(100, nodeService.countChildAssocs(writeFolderNodeRef, true)); } finally { AuthenticationUtil.popAuthentication(); } } /** * 15 files; 10 per txn; spoofed; different */ @Test public void testLoad_03() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); int created = fileFolderLoader.createFiles( writeFolderPath, 15, 10, 1024L, 1024L, Long.MAX_VALUE, false, 10, 256L); assertEquals("Incorrect number of files generated.", 15, created); // Count assertEquals(15, nodeService.countChildAssocs(writeFolderNodeRef, true)); // Check the files List fileInfos = fileFolderService.listFiles(writeFolderNodeRef); String lastText = null; String lastDescr = null; String lastUrl = null; for (FileInfo fileInfo : fileInfos) { NodeRef fileNodeRef = fileInfo.getNodeRef(); // The URLs must all be unique as we wrote the physical binaries ContentReader reader = fileFolderService.getReader(fileNodeRef); assertEquals("UTF-8", reader.getEncoding()); assertEquals(MimetypeMap.MIMETYPE_TEXT_PLAIN, reader.getMimetype()); assertEquals(1024L, reader.getSize()); if (lastUrl == null) { lastUrl = reader.getContentUrl(); } else { assertNotEquals("We expect different URLs: ", lastUrl, reader.getContentUrl()); lastUrl = reader.getContentUrl(); } // Check content if (lastText == null) { lastText = reader.getContentString(); } else { String currentStr = reader.getContentString(); assertNotEquals("All text must differ due to varying seed. ", lastText, currentStr); lastText = currentStr; } // Check description if (lastDescr == null) { lastDescr = (String) nodeService.getProperty(fileNodeRef, ContentModel.PROP_DESCRIPTION); assertEquals("cm:description length is incorrect. ", 256, lastDescr.getBytes().length); } else { String currentDescr = (String) nodeService.getProperty(fileNodeRef, ContentModel.PROP_DESCRIPTION); assertNotEquals("All descriptions must differ due to varying seed. ", lastDescr, currentDescr); lastDescr = currentDescr; } } } finally { AuthenticationUtil.popAuthentication(); } } /** * 10 files; 10 per txn; force storage; identical */ @Test public void testLoad_04() throws Exception { try { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); int created = fileFolderLoader.createFiles( writeFolderPath, 10, 10, 1024L, 1024L, 1L, true, 10, 256L); assertEquals("Incorrect number of files generated.", 10, created); // Count assertEquals(10, nodeService.countChildAssocs(writeFolderNodeRef, true)); // Check the files List fileInfos = fileFolderService.listFiles(writeFolderNodeRef); String lastText = null; String lastDescr = null; String lastUrl = null; for (FileInfo fileInfo : fileInfos) { NodeRef fileNodeRef = fileInfo.getNodeRef(); // The URLs must all be unique as we wrote the physical binaries ContentReader reader = fileFolderService.getReader(fileNodeRef); assertEquals("UTF-8", reader.getEncoding()); assertEquals(MimetypeMap.MIMETYPE_TEXT_PLAIN, reader.getMimetype()); assertEquals(1024L, reader.getSize()); if (lastUrl == null) { lastUrl = reader.getContentUrl(); } else { assertNotEquals("We expect unique URLs: ", lastUrl, reader.getContentUrl()); lastUrl = reader.getContentUrl(); } // Check content if (lastText == null) { lastText = reader.getContentString(); } else { String currentStr = reader.getContentString(); assertEquals("All text must be identical due to same seed. ", lastText, currentStr); lastText = currentStr; } // Check description if (lastDescr == null) { lastDescr = (String) nodeService.getProperty(fileNodeRef, ContentModel.PROP_DESCRIPTION); assertEquals("cm:description length is incorrect. ", 256, lastDescr.getBytes().length); } else { String currentDescr = (String) nodeService.getProperty(fileNodeRef, ContentModel.PROP_DESCRIPTION); assertEquals("All descriptions must be identical due to varying seed. ", lastDescr, currentDescr); lastDescr = currentDescr; } } } finally { AuthenticationUtil.popAuthentication(); } } }