001 /** 002 * Copyright 2005-2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * 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 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.test; 017 018 import org.kuali.rice.core.api.lifecycle.Lifecycle; 019 020 import java.lang.annotation.ElementType; 021 import java.lang.annotation.Inherited; 022 import java.lang.annotation.Retention; 023 import java.lang.annotation.RetentionPolicy; 024 import java.lang.annotation.Target; 025 import java.util.ArrayList; 026 import java.util.List; 027 028 /** 029 * Test case which supports common styles of "baselining" the test environment before/after running 030 * a unit test. 031 * Currently supports three modes, which are specifyiable either via constructor, {@link #getMode()} override, 032 * or by annotation: 033 * <dl> 034 * <dt>NONE</dt> 035 * <dd>No baselining is performed. Because the base RiceTestCase includes the ClearDatabaseLifecycle by default, this lifecycle is 036 * explicitly omitted</dd> 037 * <dt>CLEAR_DB</dt> 038 * <dd>The database is cleared for each test. The suite ClearDatabaseLifecycle is omitted (since it's getting cleared each test 039 * anyway)</dd> 040 * <dt>ROLLBACK_CLEAR_DB</dt> 041 * <dd>A TransactionalLifecycle is installed that wraps each test and rolls back data. The suite ClearDatabaseLifecycle will be 042 * invoked once initially, and subsequently if the test has detected that the environment has been left "dirty" by a previous 043 * test. After a successful rollback, the test environment is marked clean again.</dd> 044 * <dd>A TransactionalLifecycle is installed that wraps each test and rolls back data.</dd> 045 * </dl> 046 * 047 * The BaselineMode annotation can be used on a per-test-class basis to indicate to the base class which mode to use for test 048 * subclass. It accepts a {@link Mode} value. 049 * 050 * @author Kuali Rice Team (rice.collab@kuali.org) 051 * 052 */ 053 public class BaselineTestCase extends BaseModuleTestCase { 054 /** 055 * Enum of "baselining" modes that this test case supports 056 */ 057 public static enum Mode { 058 CLEAR_DB, ROLLBACK_CLEAR_DB, ROLLBACK, NONE 059 } 060 061 @Target({ElementType.TYPE}) 062 @Inherited 063 @Retention(RetentionPolicy.RUNTIME) 064 public @interface BaselineMode { 065 Mode value(); 066 } 067 068 private Mode mode = Mode.NONE; 069 070 /** 071 * Whether the test environment is in a "dirty" state. Each time the unit test starts up 072 * dirty is set to true. If a subclass installs the {@link TransactionalLifecycle} then 073 * it should clear the dirty flag. This flag can be used to perform cleanup in case a previous 074 * test left the test environment in a "dirty" state. 075 */ 076 protected static boolean dirty = false; 077 078 // propagate constructors 079 public BaselineTestCase(String moduleName) { 080 super(moduleName); 081 readModeAnnotation(); 082 } 083 084 /** 085 * Adds the ability to specify Mode 086 */ 087 public BaselineTestCase(String moduleName, Mode mode) { 088 super(moduleName); 089 if (mode == null) throw new IllegalArgumentException("Mode cannot be null"); 090 this.mode = mode; 091 } 092 093 private void readModeAnnotation() { 094 BaselineMode m = this.getClass().getAnnotation(BaselineMode.class); 095 if (m != null) { 096 if (m.value() != null) { 097 mode = m.value(); 098 } 099 } 100 } 101 102 /** 103 * @return the configured mode 104 */ 105 protected Mode getMode() { 106 return mode; 107 } 108 109 /** 110 * Overridden to set dirty=true each time 111 * @see org.kuali.rice.test.RiceTestCase#setUp() 112 */ 113 @Override 114 public void setUp() throws Exception { 115 super.setUp(); 116 dirty = true; 117 } 118 119 @Override 120 protected List<Lifecycle> getPerTestLifecycles() { 121 switch (mode) { 122 case ROLLBACK_CLEAR_DB: return getRollbackClearDbPerTestLifecycles(); 123 case ROLLBACK: return getRollbackTestLifecycles(); 124 case CLEAR_DB: return getClearDbPerTestLifecycles(); 125 case NONE: return super.getPerTestLifecycles(); 126 default: 127 throw new RuntimeException("Invalid mode specified: " + mode); 128 } 129 } 130 131 /** 132 * @return the per-test lifecycles for clearing the database 133 */ 134 protected List<Lifecycle> getClearDbPerTestLifecycles() { 135 List<Lifecycle> lifecycles = super.getPerTestLifecycles(); 136 lifecycles.add(0, new ClearDatabaseLifecycle(getPerTestTablesToClear(), getPerTestTablesNotToClear())); 137 return lifecycles; 138 } 139 140 protected List<String> getPerTestTablesToClear() { 141 return new ArrayList<String>(); 142 } 143 144 protected List<String> getPerTestTablesNotToClear() { 145 return new ArrayList<String>(); 146 } 147 148 /** 149 * @return the per-test lifecycles for rolling back & clearing the database 150 */ 151 protected List<Lifecycle> getRollbackClearDbPerTestLifecycles() { 152 List<Lifecycle> lifecycles = super.getPerTestLifecycles(); 153 lifecycles.add(0, new TransactionalLifecycle() { 154 @Override 155 public void stop() throws Exception { 156 super.stop(); 157 dirty = false; 158 } 159 160 }); 161 // if some previous test case did not roll back the data 162 // clear the db 163 if (dirty) { 164 log.warn("Previous test case did not clean up the database; clearing database..."); 165 lifecycles.add(0, new ClearDatabaseLifecycle(getPerTestTablesToClear(), getPerTestTablesNotToClear())); 166 } 167 return lifecycles; 168 } 169 170 /** 171 * @return the per-test lifecycles for rolling back the database 172 */ 173 protected List<Lifecycle> getRollbackTestLifecycles() { 174 List<Lifecycle> lifecycles = super.getPerTestLifecycles(); 175 lifecycles.add(0, new TransactionalLifecycle()); 176 return lifecycles; 177 } 178 }