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