Coverage Report - org.kuali.rice.test.TestUtilities
 
Classes in this File Line Coverage Branch Coverage Complexity
TestUtilities
0%
0/47
0%
0/24
3.25
 
 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.junit.Assert;
 19  
 
 20  
 import java.lang.annotation.Annotation;
 21  
 import java.lang.reflect.Method;
 22  
 import java.util.ArrayList;
 23  
 import java.util.List;
 24  
 import java.util.Set;
 25  
 
 26  
 public final class TestUtilities {
 27  
         
 28  
         private static Thread exceptionThreader;
 29  
         
 30  0
         private TestUtilities() {
 31  0
                 throw new UnsupportedOperationException("do not call");
 32  
         }
 33  
         
 34  
         /**
 35  
      * Waits "indefinately" for the exception routing thread to terminate.
 36  
      *
 37  
      * This actually doesn't wait forever but puts an upper bound of 5 minutes
 38  
      * on the time to wait for the exception routing thread to complete.  If a
 39  
      * document cannot go into exception routing within 5 minutes  then we got
 40  
      * problems.
 41  
      */
 42  
     public static void waitForExceptionRouting() {
 43  0
             waitForExceptionRouting(5*60*1000);
 44  0
     }
 45  
 
 46  
     public static void waitForExceptionRouting(long milliseconds) {
 47  
             try {
 48  0
                     Thread thread = getExceptionThreader();
 49  0
                     if (thread == null) {
 50  0
                             throw new IllegalStateException("No exception thread was established, likely message is not being processed for exception routing.");
 51  
                     }
 52  0
                     thread.join(milliseconds);
 53  0
             } catch (InterruptedException e) {
 54  0
                     Assert.fail("This thread was interuppted while waiting for exception routing.");
 55  0
             }
 56  0
             if (getExceptionThreader().isAlive()) {
 57  0
                     Assert.fail("Document was not put into exception routing within the specified amount of time " + milliseconds);
 58  
             }
 59  0
     }
 60  
 
 61  
     public static Thread getExceptionThreader() {
 62  0
         return exceptionThreader;
 63  
     }
 64  
 
 65  
     public static void setExceptionThreader(Thread exceptionThreader) {
 66  0
         TestUtilities.exceptionThreader = exceptionThreader;
 67  0
     }
 68  
 
 69  
     protected static boolean contains(Class[] list, Class target) {
 70  0
         for (Class c: list) {
 71  0
             if (c.getName().equals(target.getName())) {
 72  0
                 return true;
 73  
             }
 74  
         }
 75  0
         return false;
 76  
     }
 77  
 
 78  
     /**
 79  
      * This method facilitates using annotations in a unit test class hierarchy.  We walk up the class hierarchy
 80  
      * and on each class, looking for the presence of any of the specified annotation types.  If the particular class
 81  
      * defines one of the annotation types, it is marked for handling.  Once any single target annotation is found
 82  
      * on the class, it is marked and no further annotations are inspected.
 83  
      * 
 84  
      * If the annotation defines an 'overrideSuperClasses' method, and this method returns false, then processing
 85  
      * continues up the class hierarchy.  Otherwise processing stops when the first annotation is found.  Note that
 86  
      * this feature only makes sense when specifying a single annotation type.
 87  
      * 
 88  
      * After a list of classes in descending hierarchy order is compiled, the list is iterated over (again, in
 89  
      * descending hierarchy order) and if the class is not already present in the caller-supplied list of classes
 90  
      * already handled by the caller, the class is added to a list of classes that need to be handled by the caller,
 91  
      * which is then returned to the caller.
 92  
      * 
 93  
      * It is the caller's responsibility to handle the returned classes, and store them in some internal list which it may
 94  
      * give back to this method in the future.
 95  
      * 
 96  
      * @throws Exception if there is a problem in reflection on an Annotation object
 97  
      */
 98  
     public static List<Class> getHierarchyClassesToHandle(Class testClass, Class[] annotationClasses, Set<String> classesHandled) throws Exception {
 99  0
         List<Class> classesThatNeedHandling = new ArrayList<Class>();
 100  
         // get a list of all classes the current class extends from that use the PerSuiteUnitTestData annotation
 101  0
         List<Class> classesToCheck = new ArrayList<Class>();
 102  
         // here we get the list apart checking the annotations to support the perSuiteDataLoaderLifecycleNamesRun variable better
 103  
         {
 104  0
             Class clazz = testClass;
 105  0
             superClassLoop: while (!clazz.getName().equals(Object.class.getName())) {
 106  0
                 for (Annotation annotation : clazz.getDeclaredAnnotations()) {
 107  
                     // if this isn't one of the annotations we're interested in, move on
 108  0
                     if (!contains(annotationClasses, annotation.annotationType())) {
 109  0
                         continue;
 110  
                     }
 111  
 
 112  
                     // this class should be processed because it contains an annotation we are interested in
 113  0
                     classesToCheck.add(0, clazz);
 114  
                     
 115  
                     // now check to see if annotation overrides super class implementations
 116  0
                     if (annotationOverridesSuperClass(annotation)) {
 117  
                         // we're done here
 118  0
                         break superClassLoop;
 119  
                     }
 120  
                     // we just added the class to classes to check, we don't need to add it again
 121  
                     // so just stop looking at annotations in this particular class
 122  
                     break;
 123  
                 }
 124  0
                 clazz = clazz.getSuperclass();
 125  
             }
 126  
         }
 127  
         
 128  0
         for (Class clazz: classesToCheck) {
 129  0
             if (!classesHandled.contains(clazz.getName())) {
 130  0
                 classesThatNeedHandling.add(clazz);
 131  
             }
 132  
         }
 133  0
         return classesThatNeedHandling;
 134  
     }
 135  
     
 136  
     /**
 137  
      * Determines whether an annotation should override the same type of annotation on a superclass,
 138  
      * by using reflection to invoke the 'overrideSuperClasses' method on the annotation if it exists.
 139  
      * If the annotation does not supply this method, the default is true.
 140  
      * @param annotation the annotation to inspect
 141  
      * @return whether this annotation overrides any annotations of similar type in super classes
 142  
      * @throws Exception if an error occurs during reflection
 143  
      */
 144  
     protected static boolean annotationOverridesSuperClass(Annotation annotation) throws Exception {
 145  0
         boolean overrides = true; // default is to just override
 146  0
         Method m = null;;
 147  
         try {
 148  0
             m = annotation.getClass().getMethod("overrideSuperClasses", null);
 149  0
         } catch (NoSuchMethodException nsme) {
 150  
             // do nothing
 151  0
         }
 152  0
         if (m != null) {
 153  0
             Object result = m.invoke(annotation, (Object[]) null);
 154  0
             if (result instanceof Boolean) {
 155  0
                 overrides = (Boolean) result;
 156  
             } else {
 157  0
                 throw new RuntimeException("Annotation 'overrideSuperClasses' did not return Boolean value");
 158  
             }
 159  
         }
 160  0
         return overrides;
 161  
     }
 162  
 }