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 }