001    /*
002     * Copyright 2005-2007 The Kuali Foundation
003     *
004     *
005     * Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in
006     * compliance with the License. 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 distributed under the License is distributed on an "AS
011     * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
012     * language governing permissions and limitations under the License.
013     */
014    package org.kuali.rice.kew.test;
015    
016    import java.io.InputStream;
017    import java.util.ArrayList;
018    import java.util.List;
019    
020    import org.kuali.rice.core.config.Config;
021    import org.kuali.rice.core.config.ConfigContext;
022    import org.kuali.rice.core.lifecycle.BaseLifecycle;
023    import org.kuali.rice.core.lifecycle.Lifecycle;
024    import org.kuali.rice.core.web.jetty.JettyServer;
025    import org.kuali.rice.kew.batch.KEWXmlDataLoader;
026    import org.kuali.rice.kew.exception.WorkflowRuntimeException;
027    import org.kuali.rice.kew.service.KEWServiceLocator;
028    import org.kuali.rice.kew.util.KEWConstants;
029    import org.kuali.rice.kim.service.KIMServiceLocator;
030    import org.kuali.rice.kns.util.GlobalVariables;
031    import org.kuali.rice.kns.util.MessageMap;
032    import org.kuali.rice.test.ClearDatabaseLifecycle;
033    import org.kuali.rice.test.RiceInternalSuiteDataTestCase;
034    import org.kuali.rice.test.SQLDataLoader;
035    import org.springframework.transaction.support.TransactionTemplate;
036    
037    /**
038     * Useful superclass for all KEW test cases. Handles setup of test utilities and
039     * a test environment. Configures the Spring test environment providing a
040     * template method for custom context files in test mode. Also provides a
041     * template method for running custom transactional setUp. Tear down handles
042     * automatic tear down of objects created inside the test environment.
043     */
044    public abstract class KEWTestCase extends RiceInternalSuiteDataTestCase {
045    
046            /**
047             * This is the "bootstrap", aka Rice client, Spring beans file that the KEW
048             * test harness will load
049             */
050            private static final String DEFAULT_KEW_BOOTSTRAP_SPRING_FILE = "classpath:org/kuali/rice/kew/config/TestKEWSpringBeans.xml";
051    
052            @Override
053            protected String getModuleName() {
054                    return TestUtils.getModuleName();
055            }
056    
057            /**
058             * Default implementation does nothing. Subclasses should override this
059             * method if they want to perform setup work inside of a database
060             * transaction.
061             */
062            protected void setUpAfterDataLoad() throws Exception {
063                    // override
064            }
065    
066            protected void loadTestData() throws Exception {
067                    // override this to load your own test data
068            }
069    
070            protected TransactionTemplate getTransactionTemplate() {
071                    return TestUtilities.getTransactionTemplate();
072            }
073    
074            /**
075             * Override the RiceTestCase setUpInternal in order to set a system property
076             * beforehand.
077             *
078             * @see org.kuali.rice.test.RiceTestCase#setUpInternal()
079             */
080            @Override
081            protected void setUpInternal() throws Exception {
082                    System.setProperty(KEWConstants.BOOTSTRAP_SPRING_FILE,
083                                    getKEWBootstrapSpringFile());
084                    super.setUpInternal();
085            }
086    
087            /**
088             * Initiates loading of per-test data
089             */
090            @Override
091            protected void loadPerTestData() throws Exception {
092                    final long t1 = System.currentTimeMillis();
093    
094                    loadDefaultTestData();
095    
096                    final long t2 = System.currentTimeMillis();
097                    report("Time to load default test data: " + (t2 - t1));
098    
099                    loadTestData();
100    
101                    final long t3 = System.currentTimeMillis();
102                    report("Time to load test-specific test data: " + (t3 - t2));
103    
104                    setUpAfterDataLoad();
105    
106                    final long t4 = System.currentTimeMillis();
107                    report("Time to run test-specific setup: " + (t4 - t3));
108            }
109    
110            /**
111             * Returns the "bootstrap", aka Rice client, Spring beans file that the KEW
112             * test harness will load. KEW test cases can override this to provide an
113             * alternative bootstrap spring file. Currently only one file is supported,
114             * so one must override this file and then import the core file.
115             *
116             * @return the "bootstrap", aka Rice client, Spring beans file that the KEW
117             *         test harness will load
118             */
119            protected String getKEWBootstrapSpringFile() {
120                    return DEFAULT_KEW_BOOTSTRAP_SPRING_FILE;
121            }
122    
123            /**
124             * Override the standard per-test lifecycles to prepend
125             * ClearDatabaseLifecycle and ClearCacheLifecycle
126             *
127             * @see org.kuali.rice.test.RiceTestCase#getPerTestLifecycles()
128             */
129            @Override
130            protected List<Lifecycle> getPerTestLifecycles() {
131                    List<Lifecycle> lifecycles = new ArrayList<Lifecycle>();
132                    lifecycles.add(new ClearDatabaseLifecycle(getPerTestTablesToClear(),
133                                    getPerTestTablesNotToClear()));
134                    lifecycles.add(new ClearCacheLifecycle());
135                    lifecycles.addAll(super.getPerTestLifecycles());
136                    return lifecycles;
137            }
138    
139            /**
140             * Override the suite lifecycles to avoid the ClearDatabaseLifecycle (which
141             * we do on a per-test basis, as above) and to add on a JettyServer
142             * lifecycle
143             *
144             * @see org.kuali.rice.test.RiceTestCase#getSuiteLifecycles()
145             */
146            @Override
147            protected List<Lifecycle> getSuiteLifecycles() {
148                    
149                    List<Lifecycle> lifeCycles = super.getSuiteLifecycles();
150                    lifeCycles.add( buildJettyServer(getJettyServerPort(), getJettyServerContextName(), getJettyServerRelativeWebappRoot()));
151                    lifeCycles.add(new InitializeGRL());
152                    lifeCycles.add(new BaseLifecycle() {
153                            public void start() throws Exception {
154                                    KEWXmlDataLoader.loadXmlClassLoaderResource(getClass(), "DefaultSuiteTestData.xml");
155                                    super.start();
156                            }
157                    });
158                    return lifeCycles;
159            }
160    
161            @Override
162            protected void loadSuiteTestData() throws Exception {
163                    super.loadSuiteTestData();
164                    new SQLDataLoader(
165                                    "classpath:org/kuali/rice/kew/test/DefaultSuiteTestData.sql", ";")
166                                    .runSql();
167            }
168    
169            protected JettyServer buildJettyServer(int port, String contextName, String relativeWebappRoot) {
170                    JettyServer server = new JettyServer(port, contextName, relativeWebappRoot);
171                    server.setFailOnContextFailure(true);
172                    server.setTestMode(true);
173                    return server;
174            }
175    
176            /*
177             * Checks to see if a Jetty server is runningneeds to be randomly generated and then made available to subsequent
178             * tests
179             */
180            protected int getJettyServerPort() {
181                    Config cfgCtx = null;
182                    try {
183                            cfgCtx = getTestHarnessConfig();
184                    } catch (Exception e) {
185                            log.error("Caught exception attempting to load test harness prior to aggregating suite lifecycles.");
186                    }
187                    return Integer.parseInt(cfgCtx.getProperty(KEWConstants.HTTP_SERVICE_PORT));
188            }
189    
190            protected String getJettyServerContextName() {
191                    Config cfgCtx = null;
192                    try {
193                            cfgCtx = getTestHarnessConfig();
194                    } catch (Exception e) {
195                            log.error("Caught exception attempting to load test harness prior to aggregating suite lifecycles.");
196                    }
197                    return cfgCtx.getProperty(KEWConstants.KEW_SERVER_CONTEXT);             
198            }
199    
200            protected String getJettyServerRelativeWebappRoot() {
201                    return "/../web/src/main/webapp/kew";
202            }
203    
204            /**
205             * Adds any ResourceLoaders that have been registered for WebAppClassLoaders
206             * to the GlobalResourceLoader
207             */
208            private class InitializeGRL extends BaseLifecycle {
209                    @Override
210                    public void start() throws Exception {
211                            org.kuali.rice.test.TestUtilities.addWebappsToContext();
212                            super.start();
213                    }
214    
215            }
216    
217            /**
218             * Flushes the KEW cache(s)
219             */
220            public class ClearCacheLifecycle extends BaseLifecycle {
221                    @Override
222                    public void stop() throws Exception {
223                            KEWServiceLocator.getCacheAdministrator().flushAll();
224                            KIMServiceLocator.getIdentityManagementService().flushAllCaches();
225                            KIMServiceLocator.getRoleManagementService().flushRoleCaches();
226                            super.stop();
227                    }
228    
229            }
230    
231            /**
232             * Returns the List of tables that should be cleared on every test run.
233             */
234            protected List<String> getPerTestTablesToClear() {
235                    List<String> tablesToClear = new ArrayList<String>();
236                    tablesToClear.add("KREW_.*");
237                    tablesToClear.add("KRSB_.*");
238                    tablesToClear.add("KREN_.*");
239                    return tablesToClear;
240            }
241    
242            protected List<String> getPerTestTablesNotToClear() {
243                    return new ArrayList<String>();
244            }
245    
246            /**
247             * By default this loads the "default" data set from the DefaultTestData.sql
248             * and DefaultTestData.xml files. Subclasses can override this to change
249             * this behaviour
250             */
251            protected void loadDefaultTestData() throws Exception {
252                    // at this point this is constants. loading these through xml import is
253                    // problematic because of cache notification
254                    // issues in certain low level constants.
255                    new SQLDataLoader(
256                                    "classpath:org/kuali/rice/kew/test/DefaultPerTestData.sql", ";")
257                                    .runSql();
258    
259                    KEWXmlDataLoader.loadXmlClassLoaderResource(KEWTestCase.class,
260                                    "DefaultPerTestData.xml");
261                    GlobalVariables.setMessageMap(new MessageMap());
262            }
263    
264            protected void loadXmlFile(String fileName) {
265                    try {
266                            KEWXmlDataLoader.loadXmlClassLoaderResource(getClass(), fileName);
267                    } catch (Exception e) {
268                            throw new WorkflowRuntimeException(e);
269                    }
270            }
271    
272            protected void loadXmlFile(Class clazz, String fileName) {
273                    try {
274                            KEWXmlDataLoader.loadXmlClassLoaderResource(clazz, fileName);
275                    } catch (Exception e) {
276                            throw new WorkflowRuntimeException(e);
277                    }
278            }
279    
280            protected void loadXmlFileFromFileSystem(String fileName) {
281                    try {
282                            KEWXmlDataLoader.loadXmlFile(fileName);
283                    } catch (Exception e) {
284                            throw new WorkflowRuntimeException(e);
285                    }
286            }
287    
288            protected void loadXmlStream(InputStream xmlStream) {
289                    try {
290                            KEWXmlDataLoader.loadXmlStream(xmlStream);
291                    } catch (Exception e) {
292                            throw new WorkflowRuntimeException(e);
293                    }
294            }
295    
296            protected String getPrincipalIdForName(String principalName) {
297                    return KEWServiceLocator.getIdentityHelperService()
298                                    .getIdForPrincipalName(principalName);
299            }
300    
301            protected String getPrincipalNameForId(String principalId) {
302                    return KEWServiceLocator.getIdentityHelperService().getPrincipal(
303                                    principalId).getPrincipalName();
304            }
305    
306            protected String getGroupIdForName(String namespace, String groupName) {
307                    return KEWServiceLocator.getIdentityHelperService().getIdForGroupName(
308                                    namespace, groupName);
309            }
310    }