Dave Ward a2580451b9 Merged V3.3-BUG-FIX to HEAD
21242: ALF-2879: XAM Connector changes
      - Fixed setting of store name
      - Added properties:
         - xam.archive.retentionPeriodDays=0
         - xam.archive.addLock=true
   21244: ALF-2879: Updated readme.txt
   21262: ALF-3611 - tweak AVM orphan reaper test (PurgeTestP)
   21277: Fix ALF-889 - WCM/AVM folder disappears when cut-and-paste into itself
      - fixed cycle check before rename/move
      - added -ve unit test
      - externalized existing cycle error messages
   21284: ALF-2879: XAM Connector changes
      - Listen to store selector policies (incl. workaround for policy listening)
      - Set XAM retention (code is setting the value, but not successfully tested against test servers)
   21285: StoreSelectorPolicies.OnContentMovedPolicy is deprecated. Use StoreSelectorPolicies.AfterMoveContentPolicy.
      - Deprecated so old policy still exists and works
      - Will remove for 3.4 (maybe)
   21293: Fix ALF-3245: stream not closed in DictionaryBootstrap.onDictionaryInit()
   21303: ALF-2879: XAM Connector changes
      - Throw ContentIOException if setBaseRetention fails
   21313: ALF-2879: XAM Connector changes
      - Round ms to nearest second
      - Log actual ms value being set for retention
   21322: Fix AVMNodeService.createNode to close output stream and avoid "Too many open files" (also add example AVMFileFolderPerformanceTester)
   21331: ALF-2879: XAM Connector changes
      - Removed duplicate setting of base retention
      - Left code hooks for setting of other metadata
   21368: Merged V3.3 to V3.3-BUG-FIX
      21213: Merged DEV/TEMPORARY to V3.3
         21200: ALF-2978: IMAP cannot bind to all the interfaces (0.0.0.0)
            “imap.server.host” property can be used for setting IP address / network adapter to listen on for IMAP protocol.
      21219: Merged PATCHES/V3.2.1 to V3.3
         21216: ALF-3779: A few bug fixes to --FOREACH handling in SchemaBootstrap
            - New system.upgrade.default.batchsize property to control overall default batch size
            - Added in a few more missed --FOREACH markers
         21211: ALF-3779: Remaining scripts converted to use --FOREACH (as logs finally provided by test prove that they need it too!)
         21210: (RECORD ONLY) Incremented version label
         21209: ALF-3779: Solution to allow batching of mass updates in upgrade scripts into smaller transactions
            - A special preceding comment in this format specifies a numeric table column to control the batching and a global property specifying the batch size
               --FOREACH table.column batch.size.property
            - If the property isn't specified in alfresco-global.properties, the default batch size is 10,000
            - INSERT / UPDATE / DELETE statements can then tack on extra conditions on ${LOWERBOUND} and ${UPPERBOUND} variables. E.g.
               WHERE n.id >= ${LOWERBOUND} AND n.id <= ${UPPERBOUND}
            - The statements are substituted and executed for each batch range up to the maximum value of the column
            - 2.1 and 2.2 MySQL upgrades reimplemented this way
         21207: Extra debug logging to track index triggering activity
      21295: Merged HEAD to V3.3
         21255: Parameter encoding
      21298: Merged V3.2 to V3.3
         21297: ALF-3889: JBPMDeployProcessServlet is now disabled by default and enabled with this in alfresco-global.properties
            system.workflow.deployservlet.enabled=true
      21317: dod5015: Parameter encoding
      21363: Merged PATCHES/V3.2.1 to V3.3
         21338: (RECORD ONLY) Incremented version label
         21335: ALF-3779: Correction to error in --FOREACH range restriction for UPDATE statement
         21290: ALF-3960: ArrayIndexOutOfBoundsException when we set mergerMergeFactor > mergerTargetOverlays
         21278: (RECORD ONLY) Merged PATCHES/V3.1.2 to PATCHES/V3.2.1
            21264: ALF-3889: JBPMDeployProcessServlet not accessible by default
               - Should only be enabled in development environment
      21364: Merged PATCHES/V3.1.2 to V3.3 (RECORD ONLY)
         21264: ALF-3889: JBPMDeployProcessServlet not accessible by default
            - Should only be enabled in development environment
      21365: Merged PATCHES/V3.2.0 to V3.3 (RECORD ONLY)
         21276: Merged PATCHES/V3.1.2 to PATCHES/V3.2.0
            21264: ALF-3889: JBPMDeployProcessServlet not accessible by default
               - Should only be enabled in development environment
      21366: Merged PATCHES/V3.2.r to V3.3 (RECORD ONLY)
         21279: Merged PATCHES/V3.1.2 to PATCHES/V3.2.r
            21264: ALF-3889: JBPMDeployProcessServlet not accessible by default
               - Should only be enabled in development environment
      21367: Merged PATCHES/V3.3.1 to V3.3 (RECORD ONLY)
         21343: Incremented version label
         21342: ALF-3997: Merged V3.3-BUG-FIX to PATCHES/V3.3.1
            20623: Fix for ALF-3188 : Access Denied when updating doc via CIFS
         21282: Merged PATCHES/V3.1.2 to PATCHES/V3.3.1
            21264: ALF-3889: JBPMDeployProcessServlet not accessible by default
               - Should only be enabled in development environment
         21239: Created hotfix branch off ENTERPRISE/V3.3.1


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21369 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2010-07-22 18:20:24 +00:00

