Files
alfresco-community-repo/source/test-java/org/alfresco/repo/content/AbstractReadOnlyContentStoreTest.java
Alan Davis 9e3ae9c8e4 Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
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
2015-03-16 13:35:57 +00:00

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
}
}
}