1 /*
2 * Copyright 2007-2008 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 java.lang.annotation.ElementType;
19 import java.lang.annotation.Inherited;
20 import java.lang.annotation.Retention;
21 import java.lang.annotation.RetentionPolicy;
22 import java.lang.annotation.Target;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.kuali.rice.core.lifecycle.Lifecycle;
27
28 /**
29 * Test case which supports common styles of "baselining" the test environment before/after running
30 * a unit test.
31 * Currently supports three modes, which are specifyiable either via constructor, {@link #getMode()} override,
32 * or by annotation:
33 * <dl>
34 * <dt>NONE</dt>
35 * <dd>No baselining is performed. Because the base RiceTestCase includes the ClearDatabaseLifecycle by default, this lifecycle is
36 * explicitly omitted</dd>
37 * <dt>CLEAR_DB</dt>
38 * <dd>The database is cleared for each test. The suite ClearDatabaseLifecycle is omitted (since it's getting cleared each test
39 * anyway)</dd>
40 * <dt>ROLLBACK</dt>
41 * <dd>A TransactionalLifecycle is installed that wraps each test and rolls back data. The suite ClearDatabaseLifecycle will be
42 * invoked once initially, and subsequently if the test has detected that the environment has been left "dirty" by a previous
43 * test. After a successful rollback, the test environment is marked clean again.</dd>
44 * </dl>
45 *
46 * The BaselineMode annotation can be used on a per-test-class basis to indicate to the base class which mode to use for test
47 * subclass. It accepts a {@link Mode} value.
48 *
49 * @author Kuali Rice Team (rice.collab@kuali.org)
50 *
51 */
52 public class BaselineTestCase extends BaseModuleTestCase {
53 /**
54 * Enum of "baselining" modes that this test case supports
55 */
56 public static enum Mode {
57 CLEAR_DB, ROLLBACK, NONE
58 }
59
60 @Target({ElementType.TYPE})
61 @Inherited
62 @Retention(RetentionPolicy.RUNTIME)
63 public @interface BaselineMode {
64 Mode value();
65 }
66
67 private Mode mode = Mode.NONE;
68
69 /**
70 * Whether the test environment is in a "dirty" state. Each time the unit test starts up
71 * dirty is set to true. If a subclass installs the {@link TransactionalLifecycle} then
72 * it should clear the dirty flag. This flag can be used to perform cleanup in case a previous
73 * test left the test environment in a "dirty" state.
74 */
75 protected static boolean dirty = false;
76
77 // propagate constructors
78 public BaselineTestCase(String moduleName) {
79 super(moduleName);
80 readModeAnnotation();
81 }
82
83 /**
84 * Adds the ability to specify Mode
85 */
86 public BaselineTestCase(String moduleName, Mode mode) {
87 super(moduleName);
88 if (mode == null) throw new IllegalArgumentException("Mode cannot be null");
89 this.mode = mode;
90 }
91
92 private void readModeAnnotation() {
93 BaselineMode m = this.getClass().getAnnotation(BaselineMode.class);
94 if (m != null) {
95 if (m.value() != null) {
96 mode = m.value();
97 }
98 }
99 }
100
101 /**
102 * @return the configured mode
103 */
104 protected Mode getMode() {
105 return mode;
106 }
107
108 /**
109 * Overridden to set dirty=true each time
110 * @see org.kuali.rice.test.RiceTestCase#setUp()
111 */
112 @Override
113 public void setUp() throws Exception {
114 super.setUp();
115 dirty = true;
116 }
117
118 @Override
119 protected List<Lifecycle> getPerTestLifecycles() {
120 switch (mode) {
121 case ROLLBACK: return getRollbackPerTestLifecycles();
122 case CLEAR_DB: return getClearDbPerTestLifecycles();
123 case NONE: return super.getPerTestLifecycles();
124 default:
125 throw new RuntimeException("Invalid mode specified: " + mode);
126 }
127 }
128
129 /**
130 * @return the per-test lifecycles for clearing the database
131 */
132 protected List<Lifecycle> getClearDbPerTestLifecycles() {
133 List<Lifecycle> lifecycles = super.getPerTestLifecycles();
134 lifecycles.add(0, new ClearDatabaseLifecycle(getPerTestTablesToClear(), getPerTestTablesNotToClear()));
135 return lifecycles;
136 }
137
138 protected List<String> getPerTestTablesToClear() {
139 return new ArrayList<String>();
140 }
141
142 protected List<String> getPerTestTablesNotToClear() {
143 return new ArrayList<String>();
144 }
145
146 /**
147 * @return the per-test lifecycles for rolling back the database
148 */
149 protected List<Lifecycle> getRollbackPerTestLifecycles() {
150 List<Lifecycle> lifecycles = super.getPerTestLifecycles();
151 lifecycles.add(0, new TransactionalLifecycle() {
152 @Override
153 public void stop() throws Exception {
154 super.stop();
155 dirty = false;
156 }
157
158 });
159 // if some previous test case did not roll back the data
160 // clear the db
161 if (dirty) {
162 log.warn("Previous test case did not clean up the database; clearing database...");
163 lifecycles.add(0, new ClearDatabaseLifecycle(getPerTestTablesToClear(), getPerTestTablesNotToClear()));
164 }
165 return lifecycles;
166 }
167 }