/** * 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; } }