001/** 002 * Copyright 2005-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kns.service.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.junit.Test; 020import org.kuali.rice.kew.api.exception.WorkflowException; 021import org.kuali.rice.kim.api.KimConstants.PermissionNames; 022import org.kuali.rice.kim.api.identity.Person; 023import org.kuali.rice.kim.api.services.KimApiServiceLocator; 024import org.kuali.rice.kns.KNSTestCase; 025import org.kuali.rice.kns.authorization.AuthorizationConstants; 026import org.kuali.rice.krad.UserSession; 027import org.kuali.rice.krad.document.Document; 028import org.kuali.rice.krad.document.authorization.PessimisticLock; 029import org.kuali.rice.krad.exception.AuthorizationException; 030import org.kuali.rice.krad.maintenance.MaintenanceDocument; 031import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 032import org.kuali.rice.krad.service.PessimisticLockService; 033import org.kuali.rice.krad.service.impl.PessimisticLockServiceImpl; 034import org.kuali.rice.krad.test.KRADTestCase; 035import org.kuali.rice.krad.test.document.AccountRequestDocument; 036import org.kuali.rice.krad.test.document.AccountRequestDocument2; 037import org.kuali.rice.krad.util.GlobalVariables; 038import org.kuali.rice.krad.util.KRADConstants; 039import org.kuali.rice.krad.util.KRADPropertyConstants; 040import org.kuali.rice.kns.maintainable.AccountType2MaintainableImpl; 041import org.kuali.rice.test.BaselineTestCase; 042import org.kuali.rice.test.data.UnitTestData; 043import org.kuali.rice.test.data.UnitTestSql; 044 045import java.io.Serializable; 046import java.util.Arrays; 047import java.util.Collections; 048import java.util.HashMap; 049import java.util.HashSet; 050import java.util.List; 051import java.util.Map; 052import java.util.Set; 053 054import static org.junit.Assert.*; 055 056/** 057 * PessimisticLockServiceTest tests {@link PessimisticLockServiceImpl} for maintainable 058 * 059 * @author Kuali Rice Team (rice.collab@kuali.org) 060 */ 061@BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE) 062public class PessimisticLockServiceTest extends KNSTestCase { 063 064 String sessionId = "ad4d6c83-4d0f-4309-a528-c2f81ec00395"; 065 066 @Override 067 public void setUp() throws Exception { 068 super.setUp(); 069 GlobalVariables.setUserSession(new UserSession("quickstart")); 070 GlobalVariables.getUserSession().setKualiSessionId(sessionId); 071 } 072 073 /** 074 * tests the PessimisticLockService's ability to establish pessimistic locks for maintenance documents (via maintainables) that 075 * support custom lock descriptors 076 * 077 * @throws Exception 078 */ 079 @Test 080 public void testPessimisticLockingWithCustomMaintainableLockDescriptors() throws Exception { 081 MaintenanceDocument maintDoc = (MaintenanceDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountType2MaintenanceDocument"); 082 assertTrue("The AccountType2MaintenanceDocument should be using pessimistic locking", KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary( 083 ).getDocumentEntry(maintDoc.getNewMaintainableObject().getDataObjectClass().getSimpleName() + "MaintenanceDocument").getUsePessimisticLocking()); 084 assertTrue("The AccountType2MaintenanceDocument should be using custom lock descriptors", maintDoc.useCustomLockDescriptors()); 085 assertTrue("The AccountType2MaintenanceDocument's new maintainable uses the wrong class", 086 maintDoc.getNewMaintainableObject() instanceof AccountType2MaintainableImpl); 087 AccountType2MaintainableImpl newMaint = (AccountType2MaintainableImpl) maintDoc.getNewMaintainableObject(); 088 assertTrue("The AccountType2MaintainableImpl should be using custom lock descriptors", newMaint.useCustomLockDescriptors()); 089 090 // Perform the custom lock descriptor unit testing operations. 091 assertCustomLockDescriptorsAreWorking(maintDoc, AccountType2MaintainableImpl.ACCT_TYPE_2_MAINT_FIELDS_TO_EDIT, 092 AccountType2MaintainableImpl.EDIT_CODE_ONLY, AccountType2MaintainableImpl.EDIT_NAME_ONLY); 093 } 094 095 /** 096 * A convenience method for testing the custom lock descriptors of documents (and on the maintainables of maintenance documents). 097 * 098 * @param testDoc The document to test pessimistic locking on (or the maintenance document with maintainables to test on). 099 * @param LOCK_KEY The UserSession object key to use for storing the lock descriptor's key. 100 * @param LOCK_VALUE1 One possible object to store in a UserSession for generating lock descriptors on the testDoc. 101 * @param LOCK_VALUE2 Another possible object to store in a UserSession for generating lock descriptors on the testDoc. 102 * 103 * @throws Exception 104 */ 105 private void assertCustomLockDescriptorsAreWorking(Document testDoc, final String LOCK_KEY, final Serializable LOCK_VALUE1, 106 final Serializable LOCK_VALUE2) throws Exception { 107 PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService(); 108 109 // Have "quickstart" establish a pessimistic lock on the document by using a custom lock descriptor that only locks part of the document. 110 UserSession quickstartSession = new UserSession("quickstart"); 111 Person[] allPersons = { quickstartSession.getPerson(), null }; 112 Map<String,String> editMode = new HashMap<String,String>(); 113 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 114 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1); 115 String[] allDescriptors = { testDoc.getCustomLockDescriptor(quickstartSession.getPerson()), null }; 116 assertNotNull("The document should have generated a custom lock descriptor", allDescriptors[0]); 117 Map <?,?> finalModes = lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 118 119 // Verify that the lock was actually established and that the expected custom lock descriptor was used. 120 assertCorrectLocksAreInPlace(true, finalModes, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 121 122 // Attempt to establish the same lock again, which should change nothing since "quickstart" already has the lock. 123 editMode = new HashMap<String,String>(); 124 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 125 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1); 126 lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 127 assertCorrectLocksAreInPlace(false, null, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 128 129 // Now check to make sure that a different user (such as "admin") cannot establish a lock using the same lock descriptor. 130 UserSession adminSession = new UserSession("admin"); 131 editMode = new HashMap<String,String>(); 132 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 133 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1); 134 assertEquals("The document should have generated the same lock descriptors for both 'quickstart' and 'admin'", 135 allDescriptors[0], testDoc.getCustomLockDescriptor(adminSession.getPerson())); 136 finalModes = lockService.establishLocks(testDoc, editMode, adminSession.getPerson()); 137 assertCorrectLocksAreInPlace(false, finalModes, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 138 139 // Ensure that "admin" can establish a lock that has a different lock descriptor. 140 allPersons[1] = adminSession.getPerson(); 141 editMode = new HashMap<String,String>(); 142 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 143 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2); 144 allDescriptors[1] = testDoc.getCustomLockDescriptor(adminSession.getPerson()); 145 assertNotNull("The document should have generated a custom lock descriptor", allDescriptors[1]); 146 assertNotSame("'quickstart' and 'admin' should have different custom lock descriptors now", allDescriptors[0], allDescriptors[1]); 147 finalModes = lockService.establishLocks(testDoc, editMode, adminSession.getPerson()); 148 assertCorrectLocksAreInPlace(true, finalModes, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 149 150 // Verify that "quickstart" cannot acquire the lock owned by "admin". 151 editMode = new HashMap<String,String>(); 152 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 153 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2); 154 lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 155 assertCorrectLocksAreInPlace(false, null, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 156 157 // After "admin" releases his lock, check to make sure that "quickstart" can now acquire it. 158 lockService.releaseAllLocksForUser(testDoc.getPessimisticLocks(), allPersons[1], allDescriptors[1]); 159 testDoc.refreshPessimisticLocks(); 160 assertCorrectLocksAreInPlace(false, null, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 161 allPersons[1] = allPersons[0]; 162 editMode = new HashMap<String,String>(); 163 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 164 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2); 165 finalModes = lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 166 assertCorrectLocksAreInPlace(true, finalModes, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 167 168 // Release all the locks when done. 169 GlobalVariables.getUserSession().removeObject(LOCK_KEY); 170 lockService.releaseAllLocksForUser(testDoc.getPessimisticLocks(), allPersons[0]); 171 testDoc.refreshPessimisticLocks(); 172 assertTrue("There should not be any pessimistic locks present on the document", testDoc.getPessimisticLocks().isEmpty()); 173 } 174 175 /** 176 * A convenience method for checking to ensure that the proper pessimistic locks are in place. 177 * 178 * @param latestUserHasFullEntry Indicates if the map returned by PessimisticLockService.establishLocks should have a true "fullEntry" parameter. 179 * @param finalModes The map returned by the call to PessimisticLockService.establishLocks. This parameter can be null if checking it is not needed. 180 * @param expectedLockQuantity The expected number of pessimistic locks. 181 * @param pessimisticLocks The list of pessimistic locks to check for proper quantity and proper state. 182 * @param expectedOwners The users who are expected to own the corresponding locks in the previous list. 183 * @param expectedDescriptors The expected lock descriptors for the corresponding locks in the other list. This parameter can be set to null if 184 * the pessimistic locks are not using custom lock descriptors or if custom lock descriptors are not the concern of the test. 185 * @throws Exception 186 */ 187 private void assertCorrectLocksAreInPlace(boolean latestUserHasFullEntry, Map<?,?> finalModes, int expectedLockQuantity, 188 List<PessimisticLock> pessimisticLocks, Person[] expectedOwners, String[] expectedDescriptors) throws Exception { 189 // Ensure that the last user to attempt to establish locks has the expected finalModes entry (or lack of it). 190 if (finalModes != null) { 191 assertEquals("The last user that tried to establish locks does not have the expected status on their full entry privileges", 192 latestUserHasFullEntry, StringUtils.equalsIgnoreCase(KRADConstants.KUALI_DEFAULT_TRUE_VALUE, (String)(finalModes.get( 193 AuthorizationConstants.EditMode.FULL_ENTRY)))); 194 } 195 // Ensure that the expected number of locks are present. 196 assertEquals("The wrong number of pessimistic locks are in place", expectedLockQuantity, pessimisticLocks.size()); 197 // Verify that each lock has the expected owners. 198 for (int i = pessimisticLocks.size() - 1; i > -1; i--) { 199 assertTrue("The lock at index " + i + " did not have the expected owner of " + expectedOwners[i].getPrincipalName(), 200 pessimisticLocks.get(i).isOwnedByUser(expectedOwners[i])); 201 if (expectedDescriptors != null) { 202 assertTrue("The lock at index " + i + " did not have the expected lock descriptor of " + expectedDescriptors[i], 203 pessimisticLocks.get(i).getLockDescriptor().equals(expectedDescriptors[i])); 204 } 205 } 206 } 207}