View Javadoc

1   package com.atlassian.plugin.loaders;
2   
3   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginAccessor;
6   import com.atlassian.plugin.PluginException;
7   import com.atlassian.plugin.PluginParseException;
8   import com.atlassian.plugin.event.PluginEventManager;
9   import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
10  import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
11  import com.atlassian.plugin.factories.PluginFactory;
12  import com.atlassian.plugin.factories.XmlDynamicPluginFactory;
13  import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
14  import com.atlassian.plugin.impl.UnloadablePlugin;
15  import com.atlassian.plugin.loaders.classloading.AbstractTestClassLoader;
16  import com.atlassian.plugin.mock.MockAnimalModuleDescriptor;
17  import com.atlassian.plugin.mock.MockBear;
18  import com.atlassian.plugin.mock.MockMineralModuleDescriptor;
19  import com.atlassian.plugin.test.PluginJarBuilder;
20  import com.atlassian.plugin.util.collect.CollectionUtil;
21  import com.atlassian.plugin.util.collect.Predicate;
22  import org.apache.commons.io.FileUtils;
23  
24  import java.io.File;
25  import java.io.FileOutputStream;
26  import java.io.FilenameFilter;
27  import java.io.IOException;
28  import java.io.OutputStream;
29  import java.net.URISyntaxException;
30  import java.util.Collection;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.jar.JarEntry;
34  import java.util.jar.JarOutputStream;
35  
36  import static com.atlassian.plugin.util.collect.CollectionUtil.filter;
37  import static java.util.Arrays.asList;
38  import static java.util.Collections.unmodifiableList;
39  
40  public class TestDirectoryPluginLoader extends AbstractTestClassLoader
41  {
42      private PluginEventManager pluginEventManager;
43      private DirectoryPluginLoader loader;
44      private DefaultModuleDescriptorFactory moduleDescriptorFactory;
45      private static final List<PluginFactory> DEFAULT_PLUGIN_FACTORIES = unmodifiableList(asList(new LegacyDynamicPluginFactory(
46          PluginAccessor.Descriptor.FILENAME), new XmlDynamicPluginFactory("foo")));
47  
48      public static final String BAD_PLUGIN_JAR = "bad-plugins/crap-plugin.jar";
49  
50      @Override
51      public void setUp() throws Exception
52      {
53          super.setUp();
54          moduleDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
55          pluginEventManager = new DefaultPluginEventManager();
56          createFillAndCleanTempPluginDirectory();
57      }
58  
59      @Override
60      public void tearDown() throws Exception
61      {
62          FileUtils.deleteDirectory(pluginsTestDir);
63          super.tearDown();
64      }
65  
66      public void testAtlassianPlugin() throws Exception
67      {
68          addTestModuleDecriptors();
69          loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
70          final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
71  
72          assertEquals(2, plugins.size());
73  
74          for (final Plugin plugin : plugins)
75          {
76              assertTrue(plugin.getName().equals("Test Class Loaded Plugin") || plugin.getName().equals("Test Class Loaded Plugin 2"));
77  
78              if (plugin.getName().equals("Test Class Loaded Plugin")) // asserts for first plugin
79              {
80                  assertEquals("Test Class Loaded Plugin", plugin.getName());
81                  assertEquals("test.atlassian.plugin.classloaded", plugin.getKey());
82                  assertEquals(1, plugin.getModuleDescriptors().size());
83                  final MockAnimalModuleDescriptor paddingtonDescriptor = (MockAnimalModuleDescriptor) plugin.getModuleDescriptor("paddington");
84                  paddingtonDescriptor.enabled();
85                  assertEquals("Paddington Bear", paddingtonDescriptor.getName());
86                  final MockBear paddington = (MockBear) paddingtonDescriptor.getModule();
87                  assertEquals("com.atlassian.plugin.mock.MockPaddington", paddington.getClass().getName());
88              }
89              else if (plugin.getName().equals("Test Class Loaded Plugin 2")) // asserts for second plugin
90              {
91                  assertEquals("Test Class Loaded Plugin 2", plugin.getName());
92                  assertEquals("test.atlassian.plugin.classloaded2", plugin.getKey());
93                  assertEquals(1, plugin.getModuleDescriptors().size());
94                  final MockAnimalModuleDescriptor poohDescriptor = (MockAnimalModuleDescriptor) plugin.getModuleDescriptor("pooh");
95                  poohDescriptor.enabled();
96                  assertEquals("Pooh Bear", poohDescriptor.getName());
97                  final MockBear pooh = (MockBear) poohDescriptor.getModule();
98                  assertEquals("com.atlassian.plugin.mock.MockPooh", pooh.getClass().getName());
99              }
100             else
101             {
102                 fail("What plugin name?!");
103             }
104         }
105     }
106 
107     private void addTestModuleDecriptors()
108     {
109         moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
110         moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
111     }
112 
113     public void testSupportsAdditionAndRemoval()
114     {
115         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
116         assertTrue(loader.supportsAddition());
117         assertTrue(loader.supportsRemoval());
118     }
119 
120     public void testNoFoundPlugins() throws PluginParseException
121     {
122         addTestModuleDecriptors();
123         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
124         Collection<Plugin> col = loader.addFoundPlugins(moduleDescriptorFactory);
125         assertFalse(col.isEmpty());
126 
127         col = loader.addFoundPlugins(moduleDescriptorFactory);
128         assertTrue(col.isEmpty());
129     }
130 
131     public void testFoundPlugin() throws PluginParseException, IOException
132     {
133         //delete paddington for the timebeing
134         final File paddington = new File(pluginsTestDir + File.separator + PADDINGTON_JAR);
135         paddington.delete();
136 
137         addTestModuleDecriptors();
138         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
139         loader.loadAllPlugins(moduleDescriptorFactory);
140 
141         //restore paddington to test plugins dir
142         FileUtils.copyDirectory(pluginsDirectory, pluginsTestDir);
143 
144         Collection<Plugin> col = loader.addFoundPlugins(moduleDescriptorFactory);
145         assertEquals(1, col.size());
146         // next time we shouldn't find any new plugins
147         col = loader.addFoundPlugins(moduleDescriptorFactory);
148         assertEquals(0, col.size());
149     }
150 
151     public void testRemovePlugin() throws PluginException, IOException
152     {
153         addTestModuleDecriptors();
154         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
155         final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
156 
157         //duplicate the paddington plugin before removing the original
158         //the duplicate will be used to restore the deleted original after the test
159 
160         final Iterator<Plugin> iter = plugins.iterator();
161 
162         Plugin paddingtonPlugin = null;
163 
164         while (iter.hasNext())
165         {
166             final Plugin plugin = iter.next();
167 
168             if (plugin.getName().equals("Test Class Loaded Plugin"))
169             {
170                 paddingtonPlugin = plugin;
171                 break;
172             }
173         }
174 
175         if (paddingtonPlugin == null)
176         {
177             fail("Can't find test plugin 1 (paddington)");
178         }
179 
180         loader.removePlugin(paddingtonPlugin);
181     }
182 
183     public void testInvalidPluginHandled() throws IOException, PluginParseException
184     {
185         createJarFile("evilplugin.jar", PluginAccessor.Descriptor.FILENAME, pluginsTestDir.getAbsolutePath());
186 
187         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
188 
189         final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
190 
191         assertEquals("evil jar wasn't loaded, but other plugins were", pluginsTestDir.list(new FilenameFilter()
192         {
193 
194             public boolean accept(final File directory, final String fileName)
195             {
196                 return fileName.endsWith(".jar");
197             }
198         }).length, plugins.size());
199 
200         assertEquals(1, CollectionUtil.toList(filter(plugins, new Predicate<Plugin>()
201         {
202             public boolean evaluate(final Plugin input)
203             {
204                 return input instanceof UnloadablePlugin;
205             }
206         })).size());
207     }
208 
209     public void testInstallPluginTwice() throws URISyntaxException, IOException, PluginParseException, InterruptedException
210     {
211         FileUtils.cleanDirectory(pluginsTestDir);
212         final File plugin = new File(pluginsTestDir, "some-plugin.jar");
213         new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1).addResource("foo.txt", "foo").build().renameTo(plugin);
214 
215         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
216 
217         Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
218         assertEquals(1, plugins.size());
219         assertNotNull((plugins.iterator().next()).getResource("foo.txt"));
220         assertNull((plugins.iterator().next()).getResource("bar.txt"));
221 
222         Thread.currentThread();
223         // sleep to ensure the new plugin is picked up
224         Thread.sleep(1000);
225 
226         plugin.delete(); //delete the old plugin artifact to make windows happy
227         new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1).addResource("bar.txt", "bar").build().renameTo(plugin);
228         plugins = loader.addFoundPlugins(moduleDescriptorFactory);
229         assertEquals(1, plugins.size());
230         assertNull((plugins.iterator().next()).getResource("foo.txt"));
231         assertNotNull((plugins.iterator().next()).getResource("bar.txt"));
232         assertTrue(plugin.exists());
233 
234     }
235 
236     public void testMixedFactories() throws URISyntaxException, IOException, PluginParseException, InterruptedException
237     {
238         FileUtils.cleanDirectory(pluginsTestDir);
239         final File plugin = new File(pluginsTestDir, "some-plugin.jar");
240         new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1).addResource("foo.txt", "foo").build().renameTo(plugin);
241         FileUtils.writeStringToFile(new File(pluginsTestDir, "foo.xml"), "<atlassian-plugin key=\"jim\"></atlassian-plugin>");
242 
243         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
244 
245         final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
246         assertEquals(2, plugins.size());
247     }
248 
249     public void testUnknownPluginArtifact() throws URISyntaxException, IOException, PluginParseException, InterruptedException
250     {
251         FileUtils.cleanDirectory(pluginsTestDir);
252         FileUtils.writeStringToFile(new File(pluginsTestDir, "foo.bob"), "<an>");
253 
254         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
255 
256         final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
257         assertEquals(1, plugins.size());
258         assertTrue(plugins.iterator().next() instanceof UnloadablePlugin);
259     }
260 
261     public void testPluginWithModuleDescriptorWithNoKey() throws Exception, IOException, PluginParseException, InterruptedException
262     {
263         FileUtils.cleanDirectory(pluginsTestDir);
264         new PluginJarBuilder("first")
265                 .addFormattedResource("atlassian-plugin.xml",
266                         "<atlassian-plugin name='Test' key='test.plugin'>",
267                         "    <plugin-info>",
268                         "        <version>1.0</version>",
269                         "    </plugin-info>",
270                         "    <object/>",
271                         "</atlassian-plugin>")
272                 .build(pluginsTestDir);
273 
274         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
275 
276         final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
277         assertEquals(1, plugins.size());
278         assertTrue(plugins.iterator().next() instanceof UnloadablePlugin);
279         assertEquals("test.plugin", plugins.iterator().next().getKey());
280     }
281 
282     public void testPluginWithBadDescriptor() throws Exception, IOException, PluginParseException, InterruptedException
283     {
284         FileUtils.cleanDirectory(pluginsTestDir);
285         File pluginJar = new PluginJarBuilder("first")
286                 .addFormattedResource("atlassian-plugin.xml",
287                         "<atlassian-pluasdfasdf")
288                 .build(pluginsTestDir);
289 
290         loader = new DirectoryPluginLoader(pluginsTestDir, DEFAULT_PLUGIN_FACTORIES, pluginEventManager);
291 
292         final Collection<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
293         assertEquals(1, plugins.size());
294         assertTrue(plugins.iterator().next() instanceof UnloadablePlugin);
295         assertEquals(pluginJar.getName(), plugins.iterator().next().getKey());
296     }
297 
298     private void createJarFile(final String jarname, final String jarEntry, final String saveDir) throws IOException
299     {
300         final OutputStream os = new FileOutputStream(saveDir + File.separator + jarname);
301         final JarOutputStream plugin1 = new JarOutputStream(os);
302         final JarEntry jarEntry1 = new JarEntry(jarEntry);
303 
304         plugin1.putNextEntry(jarEntry1);
305         plugin1.closeEntry();
306         plugin1.flush();
307         plugin1.close();
308     }
309 
310 }