578 lines
22 KiB
Java

/*
* Copyright (C) 2005-2010 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.avm;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor;
import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.transaction.TransactionService;
import org.springframework.context.ApplicationContext;
/**
* Base class for AVMService tests.
* @author britt
*/
public class AVMServiceTestBase extends TestCase
{
/**
* The AVMService we are testing.
*/
protected static AVMService fService;
/**
* The reaper thread.
*/
protected static OrphanReaper fReaper;
/**
* The AVMSyncService.
*/
protected static AVMSyncService fSyncService;
/**
* The application context.
*/
protected static ApplicationContext fContext;
/**
* The start time of actual work for a test.
*/
private long fStartTime;
protected static RetryingTransactionHelper fRetryingTransactionHelper;
protected static AuthenticationComponent fAuthenticationComponent;
protected static AVMSnapShotTriggeredIndexingMethodInterceptor fIndexingInterceptor;
protected static TransactionService fTransactionService;
protected static IndexerAndSearcher fIndexerAndSearcher;
protected static AVMLockingService fLockingService;
protected static AuthenticationService fAuthService;
public void testSetup() throws Exception
{
setupBasicTree();
}
/**
* Setup for AVM tests. Note that we set the polling
* interval for the reaper to 4 seconds so that tests will
* finish reasonably quickly.
*/
@Override
protected void setUp() throws Exception
{
if (fContext == null)
{
fContext = AVMTestSuite.getContext();
fService = (AVMService)fContext.getBean("AVMService");
fReaper = (OrphanReaper)fContext.getBean("orphanReaper");
fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService");
fIndexerAndSearcher = (IndexerAndSearcher)fContext.getBean("indexerAndSearcherFactory");
fTransactionService = (TransactionService)fContext.getBean("transactionComponent");
fLockingService = (AVMLockingService)fContext.getBean("AVMLockingService");
fIndexingInterceptor = (AVMSnapShotTriggeredIndexingMethodInterceptor)fContext.getBean("avmSnapShotTriggeredIndexingMethodInterceptor");
fAuthService = (AuthenticationService)fContext.getBean("AuthenticationService");
fAuthenticationComponent = (AuthenticationComponent) fContext.getBean("authenticationComponent");
fRetryingTransactionHelper = (RetryingTransactionHelper) fContext.getBean("retryingTransactionHelper");
CreateStoreTxnListener cstl = (CreateStoreTxnListener)fContext.getBean("createStoreTxnListener");
cstl.addCallback(
new CreateStoreCallback()
{
public void storeCreated(String name)
{
//System.err.println("Store created: " + name);
}
}
);
PurgeStoreTxnListener pstl = (PurgeStoreTxnListener)fContext.getBean("purgeStoreTxnListener");
pstl.addCallback(
new PurgeStoreCallback()
{
public void storePurged(String name)
{
//System.err.println("Store purged: " + name);
}
}
);
CreateVersionTxnListener cvtl = (CreateVersionTxnListener)fContext.getBean("createVersionTxnListener");
cvtl.addCallback(
new CreateVersionCallback()
{
public void versionCreated(String name, int versionID)
{
//System.err.println("Version created: " + name + " " + versionID);
}
}
);
PurgeVersionTxnListener pvtl = (PurgeVersionTxnListener)fContext.getBean("purgeVersionTxnListener");
pvtl.addCallback(
new PurgeVersionCallback()
{
public void versionPurged(String name, int versionID)
{
//System.err.println("Version purged: " + name + " " + versionID);
}
}
);
}
fAuthService.authenticate(AuthenticationUtil.getAdminUserName(), "admin".toCharArray());
if (fService.getStore("main") != null)
{
fService.purgeStore("main");
}
fService.createStore("main");
if (fService.getStore("layer") != null)
{
fService.purgeStore("layer");
}
fStartTime = System.currentTimeMillis();
}
/**
* Cleanup after a test. Purge main store.
*/
@Override
protected void tearDown() throws Exception
{
long now = System.currentTimeMillis();
System.out.println("Timing: " + (now - fStartTime) + "ms");
if (fService.getStore("main") != null) { fService.purgeStore("main"); }
// Move alf_data directory aside.
// fContext.close();
// File alfData = new File("alf_data");
// File target = new File("alf_data" + now);
// alfData.renameTo(target);
AuthenticationUtil.clearCurrentSecurityContext();
}
/**
* Get the recursive contents of the given path and version.
* @param path
* @param version
* @return A string representation of the contents.
*/
protected String recursiveContents(String path, int version, boolean followLinks)
{
String val = recursiveList(path, version, 0, followLinks);
return val.substring(val.indexOf('\n'));
}
/**
* Helper to write a recursive listing of an AVMStore at a given version.
* @param repoName The name of the AVMStore.
* @param version The version to look under.
*/
protected String recursiveList(String repoName, int version, boolean followLinks)
{
return recursiveList(repoName + ":/", version, 0, followLinks);
}
/**
* Recursive list the given path.
* @param path The path.
* @param version The version.
* @param indent The current indent level.
*/
protected String recursiveList(String path, int version, int indent, boolean followLinks)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < indent; i++)
{
builder.append(' ');
}
builder.append(path.substring(path.lastIndexOf('/') + 1));
builder.append(' ');
AVMNodeDescriptor desc = fService.lookup(version, path, true);
builder.append(desc.toString());
builder.append('\n');
if (desc.getType() == AVMNodeType.PLAIN_DIRECTORY ||
(desc.getType() == AVMNodeType.LAYERED_DIRECTORY && followLinks))
{
String basename = path.endsWith("/") ? path : path + "/";
Map<String, AVMNodeDescriptor> listing = fService.getDirectoryListing(version, path, true);
for (String name : listing.keySet())
{
System.err.println(name);
builder.append(recursiveList(basename + name, version, indent + 2, followLinks));
}
}
return builder.toString();
}
/**
* Setup a basic tree.
*/
protected void setupBasicTree0()
throws IOException
{
fService.createDirectory("main:/", "a");
fService.createDirectory("main:/a", "b");
fService.createDirectory("main:/a/b", "c");
fService.createDirectory("main:/", "d");
fService.createDirectory("main:/d", "e");
fService.createDirectory("main:/d/e", "f");
fService.createFile("main:/a/b/c", "foo").close();
ContentWriter writer = fService.getContentWriter("main:/a/b/c/foo", true);
writer.setEncoding("UTF-8");
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.putContent("I am main:/a/b/c/foo");
fService.createFile("main:/a/b/c", "bar").close();
writer = fService.getContentWriter("main:/a/b/c/bar", true);
/*
// Force a conversion
writer.setEncoding("UTF-16");
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.putContent(new ByteArrayInputStream("I am main:/a/b/c/bar".getBytes("UTF-16")));
*/
writer.setEncoding("UTF-8");
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.putContent("I am main:/a/b/c/bar");
fService.createSnapshot("main", null, null);
}
protected void setupBasicTree()
throws IOException
{
setupBasicTree0();
runQueriesAgainstBasicTree("main");
}
protected void runQueriesAgainstBasicTree(String store)
{
StoreRef storeRef = AVMNodeConverter.ToStoreRef(store);
// Text index
SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef(store), true);
ResultSet results = searchService.query(storeRef, "lucene", "TEXT:\"I am main\"");
assertEquals(2, results.length());
results.close();
// Basic properties
// Note "a" is a stop word and therefore not findable ...
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":\"foo\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":foo");
assertEquals(1, results.length());
results.close();
// TODO: Fix auth in AVMDiskDriver and more??
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_CREATOR)+":admin");
assertEquals(9, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_MODIFIER)+":admin");
assertEquals(9, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_OWNER)+":admin");
assertEquals(9, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NODE_UUID)+":unknown");
assertEquals(9, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_PROTOCOL)+":avm");
assertEquals(9, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_IDENTIFIER)+":"+store);
assertEquals(9, results.length());
results.close();
// Basic paths
results = searchService.query(storeRef, "lucene", "PATH:\"/\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/foo\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/bar\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/d\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/d/e\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/d/e/f\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(9, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"//*\"");
assertEquals(8, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a//.\"");
assertEquals(5, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a//*\"");
assertEquals(4, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/*\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"//c/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*/*\"");
assertEquals(0, results.length());
results.close();
}
protected void runQueriesAgainstBasicTreeWithAOnly(String store)
{
StoreRef storeRef = AVMNodeConverter.ToStoreRef(store);
// Text index
SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef(store), true);
ResultSet results = searchService.query(storeRef, "lucene", "TEXT:\"I am main\"");
assertEquals(2, results.length());
results.close();
// Basic properties
// Note "a" is a stop word and therefore not findable ...
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":\"foo\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":foo");
assertEquals(1, results.length());
results.close();
// TODO: Fix auth in AVMDiskDriver and more??
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_CREATOR)+":admin");
if(results.length() == 10)
{
for (ResultSetRow row : results)
{
System.out.println(row.getNodeRef());
}
}
assertEquals(6, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_MODIFIER)+":admin");
assertEquals(6, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_OWNER)+":admin");
assertEquals(6, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NODE_UUID)+":unknown");
assertEquals(6, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_PROTOCOL)+":avm");
assertEquals(6, results.length());
results.close();
results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_IDENTIFIER)+":"+store);
assertEquals(6, results.length());
results.close();
// Basic paths
results = searchService.query(storeRef, "lucene", "PATH:\"/\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/foo\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/bar\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/d\"");
assertEquals(0, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/d/e\"");
assertEquals(0, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/d/e/f\"");
assertEquals(0, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(6, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"//*\"");
assertEquals(5, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a//.\"");
assertEquals(5, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a//*\"");
assertEquals(4, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/a/*\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"//c/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*\"");
assertEquals(1, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*\"");
assertEquals(2, results.length());
results.close();
results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*/*\"");
assertEquals(0, results.length());
results.close();
}
/**
* Check that history has not been screwed up.
*/
protected void checkHistory(TreeMap<Integer, String> history, String repName)
{
for (Integer i : history.keySet())
{
assertEquals(history.get(i), recursiveList(repName, i, false));
}
int latest = fService.getNextVersionID(repName);
history.put(latest - 1, recursiveList(repName, -1, false));
}
}