/*
* 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 .
*/
package org.alfresco.repo.lock;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.lock.mem.Lifetime;
import org.alfresco.repo.lock.mem.LockState;
import org.alfresco.repo.lock.mem.LockStore;
import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.SearcherComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.lock.NodeLockedException;
import org.alfresco.service.cmr.lock.UnableToAquireLockException;
import org.alfresco.service.cmr.lock.UnableToReleaseLockException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.test_category.BaseSpringTestsCategory;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.TestWithUserUtils;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Simple lock service test
*
* @author Roy Wetherall
*/
@Category(BaseSpringTestsCategory.class)
public class LockServiceImplTest extends BaseSpringTest
{
/**
* Services used in tests
*/
private NodeService nodeService;
private LockService lockService;
private MutableAuthenticationService authenticationService;
private CheckOutCheckInService cociService;
private PermissionService permissionService;
private LockService securedLockService;
/**
* Data used in tests
*/
private NodeRef parentNode;
private NodeRef childNode1;
private NodeRef childNode2;
private NodeRef noAspectNode;
private NodeRef checkedOutNode;
private static final String GOOD_USER_NAME = "goodUser";
private static final String BAD_USER_NAME = "badUser";
private static final String PWD = "password";
NodeRef rootNodeRef;
private StoreRef storeRef;
/**
* Called during the transaction setup
*/
protected void onSetUpInTransaction() throws Exception
{
this.nodeService = (NodeService)applicationContext.getBean("dbNodeService");
this.lockService = (LockService)applicationContext.getBean("lockService");
this.securedLockService = (LockService)applicationContext.getBean("LockService");
this.permissionService = (PermissionService)applicationContext.getBean("PermissionService");
this.authenticationService = (MutableAuthenticationService)applicationContext.getBean("authenticationService");
this.cociService = (CheckOutCheckInService) applicationContext.getBean("checkOutCheckInService");
// Set the authentication
AuthenticationComponent authComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
authComponent.setSystemUserAsCurrentUser();
// Create the node properties
HashMap nodeProperties = new HashMap();
nodeProperties.put(QName.createQName("{test}property1"), "value1");
// Create a workspace that contains the 'live' nodes
storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
// Get a reference to the root node
rootNodeRef = this.nodeService.getRootNode(storeRef);
// Create node
this.parentNode = this.nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{}ParentNode"),
ContentModel.TYPE_CONTAINER,
nodeProperties).getChildRef();
this.nodeService.addAspect(this.parentNode, ContentModel.ASPECT_LOCKABLE, new HashMap());
HashMap audProps = new HashMap();
audProps.put(ContentModel.PROP_CREATOR, "Monkey");
this.nodeService.addAspect(this.parentNode, ContentModel.ASPECT_AUDITABLE, audProps);
assertNotNull(this.parentNode);
// Add some children to the node
this.childNode1 = this.nodeService.createNode(
this.parentNode,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{}ChildNode1"),
ContentModel.TYPE_CONTAINER,
nodeProperties).getChildRef();
this.nodeService.addAspect(this.childNode1, ContentModel.ASPECT_LOCKABLE, new HashMap());
assertNotNull(this.childNode1);
this.childNode2 = this.nodeService.createNode(
this.parentNode,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{}ChildNode2"),
ContentModel.TYPE_CONTAINER,
nodeProperties).getChildRef();
this.nodeService.addAspect(this.childNode2, ContentModel.ASPECT_LOCKABLE, new HashMap());
assertNotNull(this.childNode2);
// Create a node with no lockAspect
this.noAspectNode = this.nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{}noAspectNode"),
ContentModel.TYPE_CONTAINER,
nodeProperties).getChildRef();
assertNotNull(this.noAspectNode);
// Create node with checkedOut
this.checkedOutNode = this.nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{}checkedOutNode"),
ContentModel.TYPE_CONTAINER,
nodeProperties).getChildRef();
assertNotNull(this.checkedOutNode);
// Check out test file
NodeRef fileWorkingCopyNodeRef = cociService.checkout(checkedOutNode);
assertNotNull(fileWorkingCopyNodeRef);
assertTrue(nodeService.hasAspect(checkedOutNode, ContentModel.ASPECT_CHECKED_OUT));
assertTrue(nodeService.hasAspect(checkedOutNode, ContentModel.ASPECT_LOCKABLE));
// Create the users
TestWithUserUtils.createUser(GOOD_USER_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
TestWithUserUtils.createUser(BAD_USER_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
this.permissionService.setPermission(rootNodeRef, GOOD_USER_NAME, PermissionService.ALL_PERMISSIONS, true);
this.permissionService.setPermission(rootNodeRef, BAD_USER_NAME, PermissionService.CHECK_OUT, true);
this.permissionService.setPermission(rootNodeRef, BAD_USER_NAME, PermissionService.WRITE, true);
this.permissionService.setPermission(rootNodeRef, BAD_USER_NAME, PermissionService.READ, true);
// Stash the user node ref's for later use
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
}
/**
* Test lock
*/
public void testLock()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Check that the node is not currently locked
assertEquals(
LockStatus.NO_LOCK,
this.lockService.getLockStatus(this.parentNode));
// Test valid lock
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
assertEquals(
LockStatus.LOCK_OWNER,
this.lockService.getLockStatus(this.parentNode));
// Check that we can retrieve LockState
LockState lockState = lockService.getLockState(parentNode);
assertEquals(parentNode, lockState.getNodeRef());
assertEquals(LockType.WRITE_LOCK, lockState.getLockType());
assertEquals(GOOD_USER_NAME, lockState.getOwner());
assertEquals(Lifetime.PERSISTENT, lockState.getLifetime());
assertEquals(null, lockState.getExpires());
assertEquals(null, lockState.getAdditionalInfo());
// Check the correct properties have been set
Map props = nodeService.getProperties(parentNode);
assertEquals(GOOD_USER_NAME, props.get(ContentModel.PROP_LOCK_OWNER));
assertEquals(LockType.WRITE_LOCK.toString(), props.get(ContentModel.PROP_LOCK_TYPE));
assertEquals(Lifetime.PERSISTENT.toString(), props.get(ContentModel.PROP_LOCK_LIFETIME));
assertEquals(null, props.get(ContentModel.PROP_EXPIRY_DATE));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(
LockStatus.LOCKED,
this.lockService.getLockStatus(this.parentNode));
// Test lock when already locked
try
{
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
fail("The user should not be able to lock the node since it is already locked by another user.");
}
catch (UnableToAquireLockException exception)
{
System.out.println(exception.getMessage());
}
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Test already locked by this user
try
{
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
}
catch (Exception exception)
{
fail("No error should be thrown when a node is re-locked by the current lock owner.");
}
// Test with no apect node
this.lockService.lock(this.noAspectNode, LockType.WRITE_LOCK);
}
public void testPersistentLockDisallowsAdditionalInfo()
{
try
{
lockService.lock(noAspectNode, LockType.NODE_LOCK, 0, Lifetime.PERSISTENT, "additional info");
fail("additionalInfo must be null for persistent lock, expected IllegalArgumentException.");
}
catch (IllegalArgumentException e)
{
// Good, exception was thrown.
}
}
public void testEphemeralLock()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Check that the node is not currently locked
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
// Check that there really is no lockable aspect
assertEquals(false, nodeService.hasAspect(noAspectNode, ContentModel.ASPECT_LOCKABLE));
// Lock the node
lockService.lock(noAspectNode, LockType.WRITE_LOCK, 86400, Lifetime.EPHEMERAL, "some extra data");
// Check additionalInfo has been stored
assertEquals("some extra data", lockService.getAdditionalInfo(noAspectNode));
// Check that we can retrieve LockState
LockState lockState = lockService.getLockState(noAspectNode);
assertEquals(noAspectNode, lockState.getNodeRef());
assertEquals(LockType.WRITE_LOCK, lockState.getLockType());
assertEquals(GOOD_USER_NAME, lockState.getOwner());
assertEquals(Lifetime.EPHEMERAL, lockState.getLifetime());
assertNotNull(lockState.getExpires());
assertEquals("some extra data", lockState.getAdditionalInfo());
// The node should be locked
assertEquals(LockStatus.LOCK_OWNER, lockService.getLockStatus(noAspectNode));
// The node must still not have the lockable aspect applied
assertEquals(false, nodeService.hasAspect(noAspectNode, ContentModel.ASPECT_LOCKABLE));
// ...though the full node service should report that it is present
NodeService fullNodeService = (NodeService) applicationContext.getBean("nodeService");
assertEquals(true, fullNodeService.hasAspect(noAspectNode, ContentModel.ASPECT_LOCKABLE));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCKED, lockService.getLockStatus(noAspectNode));
// Test lock when already locked
try
{
lockService.lock(noAspectNode, LockType.WRITE_LOCK);
fail("The user should not be able to lock the node since it is already locked by another user.");
}
catch (UnableToAquireLockException exception)
{
System.out.println(exception.getMessage());
}
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCK_OWNER, lockService.getLockStatus(noAspectNode));
// Test already locked by this user - relock
try
{
lockService.lock(noAspectNode, LockType.WRITE_LOCK, 0, Lifetime.EPHEMERAL);
}
catch (Exception exception)
{
fail("No error should be thrown when a node is re-locked by the current lock owner.");
}
// The node should be locked
assertEquals(LockStatus.LOCK_OWNER, lockService.getLockStatus(noAspectNode));
// If we remove the lock info directly from the memory store then the node should no longer
// be reported as locked (as it is an ephemeral lock)
LockStore lockStore = (LockStore) applicationContext.getBean("lockStore");
lockStore.clear();
// The node must no longer be reported as locked
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
// Lock again, ready to test unlocking an ephemeral lock.
try
{
lockService.lock(noAspectNode, LockType.WRITE_LOCK, 0, Lifetime.EPHEMERAL);
}
catch (Exception exception)
{
fail("No error should be thrown when a node is re-locked by the current lock owner.");
}
assertEquals(LockStatus.LOCK_OWNER, lockService.getLockStatus(noAspectNode));
lockService.unlock(noAspectNode);
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
}
@Test
public void testEphemeralLockIndexing()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, authenticationService);
IndexerAndSearcher indexerAndSearcher = (IndexerAndSearcher)
applicationContext.getBean("indexerAndSearcherFactory");
SearcherComponent searcher = new SearcherComponent();
searcher.setIndexerAndSearcherFactory(indexerAndSearcher);
// Create a lock (owned by the current user)
lockService.lock(noAspectNode, LockType.WRITE_LOCK, 86400, Lifetime.EPHEMERAL);
// Query for the user's locks
final String query = String.format("+@cm\\:lockOwner:\"%s\" +@cm\\:lockType:\"WRITE_LOCK\"", GOOD_USER_NAME);
ResultSet rs = searcher.query(storeRef, "lucene", query);
assertTrue(rs.getNodeRefs().contains(noAspectNode));
// Unlock the node
lockService.unlock(noAspectNode);
// Perform a new search, the index should reflect that it is not locked.
rs = searcher.query(storeRef, "lucene", query);
assertFalse(rs.getNodeRefs().contains(noAspectNode));
}
/* MNT-10477 related test */
@Test
public void testEphemeralLockModifyNode()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Check that the node is not currently locked
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
// Check that there really is no lockable aspect
assertEquals(false, nodeService.hasAspect(noAspectNode, ContentModel.ASPECT_LOCKABLE));
// Lock the node
lockService.lock(noAspectNode, LockType.WRITE_LOCK, 86400, Lifetime.EPHEMERAL, "some extra data");
// get bad user
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCKED, lockService.getLockStatus(noAspectNode));
NodeService fullNodeService = (NodeService) applicationContext.getBean("nodeService");
/* addProperties test */
try
{
Map props = new HashMap();
props.put(ContentModel.PROP_DESCRIPTION, "descr" + System.currentTimeMillis());
props.put(ContentModel.PROP_TITLE, "title" + System.currentTimeMillis());
fullNodeService.addProperties(noAspectNode, props);
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
/* setProperty test */
try
{
fullNodeService.setProperty(noAspectNode, ContentModel.PROP_DESCRIPTION, "descr" + System.currentTimeMillis());
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
/* setProperties test */
try
{
Map props = new HashMap();
props.put(ContentModel.PROP_DESCRIPTION, "descr" + System.currentTimeMillis());
props.put(ContentModel.PROP_TITLE, "title" + System.currentTimeMillis());
fullNodeService.setProperties(noAspectNode, props);
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
/* removeProperty test */
try
{
fullNodeService.removeProperty(noAspectNode, ContentModel.PROP_DESCRIPTION);
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
/* addAspect test */
try
{
fullNodeService.addAspect(noAspectNode, ContentModel.ASPECT_AUTHOR , null);
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
/* removeAspect test */
try
{
fullNodeService.removeAspect(noAspectNode, ContentModel.ASPECT_AUTHOR);
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
/* setType test */
try
{
fullNodeService.setType(noAspectNode, ContentModel.TYPE_CMOBJECT);
fail();
}
catch(NodeLockedException e)
{
// it's ok - node supposed to be locked
}
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
lockService.unlock(noAspectNode);
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
}
public void testLockRevertedOnRollback() throws NotSupportedException, SystemException
{
// Preconditions of test
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(rootNodeRef));
// Lock noAspectNode
lockService.lock(noAspectNode, LockType.WRITE_LOCK, 0, Lifetime.EPHEMERAL);
// Lock rootNodeRef
lockService.lock(rootNodeRef, LockType.NODE_LOCK, 0, Lifetime.EPHEMERAL);
// Sometime later, a refresh occurs (so this should not be reverted to unlocked, but to this state)
lockService.lock(rootNodeRef, LockType.NODE_LOCK, 3600, Lifetime.EPHEMERAL);
// Rollback
endTransaction();
// This lock should not be present.
assertEquals(LockStatus.NO_LOCK, lockService.getLockStatus(noAspectNode));
// This lock should still be present.
assertEquals(LockStatus.LOCK_OWNER, lockService.getLockStatus(rootNodeRef));
}
/**
* Test lock with lockChildren == true
*/
// TODO
public void testLockChildren()
{
}
/**
* Test lock with collection
*/
// TODO
public void testLockMany()
{
}
/**
* Test unlock node
*/
public void testUnlock()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Lock the parent node
testLock();
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Try and unlock a locked node
try
{
this.lockService.unlock(this.parentNode);
// This will pass in the open workd
//fail("A user cannot unlock a node that is currently lock by another user.");
}
catch (UnableToReleaseLockException exception)
{
System.out.println(exception.getMessage());
}
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Unlock the node
this.lockService.unlock(this.parentNode);
assertEquals(
LockStatus.NO_LOCK,
this.lockService.getLockStatus(this.parentNode));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(
LockStatus.NO_LOCK,
this.lockService.getLockStatus(this.parentNode));
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Try and unlock node with no lock
try
{
this.lockService.unlock(this.parentNode);
}
catch (Exception exception)
{
fail("Unlocking an unlocked node should not result in an exception being raised.");
}
// Test with no apect node
this.lockService.unlock(this.noAspectNode);
}
// TODO
public void testUnlockChildren()
{
}
// TODO
public void testUnlockMany()
{
}
/**
* Test getLockStatus
*/
public void testGetLockStatus()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Check an unlocked node
LockStatus lockStatus1 = this.lockService.getLockStatus(this.parentNode);
assertEquals(LockStatus.NO_LOCK, lockStatus1);
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Check for locked status
LockStatus lockStatus2 = this.lockService.getLockStatus(this.parentNode);
assertEquals(LockStatus.LOCKED, lockStatus2);
// Check lockstore is not used for persistent locks
// Previously LockStore was doubling up as a cache - the change in requirements means a test
// is necessary to ensure the work has been implemented correctly (despite being an odd test)
LockStore lockStore = (LockStore) applicationContext.getBean("lockStore");
lockStore.clear();
LockState lockState = lockStore.get(parentNode);
// Nothing stored against node ref
assertNull(lockState);
lockService.getLockStatus(parentNode);
// In-memory store still empty - only used for ephemeral locks
lockState = lockStore.get(parentNode);
assertNull(lockState);
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Check for lock owner status
LockStatus lockStatus3 = this.lockService.getLockStatus(this.parentNode);
assertEquals(LockStatus.LOCK_OWNER, lockStatus3);
// Test with no apect node
this.lockService.getLockStatus(this.noAspectNode);
// Test method overload
LockStatus lockStatus4 = this.lockService.getLockStatus(this.parentNode);
assertEquals(LockStatus.LOCK_OWNER, lockStatus4);
}
public void testGetLocks()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
LockServiceImpl lockService = (LockServiceImpl) this.lockService;
List locked1 = lockService.getLocks(this.storeRef);
assertNotNull(locked1);
assertEquals(0, locked1.size());
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
this.lockService.lock(this.childNode1, LockType.WRITE_LOCK);
this.lockService.lock(this.childNode2, LockType.READ_ONLY_LOCK);
List locked2 = lockService.getLocks(this.storeRef);
assertNotNull(locked2);
assertEquals(3, locked2.size());
List locked3 = lockService.getLocks(this.storeRef, LockType.WRITE_LOCK);
assertNotNull(locked3);
assertEquals(2, locked3.size());
List locked4 = lockService.getLocks(this.storeRef, LockType.READ_ONLY_LOCK);
assertNotNull(locked4);
assertEquals(1, locked4.size());
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
List locked5 = lockService.getLocks(this.storeRef);
assertNotNull(locked5);
assertEquals(0, locked5.size());
}
/**
* Test getLockType
*/
public void testGetLockType()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Get the lock type (should be null since the object is not locked)
LockType lockType1 = this.lockService.getLockType(this.parentNode);
assertNull(lockType1);
// Lock the object for writing
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
LockType lockType2 = this.lockService.getLockType(this.parentNode);
assertNotNull(lockType2);
assertEquals(LockType.WRITE_LOCK, lockType2);
// Unlock the node
this.lockService.unlock(this.parentNode);
LockType lockType3 = this.lockService.getLockType(this.parentNode);
assertNull(lockType3);
// Lock the object for read only
this.lockService.lock(this.parentNode, LockType.READ_ONLY_LOCK);
LockType lockType4 = this.lockService.getLockType(this.parentNode);
assertNotNull(lockType4);
assertEquals(LockType.READ_ONLY_LOCK, lockType4);
// Lock the object for node lock
this.lockService.lock(this.parentNode, LockType.NODE_LOCK);
LockType lockType5 = this.lockService.getLockType(this.parentNode);
assertNotNull(lockType5);
assertEquals(LockType.NODE_LOCK, lockType5);
// Unlock the node
this.lockService.unlock(this.parentNode);
LockType lockType6 = this.lockService.getLockType(this.parentNode);
assertNull(lockType6);
// Test with no apect node
LockType lockType7 = this.lockService.getLockType(this.noAspectNode);
assertTrue("lock type is not null", lockType7 == null);
}
public void testGetLockTypeEphemeral()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Get the lock type (should be null since the object is not locked)
LockType lockType1 = this.lockService.getLockType(this.parentNode);
assertNull(lockType1);
// Lock the object for writing
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK, 0, Lifetime.EPHEMERAL);
LockType lockType2 = this.lockService.getLockType(this.parentNode);
assertNotNull(lockType2);
assertEquals(LockType.WRITE_LOCK, lockType2);
// Unlock the node
this.lockService.unlock(this.parentNode);
LockType lockType3 = this.lockService.getLockType(this.parentNode);
assertNull(lockType3);
// Lock the object for read only
this.lockService.lock(this.parentNode, LockType.READ_ONLY_LOCK, 0, Lifetime.EPHEMERAL);
LockType lockType4 = this.lockService.getLockType(this.parentNode);
assertNotNull(lockType4);
assertEquals(LockType.READ_ONLY_LOCK, lockType4);
// Lock the object for node lock
this.lockService.lock(this.parentNode, LockType.NODE_LOCK, 0, Lifetime.EPHEMERAL);
LockType lockType5 = this.lockService.getLockType(this.parentNode);
assertNotNull(lockType5);
assertEquals(LockType.NODE_LOCK, lockType5);
// Unlock the node
this.lockService.unlock(this.parentNode);
LockType lockType6 = this.lockService.getLockType(this.parentNode);
assertNull(lockType6);
// Test with no apect node
LockType lockType7 = this.lockService.getLockType(this.noAspectNode);
assertTrue("lock type is not null", lockType7 == null);
}
public void testTimeToExpire()
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK, 1);
assertEquals(LockStatus.LOCK_OWNER, this.lockService.getLockStatus(this.parentNode));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCKED, this.lockService.getLockStatus(this.parentNode));
// Wait for 2 second before re-testing the status
try {Thread.sleep(2*1000);} catch (Exception exception){};
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCK_EXPIRED, this.lockService.getLockStatus(this.parentNode));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCK_EXPIRED, this.lockService.getLockStatus(this.parentNode));
// Re-lock and then update the time to expire before lock expires
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK, 0);
try
{
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK, 1);
fail("Can not update lock info if not lock owner");
}
catch (UnableToAquireLockException exception)
{
// Expected
}
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK, 1);
assertEquals(LockStatus.LOCK_OWNER, this.lockService.getLockStatus(this.parentNode));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCKED, this.lockService.getLockStatus(this.parentNode));
// Wait for 2 second before re-testing the status
try {Thread.sleep(2*1000);} catch (Exception exception){};
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCK_EXPIRED, this.lockService.getLockStatus(this.parentNode));
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
assertEquals(LockStatus.LOCK_EXPIRED, this.lockService.getLockStatus(this.parentNode));
}
/**
* Unit test to validate the behaviour of creating children of locked nodes.
* No lock - can create children
* READ_ONLY_LOCK - can't create children
* WRITE_LOCK - owner can create children
* non owner can't create children
* NODE_LOCK non owner can create children
* owner can create children
*/
public void testCreateChildrenOfLockedNodes() throws Exception
{
/**
* Check we can create a child of an unlocked node.
*/
assertEquals(
LockStatus.NO_LOCK,
this.lockService.getLockStatus(this.parentNode));
ChildAssociationRef child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildA"), ContentModel.TYPE_FOLDER);
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
// Owner can create children
child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildB"), ContentModel.TYPE_FOLDER);
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
try
{
// Non owner can't create children with a write lock in place
child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildB"), ContentModel.TYPE_FOLDER);
fail("could create a child with a read only lock");
}
catch (NodeLockedException e)
{
logger.debug("exception while trying to create a child of a read only lock", e);
}
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.NODE_LOCK);
// owner can create children with a node lock
child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildD"), ContentModel.TYPE_FOLDER);
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Non owner can create children with a node lock
child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildC"), ContentModel.TYPE_FOLDER);
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.lockService.lock(this.parentNode, LockType.READ_ONLY_LOCK);
// owner should not be able to create children with a READ_ONLY_LOCK
try
{
child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildD"), ContentModel.TYPE_FOLDER);
fail("could create a child with a read only lock");
}
catch (NodeLockedException e)
{
logger.debug("exception while trying to create a child of a read only lock", e);
}
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
// Non owner should not be able to create children with READ_ONLY_LOCK
try
{
child = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildE"), ContentModel.TYPE_FOLDER);
fail("could create a child with a read only lock");
}
catch (NodeLockedException e)
{
logger.debug("exception while trying to create a child of a read only lock", e);
}
}
/**
* Test that it is impossible to unlock a checked out node
*/
public void testUnlockCheckedOut() throws Exception
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
try
{
this.lockService.unlock(checkedOutNode);
fail("could unlock a checked out node");
}
catch (UnableToReleaseLockException e)
{
logger.debug("exception while trying to unlock a checked out node", e);
}
}
@SuppressWarnings("deprecation")
public void testUnlockNodeWithAdminUser()
{
for (Lifetime lt : new Lifetime[]{Lifetime.EPHEMERAL, Lifetime.PERSISTENT})
{
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
/* create node */
final NodeRef testNode =
this.nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{}testNode"), ContentModel.TYPE_CONTAINER).getChildRef();
// lock it as GOOD user
this.securedLockService.lock(testNode, LockType.WRITE_LOCK, 2 * 86400, lt, null);
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
try
{
// try to unlock as bad user
this.securedLockService.unlock(testNode);
fail("BAD user shouldn't be able to unlock " + lt + " lock");
}
catch(AccessDeniedException e)
{
// expected expetion
}
TestWithUserUtils.authenticateUser(AuthenticationUtil.getAdminUserName(), "admin", rootNodeRef, this.authenticationService);
// try to unlock as ADMIN user
this.securedLockService.unlock(testNode);
// test that bad use able to lock/unlock node
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
this.securedLockService.lock(testNode, LockType.WRITE_LOCK, 2 * 86400, lt, null);
this.securedLockService.unlock(testNode);
this.nodeService.deleteNode(testNode);
}
}
}