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