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