001 /** 002 * Copyright 2005-2011 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 */ 016 package org.kuali.rice.kew.preferences; 017 018 import static org.junit.Assert.assertFalse; 019 import static org.junit.Assert.assertNotNull; 020 import static org.junit.Assert.assertNull; 021 import static org.junit.Assert.assertTrue; 022 023 import java.util.ArrayList; 024 import java.util.Collection; 025 import java.util.List; 026 027 import org.junit.Test; 028 import org.kuali.rice.kew.api.KewApiServiceLocator; 029 import org.kuali.rice.kew.api.preferences.Preferences; 030 import org.kuali.rice.kew.api.preferences.PreferencesService; 031 import org.kuali.rice.kew.service.KEWServiceLocator; 032 import org.kuali.rice.kew.test.KEWTestCase; 033 import org.kuali.rice.kew.useroptions.UserOptions; 034 import org.kuali.rice.kew.useroptions.UserOptionsService; 035 import org.kuali.rice.kim.api.identity.principal.Principal; 036 import org.springframework.transaction.TransactionStatus; 037 import org.springframework.transaction.support.TransactionCallback; 038 import org.springframework.transaction.support.TransactionTemplate; 039 040 041 042 public class PreferencesServiceTest extends KEWTestCase { 043 044 /** 045 * Test that the preferences are saved by default when going through the preferences service. This 046 * means that the preferences service will persist any user option that was not in the db when it went 047 * to fetch that preferences. 048 */ 049 @Test public void testPreferencesDefaultSave() throws Exception { 050 //verify that user doesn't have any preferences in the db. 051 052 final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService(); 053 Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend"); 054 Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 055 assertTrue("UserOptions should be empty", userOptions.isEmpty()); 056 057 PreferencesService preferencesService = KewApiServiceLocator.getPreferencesService(); 058 Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId()); 059 assertTrue("Preferences should require a save.", preferences.isRequiresSave()); 060 061 userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 062 assertTrue("UserOptions should not empty", userOptions.isEmpty()); 063 064 preferencesService.savePreferences(principal.getPrincipalId(), preferences); 065 userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 066 assertTrue("UserOptions should not be empty", !userOptions.isEmpty()); 067 068 preferences = preferencesService.getPreferences(principal.getPrincipalId()); 069 assertFalse("Preferences should NOT require a save.", preferences.isRequiresSave()); 070 071 // now delete one of the options 072 final UserOptions refreshRateOption = userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId()); 073 assertNotNull("REFRESH_RATE option should exist.", refreshRateOption); 074 TransactionTemplate template = new TransactionTemplate(KEWServiceLocator.getPlatformTransactionManager()); 075 template.execute(new TransactionCallback() { 076 public Object doInTransaction(TransactionStatus status) { 077 userOptionsService.deleteUserOptions(refreshRateOption); 078 return null; 079 } 080 }); 081 assertNull("REFRESH_RATE option should no longer exist.", userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId())); 082 083 preferences = preferencesService.getPreferences(principal.getPrincipalId()); 084 assertTrue("Preferences should now require a save again.", preferences.isRequiresSave()); 085 086 // save refresh rate again 087 template.execute(new TransactionCallback() { 088 public Object doInTransaction(TransactionStatus status) { 089 userOptionsService.save(refreshRateOption); 090 return null; 091 } 092 }); 093 preferences = preferencesService.getPreferences(principal.getPrincipalId()); 094 assertFalse("Preferences should no longer require a save.", preferences.isRequiresSave()); 095 } 096 097 098 /** 099 * Tests default saving concurrently which can cause a race condition on startup 100 * that leads to constraint violations 101 */ 102 @Test public void testPreferencesConcurrentDefaultSave() throws Throwable { 103 //verify that user doesn't have any preferences in the db. 104 final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService(); 105 final Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend"); 106 Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 107 assertTrue("UserOptions should be empty", userOptions.isEmpty()); 108 109 final PreferencesService preferencesService = KewApiServiceLocator.getPreferencesService(); 110 Runnable getPrefRunnable = new Runnable() { 111 public void run() { 112 Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId()); 113 assertTrue("Preferences should require a save.", preferences.isRequiresSave()); 114 Collection updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 115 assertTrue("UserOptions should be empty", updatedOptions.isEmpty()); 116 } 117 }; 118 final List<Throwable> errors = new ArrayList<Throwable>(); 119 Thread.UncaughtExceptionHandler ueh = new Thread.UncaughtExceptionHandler() { 120 public void uncaughtException(Thread thread, Throwable error) { 121 errors.add(error); 122 } 123 }; 124 125 // 3 threads should do 126 Thread t1 = new Thread(getPrefRunnable); 127 Thread t2 = new Thread(getPrefRunnable); 128 Thread t3 = new Thread(getPrefRunnable); 129 t1.setUncaughtExceptionHandler(ueh); 130 t2.setUncaughtExceptionHandler(ueh); 131 t3.setUncaughtExceptionHandler(ueh); 132 t1.start(); 133 t2.start(); 134 t3.start(); 135 t1.join(); 136 t2.join(); 137 t3.join(); 138 139 if (errors.size() > 0) { 140 throw errors.iterator().next(); 141 } 142 143 Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId()); 144 assertTrue("Preferences should require a save.", preferences.isRequiresSave()); 145 Collection updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 146 assertTrue("UserOptions should be empty", updatedOptions.isEmpty()); 147 preferencesService.savePreferences(principal.getPrincipalId(), preferences); 148 updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId()); 149 assertTrue("UserOptions should not be empty", !updatedOptions.isEmpty()); 150 151 } 152 }