mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-10 14:11:58 +00:00
.externalToolBuilders
config
source
cpp
java
org
alfresco
email
filesys
jcr
linkvalidation
model
repo
action
activities
admin
attributes
audit
avm
blogIntegration
cache
clt
coci
config
configuration
content
cleanup
encoding
filestore
http
metadata
replication
selector
transform
AbstractContentAccessor.java
AbstractContentReader.java
AbstractContentStore.java
AbstractContentWriter.java
AbstractReadOnlyContentStoreTest.java
AbstractRoutingContentStore.java
AbstractWritableContentStoreTest.java
ContentContext.java
ContentDataTest.java
ContentExistsException.java
ContentServicePolicies.java
ContentStore.java
ContentTestSuite.java
ContentWorker.java
EmptyContentReader.java
MimetypeMap.java
MimetypeMapTest.java
NodeContentContext.java
RoutingContentService.java
RoutingContentServiceTest.java
RoutingContentStoreTest.java
TenantRoutingFileContentStore.java
UnsupportedContentUrlException.java
copy
deploy
descriptor
dictionary
domain
exporter
forum
i18n
importer
jscript
lock
model
module
node
ownable
person
policy
preference
processor
remote
rule
search
security
service
site
tagging
template
tenant
thumbnail
transaction
usage
version
workflow
sandbox
service
tools
util
apache
queryRegister.dtd
meta-inf
test-resources
web
.classpath
.project
build.xml
8372: Merged V2.1 to V2.2 8314: Merged V2.0 to V2.1 7750: Fix for ACT-475: ContentStoreCleaner causes OutOfMemoryError 8332: Made content URL column larger to accommodate the extra locale info present in 2.1 8334: Build fix: V2.1 tighter on authentication for getTempWriter 8376: Merged V2.1 to V2.2 8325: Fix for AWC-1089 8361: Workaround for WCM-882: All metadata extracters can now handle zero length files git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8497 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
750 lines
29 KiB
Java
750 lines
29 KiB
Java
/*
|
|
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
* As a special exception to the terms and conditions of version 2.0 of
|
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
|
* FLOSS exception. You should have recieved a copy of the text describing
|
|
* the FLOSS exception, and it is also available here:
|
|
* http://www.alfresco.com/legal/licensing"
|
|
*/
|
|
package org.alfresco.repo.content;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.FileChannel;
|
|
import java.nio.channels.ReadableByteChannel;
|
|
import java.util.Date;
|
|
import java.util.Locale;
|
|
|
|
import org.alfresco.repo.content.ContentStore.ContentUrlHandler;
|
|
import org.alfresco.service.cmr.repository.ContentIOException;
|
|
import org.alfresco.service.cmr.repository.ContentReader;
|
|
import org.alfresco.service.cmr.repository.ContentStreamListener;
|
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* 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 Derek Hulley
|
|
*/
|
|
public abstract class AbstractWritableContentStoreTest extends AbstractReadOnlyContentStoreTest
|
|
{
|
|
private static Log logger = LogFactory.getLog(AbstractWritableContentStoreTest.class);
|
|
|
|
public AbstractWritableContentStoreTest()
|
|
{
|
|
super();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* <p>
|
|
* This implementation creates some content in the store and returns the new content URL.
|
|
*/
|
|
protected String getExistingContentUrl()
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
writer.putContent("Content for " + getName());
|
|
return writer.getContentUrl();
|
|
}
|
|
|
|
/**
|
|
* Get a writer into the store. This test class assumes that the store is writable and
|
|
* that it therefore supports the ability to write content.
|
|
*
|
|
* @return
|
|
* Returns a writer for new content
|
|
*/
|
|
protected ContentWriter getWriter()
|
|
{
|
|
ContentStore store = getStore();
|
|
return store.getWriter(ContentStore.NEW_CONTENT_CONTEXT);
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
public void testWritable() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
assertTrue("The store cannot be read-only", store.isWriteSupported());
|
|
}
|
|
|
|
/**
|
|
* Helper to ensure that illegal content URLs are flagged for <b>getWriter</b> requests
|
|
*/
|
|
private void checkIllegalWritableContentUrl(ContentStore store, String contentUrl)
|
|
{
|
|
assertFalse("This check is for unsupported content URLs only", store.isContentUrlSupported(contentUrl));
|
|
ContentContext bogusContentCtx = new ContentContext(null, contentUrl);
|
|
try
|
|
{
|
|
store.getWriter(bogusContentCtx);
|
|
fail("Expected UnsupportedContentUrlException, but got nothing");
|
|
}
|
|
catch (UnsupportedContentUrlException e)
|
|
{
|
|
// Expected
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that the error handling for <i>inappropriate</i> content URLs
|
|
*/
|
|
public void testIllegalWritableContentUrls()
|
|
{
|
|
ContentStore store = getStore();
|
|
checkIllegalWritableContentUrl(store, "://bogus");
|
|
checkIllegalWritableContentUrl(store, "bogus://");
|
|
checkIllegalWritableContentUrl(store, "bogus://bogus");
|
|
}
|
|
|
|
/**
|
|
* Get a writer and write a little bit of content before reading it.
|
|
*/
|
|
public void testSimpleUse()
|
|
{
|
|
ContentStore store = getStore();
|
|
String content = "Content for " + getName();
|
|
|
|
ContentWriter writer = store.getWriter(ContentStore.NEW_CONTENT_CONTEXT);
|
|
assertNotNull("Writer may not be null", writer);
|
|
// Ensure that the URL is available
|
|
String contentUrlBefore = writer.getContentUrl();
|
|
assertNotNull("Content URL may not be null for unused writer", contentUrlBefore);
|
|
assertTrue("URL is not valid: " + contentUrlBefore, AbstractContentStore.isValidContentUrl(contentUrlBefore));
|
|
// Write something
|
|
writer.putContent(content);
|
|
String contentUrlAfter = writer.getContentUrl();
|
|
assertTrue("URL is not valid: " + contentUrlBefore, AbstractContentStore.isValidContentUrl(contentUrlAfter));
|
|
assertEquals("The content URL may not change just because the writer has put content", contentUrlBefore, contentUrlAfter);
|
|
// Get the readers
|
|
ContentReader reader = store.getReader(contentUrlBefore);
|
|
assertNotNull("Reader from store is null", reader);
|
|
assertEquals(reader.getContentUrl(), writer.getContentUrl());
|
|
String checkContent = reader.getContentString();
|
|
assertEquals("Content is different", content, checkContent);
|
|
}
|
|
|
|
/**
|
|
* Checks that the various methods of obtaining a reader are supported.
|
|
*/
|
|
public void testGetReader() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
ContentWriter writer = store.getWriter(ContentStore.NEW_CONTENT_CONTEXT);
|
|
String contentUrl = writer.getContentUrl();
|
|
|
|
// Check that a reader is available from the store
|
|
ContentReader readerFromStoreBeforeWrite = store.getReader(contentUrl);
|
|
assertNotNull("A reader must always be available from the store", readerFromStoreBeforeWrite);
|
|
|
|
// check that a reader is available from the writer
|
|
ContentReader readerFromWriterBeforeWrite = writer.getReader();
|
|
assertNotNull("A reader must always be available from the writer", readerFromWriterBeforeWrite);
|
|
|
|
String content = "Content for " + getName();
|
|
|
|
// write some content
|
|
long before = System.currentTimeMillis();
|
|
writer.setMimetype("text/plain");
|
|
writer.setEncoding("UTF-8");
|
|
writer.setLocale(Locale.CHINESE);
|
|
writer.putContent(content);
|
|
long after = System.currentTimeMillis();
|
|
|
|
// get a reader from the store
|
|
ContentReader readerFromStore = store.getReader(contentUrl);
|
|
assertNotNull(readerFromStore);
|
|
assertTrue(readerFromStore.exists());
|
|
// Store-provided readers don't have context other than URLs
|
|
// assertEquals(writer.getContentData(), readerFromStore.getContentData());
|
|
assertEquals(content, readerFromStore.getContentString());
|
|
|
|
// get a reader from the writer
|
|
ContentReader readerFromWriter = writer.getReader();
|
|
assertNotNull(readerFromWriter);
|
|
assertTrue(readerFromWriter.exists());
|
|
assertEquals(writer.getContentData(), readerFromWriter.getContentData());
|
|
assertEquals(content, readerFromWriter.getContentString());
|
|
|
|
// get another reader from the reader
|
|
ContentReader readerFromReader = readerFromWriter.getReader();
|
|
assertNotNull(readerFromReader);
|
|
assertTrue(readerFromReader.exists());
|
|
assertEquals(writer.getContentData(), readerFromReader.getContentData());
|
|
assertEquals(content, readerFromReader.getContentString());
|
|
|
|
// check that the length is correct
|
|
int length = content.getBytes(writer.getEncoding()).length;
|
|
assertEquals("Reader content length is incorrect", length, readerFromWriter.getSize());
|
|
|
|
// check that the last modified time is correct
|
|
long modifiedTimeCheck = readerFromWriter.getLastModified();
|
|
|
|
// On some versionms of Linux (e.g. Centos) this test won't work as the
|
|
// modified time accuracy is only to the second.
|
|
long beforeSeconds = before/1000L;
|
|
long afterSeconds = after/1000L;
|
|
long modifiedTimeCheckSeconds = modifiedTimeCheck/1000L;
|
|
|
|
assertTrue("Reader last modified is incorrect", beforeSeconds <= modifiedTimeCheckSeconds);
|
|
assertTrue("Reader last modified is incorrect", modifiedTimeCheckSeconds <= afterSeconds);
|
|
}
|
|
|
|
/**
|
|
* Check that a reader is immutable, i.e. that a reader fetched before a
|
|
* write doesn't suddenly become aware of the content once it has been written.
|
|
*/
|
|
public void testReaderImmutability()
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
ContentReader readerBeforeWrite = writer.getReader();
|
|
assertNotNull(readerBeforeWrite);
|
|
assertFalse(readerBeforeWrite.exists());
|
|
|
|
// Write some content
|
|
writer.putContent("Content for " + getName());
|
|
assertFalse("Reader's state changed after write", readerBeforeWrite.exists());
|
|
try
|
|
{
|
|
readerBeforeWrite.getContentString();
|
|
fail("Reader's state changed after write");
|
|
}
|
|
catch (ContentIOException e)
|
|
{
|
|
// Expected
|
|
}
|
|
|
|
// A new reader should work
|
|
ContentReader readerAfterWrite = writer.getReader();
|
|
assertTrue("New reader after write should be directed to new content", readerAfterWrite.exists());
|
|
}
|
|
|
|
public void testMimetypAndEncodingAndLocale() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
// set mimetype and encoding
|
|
writer.setMimetype("text/plain");
|
|
writer.setEncoding("UTF-16");
|
|
writer.setLocale(Locale.CHINESE);
|
|
|
|
// create a UTF-16 string
|
|
String content = "A little bit o' this and a little bit o' that";
|
|
byte[] bytesUtf16 = content.getBytes("UTF-16");
|
|
// write the bytes directly to the writer
|
|
OutputStream os = writer.getContentOutputStream();
|
|
os.write(bytesUtf16);
|
|
os.close();
|
|
|
|
// now get a reader from the writer
|
|
ContentReader reader = writer.getReader();
|
|
assertEquals("Writer -> Reader content URL mismatch", writer.getContentUrl(), reader.getContentUrl());
|
|
assertEquals("Writer -> Reader mimetype mismatch", writer.getMimetype(), reader.getMimetype());
|
|
assertEquals("Writer -> Reader encoding mismatch", writer.getEncoding(), reader.getEncoding());
|
|
assertEquals("Writer -> Reader locale mismatch", writer.getLocale(), reader.getLocale());
|
|
|
|
// now get the string directly from the reader
|
|
String contentCheck = reader.getContentString(); // internally it should have taken care of the encoding
|
|
assertEquals("Encoding and decoding of strings failed", content, contentCheck);
|
|
}
|
|
|
|
public void testClosedState() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
ContentReader readerBeforeWrite = writer.getReader();
|
|
|
|
// check that streams are not flagged as closed
|
|
assertFalse("Reader stream should not be closed", readerBeforeWrite.isClosed());
|
|
assertFalse("Writer stream should not be closed", writer.isClosed());
|
|
|
|
// write some stuff
|
|
writer.putContent("ABC");
|
|
// check that the write has been closed
|
|
assertTrue("Writer stream should be closed", writer.isClosed());
|
|
|
|
// check that we can get a reader from the writer
|
|
ContentReader readerAfterWrite = writer.getReader();
|
|
assertNotNull("No reader given by closed writer", readerAfterWrite);
|
|
assertFalse("Before-content reader should not be affected by content updates", readerBeforeWrite.isClosed());
|
|
assertFalse("After content reader should not be closed", readerAfterWrite.isClosed());
|
|
|
|
// check that the instance is new each time
|
|
ContentReader newReaderA = writer.getReader();
|
|
ContentReader newReaderB = writer.getReader();
|
|
assertFalse("Reader must always be a new instance", newReaderA == newReaderB);
|
|
|
|
// check that the readers refer to the same URL
|
|
assertEquals("Readers should refer to same URL",
|
|
readerBeforeWrite.getContentUrl(), readerAfterWrite.getContentUrl());
|
|
|
|
// read their content
|
|
try
|
|
{
|
|
readerBeforeWrite.getContentString();
|
|
}
|
|
catch (Throwable e)
|
|
{
|
|
// The content doesn't exist for this reader
|
|
}
|
|
String contentCheck = readerAfterWrite.getContentString();
|
|
assertEquals("Incorrect content", "ABC", contentCheck);
|
|
|
|
// check closed state of readers
|
|
assertFalse("Before-content reader stream should not be closed", readerBeforeWrite.isClosed());
|
|
assertTrue("After-content reader should be closed after reading", readerAfterWrite.isClosed());
|
|
}
|
|
|
|
/**
|
|
* Helper method to check if a store contains a particular URL using the getUrl method
|
|
*/
|
|
private boolean searchForUrl(ContentStore store, final String contentUrl, Date from, Date to)
|
|
{
|
|
final boolean[] found = new boolean[] {false};
|
|
ContentUrlHandler handler = new ContentUrlHandler()
|
|
{
|
|
public void handle(String checkContentUrl)
|
|
{
|
|
if (contentUrl.equals(checkContentUrl))
|
|
{
|
|
found[0] = true;
|
|
}
|
|
}
|
|
};
|
|
getStore().getUrls(from, to, handler);
|
|
return found[0];
|
|
}
|
|
|
|
public void testGetUrls()
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
writer.putContent("Content for " + getName());
|
|
final String contentUrl = writer.getContentUrl();
|
|
ContentStore store = getStore();
|
|
boolean inStore = searchForUrl(store, contentUrl, null, null);
|
|
assertTrue("New content not found in URL set", inStore);
|
|
}
|
|
|
|
public void testDeleteSimple() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
ContentWriter writer = getWriter();
|
|
writer.putContent("Content for " + getName());
|
|
String contentUrl = writer.getContentUrl();
|
|
assertTrue("Content must now exist", store.exists(contentUrl));
|
|
try
|
|
{
|
|
store.delete(contentUrl);
|
|
}
|
|
catch (UnsupportedOperationException e)
|
|
{
|
|
logger.warn("Store test " + getName() + " not possible on " + store.getClass().getName());
|
|
return;
|
|
}
|
|
assertFalse("Content must now be removed", store.exists(contentUrl));
|
|
}
|
|
|
|
/**
|
|
* Tests deletion of content.
|
|
* <p>
|
|
* Only applies when {@link #getStore()} returns a value.
|
|
*/
|
|
public void testDeleteReaderStates() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
ContentWriter writer = getWriter();
|
|
|
|
String content = "Content for " + getName();
|
|
String contentUrl = writer.getContentUrl();
|
|
|
|
// write some bytes, but don't close the stream
|
|
OutputStream os = writer.getContentOutputStream();
|
|
os.write(content.getBytes());
|
|
os.flush(); // make sure that the bytes get persisted
|
|
// close the stream
|
|
os.close();
|
|
|
|
// get a reader
|
|
ContentReader reader = store.getReader(contentUrl);
|
|
assertNotNull(reader);
|
|
|
|
ContentReader readerCheck = writer.getReader();
|
|
assertNotNull(readerCheck);
|
|
assertEquals("Store and write provided readers onto different URLs",
|
|
writer.getContentUrl(), reader.getContentUrl());
|
|
|
|
// open the stream onto the content
|
|
InputStream is = reader.getContentInputStream();
|
|
|
|
// attempt to delete the content
|
|
boolean deleted = store.delete(contentUrl);
|
|
|
|
// close the reader stream
|
|
is.close();
|
|
|
|
// get a fresh reader
|
|
reader = store.getReader(contentUrl);
|
|
assertNotNull(reader);
|
|
|
|
// the underlying system may or may not have deleted the content
|
|
if (deleted)
|
|
{
|
|
assertFalse("Content should not exist", reader.exists());
|
|
// drop out here
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
assertTrue("Content should exist", reader.exists());
|
|
}
|
|
|
|
// delete the content
|
|
store.delete(contentUrl);
|
|
|
|
// attempt to read from the reader
|
|
try
|
|
{
|
|
is = reader.getContentInputStream();
|
|
fail("Reader failed to detect underlying content deletion");
|
|
}
|
|
catch (ContentIOException e)
|
|
{
|
|
// expected
|
|
}
|
|
|
|
// get another fresh reader
|
|
reader = store.getReader(contentUrl);
|
|
assertNotNull("Reader must be returned even when underlying content is missing",
|
|
reader);
|
|
assertFalse("Content should not exist", reader.exists());
|
|
try
|
|
{
|
|
is = reader.getContentInputStream();
|
|
fail("Reader opened stream onto missing content");
|
|
}
|
|
catch (ContentIOException e)
|
|
{
|
|
// expected
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that the writer can have a listener attached
|
|
*/
|
|
public void testWriteStreamListener() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
final boolean[] streamClosed = new boolean[] {false}; // has to be final
|
|
ContentStreamListener listener = new ContentStreamListener()
|
|
{
|
|
public void contentStreamClosed() throws ContentIOException
|
|
{
|
|
streamClosed[0] = true;
|
|
}
|
|
};
|
|
writer.setRetryingTransactionHelper(null);
|
|
writer.addListener(listener);
|
|
|
|
// write some content
|
|
writer.putContent("ABC");
|
|
|
|
// check that the listener was called
|
|
assertTrue("Write stream listener was not called for the stream close", streamClosed[0]);
|
|
}
|
|
|
|
/**
|
|
* The simplest test. Write a string and read it again, checking that we receive the same values.
|
|
* If the resource accessed by {@link #getReader()} and {@link #getWriter()} is not the same, then
|
|
* values written and read won't be the same.
|
|
*/
|
|
public void testWriteAndReadString() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
String content = "ABC";
|
|
writer.putContent(content);
|
|
assertTrue("Stream close not detected", writer.isClosed());
|
|
|
|
ContentReader reader = writer.getReader();
|
|
String check = reader.getContentString();
|
|
assertTrue("Read and write may not share same resource", check.length() > 0);
|
|
assertEquals("Write and read didn't work", content, check);
|
|
}
|
|
|
|
public void testStringTruncation() throws Exception
|
|
{
|
|
String content = "1234567890";
|
|
|
|
ContentWriter writer = getWriter();
|
|
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
|
writer.setEncoding("UTF-8"); // shorter format i.t.o. bytes used
|
|
// write the content
|
|
writer.putContent(content);
|
|
|
|
// get a reader - get it in a larger format i.t.o. bytes
|
|
ContentReader reader = writer.getReader();
|
|
String checkContent = reader.getContentString(5);
|
|
assertEquals("Truncated strings don't match", "12345", checkContent);
|
|
}
|
|
|
|
public void testReadAndWriteFile() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
File sourceFile = File.createTempFile(getName(), ".txt");
|
|
sourceFile.deleteOnExit();
|
|
// dump some content into the temp file
|
|
String content = "ABC";
|
|
FileOutputStream os = new FileOutputStream(sourceFile);
|
|
os.write(content.getBytes());
|
|
os.flush();
|
|
os.close();
|
|
|
|
// put our temp file's content
|
|
writer.putContent(sourceFile);
|
|
assertTrue("Stream close not detected", writer.isClosed());
|
|
|
|
// create a sink temp file
|
|
File sinkFile = File.createTempFile(getName(), ".txt");
|
|
sinkFile.deleteOnExit();
|
|
|
|
// get the content into our temp file
|
|
ContentReader reader = writer.getReader();
|
|
reader.getContent(sinkFile);
|
|
|
|
// read the sink file manually
|
|
FileInputStream is = new FileInputStream(sinkFile);
|
|
byte[] buffer = new byte[100];
|
|
int count = is.read(buffer);
|
|
assertEquals("No content read", 3, count);
|
|
is.close();
|
|
String check = new String(buffer, 0, count);
|
|
|
|
assertEquals("Write out of and read into files failed", content, check);
|
|
}
|
|
|
|
public void testReadAndWriteStreamByPull() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
String content = "ABC";
|
|
// put the content using a stream
|
|
InputStream is = new ByteArrayInputStream(content.getBytes());
|
|
writer.putContent(is);
|
|
assertTrue("Stream close not detected", writer.isClosed());
|
|
|
|
// get the content using a stream
|
|
ByteArrayOutputStream os = new ByteArrayOutputStream(100);
|
|
ContentReader reader = writer.getReader();
|
|
reader.getContent(os);
|
|
byte[] bytes = os.toByteArray();
|
|
String check = new String(bytes);
|
|
|
|
assertEquals("Write out and read in using streams failed", content, check);
|
|
}
|
|
|
|
public void testReadAndWriteStreamByPush() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
String content = "ABC";
|
|
// get the content output stream
|
|
OutputStream os = writer.getContentOutputStream();
|
|
os.write(content.getBytes());
|
|
assertFalse("Stream has not been closed", writer.isClosed());
|
|
// close the stream and check again
|
|
os.close();
|
|
assertTrue("Stream close not detected", writer.isClosed());
|
|
|
|
// pull the content from a stream
|
|
ContentReader reader = writer.getReader();
|
|
InputStream is = reader.getContentInputStream();
|
|
byte[] buffer = new byte[100];
|
|
int count = is.read(buffer);
|
|
assertEquals("No content read", 3, count);
|
|
is.close();
|
|
String check = new String(buffer, 0, count);
|
|
|
|
assertEquals("Write out of and read into files failed", content, check);
|
|
}
|
|
|
|
/**
|
|
* Tests retrieval of all content URLs
|
|
* <p>
|
|
* Only applies when {@link #getStore()} returns a value.
|
|
*/
|
|
public void testListUrls() throws Exception
|
|
{
|
|
ContentStore store = getStore();
|
|
// Ensure that this test can be done
|
|
try
|
|
{
|
|
searchForUrl(store, "abc", null, null);
|
|
}
|
|
catch (UnsupportedOperationException e)
|
|
{
|
|
logger.warn("Store test " + getName() + " not possible on " + store.getClass().getName());
|
|
return;
|
|
}
|
|
// Proceed with the test
|
|
ContentWriter writer = getWriter();
|
|
String contentUrl = writer.getContentUrl();
|
|
|
|
boolean inStore = searchForUrl(store, contentUrl, null, null);
|
|
assertTrue("Writer URL not listed by store", inStore);
|
|
|
|
Date yesterday = new Date(System.currentTimeMillis() - 3600L * 1000L * 24L);
|
|
|
|
// write some data
|
|
writer.putContent("The quick brown fox...");
|
|
|
|
// check again
|
|
inStore = searchForUrl(store, contentUrl, null, null);
|
|
assertTrue("Writer URL not listed by store", inStore);
|
|
|
|
// check that the query for content created before this time yesterday doesn't return the URL
|
|
inStore = searchForUrl(store, contentUrl, null, yesterday);
|
|
assertFalse("URL was younger than required, but still shows up", inStore);
|
|
}
|
|
|
|
/**
|
|
* Tests random access writing
|
|
* <p>
|
|
* Only executes if the writer implements {@link RandomAccessContent}.
|
|
*/
|
|
public void testRandomAccessWrite() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
|
|
FileChannel fileChannel = writer.getFileChannel(true);
|
|
assertNotNull("No channel given", fileChannel);
|
|
|
|
// check that no other content access is allowed
|
|
try
|
|
{
|
|
writer.getWritableChannel();
|
|
fail("Second channel access allowed");
|
|
}
|
|
catch (RuntimeException e)
|
|
{
|
|
// expected
|
|
}
|
|
|
|
// write some content in a random fashion (reverse order)
|
|
byte[] content = new byte[] {1, 2, 3};
|
|
for (int i = content.length - 1; i >= 0; i--)
|
|
{
|
|
ByteBuffer buffer = ByteBuffer.wrap(content, i, 1);
|
|
fileChannel.write(buffer, i);
|
|
}
|
|
|
|
// close the channel
|
|
fileChannel.close();
|
|
assertTrue("Writer not closed", writer.isClosed());
|
|
|
|
// check the content
|
|
ContentReader reader = writer.getReader();
|
|
ReadableByteChannel channelReader = reader.getReadableChannel();
|
|
ByteBuffer buffer = ByteBuffer.allocateDirect(3);
|
|
int count = channelReader.read(buffer);
|
|
assertEquals("Incorrect number of bytes read", 3, count);
|
|
for (int i = 0; i < content.length; i++)
|
|
{
|
|
assertEquals("Content doesn't match", content[i], buffer.get(i));
|
|
}
|
|
|
|
// get a new writer from the store, using the existing content and perform a truncation check
|
|
ContentContext writerTruncateCtx = new ContentContext(writer.getReader(), null);
|
|
ContentWriter writerTruncate = getStore().getWriter(writerTruncateCtx);
|
|
assertEquals("Content size incorrect", 0, writerTruncate.getSize());
|
|
// get the channel with truncation
|
|
FileChannel fcTruncate = writerTruncate.getFileChannel(true);
|
|
fcTruncate.close();
|
|
assertEquals("Content not truncated", 0, writerTruncate.getSize());
|
|
|
|
// get a new writer from the store, using the existing content and perform a non-truncation check
|
|
ContentContext writerNoTruncateCtx = new ContentContext(writer.getReader(), null);
|
|
ContentWriter writerNoTruncate = getStore().getWriter(writerNoTruncateCtx);
|
|
assertEquals("Content size incorrect", 0, writerNoTruncate.getSize());
|
|
// get the channel without truncation
|
|
FileChannel fcNoTruncate = writerNoTruncate.getFileChannel(false);
|
|
fcNoTruncate.close();
|
|
assertEquals("Content was truncated", writer.getSize(), writerNoTruncate.getSize());
|
|
}
|
|
|
|
/**
|
|
* Tests random access reading
|
|
* <p>
|
|
* Only executes if the reader implements {@link RandomAccessContent}.
|
|
*/
|
|
public void testRandomAccessRead() throws Exception
|
|
{
|
|
ContentWriter writer = getWriter();
|
|
// put some content
|
|
String content = "ABC";
|
|
byte[] bytes = content.getBytes();
|
|
writer.putContent(content);
|
|
ContentReader reader = writer.getReader();
|
|
|
|
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
|
|
}
|
|
|
|
// read the content
|
|
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
|
|
int count = fileChannel.read(buffer);
|
|
assertEquals("Incorrect number of bytes read", bytes.length, count);
|
|
// transfer back to array
|
|
buffer.rewind();
|
|
buffer.get(bytes);
|
|
String checkContent = new String(bytes);
|
|
assertEquals("Content read failure", content, checkContent);
|
|
fileChannel.close();
|
|
}
|
|
}
|