View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.preferences;
17  
18  import static org.junit.Assert.assertFalse;
19  import static org.junit.Assert.assertNotNull;
20  import static org.junit.Assert.assertNull;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.List;
26  
27  import org.junit.Test;
28  import org.kuali.rice.kew.api.KewApiServiceLocator;
29  import org.kuali.rice.kew.api.preferences.Preferences;
30  import org.kuali.rice.kew.api.preferences.PreferencesService;
31  import org.kuali.rice.kew.service.KEWServiceLocator;
32  import org.kuali.rice.kew.test.KEWTestCase;
33  import org.kuali.rice.kew.useroptions.UserOptions;
34  import org.kuali.rice.kew.useroptions.UserOptionsService;
35  import org.kuali.rice.kim.api.identity.principal.Principal;
36  import org.springframework.transaction.TransactionStatus;
37  import org.springframework.transaction.support.TransactionCallback;
38  import org.springframework.transaction.support.TransactionTemplate;
39  
40  
41  
42  public class PreferencesServiceTest extends KEWTestCase {
43  
44      /**
45       * Test that the preferences are saved by default when going through the preferences service.  This
46       * means that the preferences service will persist any user option that was not in the db when it went
47       * to fetch that preferences.
48       */
49  	@Test public void testPreferencesDefaultSave() throws Exception {
50         //verify that user doesn't have any preferences in the db.
51  
52         final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
53         Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
54         Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
55         assertTrue("UserOptions should be empty", userOptions.isEmpty());
56  
57         PreferencesService preferencesService = KewApiServiceLocator.getPreferencesService();
58         Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
59         assertTrue("Preferences should require a save.", preferences.isRequiresSave());
60  
61         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
62         assertTrue("UserOptions should not empty", userOptions.isEmpty());
63  
64         preferencesService.savePreferences(principal.getPrincipalId(), preferences);
65         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
66         assertTrue("UserOptions should not be empty", !userOptions.isEmpty());
67  
68         preferences = preferencesService.getPreferences(principal.getPrincipalId());
69         assertFalse("Preferences should NOT require a save.", preferences.isRequiresSave());
70  
71         // now delete one of the options
72         final UserOptions refreshRateOption = userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId());
73         assertNotNull("REFRESH_RATE option should exist.", refreshRateOption);
74         TransactionTemplate template = new TransactionTemplate(KEWServiceLocator.getPlatformTransactionManager());
75         template.execute(new TransactionCallback() {
76             public Object doInTransaction(TransactionStatus status) {
77                 userOptionsService.deleteUserOptions(refreshRateOption);
78                 return null;
79             }
80         });
81         assertNull("REFRESH_RATE option should no longer exist.", userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId()));
82  
83         preferences = preferencesService.getPreferences(principal.getPrincipalId());
84         assertTrue("Preferences should now require a save again.", preferences.isRequiresSave());
85  
86         // save refresh rate again
87         template.execute(new TransactionCallback() {
88             public Object doInTransaction(TransactionStatus status) {
89                 userOptionsService.save(refreshRateOption);
90                 return null;
91             }
92         });
93         preferences = preferencesService.getPreferences(principal.getPrincipalId());
94         assertFalse("Preferences should no longer require a save.", preferences.isRequiresSave());
95      }
96  
97  
98  	/**
99       * 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        t1.stop();
151     }
152 }