001 /*
002 * $Id: ProxyRunner.java,v 1.2 2014/01/04 19:28:54 oboehm Exp $
003 *
004 * Copyright (c) 2011 by Oliver Boehm
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *
018 * (c)reated 11.11.2011 by oliver (ob@oasd.de)
019 */
020
021 package patterntesting.runtime.junit;
022
023 import java.lang.annotation.Annotation;
024 import java.lang.reflect.*;
025 import java.util.*;
026
027 import org.junit.runner.Description;
028 import org.junit.runner.notification.*;
029 import org.junit.runners.ParentRunner;
030 import org.junit.runners.model.*;
031 import org.slf4j.*;
032
033 import patterntesting.runtime.annotation.DelegateTo;
034 import patterntesting.runtime.junit.SmokeRunner;
035 import patterntesting.runtime.junit.internal.*;
036 import patterntesting.runtime.util.ReflectionHelper;
037
038 /**
039 * This is a JUnit runner which delegates the call one (or perhaps several)
040 * other JUnit runners.
041 * </br>
042 * Till 1.2.10-YEARS it was placed in the experimental package.
043 *
044 * @author oliver (ob@aosd.de)
045 * @since 1.2 (11.11.2011)
046 */
047 public class ProxyRunner extends SmokeRunner {
048
049 private static final Logger log = LoggerFactory.getLogger(ProxyRunner.class);
050 private ParentRunner<FrameworkMethod> delegateRunner;
051
052 /**
053 * Instantiates a new proxy runner.
054 *
055 * @param testClass the test class
056 * @throws InitializationError the initialization error
057 */
058 public ProxyRunner(final Class<?> testClass) throws InitializationError {
059 super(testClass);
060 }
061
062 /**
063 * Gets the Runner defined by <code>@DelegateTo</code>.
064 * <br/>
065 * Note: This class is public for testing reasons.
066 *
067 * @return the delegate runner
068 */
069 public final ParentRunner<FrameworkMethod> getDelegateRunner() {
070 if (this.delegateRunner == null) {
071 try {
072 this.delegateRunner = createDelegateRunner();
073 } catch (InitializationError ie) {
074 throw new RuntimeException(ie);
075 }
076 }
077 return this.delegateRunner;
078 }
079
080 private ParentRunner<FrameworkMethod> createDelegateRunner() throws InitializationError {
081 Class<? extends ParentRunner<FrameworkMethod>> runnerClass = getDelegateRunnerClass();
082 try {
083 Constructor<? extends ParentRunner<FrameworkMethod>> ctor = runnerClass.getDeclaredConstructor(Class.class);
084 return ctor.newInstance(this.getTestClass().getJavaClass());
085 } catch (SecurityException e) {
086 throw new ModelInitializationError(e);
087 } catch (NoSuchMethodException e) {
088 throw new ModelInitializationError(e);
089 } catch (IllegalArgumentException e) {
090 throw new ModelInitializationError(e);
091 } catch (InstantiationException e) {
092 throw new ModelInitializationError(e);
093 } catch (IllegalAccessException e) {
094 throw new ModelInitializationError(e);
095 } catch (InvocationTargetException e) {
096 throw new ModelInitializationError(e);
097 }
098 }
099
100 private Class<? extends ParentRunner<FrameworkMethod>> getDelegateRunnerClass() {
101 DelegateTo delegateTo = this.getTestClass().getJavaClass().getAnnotation(DelegateTo.class);
102 return delegateTo.value();
103 }
104
105 /**
106 * Gets the description.
107 *
108 * @return the description
109 * @see org.junit.runner.Runner#getDescription()
110 */
111 @Override
112 public Description getDescription() {
113 Description description = this.getDelegateRunner().getDescription();
114 Collection<Annotation> annotationList = description.getAnnotations();
115 Annotation[] annotations = annotationList.toArray(new Annotation[annotationList.size()]);
116 Description filtered = DescriptionUtils.createTestDescription(description, annotations);
117 for (Description descr : description.getChildren()) {
118 filtered.addChild(descr);
119 }
120 return filtered;
121 }
122
123 /**
124 * Here we decide if the whole class is to be run.
125 *
126 * @param notifier the notifier
127 * @see org.junit.runner.Runner#run(org.junit.runner.notification.RunNotifier)
128 */
129 @Override
130 public void run(final RunNotifier notifier) {
131 //delegateRunner.run(notifier);
132 super.run(notifier);
133 }
134
135 /**
136 * Gets the children.
137 *
138 * @return the children
139 * @see org.junit.runners.ParentRunner#getChildren()
140 */
141 @SuppressWarnings("unchecked")
142 @Override
143 protected List<FrameworkMethod> getChildren() {
144 // TODO: put a Proxy around each FrameworkMethod
145 List<FrameworkMethod> methods = (List<FrameworkMethod>) ReflectionHelper.invokeMethod(this.getDelegateRunner(), "getChildren");
146 return methods;
147 }
148
149 /**
150 * Run child. This method may be not called (e.g. it is not called by
151 * SpringJUnit4ClassRunner) but must be implemented because of the abstract
152 * superclass (ParentRunner).
153 *
154 * @param method the method
155 * @param notifier the notifier
156 * @see org.junit.runners.ParentRunner#runChild(java.lang.Object, org.junit.runner.notification.RunNotifier)
157 */
158 @Override
159 protected void runChild(final FrameworkMethod method, final RunNotifier notifier) {
160 Description description = describeChild(method);
161 try {
162 if (shouldBeIgnored(method)) {
163 notifier.fireTestIgnored(description);
164 return;
165 }
166 } catch (IllegalArgumentException iae) {
167 fireTestAssumptionFailed(notifier, description, iae);
168 notifier.fireTestFinished(description);
169 return;
170 }
171 long startTime = System.currentTimeMillis();
172 ReflectionHelper.invokeMethod(delegateRunner, "runChild", method, notifier);
173 logMethod(method, System.currentTimeMillis() - startTime);
174 }
175
176 private static void logMethod(final FrameworkMethod method, final long time) {
177 log.info("{}.{} (" + time + " ms)", method.getMethod().getDeclaringClass().getName(),
178 method.getName());
179 }
180
181 }
182