blob: 254ff3d2b7688263a367eaad991989dceb54f541 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.modules.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.internal.runners.statements.Fail;
import org.junit.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
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;
/**
* 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 ChildFirstURLClassLoader(
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());
}
@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);
}
// /**
// * Gets the class path. This value is cached in a static variable for performance reasons.
// *
// * @return the class path
// */
// private static String getClassPath()
// {
// if (classPathDetermined)
// {
// return classPath;
// }
//
// classPathDetermined = true;
// // running from maven, we have the classpath in this property.
// classPath = System.getProperty("surefire.test.class.path");
// if (classPath != null)
// {
// return classPath;
// }
//
// // For a multi module project, running it from the top we have to find it using another way.
// // We also need to set useSystemClassLoader=true in the POM so that we gets a jar with the classpath in it.
// String booterClassPath = System.getProperty("java.class.path");
// Vector<String> pathItems = null;
// if (booterClassPath != null)
// {
// pathItems = scanPath(booterClassPath);
// }
// // Do we have just 1 entry as classpath which is a jar?
// if (pathItems != null && pathItems.size() == 1
// && isJar((String) pathItems.get(0)))
// {
// classPath = loadJarManifestClassPath((String) pathItems.get(0),
// "META-INF/MANIFEST.MF");
// }
// return classPath;
//
// }
// /**
// * Load jar manifest class path.
// *
// * @param path the path
// * @param fileName the file name
// *
// * @return the string
// */
// private static String loadJarManifestClassPath(String path, String fileName)
// {
// File archive = new File(path);
// if (!archive.exists()) {
// return null;
// }
// ZipFile zipFile = null;
//
// try {
// zipFile = new ZipFile(archive);
// } catch (IOException io) {
// return null;
// }
//
// ZipEntry entry = zipFile.getEntry(fileName);
// if (entry == null) {
// return null;
// } try {
// Manifest mf = new Manifest();
// mf.read(zipFile.getInputStream(entry));
//
// return mf.getMainAttributes().getValue(Attributes.Name.CLASS_PATH)
// .replaceAll(" ", System.getProperty("path.separator"))
// .replaceAll("file:/", "");
// } catch (MalformedURLException e) {
// LOGGER.throwing("ClassLoaderTestSuite", "loadJarManifestClassPath", e);
// } catch (IOException e) {
// LOGGER.throwing("ClassLoaderTestSuite", "loadJarManifestClassPath", e);
// }
// return null;
// }
//
// /**
// * Checks if is jar.
// *
// * @param pathEntry the path entry
// *
// * @return true, if is jar
// */
// private static boolean isJar(String pathEntry)
// {
// return pathEntry.endsWith(".jar") || pathEntry.endsWith(".zip");
// }
//
// /**
// * Scan path for all directories.
// *
// * @param classPath the class path
// *
// * @return the vector< string>
// */
// private static Vector<String> scanPath(String classPath)
// {
// String separator = System.getProperty("path.separator");
// Vector<String> pathItems = new Vector<String>(10);
// StringTokenizer st = new StringTokenizer(classPath, separator);
// while (st.hasMoreTokens())
// {
// pathItems.addElement(st.nextToken());
// }
// return pathItems;
// }
}