mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
ACS-9259 Improve stability of HazelcastLockStoreTxTest test (#3248)
This commit is contained in:
@@ -1,494 +1,489 @@
|
|||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
* provided under the following open source license terms:
|
* provided under the following open source license terms:
|
||||||
*
|
*
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Alfresco is distributed in the hope that it will be useful,
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
package org.alfresco.repo.lock.mem;
|
package org.alfresco.repo.lock.mem;
|
||||||
|
|
||||||
import java.util.Date;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import jakarta.transaction.NotSupportedException;
|
import static org.junit.Assert.fail;
|
||||||
import jakarta.transaction.SystemException;
|
|
||||||
import jakarta.transaction.UserTransaction;
|
import java.util.Date;
|
||||||
|
import jakarta.transaction.NotSupportedException;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import jakarta.transaction.SystemException;
|
||||||
import org.alfresco.service.cmr.lock.LockType;
|
import jakarta.transaction.UserTransaction;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.junit.Before;
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Before;
|
import org.junit.Test;
|
||||||
import org.junit.BeforeClass;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.junit.Test;
|
import org.springframework.dao.ConcurrencyFailureException;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.dao.ConcurrencyFailureException;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.service.cmr.lock.LockType;
|
||||||
import static org.junit.Assert.assertEquals;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import static org.junit.Assert.assertNull;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import static org.junit.Assert.fail;
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests that check transaction related functionality of {@link LockStore} implementations.
|
* Integration tests that check transaction related functionality of {@link LockStore} implementations.
|
||||||
* @author Matt Ward
|
*
|
||||||
*/
|
* @author Matt Ward
|
||||||
public abstract class AbstractLockStoreTxTest<T extends LockStore>
|
*/
|
||||||
{
|
public abstract class AbstractLockStoreTxTest<T extends LockStore>
|
||||||
/**
|
{
|
||||||
* Instance of the Class Under Test.
|
/**
|
||||||
*/
|
* Instance of the Class Under Test.
|
||||||
protected T lockStore;
|
*/
|
||||||
|
protected T lockStore;
|
||||||
protected static ApplicationContext ctx;
|
|
||||||
protected static TransactionService transactionService;
|
protected static ApplicationContext ctx;
|
||||||
|
protected static TransactionService transactionService;
|
||||||
/**
|
|
||||||
* Concrete subclasses must implement this method to provide the tests with a LockStore instance.
|
/**
|
||||||
*
|
* Concrete subclasses must implement this method to provide the tests with a LockStore instance.
|
||||||
* @return LockStore to test
|
*
|
||||||
*/
|
* @return LockStore to test
|
||||||
protected abstract T createLockStore();
|
*/
|
||||||
|
protected abstract T createLockStore();
|
||||||
@BeforeClass
|
|
||||||
public static void setUpSpringContext()
|
@BeforeClass
|
||||||
{
|
public static void setUpSpringContext()
|
||||||
ctx = ApplicationContextHelper.getApplicationContext();
|
{
|
||||||
transactionService = (TransactionService) ctx.getBean("TransactionService");
|
ctx = ApplicationContextHelper.getApplicationContext();
|
||||||
}
|
transactionService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
|
}
|
||||||
@Before
|
|
||||||
public void setUpLockStore()
|
@Before
|
||||||
{
|
public void setUpLockStore()
|
||||||
lockStore = createLockStore();
|
{
|
||||||
}
|
lockStore = createLockStore();
|
||||||
|
}
|
||||||
/**
|
|
||||||
* <ul>
|
/**
|
||||||
* <li>Start outer txn</li>
|
* <ul>
|
||||||
* <li>Modify lock in outer txn</li>
|
* <li>Start outer txn</li>
|
||||||
* <li>Start inner txn</li>
|
* <li>Modify lock in outer txn</li>
|
||||||
* <li>Modify lock in inner txn</li>
|
* <li>Start inner txn</li>
|
||||||
* </ul>
|
* <li>Modify lock in inner txn</li>
|
||||||
* Inner transaction should fail while outer succeeds
|
* </ul>
|
||||||
*/
|
* Inner transaction should fail while outer succeeds
|
||||||
@Test
|
*/
|
||||||
public void testRepeatableRead_01() throws Exception
|
@Test
|
||||||
{
|
public void testRepeatableRead_01() throws Exception
|
||||||
|
{
|
||||||
}
|
|
||||||
|
}
|
||||||
@Test
|
|
||||||
public void testRepeatableReadsInTransaction() throws NotSupportedException, SystemException
|
@Test
|
||||||
{
|
public void testRepeatableReadsInTransaction() throws NotSupportedException, SystemException
|
||||||
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
{
|
||||||
UserTransaction txA = txService.getUserTransaction();
|
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
|
UserTransaction txA = txService.getUserTransaction();
|
||||||
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
|
||||||
final NodeRef nodeRef2 = new NodeRef("workspace://SpacesStore/UUID-2");
|
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
||||||
Date now = new Date();
|
final NodeRef nodeRef2 = new NodeRef("workspace://SpacesStore/UUID-2");
|
||||||
Date expires = new Date(now.getTime() + 180000);
|
Date now = new Date();
|
||||||
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
Date expires = new Date(now.getTime() + 180000);
|
||||||
"jbloggs", expires, Lifetime.EPHEMERAL, null);
|
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
|
"jbloggs", expires, Lifetime.EPHEMERAL, null);
|
||||||
|
|
||||||
Thread txB = new Thread("TxB")
|
Thread txB = new Thread("TxB") {
|
||||||
{
|
@Override
|
||||||
@Override
|
public void run()
|
||||||
public void run()
|
{
|
||||||
{
|
Object main = AbstractLockStoreTxTest.this;
|
||||||
Object main = AbstractLockStoreTxTest.this;
|
UserTransaction tx = txService.getUserTransaction();
|
||||||
UserTransaction tx = txService.getUserTransaction();
|
try
|
||||||
try
|
{
|
||||||
{
|
tx.begin();
|
||||||
tx.begin();
|
try
|
||||||
try
|
{
|
||||||
{
|
// txB read lock state
|
||||||
// txB read lock state
|
LockState lockState = lockStore.get(nodeRef);
|
||||||
LockState lockState = lockStore.get(nodeRef);
|
assertEquals("jbloggs", lockState.getOwner());
|
||||||
assertEquals("jbloggs", lockState.getOwner());
|
assertEquals(Lifetime.EPHEMERAL, lockState.getLifetime());
|
||||||
assertEquals(Lifetime.EPHEMERAL, lockState.getLifetime());
|
|
||||||
|
// Wait, while txA changes the lock state
|
||||||
// Wait, while txA changes the lock state
|
passControl(this, main);
|
||||||
passControl(this, main);
|
|
||||||
|
// assert txB still sees state A
|
||||||
// assert txB still sees state A
|
lockState = lockStore.get(nodeRef);
|
||||||
lockState = lockStore.get(nodeRef);
|
assertEquals("jbloggs", lockState.getOwner());
|
||||||
assertEquals("jbloggs", lockState.getOwner());
|
|
||||||
|
// Wait, while txA checks whether it can see lock for nodeRef2 (though it doesn't exist yet)
|
||||||
// Wait, while txA checks whether it can see lock for nodeRef2 (though it doesn't exist yet)
|
passControl(this, main);
|
||||||
passControl(this, main);
|
|
||||||
|
// txB sets a value, already seen as non-existent lock by txA
|
||||||
// txB sets a value, already seen as non-existent lock by txA
|
lockStore.set(nodeRef2, LockState.createLock(nodeRef2, LockType.WRITE_LOCK,
|
||||||
lockStore.set(nodeRef2, LockState.createLock(nodeRef2, LockType.WRITE_LOCK,
|
"csmith", null, Lifetime.EPHEMERAL, null));
|
||||||
"csmith", null, Lifetime.EPHEMERAL, null));
|
}
|
||||||
}
|
finally
|
||||||
finally
|
{
|
||||||
{
|
tx.rollback();
|
||||||
tx.rollback();
|
}
|
||||||
}
|
}
|
||||||
}
|
catch (Throwable e)
|
||||||
catch (Throwable e)
|
{
|
||||||
{
|
throw new RuntimeException("Error in transaction B", e);
|
||||||
throw new RuntimeException("Error in transaction B", e);
|
}
|
||||||
}
|
finally
|
||||||
finally
|
{
|
||||||
{
|
// Stop 'main' from waiting
|
||||||
// Stop 'main' from waiting
|
synchronized (main)
|
||||||
synchronized(main)
|
{
|
||||||
{
|
main.notifyAll();
|
||||||
main.notifyAll();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
txA.begin();
|
||||||
txA.begin();
|
try
|
||||||
try
|
{
|
||||||
{
|
// txA set lock state 1
|
||||||
// txA set lock state 1
|
lockStore.set(nodeRef, lockState1);
|
||||||
lockStore.set(nodeRef, lockState1);
|
|
||||||
|
// Perform a read, that we know will retrieve a null value (and null will be cached for this transaction)
|
||||||
// Wait while txB reads and checks the LockState
|
assertNull("nodeRef2 LockState", lockStore.get(nodeRef2));
|
||||||
txB.setDaemon(true);
|
|
||||||
txB.start();
|
// Wait while txB reads and checks the LockState
|
||||||
passControl(this, txB);
|
txB.setDaemon(true);
|
||||||
|
txB.start();
|
||||||
// txA set different lock state
|
passControl(this, txB);
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner needed to change lock.
|
|
||||||
final LockState lockState2 = LockState.createWithOwner(lockState1, "another");
|
// txA set different lock state
|
||||||
lockStore.set(nodeRef, lockState2);
|
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner needed to change lock.
|
||||||
|
final LockState lockState2 = LockState.createWithOwner(lockState1, "another");
|
||||||
// Wait while txB reads/checks the LockState again for nodeRef
|
lockStore.set(nodeRef, lockState2);
|
||||||
passControl(this, txB);
|
|
||||||
|
// Wait while txB reads/checks the LockState again for nodeRef
|
||||||
// Another update
|
passControl(this, txB);
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("another"); // Current lock owner needed to change lock.
|
|
||||||
final LockState lockState3 = LockState.createWithOwner(lockState2, "bsmith");
|
// Another update
|
||||||
lockStore.set(nodeRef, lockState3);
|
AuthenticationUtil.setFullyAuthenticatedUser("another"); // Current lock owner needed to change lock.
|
||||||
// Check we can see the update.
|
final LockState lockState3 = LockState.createWithOwner(lockState2, "bsmith");
|
||||||
assertEquals("bsmith", lockStore.get(nodeRef).getOwner());
|
lockStore.set(nodeRef, lockState3);
|
||||||
|
// Check we can see the update.
|
||||||
// Perform a read, that we know will retrieve a null value
|
assertEquals("bsmith", lockStore.get(nodeRef).getOwner());
|
||||||
assertNull("nodeRef2 LockState", lockStore.get(nodeRef2));
|
|
||||||
|
// Wait while txB populates the store with a value for nodeRef2
|
||||||
// Wait while txB populates the store with a value for nodeRef2
|
passControl(this, txB);
|
||||||
passControl(this, txB);
|
|
||||||
|
// Perform the read again - update should not be visible in this transaction (was already cached)
|
||||||
// Perform the read again - update should not be visible in this transaction
|
assertNull("nodeRef2 LockState", lockStore.get(nodeRef2));
|
||||||
assertNull("nodeRef2 LockState", lockStore.get(nodeRef2));
|
}
|
||||||
}
|
finally
|
||||||
finally
|
{
|
||||||
{
|
txA.rollback();
|
||||||
txA.rollback();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
protected void passControl(Object from, Object to)
|
||||||
protected void passControl(Object from, Object to)
|
{
|
||||||
{
|
synchronized (to)
|
||||||
synchronized(to)
|
{
|
||||||
{
|
to.notifyAll();
|
||||||
to.notifyAll();
|
}
|
||||||
}
|
synchronized (from)
|
||||||
synchronized(from)
|
{
|
||||||
{
|
try
|
||||||
try
|
{
|
||||||
{
|
// TODO: wait should be called in a loop with repeated wait condition check,
|
||||||
// TODO: wait should be called in a loop with repeated wait condition check,
|
// but what's the condition we're waiting on?
|
||||||
// but what's the condition we're waiting on?
|
from.wait(10000);
|
||||||
from.wait(10000);
|
}
|
||||||
}
|
catch (InterruptedException error)
|
||||||
catch (InterruptedException error)
|
{
|
||||||
{
|
throw new RuntimeException(error);
|
||||||
throw new RuntimeException(error);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testCannotSetLockWhenChangedByAnotherTx() throws NotSupportedException, SystemException
|
||||||
public void testCannotSetLockWhenChangedByAnotherTx() throws NotSupportedException, SystemException
|
{
|
||||||
{
|
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
UserTransaction txA = txService.getUserTransaction();
|
||||||
UserTransaction txA = txService.getUserTransaction();
|
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
||||||
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
Date now = new Date();
|
||||||
Date now = new Date();
|
Date expires = new Date(now.getTime() + 180000);
|
||||||
Date expires = new Date(now.getTime() + 180000);
|
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
"jbloggs", expires, Lifetime.EPHEMERAL, null);
|
||||||
"jbloggs", expires, Lifetime.EPHEMERAL, null);
|
|
||||||
|
Thread txB = new Thread("TxB") {
|
||||||
|
@Override
|
||||||
Thread txB = new Thread("TxB")
|
public void run()
|
||||||
{
|
{
|
||||||
@Override
|
Object main = AbstractLockStoreTxTest.this;
|
||||||
public void run()
|
UserTransaction tx = txService.getUserTransaction();
|
||||||
{
|
try
|
||||||
Object main = AbstractLockStoreTxTest.this;
|
{
|
||||||
UserTransaction tx = txService.getUserTransaction();
|
tx.begin();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tx.begin();
|
// txB read lock state
|
||||||
try
|
LockState lockState = lockStore.get(nodeRef);
|
||||||
{
|
assertEquals("jbloggs", lockState.getOwner());
|
||||||
// txB read lock state
|
assertEquals(Lifetime.EPHEMERAL, lockState.getLifetime());
|
||||||
LockState lockState = lockStore.get(nodeRef);
|
|
||||||
assertEquals("jbloggs", lockState.getOwner());
|
// Wait, while txA changes the lock state
|
||||||
assertEquals(Lifetime.EPHEMERAL, lockState.getLifetime());
|
passControl(this, main);
|
||||||
|
|
||||||
// Wait, while txA changes the lock state
|
try
|
||||||
passControl(this, main);
|
{
|
||||||
|
// Attempt to change the lock state for a NodeRef should fail
|
||||||
try
|
// when it has been modified by another tx since this tx last inspected it.
|
||||||
{
|
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner
|
||||||
// Attempt to change the lock state for a NodeRef should fail
|
lockStore.set(nodeRef, LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
// when it has been modified by another tx since this tx last inspected it.
|
"csmith", null, Lifetime.EPHEMERAL, null));
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner
|
fail("Exception should have been thrown but was not.");
|
||||||
lockStore.set(nodeRef, LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
}
|
||||||
"csmith", null, Lifetime.EPHEMERAL, null));
|
catch (ConcurrencyFailureException e)
|
||||||
fail("Exception should have been thrown but was not.");
|
{
|
||||||
}
|
// Good!
|
||||||
catch (ConcurrencyFailureException e)
|
}
|
||||||
{
|
}
|
||||||
// Good!
|
finally
|
||||||
}
|
{
|
||||||
}
|
tx.rollback();
|
||||||
finally
|
}
|
||||||
{
|
}
|
||||||
tx.rollback();
|
catch (Throwable e)
|
||||||
}
|
{
|
||||||
}
|
throw new RuntimeException("Error in transaction B", e);
|
||||||
catch (Throwable e)
|
}
|
||||||
{
|
finally
|
||||||
throw new RuntimeException("Error in transaction B", e);
|
{
|
||||||
}
|
// Stop 'main' from waiting
|
||||||
finally
|
synchronized (main)
|
||||||
{
|
{
|
||||||
// Stop 'main' from waiting
|
main.notifyAll();
|
||||||
synchronized(main)
|
}
|
||||||
{
|
}
|
||||||
main.notifyAll();
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
txA.begin();
|
||||||
};
|
try
|
||||||
|
{
|
||||||
txA.begin();
|
// txA set lock state 1
|
||||||
try
|
lockStore.set(nodeRef, lockState1);
|
||||||
{
|
|
||||||
// txA set lock state 1
|
// Wait while txB reads and checks the LockState
|
||||||
lockStore.set(nodeRef, lockState1);
|
txB.setDaemon(true);
|
||||||
|
txB.start();
|
||||||
// Wait while txB reads and checks the LockState
|
passControl(this, txB);
|
||||||
txB.setDaemon(true);
|
|
||||||
txB.start();
|
// txA set different lock state
|
||||||
passControl(this, txB);
|
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner needed to change lock.
|
||||||
|
final LockState lockState2 = LockState.createWithOwner(lockState1, "another");
|
||||||
// txA set different lock state
|
lockStore.set(nodeRef, lockState2);
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner needed to change lock.
|
|
||||||
final LockState lockState2 = LockState.createWithOwner(lockState1, "another");
|
// Wait while txB attempts to modify the lock info
|
||||||
lockStore.set(nodeRef, lockState2);
|
passControl(this, txB);
|
||||||
|
|
||||||
// Wait while txB attempts to modify the lock info
|
// Lock shouldn't have changed since this tx updated it.
|
||||||
passControl(this, txB);
|
assertEquals(lockState2, lockStore.get(nodeRef));
|
||||||
|
}
|
||||||
// Lock shouldn't have changed since this tx updated it.
|
finally
|
||||||
assertEquals(lockState2, lockStore.get(nodeRef));
|
{
|
||||||
}
|
txA.rollback();
|
||||||
finally
|
}
|
||||||
{
|
}
|
||||||
txA.rollback();
|
|
||||||
}
|
@Test
|
||||||
}
|
public void testCanChangeLockIfLatestValueIsHeldEvenIfAlreadyChangedByAnotherTx() throws NotSupportedException, SystemException
|
||||||
|
{
|
||||||
@Test
|
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
public void testCanChangeLockIfLatestValueIsHeldEvenIfAlreadyChangedByAnotherTx() throws NotSupportedException, SystemException
|
UserTransaction txA = txService.getUserTransaction();
|
||||||
{
|
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
||||||
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
final Date now = new Date();
|
||||||
UserTransaction txA = txService.getUserTransaction();
|
Date expired = new Date(now.getTime() - 180000);
|
||||||
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
final Date now = new Date();
|
"jbloggs", expired, Lifetime.EPHEMERAL, null);
|
||||||
Date expired = new Date(now.getTime() - 180000);
|
|
||||||
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
final LockState lockState2 = LockState.createWithOwner(lockState1, "another");
|
||||||
"jbloggs", expired, Lifetime.EPHEMERAL, null);
|
|
||||||
|
Thread txB = new Thread("TxB") {
|
||||||
final LockState lockState2 = LockState.createWithOwner(lockState1, "another");
|
@Override
|
||||||
|
public void run()
|
||||||
Thread txB = new Thread("TxB")
|
{
|
||||||
{
|
Object main = AbstractLockStoreTxTest.this;
|
||||||
@Override
|
UserTransaction tx = txService.getUserTransaction();
|
||||||
public void run()
|
try
|
||||||
{
|
{
|
||||||
Object main = AbstractLockStoreTxTest.this;
|
tx.begin();
|
||||||
UserTransaction tx = txService.getUserTransaction();
|
try
|
||||||
try
|
{
|
||||||
{
|
AuthenticationUtil.setFullyAuthenticatedUser("new-user");
|
||||||
tx.begin();
|
|
||||||
try
|
// txB read lock state
|
||||||
{
|
LockState readLockState = lockStore.get(nodeRef);
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("new-user");
|
assertEquals(lockState2, readLockState);
|
||||||
|
|
||||||
// txB read lock state
|
// Set new value, even though txA has already set new values
|
||||||
LockState readLockState = lockStore.get(nodeRef);
|
// (but not since this tx's initial read)
|
||||||
assertEquals(lockState2, readLockState);
|
Date expiresFuture = new Date(now.getTime() + 180000);
|
||||||
|
final LockState newUserLockState = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
// Set new value, even though txA has already set new values
|
"new-user", expiresFuture, Lifetime.EPHEMERAL, null);
|
||||||
// (but not since this tx's initial read)
|
lockStore.set(nodeRef, newUserLockState);
|
||||||
Date expiresFuture = new Date(now.getTime() + 180000);
|
|
||||||
final LockState newUserLockState = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
// Read
|
||||||
"new-user", expiresFuture, Lifetime.EPHEMERAL, null);
|
assertEquals(newUserLockState, lockStore.get(nodeRef));
|
||||||
lockStore.set(nodeRef, newUserLockState);
|
}
|
||||||
|
finally
|
||||||
// Read
|
{
|
||||||
assertEquals(newUserLockState, lockStore.get(nodeRef));
|
tx.rollback();
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
{
|
catch (Throwable e)
|
||||||
tx.rollback();
|
{
|
||||||
}
|
throw new RuntimeException("Error in transaction B", e);
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
finally
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Error in transaction B", e);
|
// Stop 'main' from waiting
|
||||||
}
|
synchronized (main)
|
||||||
finally
|
{
|
||||||
{
|
main.notifyAll();
|
||||||
// Stop 'main' from waiting
|
}
|
||||||
synchronized(main)
|
}
|
||||||
{
|
}
|
||||||
main.notifyAll();
|
};
|
||||||
}
|
|
||||||
}
|
txA.begin();
|
||||||
}
|
try
|
||||||
};
|
{
|
||||||
|
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner needed to change lock.
|
||||||
txA.begin();
|
|
||||||
try
|
// txA set lock state 1
|
||||||
{
|
lockStore.set(nodeRef, lockState1);
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs"); // Current lock owner needed to change lock.
|
assertEquals(lockState1, lockStore.get(nodeRef));
|
||||||
|
|
||||||
// txA set lock state 1
|
// txA set different lock state
|
||||||
lockStore.set(nodeRef, lockState1);
|
lockStore.set(nodeRef, lockState2);
|
||||||
assertEquals(lockState1, lockStore.get(nodeRef));
|
assertEquals(lockState2, lockStore.get(nodeRef));
|
||||||
|
|
||||||
// txA set different lock state
|
// Wait while txB modifies the lock info
|
||||||
lockStore.set(nodeRef, lockState2);
|
txB.setDaemon(true);
|
||||||
assertEquals(lockState2, lockStore.get(nodeRef));
|
txB.start();
|
||||||
|
passControl(this, txB);
|
||||||
// Wait while txB modifies the lock info
|
|
||||||
txB.setDaemon(true);
|
// This tx should still see the same state, though it has been changed by txB.
|
||||||
txB.start();
|
assertEquals(lockState2, lockStore.get(nodeRef));
|
||||||
passControl(this, txB);
|
}
|
||||||
|
finally
|
||||||
// This tx should still see the same state, though it has been changed by txB.
|
{
|
||||||
assertEquals(lockState2, lockStore.get(nodeRef));
|
txA.rollback();
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
{
|
|
||||||
txA.rollback();
|
@Test
|
||||||
}
|
public void testNotOnlyCurrentLockOwnerCanChangeInfo() throws NotSupportedException, SystemException
|
||||||
}
|
{
|
||||||
|
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
|
UserTransaction txA = txService.getUserTransaction();
|
||||||
@Test
|
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
||||||
public void testNotOnlyCurrentLockOwnerCanChangeInfo() throws NotSupportedException, SystemException
|
Date now = new Date();
|
||||||
{
|
Date expires = new Date(now.getTime() + 180000);
|
||||||
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
UserTransaction txA = txService.getUserTransaction();
|
"jbloggs", expires, Lifetime.EPHEMERAL, null);
|
||||||
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
|
||||||
Date now = new Date();
|
txA.begin();
|
||||||
Date expires = new Date(now.getTime() + 180000);
|
try
|
||||||
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
{
|
||||||
"jbloggs", expires, Lifetime.EPHEMERAL, null);
|
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs");
|
||||||
|
|
||||||
txA.begin();
|
// Set initial lock state
|
||||||
try
|
lockStore.set(nodeRef, lockState1);
|
||||||
{
|
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs");
|
// Set different lock state
|
||||||
|
// Current lock owner is still authenticated (jbloggs)
|
||||||
// Set initial lock state
|
final LockState lockState2 = LockState.createWithOwner(lockState1, "csmith");
|
||||||
lockStore.set(nodeRef, lockState1);
|
lockStore.set(nodeRef, lockState2);
|
||||||
|
|
||||||
// Set different lock state
|
// Check update
|
||||||
// Current lock owner is still authenticated (jbloggs)
|
assertEquals(lockState2, lockStore.get(nodeRef));
|
||||||
final LockState lockState2 = LockState.createWithOwner(lockState1, "csmith");
|
|
||||||
lockStore.set(nodeRef, lockState2);
|
// Incorrect lock owner - this shouldn't fail. See ACE-2181
|
||||||
|
final LockState lockState3 = LockState.createWithOwner(lockState1, "dsmithers");
|
||||||
// Check update
|
|
||||||
assertEquals(lockState2, lockStore.get(nodeRef));
|
lockStore.set(nodeRef, lockState3);
|
||||||
|
|
||||||
// Incorrect lock owner - this shouldn't fail. See ACE-2181
|
// Check update.
|
||||||
final LockState lockState3 = LockState.createWithOwner(lockState1, "dsmithers");
|
assertEquals(lockState3, lockStore.get(nodeRef));
|
||||||
|
}
|
||||||
lockStore.set(nodeRef, lockState3);
|
finally
|
||||||
|
{
|
||||||
// Check update.
|
txA.rollback();
|
||||||
assertEquals(lockState3, lockStore.get(nodeRef));
|
}
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
@Test
|
||||||
txA.rollback();
|
public void testOtherUserCanChangeLockInfoOnceExpired() throws NotSupportedException, SystemException
|
||||||
}
|
{
|
||||||
}
|
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
||||||
|
UserTransaction txA = txService.getUserTransaction();
|
||||||
@Test
|
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
||||||
public void testOtherUserCanChangeLockInfoOnceExpired() throws NotSupportedException, SystemException
|
Date now = new Date();
|
||||||
{
|
Date expired = new Date(now.getTime() - 900);
|
||||||
final TransactionService txService = (TransactionService) ctx.getBean("TransactionService");
|
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
UserTransaction txA = txService.getUserTransaction();
|
"jbloggs", expired, Lifetime.EPHEMERAL, null);
|
||||||
final NodeRef nodeRef = new NodeRef("workspace://SpacesStore/UUID-1");
|
|
||||||
Date now = new Date();
|
txA.begin();
|
||||||
Date expired = new Date(now.getTime() - 900);
|
try
|
||||||
final LockState lockState1 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
{
|
||||||
"jbloggs", expired, Lifetime.EPHEMERAL, null);
|
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs");
|
||||||
|
|
||||||
txA.begin();
|
// Set initial lock state
|
||||||
try
|
lockStore.set(nodeRef, lockState1);
|
||||||
{
|
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("jbloggs");
|
// Set different lock state
|
||||||
|
AuthenticationUtil.setFullyAuthenticatedUser("csmith");
|
||||||
// Set initial lock state
|
Date expiresFuture = new Date(now.getTime() + 180000);
|
||||||
lockStore.set(nodeRef, lockState1);
|
final LockState lockState2 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
||||||
|
"csmith", expiresFuture, Lifetime.EPHEMERAL, null);
|
||||||
// Set different lock state
|
lockStore.set(nodeRef, lockState2);
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("csmith");
|
|
||||||
Date expiresFuture = new Date(now.getTime() + 180000);
|
// Updated, since lock had expired.
|
||||||
final LockState lockState2 = LockState.createLock(nodeRef, LockType.WRITE_LOCK,
|
assertEquals(lockState2, lockStore.get(nodeRef));
|
||||||
"csmith", expiresFuture, Lifetime.EPHEMERAL, null);
|
|
||||||
lockStore.set(nodeRef, lockState2);
|
// Incorrect lock owner - this shouldn't fail
|
||||||
|
// LockStore does not check for lock owning
|
||||||
// Updated, since lock had expired.
|
// and is owned by csmith.
|
||||||
assertEquals(lockState2, lockStore.get(nodeRef));
|
AuthenticationUtil.setFullyAuthenticatedUser("dsmithers");
|
||||||
|
final LockState lockState3 = LockState.createWithOwner(lockState2, "dsmithers");
|
||||||
// Incorrect lock owner - this shouldn't fail
|
|
||||||
// LockStore does not check for lock owning
|
lockStore.set(nodeRef, lockState3);
|
||||||
// and is owned by csmith.
|
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser("dsmithers");
|
// Check update.
|
||||||
final LockState lockState3 = LockState.createWithOwner(lockState2, "dsmithers");
|
assertEquals(lockState3, lockStore.get(nodeRef));
|
||||||
|
}
|
||||||
lockStore.set(nodeRef, lockState3);
|
finally
|
||||||
|
{
|
||||||
// Check update.
|
txA.rollback();
|
||||||
assertEquals(lockState3, lockStore.get(nodeRef));
|
}
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
{
|
|
||||||
txA.rollback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user