Author: skitching
Date: Tue Jul  5 01:50:41 2005
New Revision: 209245

URL: http://svn.apache.org/viewcvs?rev=209245&view=rev
Log:
Added test cases for child-first behaviour of PathableClassLoader.

Added:
    
jakarta/commons/proper/logging/trunk/src/test/org/apache/commons/logging/pathable/ChildFirstTestCase.java
   (with props)

Added: 
jakarta/commons/proper/logging/trunk/src/test/org/apache/commons/logging/pathable/ChildFirstTestCase.java
URL: 
http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/src/test/org/apache/commons/logging/pathable/ChildFirstTestCase.java?rev=209245&view=auto
==============================================================================
--- 
jakarta/commons/proper/logging/trunk/src/test/org/apache/commons/logging/pathable/ChildFirstTestCase.java
 (added)
+++ 
jakarta/commons/proper/logging/trunk/src/test/org/apache/commons/logging/pathable/ChildFirstTestCase.java
 Tue Jul  5 01:50:41 2005
@@ -0,0 +1,320 @@
+/*
+ * 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 java.net.URL;
+import java.util.Enumeration;
+import java.util.ArrayList;
+import java.net.URLClassLoader;
+
+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,
+ * where lookup order for the PathableClassLoader is child-first.
+ * <p>
+ * These tests assume:
+ * <ul>
+ * <li>junit is in system classpath
+ * <li>nothing else is in system classpath
+ * </ul>
+ */
+
+public class ChildFirstTestCase extends TestCase {
+    
+    /**
+     * Set up a custom classloader hierarchy for this test case.
+     * The hierarchy is:
+     * <ul>
+     * <li> contextloader: child-first.
+     * <li> childloader: child-first, used to load test case.
+     * <li> parentloader: child-first, parent is the bootclassloader.
+     * </ul>
+     */
+    public static Test suite() throws Exception {
+        Class thisClass = ChildFirstTestCase.class;
+        ClassLoader thisClassLoader = thisClass.getClassLoader();
+        
+        // Make the parent a direct child of the bootloader to hide all
+        // other classes in the system classpath
+        PathableClassLoader parent = new PathableClassLoader(null);
+        parent.setParentFirst(false);
+        
+        // Make the junit classes visible as a special case, as junit
+        // won't be able to call this class at all without this. The
+        // junit classes must be visible from the classloader that loaded
+        // this class, so use that as the source for future access to classes
+        // from the junit package.
+        parent.useExplicitLoader("junit.", thisClassLoader);
+        
+        // Make the commons-logging.jar classes visible via the parent
+        parent.addLogicalLib("commons-logging");
+        
+        // Create a child classloader to load the test case through
+        PathableClassLoader child = new PathableClassLoader(parent);
+        child.setParentFirst(false);
+        
+        // Obviously, the child classloader needs to have the test classes
+        // in its path!
+        child.addLogicalLib("testclasses");
+        child.addLogicalLib("commons-logging-adapters");
+        
+        // Create a third classloader to be the context classloader.
+        PathableClassLoader context = new PathableClassLoader(child);
+        context.setParentFirst(false);
+
+        // reload this class via the child classloader
+        Class testClass = child.loadClass(thisClass.getName());
+        
+        // and return our custom TestSuite class
+        return new PathableTestSuite(testClass, context);
+    }
+    
+    /**
+     * Test that the classloader hierarchy is as expected, and that
+     * calling loadClass() on various classloaders works as expected.
+     * Note that for this test case, parent-first classloading is
+     * in effect.
+     */
+    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 only via the parent
+        Class logClass = 
contextLoader.loadClass("org.apache.commons.logging.Log");
+        assertSame("Log class not loaded via parent",
+                logClass.getClassLoader(), parentLoader);
+
+        // jcl adapter classes should be visible via both parent and child. 
However
+        // as the classloaders are child-first we should see the child one.
+        Class log4jClass = 
contextLoader.loadClass("org.apache.commons.logging.impl.Log4J12Logger");
+        assertSame("Log4J12Logger not loaded via child", 
+                log4jClass.getClassLoader(), thisLoader);
+        
+        // test classes should be visible via the child only
+        Class testClass = 
contextLoader.loadClass("org.apache.commons.logging.PathableTestSuite");
+        assertSame("PathableTestSuite not loaded via child", 
+                testClass.getClassLoader(), thisLoader);
+        
+        // test loading of class that is not available
+        try {
+            Class noSuchClass = contextLoader.loadClass("no.such.class");
+            fail("Class no.such.class 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());
+    }
+    
+    /**
+     * Test that the various flavours of ClassLoader.getResource work as 
expected.
+     */
+    public void testResource() {
+        URL resource;
+        
+        ClassLoader contextLoader = 
Thread.currentThread().getContextClassLoader();
+        ClassLoader childLoader = contextLoader.getParent();
+        
+        // getResource where it doesn't exist
+        resource = childLoader.getResource("nosuchfile");
+        assertNull("Non-null URL returned for invalid resource name", 
resource);
+
+        // getResource where it is accessable only to parent classloader
+        resource = 
childLoader.getResource("org/apache/commons/logging/Log.class");
+        assertNotNull("Unable to locate Log.class resource", resource);
+        
+        // getResource where it is accessable only to child classloader
+        resource = 
childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
+        assertNotNull("Unable to locate PathableTestSuite.class resource", 
resource);
+
+        // getResource where it is accessable to both classloaders. The one 
visible
+        // to the child should be returned. The URL returned will be of form
+        //  jar:file:/x/y.jar!path/to/resource. The filename part should 
include the jarname
+        // of form commons-logging-adapters-nnnn.jar, not 
commons-logging-nnnn.jar
+        resource = 
childLoader.getResource("org/apache/commons/logging/impl/Log4J12Logger.class");
+        assertNotNull("Unable to locate Log4J12Logger.class resource", 
resource);
+        assertTrue("Incorrect source for Log4J12Logger class",
+                resource.toString().indexOf("/commons-logging-adapters-1.") > 
0);
+    }
+    
+    /**
+     * Test that the various flavours of ClassLoader.getResources work as 
expected.
+     */
+    public void testResources() throws Exception {
+        Enumeration resources;
+        URL[] urls;
+        
+        // verify the classloader hierarchy
+        ClassLoader contextLoader = 
Thread.currentThread().getContextClassLoader();
+        ClassLoader childLoader = contextLoader.getParent();
+        ClassLoader parentLoader = childLoader.getParent();
+        ClassLoader bootLoader = parentLoader.getParent();
+        assertNull("Unexpected classloader hierarchy", bootLoader);
+        
+        // getResources where no instances exist
+        resources = childLoader.getResources("nosuchfile");
+        urls = toURLArray(resources);
+        assertEquals("Non-null URL returned for invalid resource name", 0, 
urls.length);
+        
+        // getResources where the resource only exists in the parent
+        resources = 
childLoader.getResources("org/apache/commons/logging/Log.class");
+        urls = toURLArray(resources);
+        assertEquals("Unexpected number of Log.class resources found", 1, 
urls.length);
+        
+        // getResources where the resource only exists in the child
+        resources = 
childLoader.getResources("org/apache/commons/logging/PathableTestSuite.class");
+        urls = toURLArray(resources);
+        assertEquals("Unexpected number of PathableTestSuite.class resources 
found", 1, urls.length);
+        
+        // getResources where the resource exists in both.
+        // resources should be returned in order (child-resource, 
parent-resource)
+        resources = 
childLoader.getResources("org/apache/commons/logging/impl/Log4J12Logger.class");
+        urls = toURLArray(resources);
+        assertEquals("Unexpected number of Log4J12Logger.class resources 
found", 2, urls.length);
+        assertTrue("Incorrect source for Log4J12Logger class",
+                urls[0].toString().indexOf("/commons-logging-adapters-1.") > 
0);
+        assertTrue("Incorrect source for Log4J12Logger class",
+                urls[1].toString().indexOf("/commons-logging-1.") > 0);
+        
+    }
+
+    /**
+     * Utility method to convert an enumeration-of-URLs into an array of URLs.
+     */
+    private static URL[] toURLArray(Enumeration e) {
+        ArrayList l = new ArrayList();
+        while (e.hasMoreElements()) {
+            URL u = (URL) e.nextElement();
+            l.add(u);
+        }
+        URL[] tmp = new URL[l.size()];
+        return (URL[]) l.toArray(tmp);
+    }
+
+    /**
+     * Test that getResourceAsStream works.
+     */
+    public void testResourceAsStream() throws Exception {
+        java.io.InputStream is;
+        
+        // verify the classloader hierarchy
+        ClassLoader contextLoader = 
Thread.currentThread().getContextClassLoader();
+        ClassLoader childLoader = contextLoader.getParent();
+        ClassLoader parentLoader = childLoader.getParent();
+        ClassLoader bootLoader = parentLoader.getParent();
+        assertNull("Unexpected classloader hierarchy", bootLoader);
+        
+        // getResourceAsStream where no instances exist
+        is = childLoader.getResourceAsStream("nosuchfile");
+        assertNull("Invalid resource returned non-null stream", is);
+        
+        // getResourceAsStream where resource does exist
+        is = 
childLoader.getResourceAsStream("org/apache/commons/logging/Log.class");
+        assertNotNull("Null returned for valid resource", is);
+        is.close();
+        
+        // It would be nice to test parent-first ordering here, but that would 
require
+        // having a resource with the same name in both the parent and child 
loaders,
+        // but with different contents. That's a little tricky to set up so 
we'll
+        // skip that for now.
+    }
+    
+    /**
+     * Verify that the context classloader is a custom one, then reset it to
+     * a non-custom one.
+     */
+    private static void checkAndSetContext() {
+        ClassLoader contextLoader = 
Thread.currentThread().getContextClassLoader();
+        assertEquals("ContextLoader is of unexpected type", 
+                contextLoader.getClass().getName(), 
+                PathableClassLoader.class.getName());
+        
+        URL[] noUrls = new URL[0];
+        Thread.currentThread().setContextClassLoader(new 
URLClassLoader(noUrls));
+    }
+    
+    /**
+     * Verify that when a test method modifies the context classloader it is
+     * reset before the next test is run.
+     * <p>
+     * This method works in conjunction with testResetContext2. There is no
+     * way of knowing which test method junit will run first, but it doesn't
+     * matter; whichever one of them runs first will modify the 
contextClassloader.
+     * If the PathableTestSuite isn't resetting the contextClassLoader then 
whichever
+     * of them runs second will fail. Of course if other methods are run 
in-between
+     * then those methods might also fail...
+     */
+    public void testResetContext1() {
+        checkAndSetContext();
+    }
+
+    /**
+     * See testResetContext1.
+     */
+    public void testResetContext2() {
+        checkAndSetContext();
+    }
+}

Propchange: 
jakarta/commons/proper/logging/trunk/src/test/org/apache/commons/logging/pathable/ChildFirstTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Id



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to