mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-22 15:12:38 +00:00
REPO-1012 : DB builds: Fix a batch of tests that (regularly) fail on SQL Server
- adding retrying transactions for the propertyValueDAO.cleanupUnusedValues() method calls as MS SQL is slow and has problems coping with other threads updating the alf_prop_ tables - changed the order of the tests to help reduce other tests failing because of these clean up tests git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@129495 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -60,13 +60,17 @@ import org.junit.runners.Suite;
|
|||||||
LocaleDAOTest.class,
|
LocaleDAOTest.class,
|
||||||
QNameDAOTest.class,
|
QNameDAOTest.class,
|
||||||
PropertyValueDAOTest.class,
|
PropertyValueDAOTest.class,
|
||||||
PropertyValueCleanupTest.class,
|
|
||||||
AuditDAOTest.class,
|
|
||||||
AppliedPatchDAOTest.class,
|
AppliedPatchDAOTest.class,
|
||||||
AclCrudDAOTest.class,
|
AclCrudDAOTest.class,
|
||||||
UsageDAOTest.class,
|
UsageDAOTest.class,
|
||||||
SOLRDAOTest.class,
|
SOLRDAOTest.class,
|
||||||
TenantAdminDAOTest.class,
|
TenantAdminDAOTest.class,
|
||||||
|
// REOPO-1012 : run AuditDAOTest and PropertyValueCleanupTest near the end
|
||||||
|
// because their failure can cause other tests to fail on MS SQL
|
||||||
|
// AuditDAOTest fails if it runs after CannedQueryDAOTest so this order is a compromise
|
||||||
|
// CannedQueryDAOTest will fail on MS SQL if either AuditDAOTest or PropertyValueCleanupTest fail
|
||||||
|
PropertyValueCleanupTest.class,
|
||||||
|
AuditDAOTest.class,
|
||||||
CannedQueryDAOTest.class
|
CannedQueryDAOTest.class
|
||||||
})
|
})
|
||||||
public class DomainTestSuite
|
public class DomainTestSuite
|
||||||
|
|||||||
@@ -719,11 +719,11 @@ public class AuditDAOTest extends TestCase
|
|||||||
if (dialect instanceof AlfrescoMySQLClusterNDBDialect)
|
if (dialect instanceof AlfrescoMySQLClusterNDBDialect)
|
||||||
{
|
{
|
||||||
throw new Exception("TODO review this test case with NDB - note: throw exeception here else causes later tests to fail (when running via DomainTestSuite)");
|
throw new Exception("TODO review this test case with NDB - note: throw exeception here else causes later tests to fail (when running via DomainTestSuite)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// single test
|
// single test
|
||||||
scriptCanDeleteOrphanedPropsWork(false);
|
scriptCanDeleteOrphanedPropsWork(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMaxResults() throws Exception
|
public void testMaxResults() throws Exception
|
||||||
{
|
{
|
||||||
@@ -804,8 +804,6 @@ public class AuditDAOTest extends TestCase
|
|||||||
txn.commit();
|
txn.commit();
|
||||||
System.out.println("Created values for " + i + " entries in " + (System.currentTimeMillis() - startCreate) + " ms.");
|
System.out.println("Created values for " + i + " entries in " + (System.currentTimeMillis() - startCreate) + " ms.");
|
||||||
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
if (!performance)
|
if (!performance)
|
||||||
{
|
{
|
||||||
// Check there are some persisted values to delete.
|
// Check there are some persisted values to delete.
|
||||||
@@ -826,9 +824,19 @@ public class AuditDAOTest extends TestCase
|
|||||||
assertEquals(dateValue, propertyValueDAO.getPropertyValue(dateValue).getSecond());
|
assertEquals(dateValue, propertyValueDAO.getPropertyValue(dateValue).getSecond());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long startDelete = System.currentTimeMillis();
|
long startDelete = System.currentTimeMillis();
|
||||||
propertyValueDAO.cleanupUnusedValues();
|
RetryingTransactionCallback<Void> callback = new RetryingTransactionCallback<Void>()
|
||||||
txn.commit();
|
{
|
||||||
|
public Void execute() throws Throwable
|
||||||
|
{
|
||||||
|
propertyValueDAO.cleanupUnusedValues();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// use a new transaction so it will retry in that transaction
|
||||||
|
txnHelper.doInTransaction(callback,false,true);
|
||||||
|
|
||||||
System.out.println("Cleaned values for " + i + " entries in " + (System.currentTimeMillis() - startDelete) + " ms.");
|
System.out.println("Cleaned values for " + i + " entries in " + (System.currentTimeMillis() - startDelete) + " ms.");
|
||||||
|
|
||||||
if (!performance)
|
if (!performance)
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ import java.util.List;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
import org.alfresco.test_category.OwnJVMTestsCategory;
|
||||||
@@ -60,15 +61,12 @@ public class PropertyValueCleanupTest
|
|||||||
|
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
private AttributeService attributeService;
|
private AttributeService attributeService;
|
||||||
private RetryingTransactionHelper txnHelper;
|
|
||||||
private PropertyValueDAO propertyValueDAO;
|
private PropertyValueDAO propertyValueDAO;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception
|
public void setUp() throws Exception
|
||||||
{
|
{
|
||||||
transactionService = (TransactionService) ctx.getBean("TransactionService");
|
transactionService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
txnHelper = transactionService.getRetryingTransactionHelper();
|
|
||||||
txnHelper.setMaxRetries(0);
|
|
||||||
|
|
||||||
attributeService = (AttributeService) ctx.getBean("AttributeService");
|
attributeService = (AttributeService) ctx.getBean("AttributeService");
|
||||||
propertyValueDAO = (PropertyValueDAO) ctx.getBean("propertyValueDAO");
|
propertyValueDAO = (PropertyValueDAO) ctx.getBean("propertyValueDAO");
|
||||||
@@ -81,81 +79,98 @@ public class PropertyValueCleanupTest
|
|||||||
{
|
{
|
||||||
((AbstractPropertyValueDAOImpl)propertyValueDAO).clearCaches();
|
((AbstractPropertyValueDAOImpl)propertyValueDAO).clearCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public synchronized void testRapidCreationDuringCleanup() throws Exception
|
public synchronized void testRapidCreationDuringCleanup() throws Exception
|
||||||
{
|
{
|
||||||
// Create and delete some well-known attributes
|
// Create and delete some well-known attributes
|
||||||
String toDeleteKey1 = "testRapidCreationDuringCleanup";
|
String toDeleteKey1 = "testRapidCreationDuringCleanup";
|
||||||
String toDeleteKey2 = UUID.randomUUID().toString();
|
String toDeleteKey2 = UUID.randomUUID().toString();
|
||||||
byte[] toDeleteProp = new String("Key is " + toDeleteKey2).getBytes("US-ASCII");
|
byte[] toDeleteProp = new String("Key is " + toDeleteKey2).getBytes("US-ASCII");
|
||||||
assertNull("Did not expect to find the attribute ", attributeService.getAttribute(toDeleteKey1, toDeleteKey2));
|
assertNull("Did not expect to find the attribute ", attributeService.getAttribute(toDeleteKey1, toDeleteKey2));
|
||||||
assertNull("Key2 should be NOT present as a property value", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
assertNull("Key2 should be NOT present as a property value", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
||||||
attributeService.createAttribute(toDeleteProp, toDeleteKey1, toDeleteKey2);
|
attributeService.createAttribute(toDeleteProp, toDeleteKey1, toDeleteKey2);
|
||||||
assertNotNull("Did not find the attribute ", attributeService.getAttribute(toDeleteKey1, toDeleteKey2));
|
assertNotNull("Did not find the attribute ", attributeService.getAttribute(toDeleteKey1, toDeleteKey2));
|
||||||
// Check that we can get hold of the underlying property
|
// Check that we can get hold of the underlying property
|
||||||
assertNotNull("Key2 should be present as a property value", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
assertNotNull("Key2 should be present as a property value", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
||||||
// Delete the attribute
|
// Delete the attribute
|
||||||
attributeService.removeAttribute(toDeleteKey1, toDeleteKey2);
|
attributeService.removeAttribute(toDeleteKey1, toDeleteKey2);
|
||||||
// Check that we can STILL get hold of the underlying property
|
// Check that we can STILL get hold of the underlying property
|
||||||
assertNotNull("Key2 should be present as a property value (even if unreferenced)", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
assertNotNull("Key2 should be present as a property value (even if unreferenced)", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
||||||
|
|
||||||
// Start threads that throw stuff into the AttributeService
|
// Start threads that throw stuff into the AttributeService
|
||||||
ThreadGroup threadGroup = new ThreadGroup("testRapidCreationDuringCleanup");
|
ThreadGroup threadGroup = new ThreadGroup("testRapidCreationDuringCleanup");
|
||||||
InsertSerializableAttributes[] runnables = new InsertSerializableAttributes[2];
|
InsertSerializableAttributes[] runnables = new InsertSerializableAttributes[2];
|
||||||
for (int i = 0; i < runnables.length; i++)
|
|
||||||
{
|
try
|
||||||
// Runnable
|
{
|
||||||
runnables[i] = new InsertSerializableAttributes();
|
for (int i = 0; i < runnables.length; i++)
|
||||||
// Put it in a thread
|
{
|
||||||
String threadName = "" + i;
|
// Runnable
|
||||||
Thread thread = new Thread(threadGroup, runnables[i], threadName);
|
runnables[i] = new InsertSerializableAttributes();
|
||||||
thread.setDaemon(true); // Precautionary
|
// Put it in a thread
|
||||||
// Start it
|
String threadName = "" + i;
|
||||||
thread.start();
|
Thread thread = new Thread(threadGroup, runnables[i], threadName);
|
||||||
}
|
thread.setDaemon(true); // Precautionary
|
||||||
|
// Start it
|
||||||
// Wait a bit for data to really get in there
|
thread.start();
|
||||||
wait(1000L);
|
}
|
||||||
|
|
||||||
// Now run the cleanup script
|
// Wait a bit for data to really get in there
|
||||||
propertyValueDAO.cleanupUnusedValues();
|
wait(1000L);
|
||||||
|
|
||||||
// Stop the threads
|
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
|
||||||
for (int i = 0; i < runnables.length; i++)
|
// do it in a retrying transaction because there may be other threads modifying
|
||||||
{
|
// the alf_prop_* and therefore the cleanup may fail sometimes
|
||||||
// Runnable
|
RetryingTransactionCallback<Void> callback = new RetryingTransactionCallback<Void>()
|
||||||
runnables[i].running.set(false);
|
{
|
||||||
}
|
public Void execute() throws Throwable
|
||||||
|
{
|
||||||
// Clear any caches
|
// Now run the cleanup script
|
||||||
clearCaches();
|
propertyValueDAO.cleanupUnusedValues();
|
||||||
|
|
||||||
// The cleanup should have removed the key2
|
return null;
|
||||||
assertNull("Key2 should be NOT present as a property value (cleanup job)", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
}
|
||||||
|
};
|
||||||
// Now check that all the properties written can still be retrieved
|
txnHelper.doInTransaction(callback);
|
||||||
for (int i = 0; i < runnables.length; i++)
|
}
|
||||||
{
|
finally
|
||||||
// Runnable
|
{
|
||||||
String key1 = runnables[i].key1;
|
// Make sure we stop the Daemons
|
||||||
String key2 = runnables[i].key2;
|
for (int i = 0; i < runnables.length; i++)
|
||||||
List<Integer> key3s = new ArrayList<Integer>(runnables[i].key3s); // Copy entire list
|
{
|
||||||
for (Integer key3 : key3s)
|
// Runnable
|
||||||
{
|
runnables[i].running.set(false);
|
||||||
// Get the attribute
|
}
|
||||||
byte[] propFetched = (byte[]) attributeService.getAttribute(key1, key2, key3);
|
}
|
||||||
if (propFetched == null)
|
// Clear any caches
|
||||||
{
|
clearCaches();
|
||||||
// This is OK. As long as we don't get a failure
|
|
||||||
continue;
|
// The cleanup should have removed the key2
|
||||||
}
|
assertNull("Key2 should be NOT present as a property value (cleanup job)", propertyValueDAO.getPropertyStringValue(toDeleteKey2));
|
||||||
assertTrue(
|
|
||||||
"Arrays were not equal for " + key1 + ", " + key2 + ", " + key3,
|
// Now check that all the properties written can still be retrieved
|
||||||
Arrays.equals(runnables[i].prop, propFetched));
|
for (int i = 0; i < runnables.length; i++)
|
||||||
}
|
{
|
||||||
}
|
// Runnable
|
||||||
}
|
String key1 = runnables[i].key1;
|
||||||
|
String key2 = runnables[i].key2;
|
||||||
|
List<Integer> key3s = new ArrayList<Integer>(runnables[i].key3s); // Copy entire list
|
||||||
|
for (Integer key3 : key3s)
|
||||||
|
{
|
||||||
|
// Get the attribute
|
||||||
|
byte[] propFetched = (byte[]) attributeService.getAttribute(key1, key2, key3);
|
||||||
|
if (propFetched == null)
|
||||||
|
{
|
||||||
|
// This is OK. As long as we don't get a failure
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assertTrue(
|
||||||
|
"Arrays were not equal for " + key1 + ", " + key2 + ", " + key3,
|
||||||
|
Arrays.equals(runnables[i].prop, propFetched));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple runnable that continuously creates new serializable attributes until stopped.
|
* Simple runnable that continuously creates new serializable attributes until stopped.
|
||||||
|
|||||||
Reference in New Issue
Block a user