/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.concurrency.locking;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.portal.concurrency.IEntityLock;
import org.apereo.portal.concurrency.IEntityLockService;
import org.apereo.portal.concurrency.LockingException;
import org.apereo.portal.properties.PropertiesManager;
import org.apereo.portal.services.EntityLockService;
/**
* Tests the entity lock framework.
*/
public class EntityLockTest extends TestCase {
private static final Log LOG = LogFactory.getLog(EntityLockTest.class);
private static Class GROUP_CLASS;
private static Class IPERSON_CLASS;
private IEntityLock[] testLocks;
private IEntityLockStore lockStore;
private int numUnexpiredIEntityGroupLocksInStore = 0;
private int numExpiredLocks = 0;
private int numUnexpiredIPersonLocksInStore = 0;
private int numIPersonLocksInStoreForTestId = 0;
private String[] testKeys = {"101", "102", "9999999", "12345"};
private String[] testIds = {"de3", "df7", "av317"};
/** EntityLockTester constructor comment. */
public EntityLockTest(String name) {
super(name);
}
/** @return org.apereo.portal.concurrency.locking.IEntityLockStore */
private IEntityLockStore getLockStore() {
return lockStore;
}
/** @return org.apereo.portal.groups.IEntityLockService */
private IEntityLockService getService() throws LockingException {
return ReferenceEntityLockService.singleton();
}
/**
* Starts the application.
*
* @param args an array of command-line arguments
*/
public static void main(java.lang.String[] args) throws Exception {
String[] mainArgs = {"org.apereo.portal.concurrency.locking.EntityLockTester"};
print("START TESTING LOCK STORE");
printBlankLine();
TestRunner.main(mainArgs);
printBlankLine();
print("END TESTING LOCK STORE");
}
private static void print(IEntityLock[] locks) {
for (int i = 0; i < locks.length; i++) {
print("(" + (i + 1) + ") " + locks[i]);
}
print(" Total: " + locks.length);
}
/** @param msg java.lang.String */
private static void print(String msg) {
LOG.debug(msg);
}
private static void printBlankLine() {
System.out.println("");
}
protected void setUp() {
try {
if (GROUP_CLASS == null) {
GROUP_CLASS = Class.forName("org.apereo.portal.groups.IEntityGroup");
}
if (IPERSON_CLASS == null) {
IPERSON_CLASS = Class.forName("org.apereo.portal.security.IPerson");
}
try {
boolean multiServer =
PropertiesManager.getPropertyAsBoolean(
"org.apereo.portal.concurrency.multiServer", false);
lockStore =
(multiServer)
? RDBMEntityLockStore.singleton()
: MemoryEntityLockStore.singleton();
} catch (Exception e) {
System.out.println(
"EntityLockTester:setUp(): Failed to instantiate entity lock store. " + e);
}
lockStore.deleteAll();
java.util.Date earlier =
new java.util.Date(System.currentTimeMillis() - 1000); // - 1 second
java.util.Date later =
new java.util.Date(System.currentTimeMillis() + 300000); // + 5 minutes
testLocks = new IEntityLock[5];
testLocks[0] = new EntityLockImpl(GROUP_CLASS, testKeys[0], 0, later, testIds[0]);
testLocks[1] = new EntityLockImpl(GROUP_CLASS, testKeys[1], 0, later, testIds[0]);
testLocks[2] = new EntityLockImpl(IPERSON_CLASS, testKeys[0], 0, earlier, testIds[0]);
testLocks[3] = new EntityLockImpl(IPERSON_CLASS, testKeys[1], 1, later, testIds[0]);
testLocks[4] = new EntityLockImpl(IPERSON_CLASS, testKeys[2], 1, later, testIds[1]);
print("Adding test locks.");
for (int i = 0; i < testLocks.length; i++) {
getLockStore().add(testLocks[i]);
// print("Added " + testLocks[i]);
}
numUnexpiredIEntityGroupLocksInStore = 2;
numExpiredLocks = 1;
numUnexpiredIPersonLocksInStore = 2;
numIPersonLocksInStoreForTestId = 1;
} catch (Exception ex) {
print("EntityLockTester.setUp(): " + ex.getMessage());
}
}
protected void tearDown() {
try {
// delete any remaining test locks.
print("Deleting test locks.");
for (int i = 0; i < testLocks.length; i++) {
getLockStore().delete(testLocks[i]);
}
} catch (Exception ex) {
print("EntityLockTester.tearDown(): " + ex.getMessage());
}
}
public void testExistsInStore() throws Exception {
String msg = null;
IEntityLock lock = testLocks[4];
msg = "Checking if " + lock + " exists in database.";
print(msg);
boolean exists = getService().existsInStore(lock);
assertTrue(msg, exists);
// Delete the lock:
print("Deleting lock from database.");
getLockStore().delete(lock);
// does lock exist?
msg = "Checking if deleted lock exists in database.";
print(msg);
exists = getService().existsInStore(lock);
assertTrue(msg, !exists);
// Add the lock back:
print("Adding back the lock just deleted from database.");
getLockStore().add(lock);
}
public void testExpirationInStore() throws Exception {
int numLocks = 0;
int ctr = 0;
String msg = null;
IEntityLock[] selectedLocks = null;
java.util.Date now = new java.util.Date(System.currentTimeMillis());
// select unexpired locks by entity type
msg = "Selecting unexpired locks by type.";
print(msg);
selectedLocks = getLockStore().findUnexpired(now, IPERSON_CLASS, null, null, null);
numLocks = selectedLocks.length;
assertEquals(numLocks, numUnexpiredIPersonLocksInStore);
for (ctr = 0; ctr < numLocks; ctr++) {
assertTrue(msg, selectedLocks[ctr].getExpirationTime().after(now));
}
// Get rid of the EXPIRED locks.
print("Deleting expired locks.");
getLockStore().deleteExpired(new java.util.Date(System.currentTimeMillis()));
// Select the remaining UNEXPIRED locks.
msg = "Selected all remaining locks.";
print(msg);
selectedLocks = getLockStore().find(null, null, null, null, null);
numLocks = selectedLocks.length;
msg = "Selected " + numLocks + " unexpired locks";
print(msg);
assertEquals(msg, testLocks.length - numExpiredLocks, numLocks);
for (ctr = 0; ctr < numLocks; ctr++) {
assertTrue(msg, selectedLocks[ctr].getExpirationTime().after(now));
}
}
public void testSelectFromStore() throws Exception {
int numLocks = 0;
int ctr = 0;
IEntityLock[] selectedLocks = null;
String msg = null;
java.util.Date now = new java.util.Date(System.currentTimeMillis());
// select locks by entity type
msg = "Selecting locks for Group type.";
print(msg);
selectedLocks = getLockStore().find(GROUP_CLASS, null, null, null, null);
numLocks = selectedLocks.length;
assertEquals(numLocks, numUnexpiredIEntityGroupLocksInStore);
for (ctr = 0; ctr < numLocks; ctr++) {
assertEquals(msg, selectedLocks[ctr].getEntityType(), GROUP_CLASS);
}
// select locks by entity type and entity key
msg = "Selecting locks by type and key.";
print(msg);
selectedLocks = getLockStore().find(GROUP_CLASS, testKeys[1], null, null, null);
numLocks = selectedLocks.length;
assertEquals(msg, numLocks, 1);
assertEquals(msg, selectedLocks[0].getEntityType(), GROUP_CLASS);
assertEquals(msg, selectedLocks[0].getEntityKey(), testKeys[1]);
// select locks by entity type, entity key and lock type
msg = "Selecting locks by type, key, and lock type";
print(msg);
selectedLocks = getLockStore().find(IPERSON_CLASS, testKeys[1], new Integer(1), null, null);
numLocks = selectedLocks.length;
assertEquals(msg, numLocks, 1);
assertEquals(msg, selectedLocks[0].getEntityType(), IPERSON_CLASS);
assertEquals(msg, selectedLocks[0].getEntityKey(), testKeys[1]);
assertEquals(msg, selectedLocks[0].getLockType(), 1);
selectedLocks = getLockStore().find(IPERSON_CLASS, testKeys[1], new Integer(0), null, null);
numLocks = selectedLocks.length;
assertEquals(msg, numLocks, 0);
// select locks by entity type and owner
msg = "Selecting locks by entity type and owner";
String id = testIds[1];
print(msg);
selectedLocks = getLockStore().find(IPERSON_CLASS, null, null, null, id);
numLocks = selectedLocks.length;
assertEquals(numLocks, numIPersonLocksInStoreForTestId);
for (ctr = 0; ctr < numLocks; ctr++) {
assertEquals(msg, selectedLocks[ctr].getEntityType(), IPERSON_CLASS);
assertEquals(msg, selectedLocks[ctr].getLockOwner(), id);
}
}
public void testService() throws Exception {
String msg = null;
IEntityLock readLock1, readLock2, writeLock = null;
String key = System.currentTimeMillis() + "";
print("Creating first read lock.");
readLock1 = EntityLockService.instance().newReadLock(IPERSON_CLASS, key, testIds[0]);
print("Creating second read lock (for same entity).");
readLock2 = EntityLockService.instance().newReadLock(IPERSON_CLASS, key, testIds[0]);
msg = "Attempting to create a write lock for the entity: should fail.";
print(msg);
try {
writeLock = EntityLockService.instance().newWriteLock(IPERSON_CLASS, key, testIds[2]);
} catch (LockingException le) {
System.out.println("Caught Exception: " + le.getMessage());
}
assertNull(msg, writeLock);
msg = "Releasing read locks: lock should be invalid.";
print(msg);
readLock1.release();
assertTrue(msg, !readLock1.isValid());
readLock2.release();
assertTrue(msg, !readLock2.isValid());
msg = "Attempting to create a write lock for the entity: should succeed.";
print(msg);
try {
writeLock = EntityLockService.instance().newWriteLock(IPERSON_CLASS, key, testIds[2]);
} catch (LockingException le) {
System.out.println("Caught Exception: " + le.getMessage());
}
assertTrue(msg, writeLock.isValid());
msg = "Releasing write lock: should be invalid.";
print(msg);
writeLock.release();
assertTrue(msg, !writeLock.isValid());
}
public void testServiceConvert() throws Exception {
String msg = null;
boolean valid = false;
IEntityLockService service = getService();
int readSecs = 30;
int writeSecs = 45;
// Create a READ lock on Group testKeys[3], owned by testIds[0]:
print("Creating new READ lock");
IEntityLock lock =
service.newLock(
GROUP_CLASS,
testKeys[3],
IEntityLockService.READ_LOCK,
testIds[0],
readSecs);
msg = "Testing if new lock is valid";
valid = service.isValid(lock);
print(msg);
assertTrue(msg, valid);
// Convert the READ lock to a WRITE lock:
print("Converting READ lock to WRITE");
service.convert(lock, IEntityLockService.WRITE_LOCK, writeSecs);
msg = "Testing if converted lock is still valid";
valid = service.isValid(lock);
print(msg);
assertTrue(msg, valid);
// Convert the WRITE lock back to a READ lock:
print("Converting WRITE lock to READ");
service.convert(lock, IEntityLockService.READ_LOCK, readSecs);
msg = "Testing if converted lock is still valid";
valid = service.isValid(lock);
print(msg);
assertTrue(msg, valid);
// Now try to create a WRITE lock on the same entity for a different owner.
IEntityLock duplicateLock = null;
msg = "Attempting to create a duplicate lock; should be null";
print(msg);
try {
duplicateLock =
service.newLock(
GROUP_CLASS, testKeys[3], IEntityLockService.WRITE_LOCK, testIds[1]);
} catch (LockingException le) {
print("Caught exception: " + le.getMessage());
}
assertNull(msg, duplicateLock);
}
public void testServiceLockRenewal() throws Exception {
String msg = null;
boolean valid = false;
IEntityLockService service = getService();
msg = "Attempting to renew an old lock";
print(msg);
IEntityLock badLock = testLocks[2];
msg = "Checking if lock was renewed.";
print(msg);
try {
service.renew(badLock);
} catch (Exception ex) {
print("Caught Exception: " + ex.getMessage());
}
assertTrue(msg, !service.isValid(badLock));
msg = "Attempting to renew a valid lock";
print(msg);
IEntityLock goodLock = testLocks[0];
msg = "Checking if lock was renewed.";
print(msg);
try {
service.renew(goodLock);
} catch (Exception ex) {
print("Caught Exception: " + ex.getMessage());
}
assertTrue(msg, service.isValid(goodLock));
}
public void testServiceNewLock() throws Exception {
String msg = null;
boolean valid = false;
print("Creating new lock");
IEntityLockService service = getService();
IEntityLock newLock =
service.newLock(
GROUP_CLASS, testKeys[3], IEntityLockService.WRITE_LOCK, testIds[0]);
msg = "Testing if new lock is valid";
valid = getService().existsInStore(newLock);
print(msg);
assertTrue(msg, valid);
print("Releasing new lock");
getService().release(newLock);
msg = "Testing if new lock is still valid";
valid = getService().existsInStore(newLock);
print(msg);
assertTrue(msg, !valid);
}
public void testStoreUpdate() throws Exception {
long fiveMinutes = 1000 * 60 * 5;
long tenMinutes = 1000 * 60 * 10;
long now = System.currentTimeMillis();
String msg = null;
print("Update expiration and lock type of testLocks[1].");
java.util.Date newExpiration = new java.util.Date(now + fiveMinutes);
int newType = IEntityLockService.WRITE_LOCK;
// Copy testLocks[1] to lock1.
IEntityLock lock1 =
new EntityLockImpl(
testLocks[1].getEntityType(),
testLocks[1].getEntityKey(),
testLocks[1].getLockType(),
testLocks[1].getExpirationTime(),
testLocks[1].getLockOwner());
// Update testLocks[1].
getLockStore().update(testLocks[1], newExpiration, new Integer(newType));
((EntityLockImpl) testLocks[1]).setExpirationTime(newExpiration);
((EntityLockImpl) testLocks[1]).setLockType(newType);
msg = "Check if the old version (lock1) still exists in store.";
print(msg);
assertTrue(msg, !getService().existsInStore(lock1));
msg = "Check if new version exists in store.";
print(msg);
IEntityLock lock2 =
new EntityLockImpl(
lock1.getEntityType(),
lock1.getEntityKey(),
newType,
newExpiration,
lock1.getLockOwner());
assertTrue(msg, getService().existsInStore(lock2));
print("Update only expiration on (updated) lock.");
newExpiration = new java.util.Date(now + tenMinutes);
getLockStore().update(lock2, newExpiration, null);
((EntityLockImpl) lock2).setExpirationTime(newExpiration);
msg = "Check if un-updated lock still exists in store.";
print(msg);
assertTrue(msg, !getService().existsInStore(testLocks[1]));
msg = "Check if the doubly-updated lock exists in store.";
print(msg);
IEntityLock lock3 =
new EntityLockImpl(
lock2.getEntityType(),
lock2.getEntityKey(),
lock2.getLockType(),
newExpiration,
lock2.getLockOwner());
assertTrue(msg, getService().existsInStore(lock3));
testLocks[0] = lock3;
}
}