View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.preferences;
18  
19  import static org.junit.Assert.assertFalse;
20  import static org.junit.Assert.assertNotNull;
21  import static org.junit.Assert.assertNull;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.List;
27  
28  import org.junit.Test;
29  import org.kuali.rice.kew.preferences.service.PreferencesService;
30  import org.kuali.rice.kew.service.KEWServiceLocator;
31  import org.kuali.rice.kew.test.KEWTestCase;
32  import org.kuali.rice.kew.useroptions.UserOptions;
33  import org.kuali.rice.kew.useroptions.UserOptionsService;
34  import org.kuali.rice.kim.api.identity.principal.Principal;
35  import org.springframework.transaction.TransactionStatus;
36  import org.springframework.transaction.support.TransactionCallback;
37  import org.springframework.transaction.support.TransactionTemplate;
38  
39  
40  
41  public class PreferencesServiceTest extends KEWTestCase {
42  
43      /**
44       * Test that the preferences are saved by default when going through the preferences service.  This
45       * means that the preferences service will persist any user option that was not in the db when it went
46       * to fetch that preference.
47       */
48  	@Test public void testPreferencesDefaultSave() throws Exception {
49         //verify that user doesn't have any preferences in the db.
50  
51         final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
52         Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
53         Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
54         assertTrue("UserOptions should be empty", userOptions.isEmpty());
55  
56         PreferencesService preferencesService = KEWServiceLocator.getPreferencesService();
57         Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
58         assertTrue("Preferences should require a save.", preferences.isRequiresSave());
59  
60         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
61         assertTrue("UserOptions should not empty", userOptions.isEmpty());
62  
63         preferencesService.savePreferences(principal.getPrincipalId(), preferences);
64         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
65         assertTrue("UserOptions should not be empty", !userOptions.isEmpty());
66  
67         preferences = preferencesService.getPreferences(principal.getPrincipalId());
68         assertFalse("Preferences should NOT require a save.", preferences.isRequiresSave());
69  
70         // now delete one of the options
71         final UserOptions refreshRateOption = userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId());
72         assertNotNull("REFRESH_RATE option should exist.", refreshRateOption);
73         TransactionTemplate template = new TransactionTemplate(KEWServiceLocator.getPlatformTransactionManager());
74         template.execute(new TransactionCallback() {
75             public Object doInTransaction(TransactionStatus status) {
76                 userOptionsService.deleteUserOptions(refreshRateOption);
77                 return null;
78             }
79         });
80         assertNull("REFRESH_RATE option should no longer exist.", userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId()));
81  
82         preferences = preferencesService.getPreferences(principal.getPrincipalId());
83         assertTrue("Preferences should now require a save again.", preferences.isRequiresSave());
84  
85         // save refresh rate again
86         template.execute(new TransactionCallback() {
87             public Object doInTransaction(TransactionStatus status) {
88                 userOptionsService.save(refreshRateOption);
89                 return null;
90             }
91         });
92         preferences = preferencesService.getPreferences(principal.getPrincipalId());
93         assertFalse("Preferences should no longer require a save.", preferences.isRequiresSave());
94      }
95  
96  
97  	/**
98       * Tests default saving concurrently which can cause a race condition on startup
99       * that leads to constraint violations
100      */
101     @Test public void testPreferencesConcurrentDefaultSave() throws Throwable {
102        //verify that user doesn't have any preferences in the db.
103        final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
104        final Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
105        Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
106        assertTrue("UserOptions should be empty", userOptions.isEmpty());
107 
108        final PreferencesService preferencesService = KEWServiceLocator.getPreferencesService();
109        Runnable getPrefRunnable = new Runnable() {
110            public void run() {
111                Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
112                assertTrue("Preferences should require a save.", preferences.isRequiresSave());
113                Collection updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
114                assertTrue("UserOptions should be empty", updatedOptions.isEmpty());
115            }
116        };
117        final List<Throwable> errors = new ArrayList<Throwable>();
118        Thread.UncaughtExceptionHandler ueh = new Thread.UncaughtExceptionHandler() {
119            public void uncaughtException(Thread thread, Throwable error) {
120                errors.add(error);
121            }
122        };
123 
124        // 3 threads should do
125        Thread t1 = new Thread(getPrefRunnable);
126        Thread t2 = new Thread(getPrefRunnable);
127        Thread t3 = new Thread(getPrefRunnable);
128        t1.setUncaughtExceptionHandler(ueh);
129        t2.setUncaughtExceptionHandler(ueh);
130        t3.setUncaughtExceptionHandler(ueh);
131        t1.start();
132        t2.start();
133        t3.start();
134        t1.join();
135        t2.join();
136        t3.join();
137 
138        if (errors.size() > 0) {
139            throw errors.iterator().next();
140        }
141 
142        Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
143        assertTrue("Preferences should require a save.", preferences.isRequiresSave());
144        Collection updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
145        assertTrue("UserOptions should be empty", updatedOptions.isEmpty());
146        preferencesService.savePreferences(principal.getPrincipalId(), preferences);
147        updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
148        assertTrue("UserOptions should not be empty", !updatedOptions.isEmpty());
149 
150     }
151 }