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 DefaultModuleDescriptorFactory moduleDescriptorFactory;
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
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
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 = 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 }