Allow testcases to control the classloader hierarchy used during the test.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@202471 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
251
src/test/org/apache/commons/logging/PathableClassLoader.java
Normal file
251
src/test/org/apache/commons/logging/PathableClassLoader.java
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* Created on 24/06/2005
|
||||||
|
*
|
||||||
|
* TODO To change the template for this generated file go to
|
||||||
|
* Window - Preferences - Java - Code Style - Code Templates
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.commons.logging;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
// TODO: use Hashtable instead of HashMap
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Vector;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ClassLoader which sees only the specified classes.
|
||||||
|
*/
|
||||||
|
public class PathableClassLoader extends URLClassLoader {
|
||||||
|
|
||||||
|
private static final URL[] NO_URLS = new URL[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of package-prefix to ClassLoader. Any class which is in
|
||||||
|
* this map is looked up via the specified classloader instead of
|
||||||
|
* the classpath associated with this classloader or its parents.
|
||||||
|
* <p>
|
||||||
|
* This is necessary in order for the rest of the world to communicate
|
||||||
|
* with classes loaded via a custom classloader. As an example, junit
|
||||||
|
* testcases which are loaded via a custom classloader needs to see
|
||||||
|
* the same junit classes as the code invoking the testcase, otherwise
|
||||||
|
* they can't pass result objects back.
|
||||||
|
* <p>
|
||||||
|
* Normally, only a classloader created with a null parent needs to
|
||||||
|
* have any lookasides defined.
|
||||||
|
*/
|
||||||
|
private HashMap lookasides = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See setParentFirst.
|
||||||
|
*/
|
||||||
|
private boolean parentFirst = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public PathableClassLoader(ClassLoader parent) {
|
||||||
|
super(NO_URLS, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether this classloader should ask the parent classloader
|
||||||
|
* to resolve a class first, before trying to resolve it via its own
|
||||||
|
* classpath.
|
||||||
|
* <p>
|
||||||
|
* Checking with the parent first is the normal approach for java, but
|
||||||
|
* components within containers such as servlet engines can use
|
||||||
|
* child-first lookup instead, to allow the components to override libs
|
||||||
|
* which are visible in shared classloaders provided by the container.
|
||||||
|
* <p>
|
||||||
|
* This value defaults to true.
|
||||||
|
*/
|
||||||
|
public void setParentFirst(boolean state) {
|
||||||
|
parentFirst = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For classes with the specified prefix, get them from the system
|
||||||
|
* classpath <i>which is active at the point this method is called</i>.
|
||||||
|
* <p>
|
||||||
|
* This method is just a shortcut for
|
||||||
|
* <pre>
|
||||||
|
* useExplicitLoader(prefix, ClassLoader.getSystemClassLoader());
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public void useSystemLoader(String prefix) {
|
||||||
|
useExplicitLoader(prefix, ClassLoader.getSystemClassLoader());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a classloader to use for specific java packages.
|
||||||
|
*/
|
||||||
|
public void useExplicitLoader(String prefix, ClassLoader loader) {
|
||||||
|
if (lookasides == null) {
|
||||||
|
lookasides = new HashMap();
|
||||||
|
}
|
||||||
|
lookasides.put(prefix, loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a collection of logical libraries. See addLogicalLib.
|
||||||
|
*/
|
||||||
|
public void addLogicalLib(String[] logicalLibs) {
|
||||||
|
for(int i=0; i<logicalLibs.length; ++i) {
|
||||||
|
addLogicalLib(logicalLibs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a logical library to be included in the classpath used to
|
||||||
|
* locate classes.
|
||||||
|
* <p>
|
||||||
|
* The specified lib name is used as a key into the system properties;
|
||||||
|
* there is expected to be a system property defined with that name
|
||||||
|
* whose value is a url that indicates where that logical library can
|
||||||
|
* be found. Typically this is the name of a jar file, or a directory
|
||||||
|
* containing class files.
|
||||||
|
* <p>
|
||||||
|
* Using logical library names allows the calling code to specify its
|
||||||
|
* desired classpath without knowing the exact location of the necessary
|
||||||
|
* classes.
|
||||||
|
*/
|
||||||
|
public void addLogicalLib(String logicalLib) {
|
||||||
|
String filename = System.getProperty(logicalLib);
|
||||||
|
if (filename == null) {
|
||||||
|
throw new UnknownError(
|
||||||
|
"Logical lib [" + logicalLib + "] is not defined"
|
||||||
|
+ " as a System property.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new File(filename).toURL();
|
||||||
|
addURL(url);
|
||||||
|
} catch(java.net.MalformedURLException e) {
|
||||||
|
throw new UnknownError(
|
||||||
|
"Invalid file [" + filename + "] for logical lib [" + logicalLib + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override ClassLoader method.
|
||||||
|
* <p>
|
||||||
|
* For each explicitly mapped package prefix, if the name matches the
|
||||||
|
* prefix associated with that entry then attempt to load the class via
|
||||||
|
* that entries' classloader.
|
||||||
|
*/
|
||||||
|
protected Class loadClass(String name, boolean resolve)
|
||||||
|
throws ClassNotFoundException {
|
||||||
|
// just for performance, check java and javax
|
||||||
|
if (name.startsWith("java.") || name.startsWith("javax.")) {
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lookasides != null) {
|
||||||
|
for(Iterator i = lookasides.entrySet().iterator(); i.hasNext(); ) {
|
||||||
|
Map.Entry entry = (Map.Entry) i.next();
|
||||||
|
String prefix = (String) entry.getKey();
|
||||||
|
if (name.startsWith(prefix) == true) {
|
||||||
|
ClassLoader loader = (ClassLoader) entry.getValue();
|
||||||
|
Class clazz = Class.forName(name, resolve, loader);
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentFirst) {
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
} else {
|
||||||
|
// ok, implement child-first
|
||||||
|
try {
|
||||||
|
Class clazz = super.findClass(name);
|
||||||
|
if (resolve) {
|
||||||
|
resolveClass(clazz);
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
} catch(ClassNotFoundException e) {
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as parent class method except that when parentFirst is false
|
||||||
|
* the resource is looked for in the local classpath before the parent
|
||||||
|
* loader is consulted.
|
||||||
|
*/
|
||||||
|
public URL getResource(String name) {
|
||||||
|
if (parentFirst) {
|
||||||
|
return super.getResource(name);
|
||||||
|
} else {
|
||||||
|
URL local = super.findResource(name);
|
||||||
|
if (local != null) {
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
return super.getResource(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as parent class method except that when parentFirst is false
|
||||||
|
* the resource is looked for in the local classpath before the parent
|
||||||
|
* loader is consulted.
|
||||||
|
*/
|
||||||
|
public InputStream getResourceAsStream(String name) {
|
||||||
|
if (parentFirst) {
|
||||||
|
return super.getResourceAsStream(name);
|
||||||
|
} else {
|
||||||
|
URL local = super.findResource(name);
|
||||||
|
if (local != null) {
|
||||||
|
try {
|
||||||
|
return local.openStream();
|
||||||
|
} catch(IOException e) {
|
||||||
|
// TODO: check if this is right or whether we should
|
||||||
|
// fall back to trying parent. The javadoc doesn't say...
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as parent class method except that when parentFirst is false
|
||||||
|
* the resources available from this class are returned at the head of
|
||||||
|
* the list instead of the tail.
|
||||||
|
*/
|
||||||
|
public Enumeration getResources(String name) throws IOException {
|
||||||
|
if (parentFirst) {
|
||||||
|
return super.getResources(name);
|
||||||
|
} else {
|
||||||
|
Enumeration local = super.findResources(name);
|
||||||
|
Enumeration parent = getParent().getResources(name);
|
||||||
|
|
||||||
|
if (!local.hasMoreElements()) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parent.hasMoreElements()) {
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector v = new Vector();
|
||||||
|
while (local.hasMoreElements()) {
|
||||||
|
v.add(local.nextElement());
|
||||||
|
}
|
||||||
|
while (parent.hasMoreElements()) {
|
||||||
|
v.add(parent.nextElement());
|
||||||
|
}
|
||||||
|
return v.elements();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/test/org/apache/commons/logging/PathableTestSuite.java
Normal file
125
src/test/org/apache/commons/logging/PathableTestSuite.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Created on 24/06/2005
|
||||||
|
*
|
||||||
|
* TODO To change the template for this generated file go to
|
||||||
|
* Window - Preferences - Java - Code Style - Code Templates
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.commons.logging;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
import junit.framework.TestResult;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom TestSuite class that can be used to control the context classloader
|
||||||
|
* in operation when a test runs.
|
||||||
|
* <p>
|
||||||
|
* For tests that need to control exactly what the classloader hierarchy is
|
||||||
|
* like when the test is run, something like the following is recommended:
|
||||||
|
* <pre>
|
||||||
|
* class SomeTestCase extends TestCase {
|
||||||
|
* public static Test suite() throws Exception {
|
||||||
|
* PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
* parent.useSystemLoader("junit.");
|
||||||
|
*
|
||||||
|
* PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
* child.addLogicalLib("testclasses");
|
||||||
|
* child.addLogicalLib("log4j12");
|
||||||
|
* child.addLogicalLib("commons-logging");
|
||||||
|
*
|
||||||
|
* Class testClass = child.loadClass(SomeTestCase.class.getName());
|
||||||
|
* ClassLoader contextClassLoader = child;
|
||||||
|
*
|
||||||
|
* PathableTestSuite suite = new PathableTestSuite(testClass, child);
|
||||||
|
* return suite;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // test methods go here
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* Note that if the suite method throws an exception then this will be handled
|
||||||
|
* reasonable gracefully by junit; it will report that the suite method for
|
||||||
|
* a test case failed with exception yyy.
|
||||||
|
* <p>
|
||||||
|
* The use of PathableClassLoader is not required to use this class, but it
|
||||||
|
* is expected that using the two classes together is common practice.
|
||||||
|
* <p>
|
||||||
|
* This class will run each test methods within the specified TestCase using
|
||||||
|
* the specified context classloader and system classloader. If different
|
||||||
|
* tests within the same class require different context classloaders,
|
||||||
|
* then the context classloader passed to the constructor should be the
|
||||||
|
* "lowest" one available, and tests that need the context set to some parent
|
||||||
|
* of this "lowest" classloader can call
|
||||||
|
* <pre>
|
||||||
|
* // NB: pseudo-code only
|
||||||
|
* setContextClassLoader(getContextClassLoader().getParent());
|
||||||
|
* </pre>
|
||||||
|
* This class ensures that any context classloader changes applied by a test
|
||||||
|
* is undone after the test is run, so tests don't need to worry about
|
||||||
|
* restoring the context classloader on exit.
|
||||||
|
* <p>
|
||||||
|
* This class does not provide facilities for manipulating system properties;
|
||||||
|
* tests that need specific system properties can simply set them in the
|
||||||
|
* fixture or at the start of a test method.
|
||||||
|
* <p>
|
||||||
|
* This class cannot control the system classloader (ie what method
|
||||||
|
* ClassLoader.getSystemClassLoader returns) because Java provides no
|
||||||
|
* mechanism for setting the system classloader. In this case, the only
|
||||||
|
* option is to invoke the unit test in a separate JVM with the appropriate
|
||||||
|
* settings.
|
||||||
|
* <p>
|
||||||
|
* <b>Important!</b> When the test case is run, "this.getClass()" refers of
|
||||||
|
* course to the Class object passed to the constructor of this class - which
|
||||||
|
* is different from the class whose suite() method was executed to determine
|
||||||
|
* the classpath. This means that the suite method cannot communicate with
|
||||||
|
* the test cases simply by setting static variables (for example to make the
|
||||||
|
* custom classloaders available to the test methods or setUp/tearDown fixtures).
|
||||||
|
* If this is really necessary then it is possible to use reflection to invoke
|
||||||
|
* static methods on the class object passed to the constructor of this class
|
||||||
|
*/
|
||||||
|
public class PathableTestSuite extends TestSuite {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The classloader that should be set as the context classloader
|
||||||
|
* before each test in the suite is run.
|
||||||
|
*/
|
||||||
|
private ClassLoader contextLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param testClass is the TestCase that is to be run, as loaded by
|
||||||
|
* the appropriate ClassLoader.
|
||||||
|
*
|
||||||
|
* @param contextClassLoader is the loader that should be returned by
|
||||||
|
* calls to Thread.currentThread.getContextClassLoader from test methods
|
||||||
|
* (or any method called by test methods).
|
||||||
|
*/
|
||||||
|
public PathableTestSuite(Class testClass, ClassLoader contextClassLoader) {
|
||||||
|
super(testClass);
|
||||||
|
contextLoader = contextClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is invoked once for each Test in the current TestSuite.
|
||||||
|
* Note that a Test may itself be a TestSuite object (ie a collection
|
||||||
|
* of tests).
|
||||||
|
*/
|
||||||
|
public void runTest(Test test, TestResult result) {
|
||||||
|
ClassLoader origContext = Thread.currentThread().getContextClassLoader();
|
||||||
|
try {
|
||||||
|
Thread.currentThread().setContextClassLoader(contextLoader);
|
||||||
|
test.run(result);
|
||||||
|
} finally {
|
||||||
|
Thread.currentThread().setContextClassLoader(origContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005 The Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* Licensed 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.commons.logging.jdk14;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestCase for Jdk14 logging when the commons-logging-api jar file is in
|
||||||
|
* the parent classpath and commons-logging.jar is in the child.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CustomConfigAPITestCase extends CustomConfigTestCase {
|
||||||
|
|
||||||
|
|
||||||
|
public CustomConfigAPITestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the tests included in this test suite.
|
||||||
|
*/
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
// the TestHandler class must be accessable from the System classloader
|
||||||
|
// in order for java.util.logging.LogManager.readConfiguration to
|
||||||
|
// be able to instantiate it. And this test case must see the same
|
||||||
|
// class in order to be able to access its data. Yes this is ugly
|
||||||
|
// but the whole jdk14 API is a ******* mess anyway.
|
||||||
|
parent.useSystemLoader("org.apache.commons.logging.jdk14.TestHandler");
|
||||||
|
parent.addLogicalLib("commons-logging-api");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
child.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(CustomConfigAPITestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005 The Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* Licensed 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.commons.logging.jdk14;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestCase for Jdk14 logging when the commons-logging jar file is in
|
||||||
|
* the parent classpath.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CustomConfigFullTestCase extends CustomConfigTestCase {
|
||||||
|
|
||||||
|
|
||||||
|
public CustomConfigFullTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the tests included in this test suite.
|
||||||
|
*/
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
// the TestHandler class must be accessable from the System classloader
|
||||||
|
// in order for java.util.logging.LogManager.readConfiguration to
|
||||||
|
// be able to instantiate it. And this test case must see the same
|
||||||
|
// class in order to be able to access its data. Yes this is ugly
|
||||||
|
// but the whole jdk14 API is a ******* mess anyway.
|
||||||
|
parent.useSystemLoader("org.apache.commons.logging.jdk14.TestHandler");
|
||||||
|
parent.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(CustomConfigFullTestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,9 @@ import java.util.logging.Logger;
|
|||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>TestCase for JDK 1.4 logging when running on a JDK 1.4 system with
|
* <p>TestCase for JDK 1.4 logging when running on a JDK 1.4 system with
|
||||||
@@ -114,8 +117,19 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
/**
|
/**
|
||||||
* Return the tests included in this test suite.
|
* Return the tests included in this test suite.
|
||||||
*/
|
*/
|
||||||
public static Test suite() {
|
public static Test suite() throws Exception {
|
||||||
return (new TestSuite(CustomConfigTestCase.class));
|
/*
|
||||||
|
PathableClassLoader loader = new PathableClassLoader(null);
|
||||||
|
loader.useSystemLoader("junit.");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
child.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(CustomConfigTestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
|
*/
|
||||||
|
return new TestSuite(CustomConfigTestCase.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,9 +234,9 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
testLevels[i], record.getLevel());
|
testLevels[i], record.getLevel());
|
||||||
assertEquals("LogRecord message",
|
assertEquals("LogRecord message",
|
||||||
testMessages[i], record.getMessage());
|
testMessages[i], record.getMessage());
|
||||||
assertEquals("LogRecord class",
|
assertTrue("LogRecord class",
|
||||||
this.getClass().getName(),
|
record.getSourceClassName().startsWith(
|
||||||
record.getSourceClassName());
|
"org.apache.commons.logging.jdk14.CustomConfig"));
|
||||||
if (thrown) {
|
if (thrown) {
|
||||||
assertEquals("LogRecord method",
|
assertEquals("LogRecord method",
|
||||||
"logExceptionMessages",
|
"logExceptionMessages",
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class DefaultConfigTestCase extends TestCase {
|
|||||||
/**
|
/**
|
||||||
* Return the tests included in this test suite.
|
* Return the tests included in this test suite.
|
||||||
*/
|
*/
|
||||||
public static Test suite() {
|
public static Test suite() throws Exception {
|
||||||
return (new TestSuite(DefaultConfigTestCase.class));
|
return (new TestSuite(DefaultConfigTestCase.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005 The Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* Licensed 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.commons.logging.log4j;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestCase for Log4J logging when the commons-logging-api jar file is in
|
||||||
|
* the parent classpath and commons-logging.jar is in the child.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CustomConfigAPITestCase extends CustomConfigTestCase {
|
||||||
|
|
||||||
|
|
||||||
|
public CustomConfigAPITestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the tests included in this test suite.
|
||||||
|
*/
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
parent.addLogicalLib("commons-logging-api");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
child.addLogicalLib("log4j12");
|
||||||
|
child.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(CustomConfigAPITestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005 The Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* Licensed 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.commons.logging.log4j;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestCase for Log4J logging when the commons-logging jar file is in
|
||||||
|
* the parent classpath.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CustomConfigFullTestCase extends CustomConfigTestCase {
|
||||||
|
|
||||||
|
|
||||||
|
public CustomConfigFullTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the tests included in this test suite.
|
||||||
|
*/
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
parent.addLogicalLib("commons-logging");
|
||||||
|
parent.addLogicalLib("log4j12");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(CustomConfigFullTestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,13 +23,15 @@ import java.util.Iterator;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
import org.apache.log4j.Level;
|
import org.apache.log4j.Level;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
import org.apache.log4j.PropertyConfigurator;
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
import org.apache.log4j.spi.LoggingEvent;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>TestCase for Log4J logging when running on a system with Log4J present,
|
* <p>TestCase for Log4J logging when running on a system with Log4J present,
|
||||||
@@ -103,8 +105,17 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
/**
|
/**
|
||||||
* Return the tests included in this test suite.
|
* Return the tests included in this test suite.
|
||||||
*/
|
*/
|
||||||
public static Test suite() {
|
public static Test suite() throws Exception {
|
||||||
return (new TestSuite(CustomConfigTestCase.class));
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
child.addLogicalLib("log4j12");
|
||||||
|
child.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(CustomConfigTestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,7 +134,6 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
|
|
||||||
// Test logging message strings with exceptions
|
// Test logging message strings with exceptions
|
||||||
public void testExceptionMessages() throws Exception {
|
public void testExceptionMessages() throws Exception {
|
||||||
|
|
||||||
logExceptionMessages();
|
logExceptionMessages();
|
||||||
checkLoggingEvents(true);
|
checkLoggingEvents(true);
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import junit.framework.TestSuite;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,8 +87,17 @@ public class DefaultConfigTestCase extends TestCase {
|
|||||||
/**
|
/**
|
||||||
* Return the tests included in this test suite.
|
* Return the tests included in this test suite.
|
||||||
*/
|
*/
|
||||||
public static Test suite() {
|
public static Test suite() throws Exception {
|
||||||
return (new TestSuite(DefaultConfigTestCase.class));
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
child.addLogicalLib("log4j12");
|
||||||
|
child.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
|
Class testClass = child.loadClass(DefaultConfigTestCase.class.getName());
|
||||||
|
return new PathableTestSuite(testClass, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005 The Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* Licensed 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.commons.logging.pathable;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.PathableTestSuite;
|
||||||
|
import org.apache.commons.logging.PathableClassLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the PathableTestSuite and PathableClassLoader functionality.
|
||||||
|
* <p>
|
||||||
|
* These tests assume:
|
||||||
|
* <ul>
|
||||||
|
* <li>junit is in system classpath
|
||||||
|
* <li>nothing else is in system classpath
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class PathableTestCase extends TestCase {
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
// make the parent a direct child of the bootloader to hide all
|
||||||
|
// other classes in the system classpath
|
||||||
|
PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
|
|
||||||
|
// make the junit classes from the system classpath visible, though,
|
||||||
|
// as junit won't be able to call this class at all without this..
|
||||||
|
parent.useSystemLoader("junit.");
|
||||||
|
|
||||||
|
// make the commons-logging-api.jar classes visible via the parent
|
||||||
|
parent.addLogicalLib("commons-logging-api");
|
||||||
|
|
||||||
|
// create a child classloader to load the test case through
|
||||||
|
PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
|
||||||
|
// obviously, the child classloader needs to have the test classes
|
||||||
|
// in its path!
|
||||||
|
child.addLogicalLib("testclasses");
|
||||||
|
|
||||||
|
// create a third classloader to be the context classloader.
|
||||||
|
PathableClassLoader context = new PathableClassLoader(child);
|
||||||
|
|
||||||
|
// reload this class via the child classloader
|
||||||
|
Class testClass = child.loadClass(PathableTestCase.class.getName());
|
||||||
|
|
||||||
|
// and return our custom TestSuite class
|
||||||
|
return new PathableTestSuite(testClass, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPaths() throws Exception {
|
||||||
|
// the context classloader is not expected to be null
|
||||||
|
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
assertNotNull("Context classloader is null", contextLoader);
|
||||||
|
assertEquals("Context classloader has unexpected type",
|
||||||
|
PathableClassLoader.class.getName(),
|
||||||
|
contextLoader.getClass().getName());
|
||||||
|
|
||||||
|
// the classloader that loaded this class is obviously not null
|
||||||
|
ClassLoader thisLoader = this.getClass().getClassLoader();
|
||||||
|
assertNotNull("thisLoader is null", thisLoader);
|
||||||
|
assertEquals("thisLoader has unexpected type",
|
||||||
|
PathableClassLoader.class.getName(),
|
||||||
|
thisLoader.getClass().getName());
|
||||||
|
|
||||||
|
// the suite method specified that the context classloader's parent
|
||||||
|
// is the loader that loaded this test case.
|
||||||
|
assertSame("Context classloader is not child of thisLoader",
|
||||||
|
thisLoader, contextLoader.getParent());
|
||||||
|
|
||||||
|
// thisLoader's parent should be available
|
||||||
|
ClassLoader parentLoader = thisLoader.getParent();
|
||||||
|
assertNotNull("Parent classloader is null", parentLoader);
|
||||||
|
assertEquals("Parent classloader has unexpected type",
|
||||||
|
PathableClassLoader.class.getName(),
|
||||||
|
parentLoader.getClass().getName());
|
||||||
|
|
||||||
|
// parent should have a parent of null
|
||||||
|
assertNull("Parent classloader has non-null parent", parentLoader.getParent());
|
||||||
|
|
||||||
|
// getSystemClassloader is not a PathableClassLoader; it's of a
|
||||||
|
// built-in type. This also verifies that system classloader is none of
|
||||||
|
// (context, child, parent).
|
||||||
|
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
|
||||||
|
assertNotNull("System classloader is null", systemLoader);
|
||||||
|
assertFalse("System classloader has unexpected type",
|
||||||
|
PathableClassLoader.class.getName().equals(
|
||||||
|
systemLoader.getClass().getName()));
|
||||||
|
|
||||||
|
// junit classes should be visible; their classloader is system.
|
||||||
|
// this will of course throw an exception if not found.
|
||||||
|
Class junitTest = contextLoader.loadClass("junit.framework.Test");
|
||||||
|
assertSame("Junit not loaded via systemloader",
|
||||||
|
systemLoader, junitTest.getClassLoader());
|
||||||
|
|
||||||
|
// jcl api classes should be visible via the parent
|
||||||
|
Class logClass = contextLoader.loadClass("org.apache.commons.logging.Log");
|
||||||
|
assertSame("Log class not loaded via parent",
|
||||||
|
logClass.getClassLoader(), parentLoader);
|
||||||
|
|
||||||
|
// jcl non-api classes should not be visible
|
||||||
|
try {
|
||||||
|
Class log4jClass = contextLoader.loadClass(
|
||||||
|
"org.apache.commons.logging.impl.Log4J12Logger");
|
||||||
|
fail("Class Log4J12Logger is unexpectedly available");
|
||||||
|
} catch(ClassNotFoundException ex) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// String class classloader is null
|
||||||
|
Class stringClass = contextLoader.loadClass("java.lang.String");
|
||||||
|
assertNull("String class classloader is not null!",
|
||||||
|
stringClass.getClassLoader());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user