/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.modules.session.junit; /** * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.internal.runners.statements.Fail; import org.junit.internal.runners.statements.RunAfters; import org.junit.internal.runners.statements.RunBefores; import org.junit.rules.MethodRule; import org.junit.rules.TestRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.logging.Logger; public class PerTestClassLoaderRunner extends NamedRunner { private static final Logger LOGGER = Logger.getLogger(PerTestClassLoaderRunner.class.getName()); // The classpath is needed because the custom class loader looks there to find the classes. private static String classPath; private static boolean classPathDetermined = false; // Some data related to the class from the custom class loader. private TestClass testClassFromClassLoader; private Object beforeFromClassLoader; private Object afterFromClassLoader; private Object ruleFromClassLoader; private Object testRuleFromClassLoader; private Object methodRuleFromClassLoader; /** * Instantiates a new test per class loader runner. * * @param klass the klass * @throws InitializationError the initialization error */ public PerTestClassLoaderRunner(Class<?> klass) throws InitializationError { super(klass); } @Override protected Object createTest() throws Exception { // Need an instance now from the class loaded by the custom loader. return testClassFromClassLoader.getJavaClass().newInstance(); } /** * Load classes (TestCase, @Before and @After with custom class loader. * * @throws ClassNotFoundException the class not found exception */ private void loadClassesWithCustomClassLoader() throws ClassNotFoundException { String classPath = System.getProperty("java.class.path"); StringTokenizer st = new StringTokenizer(classPath, ":"); List<URL> urls = new ArrayList<URL>(); while (st.hasMoreTokens()) { String u = st.nextToken(); try { if (!u.endsWith(".jar")) { u += "/"; } URL url = new URL("file://" + u); urls.add(url); } catch (MalformedURLException e) { e.printStackTrace(); } } ClassLoader classLoader = new ChildFirstClassLoader(urls.toArray(new URL[] {}), Thread.currentThread().getContextClassLoader()); Thread.currentThread().setContextClassLoader(classLoader); testClassFromClassLoader = new TestClass(classLoader.loadClass(getTestClass().getJavaClass().getName())); // See withAfters and withBefores for the reason. beforeFromClassLoader = classLoader.loadClass(Before.class.getName()); afterFromClassLoader = classLoader.loadClass(After.class.getName()); ruleFromClassLoader = classLoader.loadClass(Rule.class.getName()); testRuleFromClassLoader = classLoader.loadClass(TestRule.class.getName()); methodRuleFromClassLoader = classLoader.loadClass(MethodRule.class.getName()); } @Override protected Statement methodBlock(FrameworkMethod method) { FrameworkMethod newMethod = null; try { // Need the class from the custom loader now, so lets load the class. loadClassesWithCustomClassLoader(); // The method as parameter is from the original class and thus not found in our // class loaded by the custom name (reflection is class loader sensitive) // So find the same method but now in the class from the class Loader. Method methodFromNewlyLoadedClass = testClassFromClassLoader.getJavaClass().getMethod(method.getName()); newMethod = new FrameworkMethod(methodFromNewlyLoadedClass); } catch (ClassNotFoundException e) { // Show any problem nicely as a JUnit Test failure. return new Fail(e); } catch (SecurityException e) { return new Fail(e); } catch (NoSuchMethodException e) { return new Fail(e); } // We can carry out the normal JUnit functionality with our newly discovered method now. return super.methodBlock(newMethod); } @SuppressWarnings("unchecked") @Override protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) { // We now to need to search in the class from the custom loader. // We also need to search with the annotation loaded by the custom // class loader or otherwise we don't find any method. List<FrameworkMethod> afters = testClassFromClassLoader .getAnnotatedMethods((Class<? extends Annotation>) afterFromClassLoader); return new RunAfters(statement, afters, target); } @SuppressWarnings("unchecked") @Override protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) { // We now to need to search in the class from the custom loader. // We also need to search with the annotation loaded by the custom // class loader or otherwise we don't find any method. List<FrameworkMethod> befores = testClassFromClassLoader .getAnnotatedMethods((Class<? extends Annotation>) beforeFromClassLoader); return new RunBefores(statement, befores, target); } @SuppressWarnings("unchecked") @Override protected List<MethodRule> rules(Object target) { List<MethodRule> result = testClassFromClassLoader.getAnnotatedMethodValues(target, (Class<? extends Annotation>) ruleFromClassLoader, (Class) methodRuleFromClassLoader); result.addAll(testClassFromClassLoader.getAnnotatedFieldValues(target, (Class<? extends Annotation>) ruleFromClassLoader, (Class) methodRuleFromClassLoader)); return result; } @SuppressWarnings("unchecked") @Override protected List<TestRule> getTestRules(Object target) { List<TestRule> result = testClassFromClassLoader.getAnnotatedMethodValues(target, (Class<? extends Annotation>) ruleFromClassLoader, (Class) testRuleFromClassLoader); result.addAll(testClassFromClassLoader.getAnnotatedFieldValues(target, (Class<? extends Annotation>) ruleFromClassLoader, (Class) testRuleFromClassLoader)); return result; } }