View Javadoc

1   package com.atlassian.plugin.manager;
2   
3   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4   import com.atlassian.plugin.JarPluginArtifact;
5   import com.atlassian.plugin.MockApplication;
6   import com.atlassian.plugin.Plugin;
7   import com.atlassian.plugin.PluginAccessor;
8   import com.atlassian.plugin.PluginInformation;
9   import com.atlassian.plugin.PluginParseException;
10  import com.atlassian.plugin.PluginState;
11  import com.atlassian.plugin.descriptors.MockUnusedModuleDescriptor;
12  import com.atlassian.plugin.descriptors.RequiresRestart;
13  import com.atlassian.plugin.event.PluginEventManager;
14  import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
15  import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
16  import com.atlassian.plugin.factories.PluginFactory;
17  import com.atlassian.plugin.factories.XmlDynamicPluginFactory;
18  import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
19  import com.atlassian.plugin.impl.AbstractDelegatingPlugin;
20  import com.atlassian.plugin.impl.StaticPlugin;
21  import com.atlassian.plugin.loaders.DirectoryPluginLoader;
22  import com.atlassian.plugin.loaders.PluginLoader;
23  import com.atlassian.plugin.loaders.classloading.DirectoryPluginLoaderUtils;
24  import com.atlassian.plugin.manager.store.MemoryPluginPersistentStateStore;
25  import com.atlassian.plugin.mock.MockAnimalModuleDescriptor;
26  import com.atlassian.plugin.repositories.FilePluginInstaller;
27  import com.atlassian.plugin.test.PluginJarBuilder;
28  import com.google.common.collect.ImmutableList;
29  import com.mockobjects.dynamic.C;
30  import com.mockobjects.dynamic.Mock;
31  import org.apache.commons.io.FileUtils;
32  import org.junit.After;
33  import org.junit.Before;
34  import org.junit.Test;
35  
36  import java.io.File;
37  import java.io.InputStream;
38  import java.util.Arrays;
39  import java.util.Collections;
40  
41  import static com.atlassian.plugin.loaders.classloading.DirectoryPluginLoaderUtils.createFillAndCleanTempPluginDirectory;
42  import static org.junit.Assert.*;
43  
44  public class TestDefaultPluginManagerLongRunning
45  {
46      /**
47       * the object being tested
48       */
49      private DefaultPluginManager manager;
50  
51      private PluginPersistentStateStore pluginStateStore;
52      private DefaultModuleDescriptorFactory moduleDescriptorFactory; // we should be able to use the interface here?
53  
54      private DirectoryPluginLoader directoryPluginLoader;
55      private PluginEventManager pluginEventManager;
56  
57      @Before
58      public void setUp() throws Exception
59      {
60          pluginEventManager = new DefaultPluginEventManager();
61  
62          pluginStateStore = new MemoryPluginPersistentStateStore();
63          moduleDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
64      }
65  
66      @After
67      public void tearDown() throws Exception
68      {
69          manager = null;
70          moduleDescriptorFactory = null;
71          pluginStateStore = null;
72  
73          if (directoryPluginLoader != null)
74          {
75              directoryPluginLoader.shutDown();
76              directoryPluginLoader = null;
77          }
78      }
79  
80      private DefaultPluginManager newDefaultPluginManager(PluginLoader... pluginLoaders)
81      {
82          return new DefaultPluginManager(pluginStateStore, ImmutableList.copyOf(pluginLoaders), moduleDescriptorFactory, new DefaultPluginEventManager());
83      }
84  
85      @Test
86      public void testEnableFailed() throws PluginParseException
87      {
88          final Mock mockPluginLoader = new Mock(PluginLoader.class);
89          final Plugin plugin = new StaticPlugin()
90          {
91              public PluginState enableInternal()
92              {
93                  return PluginState.DISABLED;
94              }
95  
96              public void disableInternal()
97              {
98                  // do nothing
99              }
100         };
101         plugin.setKey("foo");
102         plugin.setEnabledByDefault(false);
103         plugin.setPluginInformation(new PluginInformation());
104 
105         mockPluginLoader.expectAndReturn("loadAllPlugins", C.ANY_ARGS, Collections.singletonList(plugin));
106 
107         manager = newDefaultPluginManager((PluginLoader) mockPluginLoader.proxy());
108         manager.init();
109 
110         assertEquals(1, manager.getPlugins().size());
111         assertEquals(0, manager.getEnabledPlugins().size());
112         assertFalse(plugin.getPluginState() == PluginState.ENABLED);
113         manager.enablePlugin("foo");
114         assertEquals(1, manager.getPlugins().size());
115         assertEquals(0, manager.getEnabledPlugins().size());
116         assertFalse(plugin.getPluginState() == PluginState.ENABLED);
117     }
118 
119     private DefaultPluginManager makeClassLoadingPluginManager(File pluginsTestDir) throws PluginParseException
120     {
121         directoryPluginLoader = new DirectoryPluginLoader(pluginsTestDir, ImmutableList.<PluginFactory>of(
122                 new LegacyDynamicPluginFactory(PluginAccessor.Descriptor.FILENAME),
123                 new XmlDynamicPluginFactory(new MockApplication().setKey("foo"))), pluginEventManager);
124 
125         manager = newDefaultPluginManager(directoryPluginLoader);
126 
127         moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
128         manager.init();
129         return manager;
130     }
131 
132     @Test
133     public void testInstallPluginTwiceWithSameName() throws Exception
134     {
135         final DirectoryPluginLoaderUtils.ScannerDirectories directories = createFillAndCleanTempPluginDirectory();
136         File pluginsTestDir = directories.pluginsTestDir;
137 
138         FileUtils.cleanDirectory(pluginsTestDir);
139         final File plugin = File.createTempFile("plugin", ".jar");
140         plugin.delete();
141         File jar = new PluginJarBuilder("plugin")
142                 .addPluginInformation("some.key", "My name", "1.0", 1)
143                 .addResource("foo.txt", "foo")
144                 .addJava("my.MyClass",
145                         "package my; public class MyClass {}")
146                 .build();
147         FileUtils.moveFile(jar, plugin);
148 
149         final DefaultPluginManager manager = makeClassLoadingPluginManager(pluginsTestDir);
150         manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
151 
152         final String pluginKey = manager.installPlugin(new JarPluginArtifact(plugin));
153 
154         assertTrue(new File(pluginsTestDir, plugin.getName()).exists());
155 
156         final Plugin installedPlugin = manager.getPlugin(pluginKey);
157         assertNotNull(installedPlugin);
158         InputStream s0 = installedPlugin.getClassLoader().getResourceAsStream("foo.txt");
159         assertNotNull(s0);
160         s0.close();
161         assertNull(installedPlugin.getClassLoader().getResourceAsStream("bar.txt"));
162         assertNotNull(installedPlugin.getClassLoader().loadClass("my.MyClass"));
163         try
164         {
165             installedPlugin.getClassLoader().loadClass("my.MyNewClass");
166             fail("Expected ClassNotFoundException for unknown class");
167         }
168         catch (final ClassNotFoundException e)
169         {
170             // expected
171         }
172 
173         // sleep to ensure the new plugin is picked up
174         Thread.sleep(1000);
175 
176         File jartmp = new PluginJarBuilder("plugin")
177                 .addPluginInformation("some.key", "My name", "1.0", 1)
178                 .addResource("bar.txt", "bar")
179                 .addJava("my.MyNewClass",
180                         "package my; public class MyNewClass {}")
181                 .build();
182         plugin.delete();
183         FileUtils.moveFile(jartmp, plugin);
184 
185         // reinstall the plugin
186         final String pluginKey2 = manager.installPlugin(new JarPluginArtifact(plugin));
187 
188         assertTrue(new File(pluginsTestDir, plugin.getName()).exists());
189 
190         final Plugin installedPlugin2 = manager.getPlugin(pluginKey2);
191         assertNotNull(installedPlugin2);
192         assertEquals(1, manager.getEnabledPlugins().size());
193         assertNull(installedPlugin2.getClassLoader().getResourceAsStream("foo.txt"));
194         InputStream s1 = installedPlugin2.getClassLoader().getResourceAsStream("bar.txt");
195         assertNotNull(s1);
196         s1.close();
197         assertNotNull(installedPlugin2.getClassLoader().loadClass("my.MyNewClass"));
198         try
199         {
200             installedPlugin2.getClassLoader().loadClass("my.MyClass");
201             fail("Expected ClassNotFoundException for unknown class");
202         }
203         catch (final ClassNotFoundException e)
204         {
205             // expected
206         }
207     }
208 
209     @Test
210     public void testInstallPluginTwiceWithDifferentName() throws Exception
211     {
212         final DirectoryPluginLoaderUtils.ScannerDirectories directories = createFillAndCleanTempPluginDirectory();
213         File pluginsTestDir = directories.pluginsTestDir;
214 
215         FileUtils.cleanDirectory(pluginsTestDir);
216         final File plugin1 = new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1).addResource("foo.txt", "foo").addJava(
217                 "my.MyClass", "package my; public class MyClass {}").build();
218 
219         final DefaultPluginManager manager = makeClassLoadingPluginManager(pluginsTestDir);
220         manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
221 
222         final String pluginKey = manager.installPlugin(new JarPluginArtifact(plugin1));
223 
224         assertTrue(new File(pluginsTestDir, plugin1.getName()).exists());
225 
226         final Plugin installedPlugin = manager.getPlugin(pluginKey);
227         assertNotNull(installedPlugin);
228         InputStream s0 = installedPlugin.getClassLoader().getResourceAsStream("foo.txt");
229         assertNotNull(s0);
230         s0.close();
231         InputStream s1 = installedPlugin.getClassLoader().getResourceAsStream("bar.txt");
232         assertNull(s1);
233         assertNotNull(installedPlugin.getClassLoader().loadClass("my.MyClass"));
234         try
235         {
236             installedPlugin.getClassLoader().loadClass("my.MyNewClass");
237             fail("Expected ClassNotFoundException for unknown class");
238         }
239         catch (final ClassNotFoundException e)
240         {
241             // expected
242         }
243 
244         // sleep to ensure the new plugin is picked up
245         Thread.sleep(1000);
246 
247         final File plugin2 = new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1)
248                 .addResource("bar.txt", "bar").addJava("my.MyNewClass", "package my; public class MyNewClass {}")
249                 .build();
250 
251         // reinstall the plugin
252         final String pluginKey2 = manager.installPlugin(new JarPluginArtifact(plugin2));
253 
254         assertFalse(new File(pluginsTestDir, plugin1.getName()).exists());
255         assertTrue(new File(pluginsTestDir, plugin2.getName()).exists());
256 
257         final Plugin installedPlugin2 = manager.getPlugin(pluginKey2);
258         assertNotNull(installedPlugin2);
259         assertEquals(1, manager.getEnabledPlugins().size());
260         InputStream s2 = installedPlugin2.getClassLoader().getResourceAsStream("foo.txt");
261         assertNull(s2);
262         InputStream s3 = installedPlugin2.getClassLoader().getResourceAsStream("bar.txt");
263         assertNotNull(s3);
264         s3.close();
265         assertNotNull(installedPlugin2.getClassLoader().loadClass("my.MyNewClass"));
266         try
267         {
268             installedPlugin2.getClassLoader().loadClass("my.MyClass");
269             fail("Expected ClassNotFoundException for unknown class");
270         }
271         catch (final ClassNotFoundException e)
272         {
273             // expected
274         }
275     }
276 
277     @Test
278     public void testAddPluginsWithDependencyIssuesNoResolution() throws Exception
279     {
280         final Plugin servicePlugin = new EnableInPassPlugin("service.plugin", 4);
281         final Plugin clientPlugin = new EnableInPassPlugin("client.plugin", 1);
282 
283         manager = newDefaultPluginManager();
284         manager.addPlugins(null, Arrays.asList(servicePlugin, clientPlugin));
285 
286         assertTrue(clientPlugin.getPluginState() == PluginState.ENABLED);
287         assertFalse(servicePlugin.getPluginState() == PluginState.ENABLED);
288     }
289 
290     public Plugin createPluginWithVersion(final String version)
291     {
292         final Plugin p = new StaticPlugin();
293         p.setKey("test.default.plugin");
294         final PluginInformation pInfo = p.getPluginInformation();
295         pInfo.setVersion(version);
296         return p;
297     }
298 
299     private static class EnableInPassPlugin extends AbstractDelegatingPlugin
300     {
301         private int pass;
302 
303         public EnableInPassPlugin(final String key, final int pass)
304         {
305             super(new StaticPlugin());
306             this.pass = pass;
307             setKey(key);
308         }
309 
310         @Override
311         public void enable()
312         {
313             if (--pass <= 0)
314             {
315                 super.enable();
316             }
317         }
318     }
319 
320     class NothingModuleDescriptor extends MockUnusedModuleDescriptor
321     {
322     }
323 
324     @RequiresRestart
325     public static class RequiresRestartModuleDescriptor extends MockUnusedModuleDescriptor
326     {
327     }
328 }