View Javadoc
1   package it.com.atlassian.plugin.classloader;
2   
3   import com.atlassian.plugin.classloader.PluginClassLoader;
4   import com.atlassian.plugin.test.PluginTestUtils;
5   import com.opensymphony.util.BeanUtils;
6   import junit.framework.TestCase;
7   import org.apache.commons.io.FileUtils;
8   import org.apache.commons.io.IOUtils;
9   
10  import java.io.File;
11  import java.io.IOException;
12  import java.io.InputStream;
13  import java.net.URL;
14  import java.util.List;
15  
16  /**
17   * To make this test pass in your IDE, make sure you run Maven to build the necessary plugins and copy
18   * them to the target directory ('mvn package') and when running the tests, set the 'project.version'
19   * system property to the current version in the POM. E.g. -Dproject.version=2.1.0-SNAPSHOT
20   */
21  public class TestPluginClassLoader extends TestCase {
22      private PluginClassLoader pluginClassLoader;
23      private File tmpDir;
24  
25      protected void setUp() throws Exception {
26          super.setUp();
27          tmpDir = PluginTestUtils.createTempDirectory(TestPluginClassLoader.class);
28  
29          final URL url = getClass().getClassLoader().getResource(PluginTestUtils.SIMPLE_TEST_JAR);
30          assertNotNull("Can't find test resource '" + PluginTestUtils.SIMPLE_TEST_JAR + "' -- see class Javadoc, and be sure to set the 'project.version' system property!", url);
31          pluginClassLoader = new PluginClassLoader(new File(url.toURI()), getClass().getClassLoader(), tmpDir);
32      }
33  
34      protected void tearDown() throws Exception {
35          FileUtils.deleteDirectory(tmpDir);
36          super.tearDown();
37      }
38  
39      public void testPluginClassLoaderFindsInnerJars() throws Exception {
40          List innerJars = pluginClassLoader.getPluginInnerJars();
41          assertEquals(2, innerJars.size());
42      }
43  
44      public void testPluginClassLoaderLoadsResourceFromOuterJarFirst() throws Exception {
45          URL resourceUrl = pluginClassLoader.getResource("testresource.txt");
46          assertNotNull(resourceUrl);
47          assertEquals("outerjar", IOUtils.toString(resourceUrl.openStream()));
48      }
49  
50      public void testPluginClassLoaderLoadsClassFromOuterJar() throws Exception {
51          Class c = pluginClassLoader.loadClass("com.atlassian.plugin.simpletest.TestClassOne");
52          assertEquals("com.atlassian.plugin.simpletest", c.getPackage().getName());  // PLUG-27
53          assertEquals("com.atlassian.plugin.simpletest.TestClassOne", c.getName());
54      }
55  
56      public void testPluginClassLoaderHandlesDeletedExtractedInnerJars() throws Exception {
57          InputStream inputStream = pluginClassLoader.getResource("innerresource.txt").openStream();
58          assertNotNull(inputStream);
59          inputStream.close();
60          FileUtils.deleteDirectory(tmpDir);
61          assertTrue(tmpDir.mkdirs());
62          try {
63              assertNotNull(pluginClassLoader.getResource("innerresource.txt").openStream());
64              fail("underlying extracted inner jar was deleted and should throw FileNotFoundException");
65          } catch (IOException e) {
66              // expected exception because we deleted the jar
67          }
68      }
69  
70      public void testPluginClassLoaderExtractsInnerJarsToSpecifiedDirectory() throws Exception {
71          final List<File> files = pluginClassLoader.getPluginInnerJars();
72          for (File file : files) {
73              assertEquals(tmpDir, file.getParentFile());
74          }
75      }
76  
77      public void testPluginClassLoaderDetectsMissingTempDirectory() throws Exception {
78          try {
79              new PluginClassLoader(null, getClass().getClassLoader(), new File("/doesnotexisthopefully"));
80              fail("should throw IllegalArgumentException when temp directory does not exist");
81          } catch (IllegalStateException e) {
82              // expected
83          }
84      }
85  
86      public void testPluginClassLoaderLoadsResourceFromInnerJarIfNotInOuterJar() throws Exception {
87          final URL resourceUrl = pluginClassLoader.getResource("innerresource.txt");
88          assertNotNull(resourceUrl);
89          InputStream inputStream = resourceUrl.openStream();
90          assertEquals("innerresource", IOUtils.toString(inputStream));
91          inputStream.close();
92      }
93  
94      public void testPluginClassLoaderDoesNotSwallowClassesFromADifferentClassLoader() throws Exception {
95          final Class c = Class.forName(getClass().getName(), true, pluginClassLoader);
96          assertEquals(getClass().getClassLoader(), c.getClassLoader());
97      }
98  
99      public void testPluginClassLoaderOverridesContainerClassesWithInnerJarClasses() throws Exception {
100         Class mockVersionedClass =
101                 Class.forName("com.atlassian.plugin.mock.MockVersionedClass", true, pluginClassLoader);
102         Object instance = mockVersionedClass.newInstance();
103 
104         assertEquals("PluginClassLoader is searching the parent classloader for classes before inner JARs",
105                 2, BeanUtils.getValue(instance, "version"));
106     }
107 
108     public void testPluginClassLoaderDoesNotLockTheJarsPermanently() throws Exception {
109         //N.B This will probably never fail on a non Windows machine
110         File original = new File(getClass().getClassLoader().getResource(PluginTestUtils.SIMPLE_TEST_JAR).toURI());
111         File tmpFile = new File(original.getAbsolutePath() + ".tmp");
112         FileUtils.copyFile(original, tmpFile);
113 
114         PluginClassLoader pluginClassLoaderThatHasNotLockedFileYet = new
115                 PluginClassLoader(tmpFile, getClass().getClassLoader());
116         Class mockVersionedClass =
117                 Class.forName("com.atlassian.plugin.mock.MockVersionedClass", true, pluginClassLoader);
118         assertTrue(tmpFile.delete());
119     }
120 }