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