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
48
49 private DefaultPluginManager manager;
50
51 private PluginPersistentStateStore pluginStateStore;
52 private DefaultModuleDescriptorFactory moduleDescriptorFactory;
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
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
171 }
172
173
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
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
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
242 }
243
244
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
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
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 }