Coverage Report - org.jitr.Jitr
 
Classes in this File Line Coverage Branch Coverage Complexity
Jitr
78%
73/93
54%
28/52
0
Jitr$1
100%
3/3
N/A
0
 
 1  
 /*
 2  
  * Copyright 2009, Josh Devins, Jitr.org.
 3  
  *
 4  
  * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
 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  
 
 17  
 package org.jitr;
 18  
 
 19  
 import java.lang.reflect.Constructor;
 20  
 import java.lang.reflect.Field;
 21  
 import java.lang.reflect.Modifier;
 22  
 import java.util.Collection;
 23  
 import java.util.Iterator;
 24  
 import java.util.LinkedList;
 25  
 
 26  
 import javax.servlet.ServletContext;
 27  
 
 28  
 import org.apache.log4j.Logger;
 29  
 import org.jitr.annotation.BaseUri;
 30  
 import org.jitr.annotation.JitrConfiguration;
 31  
 import org.jitr.annotation.Port;
 32  
 import org.jitr.core.ConfigurationModel;
 33  
 import org.jitr.core.Container;
 34  
 import org.jitr.core.JitrException;
 35  
 import org.jitr.core.OperationalMode;
 36  
 import org.junit.internal.runners.ClassRoadie;
 37  
 import org.junit.internal.runners.InitializationError;
 38  
 import org.junit.internal.runners.JUnit4ClassRunner;
 39  
 import org.junit.runner.notification.RunNotifier;
 40  
 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
 41  
 import org.springframework.context.ApplicationContext;
 42  
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 43  
 import org.springframework.core.annotation.AnnotationUtils;
 44  
 import org.springframework.test.context.ContextConfiguration;
 45  
 import org.springframework.test.context.ContextLoader;
 46  
 import org.springframework.web.context.WebApplicationContext;
 47  
 import org.springframework.web.context.support.WebApplicationContextUtils;
 48  
 
 49  
 /**
 50  
  * The heart of Jitr. This provides all of the configuration, Spring application context loading,
 51  
  * bootstrapping and wiring of test classes.
 52  
  * 
 53  
  * @author Josh Devins (info@joshdevins.net)
 54  
  */
 55  
 @JitrConfiguration
 56  5
 public final class Jitr extends JUnit4ClassRunner {
 57  
 
 58  1
     private static final Logger LOG = Logger.getLogger(Jitr.class);
 59  
 
 60  
     private ConfigurationModel config;
 61  
 
 62  
     private Container<?> container;
 63  
 
 64  
     private AutowireCapableBeanFactory autowireCapableBeanFactory;
 65  
 
 66  
     public Jitr(final Class<?> clazz) throws InitializationError {
 67  5
         super(clazz);
 68  5
     }
 69  
 
 70  
     @Override
 71  
     public void run(final RunNotifier notifier) {
 72  
 
 73  5
         if (LOG.isInfoEnabled()) {
 74  5
             LOG.info("Jitr loaded");
 75  
         }
 76  
 
 77  
         // get the Jitr configuration (if any) from the test class
 78  5
         JitrConfiguration annot =
 79  
                 AnnotationUtils.findAnnotation(getTestClass().getJavaClass(),
 80  
                         JitrConfiguration.class);
 81  
 
 82  5
         if (LOG.isInfoEnabled() && annot == null) {
 83  1
             LOG.info("No @JitrConfiguration found on test class");
 84  
         }
 85  
 
 86  5
         config = JitrConfigurationFactory.createConfigurationFromAnnotation(annot);
 87  
 
 88  5
         if (config == null) {
 89  0
             throw new JitrException("Configuration could not be created.");
 90  
         }
 91  
 
 92  5
         final ServletContext servletContext = initAndStartContainerIfNeeded();
 93  
 
 94  
         // setup Spring if we can
 95  5
         setSpringAutowireCapableBeanFactory(servletContext);
 96  
 
 97  
         // create JUnit class roadie for running tests
 98  5
         final ClassRoadie roadie =
 99  5
                 new ClassRoadie(notifier, getTestClass(), getDescription(), new Runnable() {
 100  
                     public void run() {
 101  5
                         runMethods(notifier);
 102  5
                     }
 103  
                 });
 104  
 
 105  5
         if (LOG.isInfoEnabled()) {
 106  5
             LOG.info("Running tests");
 107  
         }
 108  
 
 109  
         // run tests regularly with JUnit class roadie
 110  5
         roadie.runProtected();
 111  
 
 112  5
         if (config.getMode().isContainerEnabled()) {
 113  
 
 114  5
             if (LOG.isInfoEnabled()) {
 115  5
                 LOG.info("Stopping container: " + container.getName());
 116  
             }
 117  
 
 118  5
             container.stop();
 119  
         }
 120  5
     }
 121  
 
 122  
     @Override
 123  
     protected Object createTest() throws Exception {
 124  9
         Object testInstance = super.createTest();
 125  
 
 126  
         // autowire the test if we can
 127  9
         if (autowireCapableBeanFactory != null) {
 128  9
             autowireCapableBeanFactory.autowireBean(testInstance);
 129  
         }
 130  
 
 131  
         // set @Port field
 132  9
         final Field portField =
 133  
                 JitrUtils.getMostSpecificAnnotatedDeclaredField(testInstance.getClass(), Port.class);
 134  
 
 135  9
         if (portField != null) {
 136  
 
 137  9
             validateModifiersAndSetAccessible(portField, "Port");
 138  9
             portField.setInt(testInstance, config.getPort());
 139  
         }
 140  
 
 141  
         // set @BaseUri field
 142  9
         final Field baseUriField =
 143  
                 JitrUtils.getMostSpecificAnnotatedDeclaredField(testInstance.getClass(),
 144  
                         BaseUri.class);
 145  
 
 146  9
         if (baseUriField != null) {
 147  
 
 148  9
             validateModifiersAndSetAccessible(baseUriField, "BaseUri");
 149  9
             baseUriField.set(testInstance, config.getBaseUri());
 150  
         }
 151  
 
 152  9
         return testInstance;
 153  
     }
 154  
 
 155  
     private ServletContext initAndStartContainerIfNeeded() {
 156  
 
 157  
         // if the container is disabled, then we don't need to do any of this
 158  5
         if (!config.getMode().isContainerEnabled()) {
 159  0
             return null;
 160  
         }
 161  
 
 162  5
         final Class<?> containerClass = config.getContainerClass();
 163  
 
 164  
         // try to instantiate the container implementation class
 165  
         try {
 166  5
             Constructor<?> containerConstructor = containerClass.getConstructor();
 167  5
             container = (Container<?>) containerConstructor.newInstance();
 168  
 
 169  0
         } catch (final Exception e) {
 170  0
             throw new JitrException("Could not instantiate Container implementation class: "
 171  
                     + containerClass.toString(), e);
 172  5
         }
 173  
 
 174  5
         if (LOG.isInfoEnabled()) {
 175  5
             LOG.info("Initializing container: " + container.getName());
 176  
         }
 177  
 
 178  5
         ServletContext servletContext =
 179  
                 container.initialize(config, getTestClass().getJavaClass().getAnnotations());
 180  
 
 181  5
         if (LOG.isInfoEnabled()) {
 182  5
             LOG.info("Starting container: " + container.getName());
 183  
         }
 184  
 
 185  5
         container.start();
 186  
 
 187  5
         return servletContext;
 188  
     }
 189  
 
 190  
     private void setSpringAutowireCapableBeanFactory(final ServletContext servletContext) {
 191  
 
 192  
         // using same Spring application context as webapp
 193  5
         if (config.getMode() == OperationalMode.INTERNAL) {
 194  
 
 195  
             // load web app context from current Thread
 196  4
             WebApplicationContext webApplicationContext =
 197  
                     org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext();
 198  
 
 199  
             // sometimes Spring will be loaded in another thread, make sure we have a ServletContext
 200  4
             if (webApplicationContext == null && servletContext == null) {
 201  0
                 throw new JitrException(
 202  
                         "Servlet context was null and no Spring web application context could"
 203  
                                 + " be found in the current Thread.");
 204  
             }
 205  
 
 206  4
             if (webApplicationContext == null) {
 207  1
                 webApplicationContext =
 208  
                         WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
 209  
             }
 210  
 
 211  
             // make sure there is a Spring web application context
 212  4
             if (webApplicationContext == null) {
 213  0
                 LOG.warn("No Spring web application context was found and Jitr is not configured "
 214  
                         + "to use an external Spring application context configuration.");
 215  0
                 return;
 216  
             }
 217  
 
 218  4
             autowireCapableBeanFactory = webApplicationContext.getAutowireCapableBeanFactory();
 219  
 
 220  4
             return;
 221  
         }
 222  
 
 223  
         // need to load an external Spring application context configuration
 224  1
         ContextConfiguration contextConfiguration =
 225  
                 AnnotationUtils.findAnnotation(getTestClass().getJavaClass(),
 226  
                         ContextConfiguration.class);
 227  
 
 228  
         // make sure we can find the configuration
 229  1
         if (contextConfiguration == null) {
 230  0
             throw new JitrException(
 231  
                     "Jitr is configured to use an external Spring application context but none"
 232  
                             + " has been configured. Use @ContextConfiguration on your test class"
 233  
                             + " to define what Spring application context configurations should"
 234  
                             + " be loaded.");
 235  
         }
 236  
 
 237  
         // TODO: Implement location inheritance.
 238  
         // boolean inheritLocations =
 239  
         // contextConfiguration.inheritLocations();
 240  
 
 241  1
         Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
 242  1
         String[] locations = contextConfiguration.locations();
 243  
         ApplicationContext applicationContext;
 244  
 
 245  
         // if a ContextLoader class was specified on the annotation, use it
 246  1
         if (contextLoaderClass != null && contextLoaderClass != ContextLoader.class) {
 247  
             try {
 248  1
                 Constructor<? extends ContextLoader> constructor =
 249  
                         contextLoaderClass.getConstructor();
 250  1
                 ContextLoader contextLoader = constructor.newInstance();
 251  1
                 String[] processedLocations =
 252  
                         contextLoader.processLocations(getTestClass().getJavaClass(), locations);
 253  1
                 applicationContext = contextLoader.loadContext(processedLocations);
 254  
 
 255  0
             } catch (final Exception e) {
 256  0
                 throw new JitrException("Error loading Spring application contexts.", e);
 257  1
             }
 258  
         } else {
 259  
             // use a default XML context loader
 260  0
             applicationContext = new ClassPathXmlApplicationContext(locations);
 261  
         }
 262  
 
 263  1
         autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
 264  1
     }
 265  
 
 266  
     private void validateModifiersAndSetAccessible(final Field field, final String annotationName) {
 267  
 
 268  18
         final int modifiers = field.getModifiers();
 269  18
         final Collection<String> problemModifiers = new LinkedList<String>();
 270  
 
 271  18
         if (Modifier.isStatic(modifiers)) {
 272  0
             problemModifiers.add("static");
 273  
         }
 274  
 
 275  18
         if (Modifier.isFinal(modifiers)) {
 276  0
             problemModifiers.add("final");
 277  
         }
 278  
 
 279  18
         if (!problemModifiers.isEmpty()) {
 280  
 
 281  0
             final Iterator<String> iterator = problemModifiers.iterator();
 282  0
             final StringBuilder stringBuilder = new StringBuilder();
 283  
 
 284  0
             while (iterator.hasNext()) {
 285  0
                 stringBuilder.append(iterator.next());
 286  
 
 287  0
                 if (iterator.hasNext()) {
 288  0
                     stringBuilder.append(", ");
 289  
                 }
 290  
             }
 291  
 
 292  0
             throw new JitrException("Field annotated with @" + annotationName + " cannot be: "
 293  
                     + stringBuilder.toString());
 294  
         }
 295  
 
 296  18
         field.setAccessible(true);
 297  18
     }
 298  
 }