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
44
45 private DefaultPluginManager manager;
46
47 private PluginPersistentStateStore pluginStateStore;
48 private List<PluginLoader> pluginLoaders;
49 private DefaultModuleDescriptorFactory moduleDescriptorFactory;
50
51 private DirectoryPluginLoader directoryPluginLoader;
52 private PluginEventManager pluginEventManager;
53
54 @Override
55 protected void setUp() throws Exception
56 {
57 super.setUp();
58 pluginEventManager = new DefaultPluginEventManager();
59
60 pluginStateStore = new MemoryPluginPersistentStateStore();
61 pluginLoaders = new ArrayList<PluginLoader>();
62 moduleDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
63
64 manager = new DefaultPluginManager(pluginStateStore, pluginLoaders, moduleDescriptorFactory, new DefaultPluginEventManager());
65 }
66
67 @Override
68 protected void tearDown() throws Exception
69 {
70 manager = null;
71 moduleDescriptorFactory = null;
72 pluginLoaders = null;
73 pluginStateStore = null;
74
75 if (directoryPluginLoader != null)
76 {
77 directoryPluginLoader.shutDown();
78 directoryPluginLoader = null;
79 }
80
81 super.tearDown();
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
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 final PluginLoader proxy = (PluginLoader) mockPluginLoader.proxy();
106 pluginLoaders.add(proxy);
107 manager.init();
108
109 assertEquals(1, manager.getPlugins().size());
110 assertEquals(0, manager.getEnabledPlugins().size());
111 assertFalse(plugin.getPluginState() == PluginState.ENABLED);
112 manager.enablePlugin("foo");
113 assertEquals(1, manager.getPlugins().size());
114 assertEquals(0, manager.getEnabledPlugins().size());
115 assertFalse(plugin.getPluginState() == PluginState.ENABLED);
116 }
117
118 private DefaultPluginManager makeClassLoadingPluginManager() throws PluginParseException
119 {
120 directoryPluginLoader = new DirectoryPluginLoader(pluginsTestDir, ImmutableList.<PluginFactory>of(
121 new LegacyDynamicPluginFactory(PluginAccessor.Descriptor.FILENAME),
122 new XmlDynamicPluginFactory(new MockApplication().setKey("foo"))), pluginEventManager);
123 pluginLoaders.add(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
167 }
168
169
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
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
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
236 }
237
238
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
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
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.addPlugins(null, Arrays.asList(servicePlugin, clientPlugin));
277
278 assertTrue(clientPlugin.getPluginState() == PluginState.ENABLED);
279 assertFalse(servicePlugin.getPluginState() == PluginState.ENABLED);
280 }
281
282 public Plugin createPluginWithVersion(final String version)
283 {
284 final Plugin p = new StaticPlugin();
285 p.setKey("test.default.plugin");
286 final PluginInformation pInfo = p.getPluginInformation();
287 pInfo.setVersion(version);
288 return p;
289 }
290
291 private static class EnableInPassPlugin extends AbstractDelegatingPlugin
292 {
293 private int pass;
294
295 public EnableInPassPlugin(final String key, final int pass)
296 {
297 super(new StaticPlugin());
298 this.pass = pass;
299 setKey(key);
300 }
301
302 @Override
303 public void enable()
304 {
305 if (--pass <= 0)
306 {
307 super.enable();
308 }
309 }
310 }
311
312 class NothingModuleDescriptor extends MockUnusedModuleDescriptor
313 {
314 }
315
316 @RequiresRestart
317 public static class RequiresRestartModuleDescriptor extends MockUnusedModuleDescriptor
318 {
319 }
320 }