Coverage Report - org.kuali.rice.test.RiceTestCase
 
Classes in this File Line Coverage Branch Coverage Complexity
RiceTestCase
0%
0/141
0%
0/34
1.71
RiceTestCase$1
0%
0/5
N/A
1.71
RiceTestCase$2
0%
0/4
N/A
1.71
RiceTestCase$3
0%
0/4
N/A
1.71
RiceTestCase$4
0%
0/4
N/A
1.71
 
 1  
 /*
 2  
  * Copyright 2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in
 5  
  * compliance with the License. You may obtain a copy of the License at
 6  
  * 
 7  
  * http://www.opensource.org/licenses/ecl2.php
 8  
  * 
 9  
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS
 10  
  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 11  
  * language governing permissions and limitations under the License.
 12  
  */
 13  
 package org.kuali.rice.test;
 14  
 
 15  
 import java.io.IOException;
 16  
 import java.util.ArrayList;
 17  
 import java.util.HashSet;
 18  
 import java.util.LinkedList;
 19  
 import java.util.List;
 20  
 import java.util.ListIterator;
 21  
 import java.util.Properties;
 22  
 import java.util.Set;
 23  
 
 24  
 import javax.xml.namespace.QName;
 25  
 
 26  
 import org.apache.commons.lang.StringUtils;
 27  
 import org.apache.log4j.Logger;
 28  
 import org.apache.log4j.PropertyConfigurator;
 29  
 import org.junit.After;
 30  
 import org.junit.Before;
 31  
 import org.kuali.rice.core.api.config.property.Config;
 32  
 import org.kuali.rice.core.api.config.property.ConfigContext;
 33  
 import org.kuali.rice.core.api.lifecycle.BaseLifecycle;
 34  
 import org.kuali.rice.core.api.lifecycle.Lifecycle;
 35  
 import org.kuali.rice.core.impl.config.property.JAXBConfigImpl;
 36  
 import org.kuali.rice.core.framework.resourceloader.SpringResourceLoader;
 37  
 import org.kuali.rice.test.data.PerSuiteUnitTestData;
 38  
 import org.kuali.rice.test.lifecycles.PerSuiteDataLoaderLifecycle;
 39  
 import org.springframework.core.io.FileSystemResourceLoader;
 40  
 import org.springframework.core.io.Resource;
 41  
 import org.springframework.core.io.ResourceLoader;
 42  
 
 43  
 /**
 44  
  * Useful superclass for all Rice test cases. Handles setup of test utilities and a test environment. Configures the
 45  
  * Spring test environment providing a template method for custom context files in test mode. Also provides a template method
 46  
  * for running custom transactional setUp. Tear down handles automatic tear down of objects created inside the test
 47  
  * environment.
 48  
  * 
 49  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 50  
  * @since 0.9
 51  
  */
 52  0
 public abstract class RiceTestCase extends BaseRiceTestCase {
 53  
 
 54  0
     private static final Logger LOG = Logger.getLogger(RiceTestCase.class);
 55  
 
 56  
     private static final String ALT_LOG4J_CONFIG_LOCATION_PROP = "alt.log4j.config.location";
 57  
     private static final String DEFAULT_LOG4J_CONFIG = "classpath:rice-testharness-default-log4j.properties";
 58  
     protected static final String DEFAULT_TEST_HARNESS_SPRING_BEANS = "classpath:TestHarnessSpringBeans.xml";
 59  0
     protected static boolean SUITE_LIFE_CYCLES_RAN = false;
 60  0
     protected static boolean SUITE_LIFE_CYCLES_FAILED = false;
 61  
     protected static String failedSuiteTestName;
 62  
 
 63  0
     protected List<Lifecycle> perTestLifeCycles = new LinkedList<Lifecycle>();
 64  
 
 65  0
     protected List<Lifecycle> suiteLifeCycles = new LinkedList<Lifecycle>();
 66  
 
 67  0
     private static Set<String> perSuiteDataLoaderLifecycleNamesRun = new HashSet<String>();
 68  
 
 69  0
     private List<String> reports = new ArrayList<String>();
 70  
 
 71  
     private SpringResourceLoader testHarnessSpringResourceLoader;
 72  
 
 73  
     @Before
 74  
     public void setUp() throws Exception {
 75  
         try {
 76  0
             configureLogging();
 77  0
             logBeforeRun();
 78  
 
 79  0
             final long initTime = System.currentTimeMillis();
 80  
 
 81  0
             setUpInternal();
 82  
 
 83  0
             report("Time to start all Lifecycles: " + (System.currentTimeMillis() - initTime));
 84  0
         } catch (Throwable e) {
 85  0
             e.printStackTrace();
 86  0
             tearDown();
 87  0
             throw new RuntimeException(e);
 88  0
         }
 89  0
     }
 90  
 
 91  
     /**
 92  
      * Internal setUp() implementation which is invoked by the main setUp() and wrapped
 93  
      * with exception handling.  Subclasses should override this method if they want to
 94  
      * add set up steps that should occur in the standard set up process, wrapped by
 95  
      * exception handling.
 96  
      */
 97  
     protected void setUpInternal() throws Exception {
 98  0
         assertNotNull(getModuleName());
 99  0
         setModuleName(getModuleName());
 100  0
         setBaseDirSystemProperty(getModuleName());
 101  
 
 102  0
         this.perTestLifeCycles = getPerTestLifecycles();
 103  0
         this.suiteLifeCycles = getSuiteLifecycles();
 104  
 
 105  0
         if (SUITE_LIFE_CYCLES_FAILED) {
 106  0
                 fail("Suite Lifecycles startup failed on test " + failedSuiteTestName + "!!!  Please see logs for details.");
 107  
         }
 108  0
         if (!SUITE_LIFE_CYCLES_RAN) {
 109  
                 try {
 110  0
                     startLifecycles(this.suiteLifeCycles);
 111  0
                     SUITE_LIFE_CYCLES_RAN = true;
 112  0
                 } catch (Throwable e) {
 113  0
                         e.printStackTrace();
 114  0
                 SUITE_LIFE_CYCLES_RAN = false;
 115  0
                 SUITE_LIFE_CYCLES_FAILED = true;
 116  0
                 failedSuiteTestName = getFullTestName();
 117  0
                 tearDown();
 118  0
                 stopLifecycles(this.suiteLifeCycles);
 119  0
                 throw new RuntimeException(e);
 120  0
             }
 121  
         }
 122  
 
 123  0
         startSuiteDataLoaderLifecycles();
 124  
 
 125  0
         startLifecycles(this.perTestLifeCycles);
 126  
 
 127  0
     }
 128  
 
 129  
     /**
 130  
      * This block is walking up the class hierarchy of the current unit test looking for PerSuiteUnitTestData annotations. If it finds one,
 131  
      * it will run it once, then add it to a set so that it does not get run again. This is needed so that multiple 
 132  
      * tests can extend from the same suite and so that there can be multiple suites throughout the test source branch.
 133  
      * 
 134  
      * @throws Exception if a PerSuiteDataLoaderLifecycle is unable to be started
 135  
      */
 136  
     protected void startSuiteDataLoaderLifecycles() throws Exception {
 137  0
         List<Class> classes = TestUtilities.getHierarchyClassesToHandle(getClass(), new Class[] { PerSuiteUnitTestData.class }, perSuiteDataLoaderLifecycleNamesRun);
 138  0
         for (Class c: classes) {
 139  0
             new PerSuiteDataLoaderLifecycle(c).start();
 140  0
             perSuiteDataLoaderLifecycleNamesRun.add(c.getName());
 141  
         }
 142  0
     }
 143  
 
 144  
     /**
 145  
      * maven will set this property and find resources from the config based on it. This makes eclipse testing work because
 146  
      * we have to put the basedir in our config files in order to find things when testing from maven
 147  
      */
 148  
     protected void setBaseDirSystemProperty(String moduleBaseDir) {
 149  0
         if (System.getProperty("basedir") == null) {
 150  0
             System.setProperty("basedir", System.getProperty("user.dir") + "/" + moduleBaseDir);
 151  
         }
 152  0
     }
 153  
 
 154  
     /**
 155  
      * Returns the basedir for the module under which the tests are currently executing.
 156  
      */
 157  
     protected String getBaseDir() {
 158  0
         return System.getProperty("basedir");
 159  
     }
 160  
 
 161  
     protected void setModuleName(String moduleName) {
 162  0
         if (System.getProperty("module.name") == null) {
 163  0
             System.setProperty("module.name", moduleName);
 164  
         }
 165  0
     }
 166  
 
 167  
     @After
 168  
     public void tearDown() throws Exception {
 169  
             // wait for outstanding threads to complete for 1 minute
 170  0
             ThreadMonitor.tearDown(60000);
 171  0
         stopLifecycles(this.perTestLifeCycles);
 172  0
         logAfterRun();
 173  0
     }
 174  
 
 175  
     protected void logBeforeRun() {
 176  0
         LOG.info("##############################################################");
 177  0
         LOG.info("# Starting test " + getFullTestName() + "...");
 178  0
         LOG.info("# " + dumpMemory());
 179  0
         LOG.info("##############################################################");
 180  0
     }
 181  
 
 182  
     protected void logAfterRun() {
 183  0
         LOG.info("##############################################################");
 184  0
         LOG.info("# ...finished test " + getFullTestName());
 185  0
         LOG.info("# " + dumpMemory());
 186  0
         for (final String report : this.reports) {
 187  0
             LOG.info("# " + report);
 188  
         }
 189  0
         LOG.info("##############################################################\n\n\n");
 190  0
     }
 191  
     
 192  
     protected String getFullTestName() {
 193  0
             return getClass().getSimpleName() + "." + getName();
 194  
     }
 195  
 
 196  
         protected void configureLogging() throws IOException {
 197  0
         ResourceLoader resourceLoader = new FileSystemResourceLoader();
 198  0
         String altLog4jConfigLocation = System.getProperty(ALT_LOG4J_CONFIG_LOCATION_PROP);
 199  0
         Resource log4jConfigResource = null;
 200  0
         if (!StringUtils.isEmpty(altLog4jConfigLocation)) { 
 201  0
             log4jConfigResource = resourceLoader.getResource(altLog4jConfigLocation);
 202  
         }
 203  0
         if (log4jConfigResource == null || !log4jConfigResource.exists()) {
 204  0
             System.out.println("Alternate Log4j config resource does not exist! " + altLog4jConfigLocation);
 205  0
             System.out.println("Using default log4j configuration: " + DEFAULT_LOG4J_CONFIG);
 206  0
             log4jConfigResource = resourceLoader.getResource(DEFAULT_LOG4J_CONFIG);
 207  
         } else {
 208  0
             System.out.println("Using alternate log4j configuration at: " + altLog4jConfigLocation);
 209  
         }
 210  0
         Properties p = new Properties();
 211  0
         p.load(log4jConfigResource.getInputStream());
 212  0
         PropertyConfigurator.configure(p);
 213  0
     }
 214  
 
 215  
         /**
 216  
          * Executes the start() method of each of the lifecycles in the given list.
 217  
          */
 218  
     protected void startLifecycles(List<Lifecycle> lifecycles) throws Exception {
 219  0
         for (Lifecycle lifecycle : lifecycles) {
 220  0
             lifecycle.start();
 221  
         }
 222  0
     }
 223  
 
 224  
     /**
 225  
      * Executes the stop() method of each of the lifecyles in the given list.  The
 226  
      * List of lifecycles is processed in reverse order.
 227  
      */
 228  
     protected void stopLifecycles(List<Lifecycle> lifecycles) throws Exception {
 229  0
         final ListIterator<Lifecycle> iter = lifecycles.listIterator();
 230  0
         while (iter.hasNext()) {
 231  0
             iter.next();
 232  
         }
 233  0
         while (iter.hasPrevious()) {
 234  0
             final Lifecycle lifeCycle = iter.previous();
 235  
             try {
 236  0
                     if (lifeCycle == null) {
 237  0
                             LOG.warn("Attempted to stop a null lifecycle");
 238  
                     } else {
 239  0
                             if (lifeCycle.isStarted()) {
 240  0
                                     lifeCycle.stop();
 241  
                             }
 242  
                     }
 243  0
             } catch (Exception e) {
 244  0
                 LOG.warn("Failed to shutdown one of the lifecycles!", e);
 245  0
             }
 246  0
         }
 247  0
     }
 248  
 
 249  
     /**
 250  
      * Returns the List of Lifecycles to start when the unit test suite is started
 251  
      */
 252  
     protected List<Lifecycle> getSuiteLifecycles() {
 253  0
         List<Lifecycle> lifecycles = new LinkedList<Lifecycle>();
 254  
         
 255  
         /**
 256  
          * Initializes Rice configuration from the test harness configuration file.
 257  
          */
 258  0
         lifecycles.add(new BaseLifecycle() {
 259  
             public void start() throws Exception {
 260  0
                 Config config = getTestHarnessConfig();
 261  0
                 ConfigContext.init(config);
 262  0
                 super.start();
 263  0
             }
 264  
         });
 265  
         
 266  
         /**
 267  
          * Loads the TestHarnessSpringBeans.xml file which obtains connections to the DB for us
 268  
          */
 269  0
         lifecycles.add(getTestHarnessSpringResourceLoader());
 270  
         
 271  
         /**
 272  
          * Establishes the TestHarnessServiceLocator so that it has a reference to the Spring context
 273  
          * created from TestHarnessSpringBeans.xml
 274  
          */
 275  0
         lifecycles.add(new BaseLifecycle() {
 276  
             public void start() throws Exception {
 277  0
                 TestHarnessServiceLocator.setContext(getTestHarnessSpringResourceLoader().getContext());
 278  0
                 super.start();
 279  0
             }
 280  
         });
 281  
         
 282  
         /**
 283  
          * Clears the tables in the database.
 284  
          */
 285  0
         lifecycles.add(new ClearDatabaseLifecycle());
 286  
         
 287  
         /**
 288  
          * Loads Suite Test Data
 289  
          */
 290  0
         lifecycles.add(new BaseLifecycle() {
 291  
                 public void start() throws Exception {
 292  0
                         loadSuiteTestData();
 293  0
                         super.start();
 294  0
                 }
 295  
         });
 296  
         
 297  0
         Lifecycle loadApplicationLifecycle = getLoadApplicationLifecycle();
 298  0
         if (loadApplicationLifecycle != null) {
 299  0
                 lifecycles.add(loadApplicationLifecycle);
 300  
         }
 301  0
         return lifecycles;
 302  
     }
 303  
     
 304  
     /**
 305  
      * This should return a Lifecycle that can be used to load the application
 306  
      * being tested.  For example, this could start a Jetty Server which loads
 307  
      * the application, or load a Spring context to establish a set of services,
 308  
      * or any other application startup activities that the test depends upon.
 309  
      */
 310  
     protected Lifecycle getLoadApplicationLifecycle() {
 311  
             // by default return null, do nothing
 312  0
             return null;
 313  
     }
 314  
 
 315  
     /**
 316  
      * @return Lifecycles run every test run
 317  
      */
 318  
     protected List<Lifecycle> getPerTestLifecycles() {
 319  0
             List<Lifecycle> lifecycles = new LinkedList<Lifecycle>();
 320  0
             if (getClass().isAnnotationPresent(TransactionalTest.class)) {
 321  0
                     String transactionManagerName = getClass().getAnnotation(TransactionalTest.class).transactionManager();
 322  0
                         TransactionalLifecycle transactionalLifecycle = new TransactionalLifecycle(transactionManagerName);
 323  0
                         lifecycles.add(transactionalLifecycle);
 324  
                 }
 325  0
         lifecycles.add(getPerTestDataLoaderLifecycle());
 326  0
         lifecycles.add(new BaseLifecycle() {
 327  
             public void start() throws Exception {
 328  0
                 loadPerTestData();
 329  0
                 super.start();
 330  0
             }
 331  
         });
 332  0
         return lifecycles;
 333  
     }
 334  
     
 335  
     /**
 336  
      * A method that can be overridden to load test data for the unit test Suite.
 337  
      */
 338  
     protected void loadSuiteTestData() throws Exception {
 339  
             // do nothing by default, subclass can override
 340  0
     }
 341  
     
 342  
     /**
 343  
      * A method that can be overridden to load test data on a test-by-test basis
 344  
      */
 345  
     protected void loadPerTestData() throws Exception {
 346  
             // do nothing by default, subclass can override
 347  0
     }
 348  
 
 349  
     protected void report(final String report) {
 350  0
         this.reports.add(report);
 351  0
     }
 352  
 
 353  
     protected String dumpMemory() {
 354  0
         final long total = Runtime.getRuntime().totalMemory();
 355  0
         final long free = Runtime.getRuntime().freeMemory();
 356  0
         final long max = Runtime.getRuntime().maxMemory();
 357  0
         return "[Memory] max: " + max + ", total: " + total + ", free: " + free;
 358  
     }
 359  
 
 360  
     public SpringResourceLoader getTestHarnessSpringResourceLoader() {
 361  0
         if (testHarnessSpringResourceLoader == null) {
 362  0
             testHarnessSpringResourceLoader = new SpringResourceLoader(new QName("TestHarnessSpringContext"), getTestHarnessSpringBeansLocation(), null);
 363  
         }
 364  0
         return testHarnessSpringResourceLoader;
 365  
     }
 366  
 
 367  
     /**
 368  
      * Returns the location of the test harness spring beans context file.
 369  
      * Subclasses may override to specify a different location.
 370  
      * @return the location of the test harness spring beans context file.
 371  
      */
 372  
     protected String getTestHarnessSpringBeansLocation() {
 373  0
         return DEFAULT_TEST_HARNESS_SPRING_BEANS;
 374  
     }
 375  
 
 376  
     protected Config getTestHarnessConfig() throws Exception {
 377  0
         Config config = new JAXBConfigImpl(getConfigLocations(), System.getProperties());
 378  0
         config.parseConfig();
 379  0
         return config;
 380  
     }
 381  
 
 382  
     /**
 383  
      * Subclasses may override this method to customize the location(s) of the Rice configuration.
 384  
      * By default it is: classpath:META-INF/" + getModuleName().toLowerCase() + "-test-config.xml"
 385  
      * @return List of config locations to add to this tests config location.
 386  
      */
 387  
     protected List<String> getConfigLocations() {
 388  0
         List<String> configLocations = new ArrayList<String>();
 389  0
         configLocations.add(getRiceMasterDefaultConfigFile());
 390  0
         configLocations.add(getModuleTestConfigLocation());
 391  0
         return configLocations;
 392  
     }
 393  
     
 394  
     protected String getModuleTestConfigLocation() {
 395  0
         return "classpath:META-INF/" + getModuleName().toLowerCase() + "-test-config.xml";
 396  
     }
 397  
 
 398  
     protected String getRiceMasterDefaultConfigFile() {
 399  0
         return "classpath:META-INF/test-config-defaults.xml";
 400  
     }
 401  
 
 402  
     /**
 403  
      * same as the module directory in the project.
 404  
      * 
 405  
      * @return name of module that the tests located
 406  
      */
 407  
     protected abstract String getModuleName();
 408  
 
 409  
 }