View Javadoc

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 }