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