mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
99376: BENCH-371: BM-0004: Copy Alfresco and set up build plan - Modify FileContentStore to service 'spoof://' URLs - SpoofedTextContentReader to generate consistent text for URL - Fix FileContentStoreTest so that tests actually execute - Add override for @After so that no NPEs are thrown - Add tests for the 'spoof://' protocol - Some additional checks for IllegalArgumentException on SpoofedTextContentReader construction - Force delete of 'spoof' to return false but not fail with an exception This is handled neatly by the EagerContentStoreCleaner, which accepts that the stores may protect data according to their own needs e.g. Centera - Add spoofing option to FileFolderPerformanceTester 290 files/s for 1K files vs 460 files/s for spoofed text files (no binary streaming required) - Start FileFolderLoader component that will be used by the API git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@99502 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
324 lines
10 KiB
Java
324 lines
10 KiB
Java
/*
|
|
* Copyright (C) 2005-2014 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.repo.content;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.FileChannel;
|
|
import java.nio.channels.ReadableByteChannel;
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
|
|
import javax.transaction.UserTransaction;
|
|
|
|
import org.alfresco.repo.content.ContentStore.ContentUrlHandler;
|
|
import org.alfresco.service.cmr.repository.ContentReader;
|
|
import org.alfresco.service.transaction.TransactionService;
|
|
import org.alfresco.util.ApplicationContextHelper;
|
|
import org.alfresco.util.BaseApplicationContextHelper;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.rules.TestName;
|
|
import org.springframework.context.ApplicationContext;
|
|
|
|
import static org.junit.Assert.assertFalse;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.assertTrue;
|
|
import static org.junit.Assert.fail;
|
|
|
|
/**
|
|
* Abstract base class that provides a set of tests for implementations
|
|
* of {@link ContentStore}.
|
|
*
|
|
* @see ContentStore
|
|
* @see org.alfresco.service.cmr.repository.ContentReader
|
|
* @see org.alfresco.service.cmr.repository.ContentWriter
|
|
*
|
|
* @author sglover
|
|
* @author Derek Hulley
|
|
*/
|
|
public abstract class AbstractReadOnlyContentStoreTest
|
|
{
|
|
protected static ApplicationContext ctx;
|
|
|
|
private static Log logger = LogFactory.getLog(AbstractReadOnlyContentStoreTest.class);
|
|
|
|
@Rule public TestName name = new TestName();
|
|
|
|
protected String getName()
|
|
{
|
|
return name.getMethodName();
|
|
}
|
|
|
|
protected TransactionService transactionService;
|
|
private UserTransaction txn;
|
|
|
|
public AbstractReadOnlyContentStoreTest()
|
|
{
|
|
super();
|
|
}
|
|
|
|
@BeforeClass
|
|
public static void beforeClass() throws Exception
|
|
{
|
|
ctx = BaseApplicationContextHelper.getApplicationContext(ApplicationContextHelper.CONFIG_LOCATIONS);
|
|
}
|
|
|
|
/**
|
|
* Starts a transaction
|
|
*/
|
|
@Before
|
|
public void before() throws Exception
|
|
{
|
|
transactionService = (TransactionService) ctx.getBean("TransactionService");
|
|
txn = transactionService.getUserTransaction();
|
|
txn.begin();
|
|
}
|
|
|
|
/**
|
|
* Rolls back the transaction
|
|
*/
|
|
@After
|
|
public void after() throws Exception
|
|
{
|
|
try { txn.rollback(); } catch (Throwable e) {e.printStackTrace();}
|
|
}
|
|
|
|
/**
|
|
* Fetch the store to be used during a test. This method is invoked once per test - it is
|
|
* therefore safe to use <code>setUp</code> to initialise resources.
|
|
* <p>
|
|
* Usually tests will construct a static instance of the store to use throughout all the
|
|
* tests.
|
|
*
|
|
* @return Returns the <b>same instance</b> of a store for all invocations.
|
|
*/
|
|
protected abstract ContentStore getStore();
|
|
|
|
/**
|
|
* Gets a reader for the given content URL from the store
|
|
*
|
|
* @see #getStore()
|
|
*/
|
|
protected final ContentReader getReader(String contentUrl)
|
|
{
|
|
return getStore().getReader(contentUrl);
|
|
}
|
|
|
|
/**
|
|
* Fetch a valid URL from the store. The default implementation will attempt to get
|
|
* all the available URLs from the store and pick the first one. Writable store tests
|
|
* can create some content to be sure of its existence.
|
|
*
|
|
* @return
|
|
* Return any valid URL for the store, or <tt>null</tt> if the store is empty.
|
|
*/
|
|
@SuppressWarnings("deprecation")
|
|
protected String getExistingContentUrl()
|
|
{
|
|
ContentStore store = getStore();
|
|
try
|
|
{
|
|
final Set<String> contentUrls = new HashSet<String>(5);
|
|
ContentUrlHandler handler = new ContentUrlHandler()
|
|
{
|
|
public void handle(String contentUrl)
|
|
{
|
|
if (contentUrls.size() < 50)
|
|
{
|
|
contentUrls.add(contentUrl);
|
|
}
|
|
}
|
|
};
|
|
store.getUrls(handler);
|
|
if (contentUrls.size() > 0)
|
|
{
|
|
return (String) contentUrls.toArray()[0];
|
|
}
|
|
else
|
|
{
|
|
// We can't do anything with this
|
|
return null;
|
|
}
|
|
}
|
|
catch (UnsupportedOperationException e)
|
|
{
|
|
// The store doesn't support this
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testSetUp() throws Exception
|
|
{
|
|
// check that the store remains the same
|
|
ContentStore store = getStore();
|
|
assertNotNull("No store provided", store);
|
|
assertTrue("The same instance of the store must be returned for getStore", store == getStore());
|
|
}
|
|
|
|
/**
|
|
* Helper to ensure that illegal content URLs are flagged for
|
|
* <b>getReader()</b> and <b>exists()</b> requests.
|
|
*/
|
|
private void checkIllegalReadContentUrl(ContentStore store, String contentUrl)
|
|
{
|
|
assertFalse("This check is for unsupported content URLs only", store.isContentUrlSupported(contentUrl));
|
|
try
|
|
{
|
|
store.getReader(contentUrl);
|
|
fail("Expected UnsupportedContentUrlException for getReader(), but got nothing: " + contentUrl);
|
|
}
|
|
catch (UnsupportedContentUrlException e)
|
|
{
|
|
// Expected
|
|
}
|
|
try
|
|
{
|
|
store.exists(contentUrl);
|
|
fail("Expected UnsupportedContentUrlException for exists(), but got nothing: " + contentUrl);
|
|
}
|
|
catch (UnsupportedContentUrlException e)
|
|
{
|
|
// Expected
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that the error handling for <i>inappropriate</i> content URLs
|
|
*/
|
|
@Test
|
|
public void testIllegalReadableContentUrls()
|
|
{
|
|
ContentStore store = getStore();
|
|
checkIllegalReadContentUrl(store, "://bogus");
|
|
checkIllegalReadContentUrl(store, "bogus://");
|
|
checkIllegalReadContentUrl(store, "bogus://bogus");
|
|
}
|
|
|
|
/**
|
|
* Checks that the various methods of obtaining a reader are supported.
|
|
*/
|
|
@Test
|
|
public void testGetReaderForExistingContentUrl() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
String contentUrl = getExistingContentUrl();
|
|
if (contentUrl == null)
|
|
{
|
|
logger.warn("Store test testGetReaderForExistingContentUrl not possible on " + store.getClass().getName());
|
|
return;
|
|
}
|
|
// Get the reader
|
|
assertTrue("URL returned in set seems to no longer exist", store.exists(contentUrl));
|
|
ContentReader reader = store.getReader(contentUrl);
|
|
assertNotNull("Reader should never be null", reader);
|
|
assertTrue("Reader says content doesn't exist", reader.exists());
|
|
assertFalse("Reader should not be closed before a read", reader.isClosed());
|
|
assertFalse("The reader channel should not be open yet", reader.isChannelOpen());
|
|
|
|
// Open the channel
|
|
ReadableByteChannel readChannel = reader.getReadableChannel();
|
|
readChannel.read(ByteBuffer.wrap(new byte[500]));
|
|
assertFalse("Reader should not be closed during a read", reader.isClosed());
|
|
assertTrue("The reader channel should be open during a read", reader.isChannelOpen());
|
|
|
|
// Close the channel
|
|
readChannel.close();
|
|
assertTrue("Reader should be closed after a read", reader.isClosed());
|
|
assertFalse("The reader channel should be closed after a read", reader.isChannelOpen());
|
|
}
|
|
|
|
/**
|
|
* Tests random access reading
|
|
* <p>
|
|
* Only executes if the reader implements {@link RandomAccessContent}.
|
|
*/
|
|
@Test
|
|
public void testRandomAccessRead() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
String contentUrl = getExistingContentUrl();
|
|
if (contentUrl == null)
|
|
{
|
|
logger.warn("Store test testRandomAccessRead not possible on " + store.getClass().getName());
|
|
return;
|
|
}
|
|
// Get the reader
|
|
ContentReader reader = store.getReader(contentUrl);
|
|
assertNotNull("Reader should never be null", reader);
|
|
|
|
FileChannel fileChannel = reader.getFileChannel();
|
|
assertNotNull("No channel given", fileChannel);
|
|
|
|
// check that no other content access is allowed
|
|
try
|
|
{
|
|
reader.getReadableChannel();
|
|
fail("Second channel access allowed");
|
|
}
|
|
catch (RuntimeException e)
|
|
{
|
|
// expected
|
|
}
|
|
fileChannel.close();
|
|
}
|
|
|
|
@Test
|
|
public void testBlockedWriteOperations() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
if (store.isWriteSupported())
|
|
{
|
|
// Just ignore this test
|
|
return;
|
|
}
|
|
// Ensure that we can't get a writer
|
|
try
|
|
{
|
|
store.getWriter(ContentStore.NEW_CONTENT_CONTEXT);
|
|
fail("Read-only store provided a writer: " + store);
|
|
}
|
|
catch (UnsupportedOperationException e)
|
|
{
|
|
// Expected
|
|
}
|
|
String contentUrl = getExistingContentUrl();
|
|
if (contentUrl == null)
|
|
{
|
|
logger.warn("Store test testBlockedWriteOperations not possible on " + store.getClass().getName());
|
|
return;
|
|
}
|
|
// Ensure that we can't delete a URL
|
|
try
|
|
{
|
|
store.delete(contentUrl);
|
|
fail("Read-only store allowed deletion: " + store);
|
|
}
|
|
catch (UnsupportedOperationException e)
|
|
{
|
|
// Expected
|
|
}
|
|
}
|
|
}
|