View Javadoc
1   /**
2    * Copyright 2005-2014 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.io.StringReader;
24  import java.io.StringWriter;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  
31  import junit.framework.Assert;
32  import org.junit.Test;
33  import org.kuali.rice.kew.api.KewApiServiceLocator;
34  import org.kuali.rice.kew.api.preferences.Preferences;
35  import org.kuali.rice.kew.api.preferences.PreferencesService;
36  import org.kuali.rice.kew.service.KEWServiceLocator;
37  import org.kuali.rice.kew.test.KEWTestCase;
38  import org.kuali.rice.kew.useroptions.UserOptions;
39  import org.kuali.rice.kew.useroptions.UserOptionsService;
40  import org.kuali.rice.kim.api.identity.principal.Principal;
41  
42  import javax.xml.bind.JAXBContext;
43  import javax.xml.bind.Marshaller;
44  import javax.xml.bind.Unmarshaller;
45  
46  public class PreferencesServiceTest extends KEWTestCase {
47  
48      /**
49       * Test that the preferences are saved by default when going through the preferences service.  This
50       * means that the preferences service will persist any user option that was not in the db when it went
51       * to fetch that preferences.
52       */
53  	@Test public void testPreferencesDefaultSave() throws Exception {
54         //verify that user doesn't have any preferences in the db.
55  
56         final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
57         Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
58         Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
59         assertTrue("UserOptions should be empty", userOptions.isEmpty());
60  
61         PreferencesService preferencesService = KewApiServiceLocator.getPreferencesService();
62         Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
63         assertTrue("Preferences should require a save.", preferences.isRequiresSave());
64  
65         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
66         assertTrue("UserOptions should not empty", userOptions.isEmpty());
67  
68         preferencesService.savePreferences(principal.getPrincipalId(), preferences);
69         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
70         assertTrue("UserOptions should not be empty", !userOptions.isEmpty());
71  
72         preferences = preferencesService.getPreferences(principal.getPrincipalId());
73         assertFalse("Preferences should NOT require a save.", preferences.isRequiresSave());
74  
75         // now delete one of the options
76         final UserOptions refreshRateOption = userOptionsService.findByOptionId("REFRESH_RATE", principal.getPrincipalId());
77         assertNotNull("REFRESH_RATE option should exist.", refreshRateOption);
78         userOptionsService.deleteUserOptions(refreshRateOption);
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         refreshRateOption.setLockVerNbr(null);
87         userOptionsService.save(refreshRateOption);
88  
89         preferences = preferencesService.getPreferences(principal.getPrincipalId());
90         assertFalse("Preferences should no longer require a save.", preferences.isRequiresSave());
91      }
92  
93      /**
94       * Tests preference marshalling with invalid json.
95       */
96      @Test
97      public void testPreferencesMarshallingWithInvalidJson() {
98          final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
99          Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("ewestfal");
100         Collection<UserOptions> userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
101         assertTrue("UserOptions should be empty", userOptions.isEmpty());
102 
103         PreferencesService preferencesService = KewApiServiceLocator.getPreferencesService();
104         Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
105         assertTrue("Preferences should require a save.", preferences.isRequiresSave());
106         preferencesService.savePreferences(principal.getPrincipalId(), preferences);
107         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
108 
109         UserOptions docSearchOrder = new UserOptions();
110         docSearchOrder.setOptionId("DocSearch.LastSearch.Order");
111         docSearchOrder.setWorkflowId(principal.getPrincipalId());
112         docSearchOrder.setOptionVal("DocSearch.LastSearch.Holding0");
113 
114         UserOptions badJsonOption = new UserOptions();
115         badJsonOption.setOptionId("DocSearch.LastSearch.Holding0");
116         badJsonOption.setWorkflowId(principal.getPrincipalId());
117 
118         //this be invalid
119         badJsonOption.setOptionVal("{isAdvancedSearch\":\"NO\",\"dateCreatedFrom\":1339168393063,\"documentStatuses\":[],\"documentStatusCategories\":[],\"documentAttributeValues\":{},\"additionalDocumentTypeNames\":[]}");
120 
121         userOptionsService.save(docSearchOrder);
122         userOptionsService.save(badJsonOption);
123 
124 
125         userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
126         assertTrue("UserOptions should not empty", !userOptions.isEmpty());
127 
128         //UserOptions previousDocSearch0 = userOptionsService.findByOptionId("DocSearch.LastSearch.Holding0", principal.getPrincipalId());
129         preferences = preferencesService.getPreferences(principal.getPrincipalId());
130         Preferences.Builder pBuilder = Preferences.Builder.create(preferences);
131         Map<String, String> docTypeNotification = new HashMap<String, String>();
132 
133         docTypeNotification.put("hello", "world");
134         docTypeNotification.put("does_this_thing_have_a", "bookstore example");
135         pBuilder.setDocumentTypeNotificationPreferences(docTypeNotification);
136 
137         String marshaledXml = null;
138         try {
139             JAXBContext jaxbContext = JAXBContext.newInstance(Preferences.class);
140             Marshaller marshaller = jaxbContext.createMarshaller();
141 
142             StringWriter stringWriter = new StringWriter();
143 
144             marshaller.marshal(pBuilder.build(), stringWriter);
145 
146             marshaledXml = stringWriter.toString();
147 
148             Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
149             Preferences actual = (Preferences)unmarshaller.unmarshal(new StringReader(marshaledXml));
150             //Object expected = unmarshaller.unmarshal(new StringReader(XML))
151             Assert.assertEquals(pBuilder.build(), actual);
152 
153         } catch (Throwable e) {
154             e.printStackTrace();
155         }
156 
157 
158     }
159 
160 
161 	/**
162      * Tests default saving concurrently which can cause a race condition on startup
163      * that leads to constraint violations.
164      */
165     @Test public void testPreferencesConcurrentDefaultSave() throws Throwable {
166        //verify that user doesn't have any preferences in the db.
167        final UserOptionsService userOptionsService = KEWServiceLocator.getUserOptionsService();
168        final Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
169        Collection userOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
170        assertTrue("UserOptions should be empty", userOptions.isEmpty());
171 
172        final PreferencesService preferencesService = KewApiServiceLocator.getPreferencesService();
173        Runnable getPrefRunnable = new Runnable() {
174            public void run() {
175                Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
176                assertTrue("Preferences should require a save.", preferences.isRequiresSave());
177                Collection updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
178                assertTrue("UserOptions should be empty", updatedOptions.isEmpty());
179            }
180        };
181        final List<Throwable> errors = new ArrayList<Throwable>();
182        Thread.UncaughtExceptionHandler ueh = new Thread.UncaughtExceptionHandler() {
183            public void uncaughtException(Thread thread, Throwable error) {
184                errors.add(error);
185            }
186        };
187 
188        // 3 threads should do
189        Thread t1 = new Thread(getPrefRunnable);
190        Thread t2 = new Thread(getPrefRunnable);
191        Thread t3 = new Thread(getPrefRunnable);
192        t1.setUncaughtExceptionHandler(ueh);
193        t2.setUncaughtExceptionHandler(ueh);
194        t3.setUncaughtExceptionHandler(ueh);
195        t1.start();
196        t2.start();
197        t3.start();
198        t1.join();
199        t2.join();
200        t3.join();
201 
202        if (errors.size() > 0) {
203            throw errors.iterator().next();
204        }
205 
206        Preferences preferences = preferencesService.getPreferences(principal.getPrincipalId());
207        assertTrue("Preferences should require a save.", preferences.isRequiresSave());
208        Collection updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
209        assertTrue("UserOptions should be empty", updatedOptions.isEmpty());
210        preferencesService.savePreferences(principal.getPrincipalId(), preferences);
211        updatedOptions = userOptionsService.findByWorkflowUser(principal.getPrincipalId());
212        assertTrue("UserOptions should not be empty", !updatedOptions.isEmpty());
213        t1.stop();
214     }
215 }