alfresco-community-repo/source/java/org/alfresco/repo/content/RoutingContentStoreTest.java
Derek Hulley f30ccf8d6c Allow other types of content URLs other than store://...
Enforce restriction that all content URLs must be of form protocol://identifier
Allow for read-only stores.
Improved tests so that it is easier, when writing a new store, to determine if the store is compliant or not.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5899 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2007-06-09 00:43:02 +00:00

244 lines
8.3 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.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.TempFileProvider;
/**
* Ensures that the routing of URLs based on context is working. A combination
* of fully featured and incompletely featured stores is used to ensure that
* all routing scenarios are handled.
*
* @see AbstractRoutingContentStore
* @since 2.1
*
* @author Derek Hulley
*/
public class RoutingContentStoreTest extends AbstractWritableContentStoreTest
{
private ContentStore storeA;
private ContentStore storeB;
private ContentStore storeC;
private ContentStore storeD;
private ContentStore routingStore;
@Override
public void setUp() throws Exception
{
super.setUp();
File tempDir = TempFileProvider.getTempDir();
// Create a subdirectory for A
File storeADir = new File(tempDir, "A");
storeA = new FileContentStore(storeADir);
// Create a subdirectory for B
File storeBDir = new File(tempDir, "B");
storeB = new FileContentStore(storeBDir);
// Create a subdirectory for C
File storeCDir = new File(tempDir, "C");
storeC = new DumbReadOnlyFileStore(new FileContentStore(storeCDir));
// No subdirectory for D
storeD = new SupportsNoUrlFormatStore();
// Create the routing store
routingStore = new RandomRoutingContentStore(storeA, storeB, storeC, storeD);
}
@Override
protected ContentStore getStore()
{
return routingStore;
}
public void testSetUp() throws Exception
{
assertNotNull(routingStore);
}
private void checkForContent(String contentUrl, String content)
{
for (ContentStore store : new ContentStore[] {storeA, storeB})
{
// Does the store have it
if (store.exists(contentUrl))
{
// Check it
ContentReader reader = store.getReader(contentUrl);
String checkContent = reader.getContentString();
assertEquals("Content found but is incorrect", content, checkContent);
return;
}
}
fail("Content not found in any of the stores: " + contentUrl);
}
/**
* Checks that requests for missing content URLs are served.
*/
public void testMissingUrl()
{
String missingContentUrl = FileContentStore.createNewFileStoreUrl();
ContentReader reader = routingStore.getReader(missingContentUrl);
assertNotNull("Missing URL should not return null", reader);
assertFalse("Empty reader should say content doesn't exist.", reader.exists());
try
{
reader.getContentString();
fail("Empty reader cannot return content.");
}
catch (Throwable e)
{
// Expected
}
}
public void testGeneralUse()
{
for (int i = 0 ; i < 20; i++)
{
ContentContext contentContext = new ContentContext(null, null);
ContentWriter writer = routingStore.getWriter(contentContext);
String content = "This was generated by " + this.getClass().getName() + "#" + getName() + " number " + i;
writer.putContent(content);
// Check that it exists
String contentUrl = writer.getContentUrl();
checkForContent(contentUrl, content);
// Now go direct to the routing store and check that it is able to find the appropriate URLs
ContentReader reader = routingStore.getReader(contentUrl);
assertNotNull("Null reader returned", reader);
assertTrue("Reader should be onto live content", reader.exists());
}
}
/**
* A test routing store that directs content writes to a randomly-chosen store.
* Matching of content URLs back to the stores is handled by the base class.
*
* @author Derek Hulley
*/
private static class RandomRoutingContentStore extends AbstractRoutingContentStore
{
private List<ContentStore> stores;
public RandomRoutingContentStore(ContentStore ... stores)
{
this.stores = new ArrayList<ContentStore>(5);
for (ContentStore store : stores)
{
this.stores.add(store);
}
Cache ehCache = new Cache("RandomRoutingContentStore", 50, false, true, 0L, 0L);
CacheManager cacheManager = new CacheManager();
cacheManager.addCache(ehCache);
EhCacheAdapter<String, ContentStore> cache = new EhCacheAdapter<String, ContentStore>();
cache.setCache(ehCache);
super.setStoresCache(cache);
}
@Override
protected List<ContentStore> getAllStores()
{
return stores;
}
@Override
protected ContentStore selectWriteStore(ContentContext ctx)
{
// Shuffle the list of writable stores
List<ContentStore> shuffled = new ArrayList<ContentStore>(stores);
Collections.shuffle(shuffled);
// Pick the first writable store
for (ContentStore store : shuffled)
{
if (store.isWriteSupported())
{
return store;
}
}
// Nothing found
fail("A request came for a writer when there is no writable store to choose from");
return null;
}
}
/**
* The simplest possible store.
*
* @author Derek Hulley
*/
private static class DumbReadOnlyFileStore extends AbstractContentStore
{
FileContentStore fileStore;
public DumbReadOnlyFileStore(FileContentStore fileStore)
{
this.fileStore = fileStore;
}
public boolean isWriteSupported()
{
return false;
}
public ContentReader getReader(String contentUrl)
{
return fileStore.getReader(contentUrl);
}
}
/**
* This store supports nothing. It is designed to catch the routing code out.
*
* @author Derek Hulley
*/
private static class SupportsNoUrlFormatStore extends AbstractContentStore
{
public SupportsNoUrlFormatStore()
{
}
public boolean isWriteSupported()
{
return false;
}
public ContentReader getReader(String contentUrl)
{
throw new UnsupportedContentUrlException(this, contentUrl);
}
}
}