1 package com.atlassian.plugin.manager;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.net.URL;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.List;
13
14 import com.atlassian.plugin.DefaultModuleDescriptorFactory;
15 import com.atlassian.plugin.JarPluginArtifact;
16 import com.atlassian.plugin.MockModuleDescriptor;
17 import com.atlassian.plugin.ModuleDescriptor;
18 import com.atlassian.plugin.ModuleDescriptorFactory;
19 import com.atlassian.plugin.Plugin;
20 import com.atlassian.plugin.PluginAccessor;
21 import com.atlassian.plugin.PluginArtifact;
22 import com.atlassian.plugin.PluginException;
23 import com.atlassian.plugin.PluginInformation;
24 import com.atlassian.plugin.PluginInstaller;
25 import com.atlassian.plugin.PluginParseException;
26 import com.atlassian.plugin.PluginRestartState;
27 import com.atlassian.plugin.PluginState;
28 import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
29 import com.atlassian.plugin.descriptors.MockUnusedModuleDescriptor;
30 import com.atlassian.plugin.descriptors.RequiresRestart;
31 import com.atlassian.plugin.event.PluginEventListener;
32 import com.atlassian.plugin.event.PluginEventManager;
33 import com.atlassian.plugin.event.events.PluginContainerUnavailableEvent;
34 import com.atlassian.plugin.event.events.PluginDisabledEvent;
35 import com.atlassian.plugin.event.events.PluginEnabledEvent;
36 import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
37 import com.atlassian.plugin.event.events.PluginModuleAvailableEvent;
38 import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
39 import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
40 import com.atlassian.plugin.event.events.PluginModuleUnavailableEvent;
41 import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
42 import com.atlassian.plugin.event.listeners.FailListener;
43 import com.atlassian.plugin.event.listeners.PassListener;
44 import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
45 import com.atlassian.plugin.factories.XmlDynamicPluginFactory;
46 import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
47 import com.atlassian.plugin.impl.AbstractDelegatingPlugin;
48 import com.atlassian.plugin.impl.StaticPlugin;
49 import com.atlassian.plugin.impl.UnloadablePlugin;
50 import com.atlassian.plugin.loaders.DirectoryPluginLoader;
51 import com.atlassian.plugin.loaders.DynamicPluginLoader;
52 import com.atlassian.plugin.loaders.PluginLoader;
53 import com.atlassian.plugin.loaders.SinglePluginLoader;
54 import com.atlassian.plugin.loaders.classloading.AbstractTestClassLoader;
55 import com.atlassian.plugin.manager.store.MemoryPluginPersistentStateStore;
56 import com.atlassian.plugin.metadata.ClasspathFilePluginMetadata;
57 import com.atlassian.plugin.mock.MockAnimal;
58 import com.atlassian.plugin.mock.MockAnimalModuleDescriptor;
59 import com.atlassian.plugin.mock.MockBear;
60 import com.atlassian.plugin.mock.MockMineral;
61 import com.atlassian.plugin.mock.MockMineralModuleDescriptor;
62 import com.atlassian.plugin.mock.MockThing;
63 import com.atlassian.plugin.mock.MockVegetableModuleDescriptor;
64 import com.atlassian.plugin.mock.MockVegetableSubclassModuleDescriptor;
65 import com.atlassian.plugin.module.ModuleFactory;
66 import com.atlassian.plugin.parsers.DescriptorParser;
67 import com.atlassian.plugin.parsers.DescriptorParserFactory;
68 import com.atlassian.plugin.predicate.ModuleDescriptorPredicate;
69 import com.atlassian.plugin.predicate.PluginPredicate;
70 import com.atlassian.plugin.repositories.FilePluginInstaller;
71 import com.atlassian.plugin.test.PluginJarBuilder;
72 import com.mockobjects.dynamic.C;
73 import com.mockobjects.dynamic.Mock;
74
75 import org.apache.commons.io.FileUtils;
76 import org.apache.commons.io.IOUtils;
77
78 import static java.util.Arrays.asList;
79 import static java.util.Collections.singleton;
80 import static org.mockito.Mockito.any;
81 import static org.mockito.Mockito.doThrow;
82 import static org.mockito.Mockito.mock;
83 import static org.mockito.Mockito.never;
84 import static org.mockito.Mockito.verify;
85 import static org.mockito.Mockito.when;
86
87 public class TestDefaultPluginManager extends AbstractTestClassLoader
88 {
89
90
91
92 protected DefaultPluginManager manager;
93
94 private PluginPersistentStateStore pluginStateStore;
95 private List<PluginLoader> pluginLoaders;
96 private DefaultModuleDescriptorFactory moduleDescriptorFactory;
97
98 private DirectoryPluginLoader directoryPluginLoader;
99 protected PluginEventManager pluginEventManager;
100
101 @Override
102 protected void setUp() throws Exception
103 {
104 super.setUp();
105 pluginEventManager = new DefaultPluginEventManager();
106
107 pluginStateStore = new MemoryPluginPersistentStateStore();
108 pluginLoaders = new ArrayList<PluginLoader>();
109 moduleDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
110
111 manager = new DefaultPluginManager(pluginStateStore, pluginLoaders, moduleDescriptorFactory, pluginEventManager, true);
112 }
113
114 @Override
115 protected void tearDown() throws Exception
116 {
117 manager = null;
118 moduleDescriptorFactory = null;
119 pluginLoaders = null;
120 pluginStateStore = null;
121
122 if (directoryPluginLoader != null)
123 {
124 directoryPluginLoader = null;
125 }
126
127 super.tearDown();
128 }
129
130 protected PluginAccessor getPluginAccessor()
131 {
132 return manager;
133 }
134
135 public void testRetrievePlugins() throws PluginParseException
136 {
137 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
138 pluginLoaders.add(new SinglePluginLoader("test-disabled-plugin.xml"));
139
140 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
141 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
142 manager.init();
143
144 assertEquals(2, manager.getPlugins().size());
145 assertEquals(1, manager.getEnabledPlugins().size());
146 manager.enablePlugin("test.disabled.plugin");
147 assertEquals(2, manager.getEnabledPlugins().size());
148 }
149
150 public void testEnableModuleFailed() throws PluginParseException
151 {
152 final Mock mockPluginLoader = new Mock(PluginLoader.class);
153 final ModuleDescriptor<Object> badModuleDescriptor = new AbstractModuleDescriptor<Object>(ModuleFactory.LEGACY_MODULE_FACTORY)
154 {
155 @Override
156 public String getKey()
157 {
158 return "bar";
159 }
160
161 @Override
162 public String getCompleteKey()
163 {
164 return "foo:bar";
165 }
166
167 @Override
168 public void enabled()
169 {
170 throw new IllegalArgumentException("Cannot enable");
171 }
172
173 @Override
174 public Object getModule()
175 {
176 return null;
177 }
178 };
179
180 final AbstractModuleDescriptor goodModuleDescriptor = mock(AbstractModuleDescriptor.class);
181 when(goodModuleDescriptor.getKey()).thenReturn("baz");
182 when(goodModuleDescriptor.getCompleteKey()).thenReturn("foo:baz");
183
184 Plugin plugin = new StaticPlugin()
185 {
186 @Override
187 public Collection<ModuleDescriptor<?>> getModuleDescriptors()
188 {
189 return Arrays.<ModuleDescriptor<?>>asList(goodModuleDescriptor, badModuleDescriptor);
190 }
191
192 @Override
193 public ModuleDescriptor<Object> getModuleDescriptor(final String key)
194 {
195 return badModuleDescriptor;
196 }
197 };
198 plugin.setKey("foo");
199 plugin.setEnabledByDefault(true);
200 plugin.setPluginInformation(new PluginInformation());
201
202 mockPluginLoader.expectAndReturn("loadAllPlugins", C.ANY_ARGS, Collections.singletonList(plugin));
203
204 @SuppressWarnings("unchecked")
205 final PluginLoader loader = (PluginLoader) mockPluginLoader.proxy();
206 pluginLoaders.add(loader);
207
208 pluginEventManager.register(new FailListener(PluginEnabledEvent.class));
209
210
211 MyModuleDisabledListener listener = new MyModuleDisabledListener(goodModuleDescriptor);
212 pluginEventManager.register(listener);
213 manager.init();
214
215
216 assertEquals(1, getPluginAccessor().getPlugins().size());
217 assertEquals(0, getPluginAccessor().getEnabledPlugins().size());
218 plugin = getPluginAccessor().getPlugin("foo");
219 assertFalse(plugin.getPluginState() == PluginState.ENABLED);
220 assertTrue(plugin instanceof UnloadablePlugin);
221 assertTrue(listener.isCalled());
222 }
223
224 public static class MyModuleDisabledListener
225 {
226 private final ModuleDescriptor goodModuleDescriptor;
227 private volatile boolean disableCalled = false;
228
229 public MyModuleDisabledListener(ModuleDescriptor goodModuleDescriptor)
230 {
231 this.goodModuleDescriptor = goodModuleDescriptor;
232 }
233
234 @PluginEventListener
235 public void onDisable(PluginModuleDisabledEvent evt)
236 {
237 if (evt.getModule().equals(goodModuleDescriptor))
238 {
239 disableCalled = true;
240 }
241 }
242
243 public boolean isCalled()
244 {
245 return disableCalled;
246 }
247 }
248
249 public void testEnabledModuleOutOfSyncWithPlugin() throws PluginParseException
250 {
251 final Mock mockPluginLoader = new Mock(PluginLoader.class);
252 Plugin plugin = new StaticPlugin();
253 plugin.setKey("foo");
254 plugin.setEnabledByDefault(true);
255 plugin.setPluginInformation(new PluginInformation());
256
257 mockPluginLoader.expectAndReturn("loadAllPlugins", C.ANY_ARGS, Collections.singletonList(plugin));
258
259 @SuppressWarnings("unchecked")
260 final PluginLoader loader = (PluginLoader) mockPluginLoader.proxy();
261 pluginLoaders.add(loader);
262 manager.init();
263
264 assertEquals(1, getPluginAccessor().getPlugins().size());
265 assertEquals(1, getPluginAccessor().getEnabledPlugins().size());
266 plugin = getPluginAccessor().getPlugin("foo");
267 assertTrue(plugin.getPluginState() == PluginState.ENABLED);
268 assertTrue(getPluginAccessor().isPluginEnabled("foo"));
269 plugin.disable();
270 assertFalse(plugin.getPluginState() == PluginState.ENABLED);
271 assertFalse(getPluginAccessor().isPluginEnabled("foo"));
272 }
273
274 public void testDisablePluginModuleWithCannotDisableAnnotation()
275 {
276 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
277 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
278 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
279 moduleDescriptorFactory.addModuleDescriptor("bullshit", MockUnusedModuleDescriptor.class);
280 moduleDescriptorFactory.addModuleDescriptor("vegetable", MockVegetableModuleDescriptor.class);
281
282 manager.init();
283
284 final String pluginKey = "test.atlassian.plugin";
285 final String disablableModuleKey = pluginKey + ":bear";
286 final String moduleKey = pluginKey + ":veg";
287
288
289 manager.disablePluginModule(disablableModuleKey);
290 assertNull(getPluginAccessor().getEnabledPluginModule(disablableModuleKey));
291
292
293 manager.disablePluginModule(moduleKey);
294 assertNotNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
295 }
296
297 public void testDisablePluginModuleWithCannotDisableAnnotationinSuperclass()
298 {
299 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
300 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
301 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
302 moduleDescriptorFactory.addModuleDescriptor("bullshit", MockUnusedModuleDescriptor.class);
303 moduleDescriptorFactory.addModuleDescriptor("vegetable", MockVegetableModuleDescriptor.class);
304 moduleDescriptorFactory.addModuleDescriptor("vegetableSubclass", MockVegetableSubclassModuleDescriptor.class);
305
306 manager.init();
307
308 final String pluginKey = "test.atlassian.plugin";
309 final String disablableModuleKey = pluginKey + ":bear";
310 final String moduleKey = pluginKey + ":vegSubclass";
311
312
313 manager.disablePluginModule(disablableModuleKey);
314 assertNull(getPluginAccessor().getEnabledPluginModule(disablableModuleKey));
315
316
317 manager.disablePluginModule(moduleKey);
318 assertNotNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
319 }
320
321 public void testEnabledDisabledRetrieval() throws PluginParseException
322 {
323 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
324 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
325 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
326 moduleDescriptorFactory.addModuleDescriptor("bullshit", MockUnusedModuleDescriptor.class);
327 moduleDescriptorFactory.addModuleDescriptor("vegetable", MockVegetableModuleDescriptor.class);
328
329 final PassListener enabledListener = new PassListener(PluginEnabledEvent.class);
330 final PassListener disabledListener = new PassListener(PluginDisabledEvent.class);
331 pluginEventManager.register(enabledListener);
332 pluginEventManager.register(disabledListener);
333
334 manager.init();
335
336
337 assertNull(getPluginAccessor().getPlugin("bull:shit"));
338 assertNull(getPluginAccessor().getEnabledPlugin("bull:shit"));
339 assertNull(getPluginAccessor().getPluginModule("bull:shit"));
340 assertNull(getPluginAccessor().getEnabledPluginModule("bull:shit"));
341 assertTrue(getPluginAccessor().getEnabledModuleDescriptorsByClass(NothingModuleDescriptor.class).isEmpty());
342 assertTrue(getPluginAccessor().getEnabledModuleDescriptorsByType("bullshit").isEmpty());
343
344 final String pluginKey = "test.atlassian.plugin";
345 final String moduleKey = pluginKey + ":bear";
346
347
348 assertNotNull(getPluginAccessor().getPlugin(pluginKey));
349 assertNotNull(getPluginAccessor().getEnabledPlugin(pluginKey));
350 assertNotNull(getPluginAccessor().getPluginModule(moduleKey));
351 assertNotNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
352 assertNull(getPluginAccessor().getEnabledPluginModule(pluginKey + ":shit"));
353 assertFalse(getPluginAccessor().getEnabledModuleDescriptorsByClass(MockAnimalModuleDescriptor.class).isEmpty());
354 assertFalse(getPluginAccessor().getEnabledModuleDescriptorsByType("animal").isEmpty());
355 assertFalse(getPluginAccessor().getEnabledModulesByClass(MockBear.class).isEmpty());
356 assertEquals(new MockBear(), getPluginAccessor().getEnabledModulesByClass(MockBear.class).get(0));
357 enabledListener.assertCalled();
358
359
360 manager.disablePlugin(pluginKey);
361 assertNotNull(getPluginAccessor().getPlugin(pluginKey));
362 assertNull(getPluginAccessor().getEnabledPlugin(pluginKey));
363 assertNotNull(getPluginAccessor().getPluginModule(moduleKey));
364 assertNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
365 assertTrue(getPluginAccessor().getEnabledModulesByClass(com.atlassian.plugin.mock.MockBear.class).isEmpty());
366 assertTrue(getPluginAccessor().getEnabledModuleDescriptorsByClass(MockAnimalModuleDescriptor.class).isEmpty());
367 assertTrue(getPluginAccessor().getEnabledModuleDescriptorsByType("animal").isEmpty());
368 disabledListener.assertCalled();
369
370
371 manager.enablePlugin(pluginKey);
372 assertNotNull(getPluginAccessor().getPlugin(pluginKey));
373 assertNotNull(getPluginAccessor().getEnabledPlugin(pluginKey));
374 assertNotNull(getPluginAccessor().getPluginModule(moduleKey));
375 assertNotNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
376 assertFalse(getPluginAccessor().getEnabledModulesByClass(com.atlassian.plugin.mock.MockBear.class).isEmpty());
377 assertFalse(getPluginAccessor().getEnabledModuleDescriptorsByClass(MockAnimalModuleDescriptor.class).isEmpty());
378 assertFalse(getPluginAccessor().getEnabledModuleDescriptorsByType("animal").isEmpty());
379 enabledListener.assertCalled();
380
381
382 pluginEventManager.register(new FailListener(PluginEnabledEvent.class));
383 manager.disablePluginModule(moduleKey);
384 assertNotNull(getPluginAccessor().getPlugin(pluginKey));
385 assertNotNull(getPluginAccessor().getEnabledPlugin(pluginKey));
386 assertNotNull(getPluginAccessor().getPluginModule(moduleKey));
387 assertNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
388 assertTrue(getPluginAccessor().getEnabledModulesByClass(com.atlassian.plugin.mock.MockBear.class).isEmpty());
389 assertTrue(getPluginAccessor().getEnabledModuleDescriptorsByClass(MockAnimalModuleDescriptor.class).isEmpty());
390 assertTrue(getPluginAccessor().getEnabledModuleDescriptorsByType("animal").isEmpty());
391
392
393 pluginEventManager.register(new FailListener(PluginDisabledEvent.class));
394 manager.enablePluginModule(moduleKey);
395 assertNotNull(getPluginAccessor().getPlugin(pluginKey));
396 assertNotNull(getPluginAccessor().getEnabledPlugin(pluginKey));
397 assertNotNull(getPluginAccessor().getPluginModule(moduleKey));
398 assertNotNull(getPluginAccessor().getEnabledPluginModule(moduleKey));
399 assertFalse(getPluginAccessor().getEnabledModulesByClass(com.atlassian.plugin.mock.MockBear.class).isEmpty());
400 assertFalse(getPluginAccessor().getEnabledModuleDescriptorsByClass(MockAnimalModuleDescriptor.class).isEmpty());
401 assertFalse(getPluginAccessor().getEnabledModuleDescriptorsByType("animal").isEmpty());
402 }
403
404 public void testDuplicatePluginKeysAreBad() throws PluginParseException
405 {
406 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
407 pluginLoaders.add(new SinglePluginLoader("test-disabled-plugin.xml"));
408 pluginLoaders.add(new SinglePluginLoader("test-disabled-plugin.xml"));
409 try
410 {
411 manager.init();
412 fail("Should have died with duplicate key exception.");
413 }
414 catch (final PluginParseException e)
415 {
416 assertEquals("Duplicate plugin found (installed version is the same or older) and could not be unloaded: 'test.disabled.plugin'",
417 e.getMessage());
418 }
419 }
420
421 public void testLoadOlderDuplicatePlugin() throws PluginParseException
422 {
423 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
424 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
425 pluginLoaders.add(new MultiplePluginLoader("test-atlassian-plugin-newer.xml"));
426 pluginLoaders.add(new MultiplePluginLoader("test-atlassian-plugin.xml", "test-another-plugin.xml"));
427 manager.init();
428 assertEquals(2, getPluginAccessor().getEnabledPlugins().size());
429 }
430
431 public void testLoadOlderDuplicatePluginDoesNotTryToEnableIt()
432 {
433 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
434 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
435 pluginLoaders.add(new MultiplePluginLoader("test-atlassian-plugin-newer.xml"));
436 final Plugin plugin = new StaticPlugin()
437 {
438 @Override
439 protected PluginState enableInternal()
440 {
441 fail("enable() must never be called on a earlier version of plugin when later version is installed");
442 return null;
443 }
444
445 @Override
446 public void disableInternal()
447 {
448 fail("disable() must never be called on a earlier version of plugin when later version is installed");
449 }
450 };
451 plugin.setKey("test.atlassian.plugin");
452 plugin.getPluginInformation().setVersion("1.0");
453 manager.init();
454 manager.addPlugins(null, Collections.singletonList(plugin));
455 }
456
457 public void testLoadNewerDuplicatePlugin() throws PluginParseException
458 {
459 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
460 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
461 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
462 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin-newer.xml"));
463 try
464 {
465 manager.init();
466 fail("Should have died with duplicate key exception.");
467 }
468 catch (final PluginParseException e)
469 {
470 assertEquals("Duplicate plugin found (installed version is the same or older) and could not be unloaded: 'test.atlassian.plugin'",
471 e.getMessage());
472 }
473 }
474
475 public void testLoadNewerDuplicateDynamicPluginPreservesPluginState() throws PluginParseException
476 {
477 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
478 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
479
480 pluginLoaders.add(new SinglePluginLoaderWithRemoval("test-atlassian-plugin.xml"));
481 manager.init();
482
483 pluginStateStore.save(PluginPersistentState.Builder.create(pluginStateStore.load()).setEnabled(manager.getPlugin("test.atlassian.plugin"),
484 false).toState());
485
486 assertFalse(getPluginAccessor().isPluginEnabled("test.atlassian.plugin"));
487 manager.shutdown();
488
489 pluginLoaders.add(new SinglePluginLoaderWithRemoval("test-atlassian-plugin-newer.xml"));
490 manager.init();
491
492 final Plugin plugin = getPluginAccessor().getPlugin("test.atlassian.plugin");
493 assertEquals("1.1", plugin.getPluginInformation().getVersion());
494 assertFalse(getPluginAccessor().isPluginEnabled("test.atlassian.plugin"));
495 }
496
497 public void testLoadNewerDuplicateDynamicPluginPreservesModuleState() throws PluginParseException
498 {
499 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
500 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
501
502 pluginLoaders.add(new SinglePluginLoaderWithRemoval("test-atlassian-plugin.xml"));
503 manager.init();
504
505 pluginStateStore.save(PluginPersistentState.Builder.create(pluginStateStore.load()).setEnabled(
506 getPluginAccessor().getPluginModule("test.atlassian.plugin:bear"), false).toState());
507
508 manager.shutdown();
509
510 pluginLoaders.add(new SinglePluginLoaderWithRemoval("test-atlassian-plugin-newer.xml"));
511 manager.init();
512
513 final Plugin plugin = getPluginAccessor().getPlugin("test.atlassian.plugin");
514 assertEquals("1.1", plugin.getPluginInformation().getVersion());
515 assertFalse(getPluginAccessor().isPluginModuleEnabled("test.atlassian.plugin:bear"));
516 assertTrue(getPluginAccessor().isPluginModuleEnabled("test.atlassian.plugin:gold"));
517 }
518
519 public void testLoadChangedDynamicPluginWithSameVersionNumberReplacesExisting() throws PluginParseException
520 {
521 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
522 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
523
524 pluginLoaders.add(new SinglePluginLoaderWithRemoval("test-atlassian-plugin.xml"));
525 pluginLoaders.add(new SinglePluginLoaderWithRemoval("test-atlassian-plugin-changed-same-version.xml"));
526
527 manager.init();
528
529 final Plugin plugin = getPluginAccessor().getPlugin("test.atlassian.plugin");
530 assertEquals("Test Plugin (Changed)", plugin.getName());
531 }
532
533 public void testGetPluginsWithPluginMatchingPluginPredicate() throws Exception
534 {
535 final Mock mockPlugin = mockTestPlugin(Collections.emptyList());
536 final Plugin plugin = (Plugin) mockPlugin.proxy();
537
538 final Mock mockPluginPredicate = new Mock(PluginPredicate.class);
539 mockPluginPredicate.expectAndReturn("matches", C.eq(plugin), true);
540
541 manager.addPlugins(null, Collections.singletonList(plugin));
542 final Collection<Plugin> plugins = getPluginAccessor().getPlugins((PluginPredicate) mockPluginPredicate.proxy());
543
544 assertEquals(1, plugins.size());
545 assertTrue(plugins.contains(plugin));
546 mockPluginPredicate.verify();
547 }
548
549 public void testGetPluginsWithPluginNotMatchingPluginPredicate() throws Exception
550 {
551 final Mock mockPlugin = mockTestPlugin(Collections.emptyList());
552 final Plugin plugin = (Plugin) mockPlugin.proxy();
553
554 final Mock mockPluginPredicate = new Mock(PluginPredicate.class);
555 mockPluginPredicate.expectAndReturn("matches", C.eq(plugin), false);
556
557 manager.addPlugins(null, Collections.singletonList(plugin));
558 final Collection<Plugin> plugins = getPluginAccessor().getPlugins((PluginPredicate) mockPluginPredicate.proxy());
559
560 assertEquals(0, plugins.size());
561 mockPluginPredicate.verify();
562 }
563
564 public void testGetPluginModulesWithModuleMatchingPredicate() throws Exception
565 {
566 final MockThing module = new MockThing()
567 {
568 };
569 final Mock mockModuleDescriptor = new Mock(ModuleDescriptor.class);
570 @SuppressWarnings("unchecked")
571 final ModuleDescriptor<MockThing> moduleDescriptor = (ModuleDescriptor<MockThing>) mockModuleDescriptor.proxy();
572 mockModuleDescriptor.expectAndReturn("getModule", module);
573 mockModuleDescriptor.matchAndReturn("getCompleteKey", "some-plugin-key:module");
574 mockModuleDescriptor.matchAndReturn("isEnabledByDefault", true);
575 mockModuleDescriptor.matchAndReturn("hashCode", mockModuleDescriptor.hashCode());
576
577 final Mock mockPlugin = mockTestPlugin(Collections.singleton(moduleDescriptor));
578 mockPlugin.matchAndReturn("getModuleDescriptor", "module", moduleDescriptor);
579
580 final Plugin plugin = (Plugin) mockPlugin.proxy();
581
582 final Mock mockModulePredicate = new Mock(ModuleDescriptorPredicate.class);
583 mockModulePredicate.expectAndReturn("matches", C.eq(moduleDescriptor), true);
584
585 manager.addPlugins(null, Collections.singletonList(plugin));
586 @SuppressWarnings("unchecked")
587 final ModuleDescriptorPredicate<MockThing> predicate = (ModuleDescriptorPredicate<MockThing>) mockModulePredicate.proxy();
588 final Collection<MockThing> modules = getPluginAccessor().getModules(predicate);
589
590 assertEquals(1, modules.size());
591 assertTrue(modules.contains(module));
592
593 mockModulePredicate.verify();
594 }
595
596 public void testGetPluginModulesWithGetModuleThrowingException() throws Exception
597 {
598 final Plugin badPlugin = new StaticPlugin();
599 badPlugin.setKey("bad");
600 final MockModuleDescriptor<Object> badDescriptor = new MockModuleDescriptor<Object>(badPlugin, "bad", new Object())
601 {
602 @Override
603 public Object getModule()
604 {
605 throw new RuntimeException();
606 }
607 };
608 badPlugin.addModuleDescriptor(badDescriptor);
609
610 final Plugin goodPlugin = new StaticPlugin();
611 goodPlugin.setKey("good");
612 final MockModuleDescriptor<Object> goodDescriptor = new MockModuleDescriptor<Object>(goodPlugin, "good", new Object());
613 goodPlugin.addModuleDescriptor(goodDescriptor);
614
615 manager.addPlugins(null, Arrays.asList(goodPlugin, badPlugin));
616 manager.enablePlugin("bad");
617 manager.enablePlugin("good");
618
619 assertTrue(getPluginAccessor().isPluginEnabled("bad"));
620 assertTrue(getPluginAccessor().isPluginEnabled("good"));
621 final Collection<Object> modules = getPluginAccessor().getEnabledModulesByClass(Object.class);
622
623 assertEquals(1, modules.size());
624 assertFalse(getPluginAccessor().isPluginEnabled("bad"));
625 assertTrue(getPluginAccessor().isPluginEnabled("good"));
626 }
627
628 public void testGetPluginModulesWith2GetModulesThrowingExceptionOnlyNotifiesOnce() throws Exception
629 {
630 final Plugin badPlugin = new StaticPlugin();
631 badPlugin.setKey("bad");
632 final MockModuleDescriptor<Object> badDescriptor = new MockModuleDescriptor<Object>(badPlugin, "bad", new Object())
633 {
634 @Override
635 public Object getModule()
636 {
637 throw new RuntimeException();
638 }
639 };
640 badPlugin.addModuleDescriptor(badDescriptor);
641 final MockModuleDescriptor<Object> badDescriptor2 = new MockModuleDescriptor<Object>(badPlugin, "bad2", new Object())
642 {
643 @Override
644 public Object getModule()
645 {
646 throw new RuntimeException();
647 }
648 };
649 badPlugin.addModuleDescriptor(badDescriptor2);
650
651 final Plugin goodPlugin = new StaticPlugin();
652 goodPlugin.setKey("good");
653 final MockModuleDescriptor<Object> goodDescriptor = new MockModuleDescriptor<Object>(goodPlugin, "good", new Object());
654 goodPlugin.addModuleDescriptor(goodDescriptor);
655 DisabledPluginCounter counter = new DisabledPluginCounter();
656 pluginEventManager.register(counter);
657
658 manager.addPlugins(null, Arrays.asList(goodPlugin, badPlugin));
659 manager.enablePlugin("bad");
660 manager.enablePlugin("good");
661
662 assertTrue(getPluginAccessor().isPluginEnabled("bad"));
663 assertTrue(getPluginAccessor().isPluginEnabled("good"));
664 final Collection<Object> modules = getPluginAccessor().getEnabledModulesByClass(Object.class);
665
666 assertEquals(1, modules.size());
667 assertFalse(getPluginAccessor().isPluginEnabled("bad"));
668 assertTrue(getPluginAccessor().isPluginEnabled("good"));
669 assertEquals(1, counter.disableCount);
670 }
671
672 public static class DisabledPluginCounter
673 {
674 int disableCount = 0;
675 @PluginEventListener
676 public void consume(PluginDisabledEvent element)
677 {
678 disableCount++;
679 }
680 }
681
682 public void testGetPluginModulesWithModuleNotMatchingPredicate() throws Exception
683 {
684 final Mock mockModuleDescriptor = new Mock(ModuleDescriptor.class);
685 @SuppressWarnings("unchecked")
686 final ModuleDescriptor<MockThing> moduleDescriptor = (ModuleDescriptor<MockThing>) mockModuleDescriptor.proxy();
687 mockModuleDescriptor.matchAndReturn("getCompleteKey", "some-plugin-key:module");
688 mockModuleDescriptor.matchAndReturn("isEnabledByDefault", true);
689 mockModuleDescriptor.matchAndReturn("hashCode", mockModuleDescriptor.hashCode());
690
691 final Mock mockPlugin = mockTestPlugin(Collections.singleton(moduleDescriptor));
692 mockPlugin.matchAndReturn("getModuleDescriptor", "module", moduleDescriptor);
693 final Plugin plugin = (Plugin) mockPlugin.proxy();
694
695 final Mock mockModulePredicate = new Mock(ModuleDescriptorPredicate.class);
696 mockModulePredicate.expectAndReturn("matches", C.eq(moduleDescriptor), false);
697
698 manager.addPlugins(null, Collections.singletonList(plugin));
699 @SuppressWarnings("unchecked")
700 final ModuleDescriptorPredicate<MockThing> predicate = (ModuleDescriptorPredicate<MockThing>) mockModulePredicate.proxy();
701 final Collection<MockThing> modules = getPluginAccessor().getModules(predicate);
702
703 assertEquals(0, modules.size());
704
705 mockModulePredicate.verify();
706 }
707
708 public void testGetPluginModuleDescriptorWithModuleMatchingPredicate() throws Exception
709 {
710 final Mock mockModuleDescriptor = new Mock(ModuleDescriptor.class);
711 @SuppressWarnings("unchecked")
712 final ModuleDescriptor<MockThing> moduleDescriptor = (ModuleDescriptor) mockModuleDescriptor.proxy();
713 mockModuleDescriptor.matchAndReturn("getCompleteKey", "some-plugin-key:module");
714 mockModuleDescriptor.matchAndReturn("isEnabledByDefault", true);
715 mockModuleDescriptor.matchAndReturn("hashCode", mockModuleDescriptor.hashCode());
716
717 final Mock mockPlugin = mockTestPlugin(Collections.singleton(moduleDescriptor));
718 mockPlugin.matchAndReturn("getModuleDescriptor", "module", moduleDescriptor);
719 final Plugin plugin = (Plugin) mockPlugin.proxy();
720
721 final Mock mockModulePredicate = new Mock(ModuleDescriptorPredicate.class);
722 mockModulePredicate.expectAndReturn("matches", C.eq(moduleDescriptor), true);
723
724 manager.addPlugins(null, Collections.singletonList(plugin));
725 @SuppressWarnings("unchecked")
726 final ModuleDescriptorPredicate<MockThing> predicate = (ModuleDescriptorPredicate<MockThing>) mockModulePredicate.proxy();
727 final Collection<ModuleDescriptor<MockThing>> modules = getPluginAccessor().getModuleDescriptors(predicate);
728
729 assertEquals(1, modules.size());
730 assertTrue(modules.contains(moduleDescriptor));
731
732 mockModulePredicate.verify();
733 }
734
735 public void testGetPluginModuleDescriptorsWithModuleNotMatchingPredicate() throws Exception
736 {
737 final Mock mockModuleDescriptor = new Mock(ModuleDescriptor.class);
738 @SuppressWarnings("unchecked")
739 final ModuleDescriptor<MockThing> moduleDescriptor = (ModuleDescriptor<MockThing>) mockModuleDescriptor.proxy();
740 mockModuleDescriptor.matchAndReturn("getCompleteKey", "some-plugin-key:module");
741 mockModuleDescriptor.matchAndReturn("isEnabledByDefault", true);
742 mockModuleDescriptor.matchAndReturn("hashCode", mockModuleDescriptor.hashCode());
743
744 final Mock mockPlugin = mockTestPlugin(Collections.singleton(moduleDescriptor));
745 mockPlugin.matchAndReturn("getModuleDescriptor", "module", moduleDescriptor);
746 final Plugin plugin = (Plugin) mockPlugin.proxy();
747
748 final Mock mockModulePredicate = new Mock(ModuleDescriptorPredicate.class);
749 mockModulePredicate.expectAndReturn("matches", C.eq(moduleDescriptor), false);
750
751 manager.addPlugins(null, Collections.singletonList(plugin));
752 @SuppressWarnings("unchecked")
753 final ModuleDescriptorPredicate<MockThing> predicate = (ModuleDescriptorPredicate<MockThing>) mockModulePredicate.proxy();
754 final Collection<MockThing> modules = getPluginAccessor().getModules(predicate);
755
756 assertEquals(0, modules.size());
757
758 mockModulePredicate.verify();
759 }
760
761 private Mock mockTestPlugin(Collection moduleDescriptors)
762 {
763 final Mock mockPlugin = new Mock(Plugin.class);
764 mockPlugin.matchAndReturn("getKey", "some-plugin-key");
765 mockPlugin.matchAndReturn("hashCode", 12);
766 mockPlugin.expect("install");
767 mockPlugin.expect("enable");
768 mockPlugin.expectAndReturn("isSystemPlugin", false);
769 mockPlugin.matchAndReturn("isEnabledByDefault", true);
770 mockPlugin.matchAndReturn("isEnabled", true);
771 mockPlugin.matchAndReturn("getPluginState", PluginState.ENABLED);
772 mockPlugin.matchAndReturn("getModuleDescriptors", moduleDescriptors);
773 mockPlugin.matchAndReturn("compareTo", mockPlugin.proxy(), 0);
774 return mockPlugin;
775 }
776
777 public void testGetPluginAndModules() throws PluginParseException
778 {
779 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
780
781 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
782 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
783
784 manager.init();
785
786 final Plugin plugin = manager.getPlugin("test.atlassian.plugin");
787 assertNotNull(plugin);
788 assertEquals("Test Plugin", plugin.getName());
789
790 final ModuleDescriptor<?> bear = plugin.getModuleDescriptor("bear");
791 assertEquals(bear, getPluginAccessor().getPluginModule("test.atlassian.plugin:bear"));
792 }
793
794 public void testGetModuleByModuleClassOneFound() throws PluginParseException
795 {
796 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
797
798 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
799 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
800
801 manager.init();
802
803 final List<MockAnimalModuleDescriptor> animalDescriptors = getPluginAccessor().getEnabledModuleDescriptorsByClass(MockAnimalModuleDescriptor.class);
804 assertNotNull(animalDescriptors);
805 assertEquals(1, animalDescriptors.size());
806 final ModuleDescriptor<MockAnimal> moduleDescriptor = animalDescriptors.iterator().next();
807 assertEquals("Bear Animal", moduleDescriptor.getName());
808
809 final List<MockMineralModuleDescriptor> mineralDescriptors = getPluginAccessor().getEnabledModuleDescriptorsByClass(MockMineralModuleDescriptor.class);
810 assertNotNull(mineralDescriptors);
811 assertEquals(1, mineralDescriptors.size());
812 final ModuleDescriptor<MockMineral> mineralDescriptor = mineralDescriptors.iterator().next();
813 assertEquals("Bar", mineralDescriptor.getName());
814 }
815
816 public void testGetModuleByModuleClassAndDescriptor() throws PluginParseException
817 {
818 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
819
820 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
821 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
822
823 manager.init();
824
825 final Collection<MockBear> bearModules = getPluginAccessor().getEnabledModulesByClassAndDescriptor(
826 new Class[]{MockAnimalModuleDescriptor.class, MockMineralModuleDescriptor.class}, MockBear.class);
827 assertNotNull(bearModules);
828 assertEquals(1, bearModules.size());
829 assertTrue(bearModules.iterator().next() instanceof MockBear);
830
831 final Collection<MockBear> noModules = getPluginAccessor().getEnabledModulesByClassAndDescriptor(new Class[]{}, MockBear.class);
832 assertNotNull(noModules);
833 assertEquals(0, noModules.size());
834
835 final Collection<MockThing> mockThings = getPluginAccessor().getEnabledModulesByClassAndDescriptor(
836 new Class[]{MockAnimalModuleDescriptor.class, MockMineralModuleDescriptor.class}, MockThing.class);
837 assertNotNull(mockThings);
838 assertEquals(2, mockThings.size());
839 assertTrue(mockThings.iterator().next() instanceof MockThing);
840 assertTrue(mockThings.iterator().next() instanceof MockThing);
841
842 final Collection<MockThing> mockThingsFromMineral = getPluginAccessor().getEnabledModulesByClassAndDescriptor(
843 new Class[]{MockMineralModuleDescriptor.class}, MockThing.class);
844 assertNotNull(mockThingsFromMineral);
845 assertEquals(1, mockThingsFromMineral.size());
846 final Object o = mockThingsFromMineral.iterator().next();
847 assertTrue(o instanceof MockMineral);
848 }
849
850 public void testGetModuleByModuleClassNoneFound() throws PluginParseException
851 {
852 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
853
854 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
855 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
856
857 manager.init();
858
859 class MockSilver implements MockMineral
860 {
861 public int getWeight()
862 {
863 return 3;
864 }
865 }
866
867 final Collection<MockSilver> descriptors = getPluginAccessor().getEnabledModulesByClass(MockSilver.class);
868 assertNotNull(descriptors);
869 assertTrue(descriptors.isEmpty());
870 }
871
872 public void testGetModuleDescriptorsByType() throws PluginParseException
873 {
874 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
875
876 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
877 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
878
879 manager.init();
880
881 Collection<ModuleDescriptor<MockThing>> descriptors = getPluginAccessor().getEnabledModuleDescriptorsByType("animal");
882 assertNotNull(descriptors);
883 assertEquals(1, descriptors.size());
884 ModuleDescriptor<MockThing> moduleDescriptor = descriptors.iterator().next();
885 assertEquals("Bear Animal", moduleDescriptor.getName());
886
887 descriptors = getPluginAccessor().getEnabledModuleDescriptorsByType("mineral");
888 assertNotNull(descriptors);
889 assertEquals(1, descriptors.size());
890 moduleDescriptor = descriptors.iterator().next();
891 assertEquals("Bar", moduleDescriptor.getName());
892
893 try
894 {
895 getPluginAccessor().getEnabledModuleDescriptorsByType("foobar");
896 }
897 catch (final IllegalArgumentException e)
898 {
899 fail("Shouldn't have thrown exception.");
900 }
901 }
902
903 public void testRetrievingDynamicResources() throws PluginParseException, IOException
904 {
905 createFillAndCleanTempPluginDirectory();
906
907 final DefaultPluginManager manager = makeClassLoadingPluginManager();
908
909 final InputStream is = manager.getPluginResourceAsStream("test.atlassian.plugin.classloaded", "atlassian-plugin.xml");
910 assertNotNull(is);
911 IOUtils.closeQuietly(is);
912 }
913
914 public void testGetDynamicPluginClass() throws IOException, PluginParseException
915 {
916 createFillAndCleanTempPluginDirectory();
917
918 final DefaultPluginManager manager = makeClassLoadingPluginManager();
919 try
920 {
921 manager.getDynamicPluginClass("com.atlassian.plugin.mock.MockPooh");
922 }
923 catch (final ClassNotFoundException e)
924 {
925 fail(e.getMessage());
926 }
927 }
928
929
930
931 public void testGetEnabledPluginsDoesNotReturnEnablingPlugins() throws Exception
932 {
933 final Mock mockPluginLoader = new Mock(PluginLoader.class);
934
935 final Plugin firstPlugin = new StaticPlugin();
936 firstPlugin.setKey("first");
937 firstPlugin.setEnabledByDefault(false);
938 firstPlugin.setPluginInformation(new PluginInformation());
939 manager.enablePluginState(firstPlugin, pluginStateStore);
940
941 final Plugin secondPlugin = new StaticPlugin()
942 {
943 public PluginState enableInternal()
944 {
945 try
946 {
947
948 assertEquals(2, manager.getPlugins().size());
949 assertEquals("First plugin should not be enabled", 0, manager.getEnabledPlugins().size());
950 }
951 catch (Exception e)
952 {
953 throw new RuntimeException(e);
954 }
955 return PluginState.ENABLED;
956 }
957
958 public void disableInternal()
959 {
960
961 }
962 };
963 secondPlugin.setKey("second");
964 secondPlugin.setEnabledByDefault(false);
965 secondPlugin.setPluginInformation(new PluginInformation());
966 manager.enablePluginState(secondPlugin, pluginStateStore);
967
968 mockPluginLoader.expectAndReturn("loadAllPlugins", C.ANY_ARGS, Arrays.asList(firstPlugin, secondPlugin));
969
970 final PluginLoader proxy = (PluginLoader) mockPluginLoader.proxy();
971 pluginLoaders.add(proxy);
972
973 manager.init();
974 }
975
976 public void testFindingNewPlugins() throws PluginParseException, IOException
977 {
978 createFillAndCleanTempPluginDirectory();
979
980
981 final File paddington = new File(pluginsTestDir, PADDINGTON_JAR);
982 paddington.delete();
983
984 final DefaultPluginManager manager = makeClassLoadingPluginManager();
985
986 assertEquals(1, manager.getPlugins().size());
987 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
988
989
990 FileUtils.copyDirectory(pluginsDirectory, pluginsTestDir);
991
992 manager.scanForNewPlugins();
993 assertEquals(2, manager.getPlugins().size());
994 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
995 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded"));
996
997 manager.scanForNewPlugins();
998 assertEquals(2, manager.getPlugins().size());
999 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
1000 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded"));
1001 }
1002
1003 public void testFindingNewPluginsNotLoadingRestartRequiredDescriptors() throws PluginParseException, IOException
1004 {
1005 createFillAndCleanTempPluginDirectory();
1006
1007 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1008 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1009
1010 assertEquals(2, manager.getPlugins().size());
1011 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
1012
1013 pluginLoaders.add(new DynamicSinglePluginLoader("test.atlassian.plugin", "test-requiresRestart-plugin.xml"));
1014
1015 manager.scanForNewPlugins();
1016 assertEquals(3, manager.getPlugins().size());
1017 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
1018 assertNotNull(manager.getPlugin("test.atlassian.plugin"));
1019
1020 final Plugin plugin = manager.getPlugin("test.atlassian.plugin");
1021 assertTrue(plugin instanceof UnloadablePlugin);
1022 assertTrue(((UnloadablePlugin)plugin).getErrorText().contains("foo"));
1023
1024 assertEquals(PluginRestartState.INSTALL, manager.getPluginRestartState("test.atlassian.plugin"));
1025 }
1026
1027
1028
1029
1030 public void testFindingUpgradePluginsNotLoadingRestartRequiredDescriptors() throws PluginParseException, IOException
1031 {
1032 createFillAndCleanTempPluginDirectory();
1033
1034 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1035 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1036
1037 assertEquals(2, manager.getPlugins().size());
1038 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
1039 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1040
1041 pluginLoaders.add(new DynamicSinglePluginLoader("test.atlassian.plugin.classloaded2", "test-requiresRestartWithUpgrade-plugin.xml"));
1042
1043 manager.scanForNewPlugins();
1044 assertEquals(2, manager.getPlugins().size());
1045 assertNotNull(manager.getPlugin("test.atlassian.plugin.classloaded2"));
1046 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.atlassian.plugin.classloaded2"));
1047 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1048 }
1049
1050 public void testInstallPluginThatRequiresRestart() throws PluginParseException, IOException, InterruptedException
1051 {
1052 createFillAndCleanTempPluginDirectory();
1053 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1054 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1055 assertEquals(2, manager.getPlugins().size());
1056
1057 new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1058 "<atlassian-plugin name='Test 2' i18n-name-key='test.name' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1059 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1060 manager.scanForNewPlugins();
1061
1062 assertEquals(3, manager.getPlugins().size());
1063 Plugin plugin = manager.getPlugin("test.restartrequired");
1064 assertNotNull(plugin);
1065 assertEquals("Test 2", plugin.getName());
1066 assertEquals("test.name", plugin.getI18nNameKey());
1067 assertEquals(1, plugin.getPluginsVersion());
1068 assertEquals("1.0", plugin.getPluginInformation().getVersion());
1069 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1070 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1071 assertEquals(PluginRestartState.INSTALL, manager.getPluginRestartState("test.restartrequired"));
1072
1073 manager.shutdown();
1074 manager.init();
1075
1076 assertEquals(3, manager.getPlugins().size());
1077 assertNotNull(plugin);
1078 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1079 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1080 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1081 }
1082
1083 public void testInstallPluginThatRequiresRestartThenRevert() throws PluginParseException, IOException, InterruptedException
1084 {
1085 createFillAndCleanTempPluginDirectory();
1086 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1087 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1088 manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
1089 assertEquals(2, manager.getPlugins().size());
1090
1091 File pluginJar = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1092 "<atlassian-plugin name='Test 2' i18n-name-key='test.name' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1093 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build();
1094 manager.installPlugin(new JarPluginArtifact(pluginJar));
1095
1096 assertEquals(3, manager.getPlugins().size());
1097 Plugin plugin = manager.getPlugin("test.restartrequired");
1098 assertNotNull(plugin);
1099 assertEquals("Test 2", plugin.getName());
1100 assertEquals("test.name", plugin.getI18nNameKey());
1101 assertEquals(1, plugin.getPluginsVersion());
1102 assertEquals("1.0", plugin.getPluginInformation().getVersion());
1103 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1104 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1105 assertEquals(PluginRestartState.INSTALL, manager.getPluginRestartState("test.restartrequired"));
1106
1107 manager.revertRestartRequiredChange("test.restartrequired");
1108 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1109
1110 manager.shutdown();
1111 manager.init();
1112
1113 assertEquals(2, manager.getPlugins().size());
1114 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1115 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1116 }
1117
1118 public void testUpgradePluginThatRequiresRestart() throws PluginParseException, IOException, InterruptedException
1119 {
1120 createFillAndCleanTempPluginDirectory();
1121 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1122
1123 final File origFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1124 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1125 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1126
1127 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1128
1129 assertEquals(3, manager.getPlugins().size());
1130 assertNotNull(manager.getPlugin("test.restartrequired"));
1131 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1132 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1133 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1134
1135
1136 Thread.sleep(1000);
1137 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1138 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1139 " </plugin-info>", " <requiresRestart key='foo' />", " <requiresRestart key='bar' />", "</atlassian-plugin>").build();
1140
1141 origFile.delete();
1142 FileUtils.moveFile(updateFile, origFile);
1143
1144 manager.scanForNewPlugins();
1145 assertEquals(3, manager.getPlugins().size());
1146 assertNotNull(manager.getPlugin("test.restartrequired"));
1147 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1148 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1149 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1150
1151 manager.shutdown();
1152 manager.init();
1153
1154 assertEquals(3, manager.getPlugins().size());
1155 assertNotNull(manager.getPlugin("test.restartrequired"));
1156 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1157 assertEquals(2, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1158 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1159 }
1160
1161 public void testUpgradePluginThatRequiresRestartThenReverted() throws PluginParseException, IOException, InterruptedException
1162 {
1163 createFillAndCleanTempPluginDirectory();
1164 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1165
1166 final File origFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1167 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1168 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1169
1170 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1171 manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
1172
1173 assertEquals(3, manager.getPlugins().size());
1174 assertNotNull(manager.getPlugin("test.restartrequired"));
1175 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1176 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1177 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1178
1179
1180 Thread.sleep(1000);
1181 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1182 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1183 " </plugin-info>", " <requiresRestart key='foo' />", " <requiresRestart key='bar' />", "</atlassian-plugin>").build();
1184
1185 manager.installPlugin(new JarPluginArtifact(updateFile));
1186
1187 assertEquals(3, manager.getPlugins().size());
1188 assertNotNull(manager.getPlugin("test.restartrequired"));
1189 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1190 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1191 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1192
1193 manager.revertRestartRequiredChange("test.restartrequired");
1194 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1195
1196 manager.shutdown();
1197 manager.init();
1198
1199 assertEquals(3, manager.getPlugins().size());
1200 assertNotNull(manager.getPlugin("test.restartrequired"));
1201 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1202 assertEquals("1.0", manager.getPlugin("test.restartrequired").getPluginInformation().getVersion());
1203 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1204 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1205 }
1206
1207 public void testUpgradePluginThatRequiresRestartThenRevertedRevertsToOriginalPlugin() throws PluginParseException, IOException, InterruptedException
1208 {
1209 createFillAndCleanTempPluginDirectory();
1210 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1211
1212
1213 new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1214 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1215 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1216
1217 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1218 manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
1219
1220 assertEquals(3, manager.getPlugins().size());
1221 assertNotNull(manager.getPlugin("test.restartrequired"));
1222 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1223 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1224 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1225
1226
1227 Thread.sleep(1000);
1228 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1229 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1230 " </plugin-info>", " <requiresRestart key='foo' />", " <requiresRestart key='bar' />", "</atlassian-plugin>").build();
1231
1232
1233 manager.installPlugin(new JarPluginArtifact(updateFile));
1234
1235 assertEquals(3, manager.getPlugins().size());
1236 assertNotNull(manager.getPlugin("test.restartrequired"));
1237 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1238 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1239 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1240
1241 Thread.sleep(1000);
1242 final File updateFile2 = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1243 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>3.0</version>",
1244 " </plugin-info>", " <requiresRestart key='foo' />", " <requiresRestart key='bar' />", "</atlassian-plugin>").build();
1245
1246
1247 manager.installPlugin(new JarPluginArtifact(updateFile2));
1248
1249 assertEquals(3, manager.getPlugins().size());
1250 assertNotNull(manager.getPlugin("test.restartrequired"));
1251 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1252 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1253 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1254
1255
1256 manager.revertRestartRequiredChange("test.restartrequired");
1257 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1258 assertEquals("1.0", manager.getPlugin("test.restartrequired").getPluginInformation().getVersion());
1259
1260 manager.shutdown();
1261 manager.init();
1262
1263 assertEquals(3, manager.getPlugins().size());
1264 assertNotNull(manager.getPlugin("test.restartrequired"));
1265 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1266 assertEquals("1.0", manager.getPlugin("test.restartrequired").getPluginInformation().getVersion());
1267 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1268 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1269 }
1270
1271 public void testUpgradePluginThatRequiresRestartMultipleTimeStaysUpgraded() throws PluginParseException, IOException, InterruptedException
1272 {
1273 createFillAndCleanTempPluginDirectory();
1274 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1275
1276 final File origFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1277 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1278 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1279
1280 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1281 manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
1282
1283 assertEquals(3, manager.getPlugins().size());
1284 assertNotNull(manager.getPlugin("test.restartrequired"));
1285 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1286 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1287 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1288
1289
1290 Thread.sleep(1000);
1291 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1292 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1293 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build();
1294
1295 manager.installPlugin(new JarPluginArtifact(updateFile));
1296
1297 assertEquals(3, manager.getPlugins().size());
1298 assertNotNull(manager.getPlugin("test.restartrequired"));
1299 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1300 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1301 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1302
1303 Thread.sleep(1000);
1304 final File updateFile2 = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1305 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>3.0</version>",
1306 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build();
1307
1308 manager.installPlugin(new JarPluginArtifact(updateFile2));
1309
1310 assertEquals(3, manager.getPlugins().size());
1311 assertNotNull(manager.getPlugin("test.restartrequired"));
1312 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1313 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1314 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1315
1316 manager.shutdown();
1317 manager.init();
1318
1319 assertEquals(3, manager.getPlugins().size());
1320 assertNotNull(manager.getPlugin("test.restartrequired"));
1321 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1322 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1323 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1324 }
1325
1326 public void testUpgradePluginThatPreviouslyRequiredRestart() throws PluginParseException, IOException, InterruptedException
1327 {
1328 createFillAndCleanTempPluginDirectory();
1329 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1330
1331 final File origFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1332 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1333 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1334
1335 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1336
1337 assertEquals(3, manager.getPlugins().size());
1338 assertNotNull(manager.getPlugin("test.restartrequired"));
1339 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1340 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1341 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1342
1343
1344 Thread.sleep(1000);
1345 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1346 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1347 " </plugin-info>", "</atlassian-plugin>").build(pluginsTestDir);
1348
1349 origFile.delete();
1350 FileUtils.moveFile(updateFile, origFile);
1351
1352 manager.scanForNewPlugins();
1353 assertEquals(3, manager.getPlugins().size());
1354 assertNotNull(manager.getPlugin("test.restartrequired"));
1355 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1356 assertEquals(PluginRestartState.UPGRADE, manager.getPluginRestartState("test.restartrequired"));
1357 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1358
1359 manager.shutdown();
1360 manager.init();
1361
1362 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1363 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1364 }
1365
1366 public void testInstallPluginThatPreviouslyRequiredRestart() throws PluginParseException, IOException, InterruptedException
1367 {
1368 createFillAndCleanTempPluginDirectory();
1369 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1370
1371 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1372
1373 assertEquals(2, manager.getPlugins().size());
1374 assertNull(manager.getPlugin("test.restartrequired"));
1375
1376 final File origFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1377 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1378 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1379
1380 manager.scanForNewPlugins();
1381 assertEquals(3, manager.getPlugins().size());
1382 assertNotNull(manager.getPlugin("test.restartrequired"));
1383 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1384 assertEquals(PluginRestartState.INSTALL, manager.getPluginRestartState("test.restartrequired"));
1385
1386
1387 Thread.sleep(1000);
1388 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1389 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1390 " </plugin-info>", "</atlassian-plugin>").build(pluginsTestDir);
1391
1392 origFile.delete();
1393 FileUtils.moveFile(updateFile, origFile);
1394
1395 manager.scanForNewPlugins();
1396 assertEquals(3, manager.getPlugins().size());
1397 assertNotNull(manager.getPlugin("test.restartrequired"));
1398 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1399 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1400 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1401
1402 manager.shutdown();
1403 manager.init();
1404
1405 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1406 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1407 }
1408
1409 public void testInstallPluginMoreThanOnceStaysAsInstall() throws PluginParseException, IOException, InterruptedException
1410 {
1411 createFillAndCleanTempPluginDirectory();
1412 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1413
1414 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1415
1416 assertEquals(2, manager.getPlugins().size());
1417 assertNull(manager.getPlugin("test.restartrequired"));
1418 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1419
1420 final File origFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1421 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1422 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1423
1424 manager.scanForNewPlugins();
1425 assertEquals(3, manager.getPlugins().size());
1426 assertNotNull(manager.getPlugin("test.restartrequired"));
1427 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1428 assertEquals(PluginRestartState.INSTALL, manager.getPluginRestartState("test.restartrequired"));
1429
1430
1431 Thread.sleep(1000);
1432 final File updateFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1433 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>2.0</version>",
1434 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1435
1436 origFile.delete();
1437 FileUtils.moveFile(updateFile, origFile);
1438
1439 manager.scanForNewPlugins();
1440 assertEquals(3, manager.getPlugins().size());
1441 assertNotNull(manager.getPlugin("test.restartrequired"));
1442 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1443 assertEquals(PluginRestartState.INSTALL, manager.getPluginRestartState("test.restartrequired"));
1444
1445 manager.shutdown();
1446 manager.init();
1447
1448 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1449 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1450 }
1451
1452 public void testRemovePluginThatRequiresRestart() throws PluginParseException, IOException
1453 {
1454 createFillAndCleanTempPluginDirectory();
1455 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1456
1457 final File pluginFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1458 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1459 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1460
1461 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1462
1463 assertEquals(3, manager.getPlugins().size());
1464 assertNotNull(manager.getPlugin("test.restartrequired"));
1465 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1466 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1467 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1468
1469 manager.uninstall(manager.getPlugin("test.restartrequired"));
1470
1471 assertEquals(3, manager.getPlugins().size());
1472 assertNotNull(manager.getPlugin("test.restartrequired"));
1473 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1474 assertEquals(PluginRestartState.REMOVE, manager.getPluginRestartState("test.restartrequired"));
1475 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1476
1477 manager.shutdown();
1478 manager.init();
1479
1480 assertFalse(pluginFile.exists());
1481 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1482 assertEquals(2, manager.getPlugins().size());
1483 }
1484
1485 public void testRemovePluginThatRequiresRestartThenReverted() throws PluginParseException, IOException
1486 {
1487 createFillAndCleanTempPluginDirectory();
1488 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1489
1490 final File pluginFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1491 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1492 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1493
1494 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1495
1496 assertEquals(3, manager.getPlugins().size());
1497 assertNotNull(manager.getPlugin("test.restartrequired"));
1498 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1499 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1500 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1501
1502 manager.uninstall(manager.getPlugin("test.restartrequired"));
1503
1504 assertEquals(3, manager.getPlugins().size());
1505 assertNotNull(manager.getPlugin("test.restartrequired"));
1506 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1507 assertEquals(PluginRestartState.REMOVE, manager.getPluginRestartState("test.restartrequired"));
1508 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1509
1510 manager.revertRestartRequiredChange("test.restartrequired");
1511 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1512
1513 manager.shutdown();
1514 manager.init();
1515
1516 assertEquals(3, manager.getPlugins().size());
1517 assertNotNull(manager.getPlugin("test.restartrequired"));
1518 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1519 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1520 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1521 }
1522
1523 public void testRemovePluginThatRequiresRestartViaSubclass() throws PluginParseException, IOException
1524 {
1525 createFillAndCleanTempPluginDirectory();
1526 moduleDescriptorFactory.addModuleDescriptor("requiresRestartSubclass", RequiresRestartSubclassModuleDescriptor.class);
1527
1528 final File pluginFile = new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1529 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1530 " </plugin-info>", " <requiresRestartSubclass key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1531
1532 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1533
1534 assertEquals(3, manager.getPlugins().size());
1535 assertNotNull(manager.getPlugin("test.restartrequired"));
1536 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1537 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartSubclassModuleDescriptor.class).size());
1538 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1539
1540 manager.uninstall(manager.getPlugin("test.restartrequired"));
1541
1542 assertEquals(3, manager.getPlugins().size());
1543 assertNotNull(manager.getPlugin("test.restartrequired"));
1544 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1545 assertEquals(PluginRestartState.REMOVE, manager.getPluginRestartState("test.restartrequired"));
1546 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartSubclassModuleDescriptor.class).size());
1547
1548 manager.shutdown();
1549 manager.init();
1550
1551 assertFalse(pluginFile.exists());
1552 assertEquals(0, manager.getEnabledModuleDescriptorsByClass(RequiresRestartSubclassModuleDescriptor.class).size());
1553 assertEquals(2, manager.getPlugins().size());
1554 }
1555
1556 public void testDisableEnableOfPluginThatRequiresRestart() throws PluginParseException, IOException
1557 {
1558 createFillAndCleanTempPluginDirectory();
1559 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1560
1561 new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
1562 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='1'>", " <plugin-info>", " <version>1.0</version>",
1563 " </plugin-info>", " <requiresRestart key='foo' />", "</atlassian-plugin>").build(pluginsTestDir);
1564
1565 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1566
1567 assertEquals(3, manager.getPlugins().size());
1568 assertNotNull(manager.getPlugin("test.restartrequired"));
1569 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1570 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1571 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1572
1573 manager.disablePlugin("test.restartrequired");
1574 assertFalse(manager.isPluginEnabled("test.restartrequired"));
1575 manager.enablePlugins("test.restartrequired");
1576
1577 assertEquals(3, manager.getPlugins().size());
1578 assertNotNull(manager.getPlugin("test.restartrequired"));
1579 assertTrue(manager.isPluginEnabled("test.restartrequired"));
1580 assertEquals(PluginRestartState.NONE, manager.getPluginRestartState("test.restartrequired"));
1581 assertEquals(1, manager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1582 }
1583
1584 public void testCannotRemovePluginFromStaticLoader() throws PluginParseException, IOException
1585 {
1586 createFillAndCleanTempPluginDirectory();
1587 moduleDescriptorFactory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
1588
1589 directoryPluginLoader = new DirectoryPluginLoader(pluginsTestDir, Arrays.asList(new LegacyDynamicPluginFactory(
1590 PluginAccessor.Descriptor.FILENAME), new XmlDynamicPluginFactory("key")), pluginEventManager);
1591 pluginLoaders.add(directoryPluginLoader);
1592 pluginLoaders.add(new SinglePluginLoader("test-requiresRestart-plugin.xml"));
1593
1594 manager.init();
1595
1596 assertEquals(3, getPluginAccessor().getPlugins().size());
1597 assertNotNull(getPluginAccessor().getPlugin("test.atlassian.plugin"));
1598 assertTrue(getPluginAccessor().isPluginEnabled("test.atlassian.plugin"));
1599 assertEquals(1, getPluginAccessor().getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1600 assertEquals(PluginRestartState.NONE, getPluginAccessor().getPluginRestartState("test.atlassian.plugin"));
1601
1602 try
1603 {
1604 manager.uninstall(getPluginAccessor().getPlugin("test.atlassian.plugin"));
1605 fail();
1606 }
1607 catch (final PluginException ex)
1608 {
1609
1610 }
1611
1612 assertEquals(3, getPluginAccessor().getPlugins().size());
1613 assertNotNull(getPluginAccessor().getPlugin("test.atlassian.plugin"));
1614 assertTrue(getPluginAccessor().isPluginEnabled("test.atlassian.plugin"));
1615 assertEquals(PluginRestartState.NONE, getPluginAccessor().getPluginRestartState("test.atlassian.plugin"));
1616 assertEquals(1, getPluginAccessor().getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
1617 }
1618
1619 private DefaultPluginManager makeClassLoadingPluginManager() throws PluginParseException
1620 {
1621 directoryPluginLoader = new DirectoryPluginLoader(pluginsTestDir, Arrays.asList(new LegacyDynamicPluginFactory(
1622 PluginAccessor.Descriptor.FILENAME), new XmlDynamicPluginFactory("key")), pluginEventManager);
1623 pluginLoaders.add(directoryPluginLoader);
1624
1625 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
1626 manager.init();
1627 return manager;
1628 }
1629
1630 public void testRemovingPlugins() throws PluginException, IOException
1631 {
1632 createFillAndCleanTempPluginDirectory();
1633
1634 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1635 assertEquals(2, manager.getPlugins().size());
1636 final MockAnimalModuleDescriptor moduleDescriptor = (MockAnimalModuleDescriptor) manager.getPluginModule("test.atlassian.plugin.classloaded:paddington");
1637 assertFalse(moduleDescriptor.disabled);
1638 final PassListener disabledListener = new PassListener(PluginDisabledEvent.class);
1639 pluginEventManager.register(disabledListener);
1640 final Plugin plugin = manager.getPlugin("test.atlassian.plugin.classloaded");
1641 manager.uninstall(plugin);
1642 assertTrue("Module must have had disable() called before being removed", moduleDescriptor.disabled);
1643
1644
1645 assertTrue(pluginStateStore.load().getPluginStateMap(plugin).isEmpty());
1646
1647 assertEquals(1, manager.getPlugins().size());
1648
1649 assertNull(manager.getPlugin("test.atlassian.plugin.classloaded"));
1650 assertEquals(1, pluginsTestDir.listFiles().length);
1651 disabledListener.assertCalled();
1652 }
1653
1654 public void testPluginModuleAvailableAfterInstallation()
1655 {
1656 PluginLoader pluginLoader = mock(PluginLoader.class);
1657 when(pluginLoader.supportsRemoval()).thenReturn(true);
1658 Plugin plugin = mock(Plugin.class);
1659 when(plugin.getKey()).thenReturn("dynPlugin");
1660 when(plugin.isEnabledByDefault()).thenReturn(true);
1661 when(plugin.isDeleteable()).thenReturn(true);
1662 when(plugin.isUninstallable()).thenReturn(true);
1663 when(plugin.getPluginState()).thenReturn(PluginState.ENABLED);
1664 when(plugin.compareTo(any(Plugin.class))).thenReturn(-1);
1665 when (pluginLoader.loadAllPlugins(any(ModuleDescriptorFactory.class))).thenReturn(asList(plugin));
1666 pluginLoaders.add(pluginLoader);
1667 manager.init();
1668
1669 PluginModuleEnabledListener listener = new PluginModuleEnabledListener();
1670 pluginEventManager.register(listener);
1671 Collection<ModuleDescriptor<?>> mods = new ArrayList<ModuleDescriptor<?>>();
1672 MockModuleDescriptor<String> moduleDescriptor = new MockModuleDescriptor<String>(plugin, "foo", "foo");
1673 mods.add(moduleDescriptor);
1674 when(plugin.getModuleDescriptors()).thenReturn(mods);
1675 when(plugin.getModuleDescriptor("foo")).thenReturn((ModuleDescriptor)moduleDescriptor);
1676 pluginEventManager.broadcast(new PluginModuleAvailableEvent(moduleDescriptor));
1677
1678 assertTrue(getPluginAccessor().isPluginModuleEnabled("dynPlugin:foo"));
1679 assertTrue(listener.called);
1680 }
1681
1682 public void testPluginModuleAvailableAfterInstallationButConfiguredToBeDisabled()
1683 {
1684 PluginLoader pluginLoader = mock(PluginLoader.class);
1685 when(pluginLoader.supportsRemoval()).thenReturn(true);
1686 Plugin plugin = mock(Plugin.class);
1687 when(plugin.getKey()).thenReturn("dynPlugin");
1688 when(plugin.isEnabledByDefault()).thenReturn(true);
1689 when(plugin.isDeleteable()).thenReturn(true);
1690 when(plugin.isUninstallable()).thenReturn(true);
1691 when(plugin.getPluginState()).thenReturn(PluginState.ENABLED);
1692 when(plugin.compareTo(any(Plugin.class))).thenReturn(-1);
1693 when (pluginLoader.loadAllPlugins(any(ModuleDescriptorFactory.class))).thenReturn(asList(plugin));
1694 pluginLoaders.add(pluginLoader);
1695 manager.init();
1696
1697 MockModuleDescriptor<String> moduleDescriptor = new MockModuleDescriptor<String>(plugin, "foo", "foo");
1698
1699 manager.disablePluginModuleState(moduleDescriptor, manager.getStore());
1700
1701 PluginModuleEnabledListener listener = new PluginModuleEnabledListener();
1702 pluginEventManager.register(listener);
1703 Collection<ModuleDescriptor<?>> mods = new ArrayList<ModuleDescriptor<?>>();
1704 mods.add(moduleDescriptor);
1705
1706 when(plugin.getModuleDescriptors()).thenReturn(mods);
1707 when(plugin.getModuleDescriptor("foo")).thenReturn((ModuleDescriptor)moduleDescriptor);
1708 pluginEventManager.broadcast(new PluginModuleAvailableEvent(moduleDescriptor));
1709
1710 assertFalse(getPluginAccessor().isPluginModuleEnabled("dynPlugin:foo"));
1711 assertFalse(listener.called);
1712 }
1713
1714 public void testPluginModuleUnavailableAfterInstallation()
1715 {
1716 PluginLoader pluginLoader = mock(PluginLoader.class);
1717 when(pluginLoader.supportsRemoval()).thenReturn(true);
1718 Plugin plugin = mock(Plugin.class);
1719 when(plugin.getKey()).thenReturn("dynPlugin");
1720 when(plugin.isEnabledByDefault()).thenReturn(true);
1721 when(plugin.isDeleteable()).thenReturn(true);
1722 when(plugin.isUninstallable()).thenReturn(true);
1723 when(plugin.getPluginState()).thenReturn(PluginState.ENABLED);
1724 when(plugin.compareTo(any(Plugin.class))).thenReturn(-1);
1725 when (pluginLoader.loadAllPlugins(any(ModuleDescriptorFactory.class))).thenReturn(asList(plugin));
1726 pluginLoaders.add(pluginLoader);
1727 manager.init();
1728
1729 PluginModuleDisabledListener listener = new PluginModuleDisabledListener();
1730 pluginEventManager.register(listener);
1731 Collection<ModuleDescriptor<?>> mods = new ArrayList<ModuleDescriptor<?>>();
1732 MockModuleDescriptor<String> moduleDescriptor = new MockModuleDescriptor<String>(plugin, "foo", "foo");
1733 mods.add(moduleDescriptor);
1734 when(plugin.getModuleDescriptors()).thenReturn(mods);
1735 when(plugin.getModuleDescriptor("foo")).thenReturn((ModuleDescriptor)moduleDescriptor);
1736 pluginEventManager.broadcast(new PluginModuleAvailableEvent(moduleDescriptor));
1737 assertTrue(getPluginAccessor().isPluginModuleEnabled("dynPlugin:foo"));
1738 assertFalse(listener.called);
1739 pluginEventManager.broadcast(new PluginModuleUnavailableEvent(moduleDescriptor));
1740 assertTrue(listener.called);
1741 }
1742
1743 public void testPluginContainerUnavailable()
1744 {
1745 PluginLoader pluginLoader = mock(PluginLoader.class);
1746 when(pluginLoader.supportsRemoval()).thenReturn(true);
1747 Plugin plugin = mock(Plugin.class);
1748 when(plugin.getKey()).thenReturn("dynPlugin");
1749 when(plugin.isEnabledByDefault()).thenReturn(true);
1750 when(plugin.isDeleteable()).thenReturn(true);
1751 when(plugin.isUninstallable()).thenReturn(true);
1752 when(plugin.getPluginState()).thenReturn(PluginState.ENABLED);
1753 when(plugin.compareTo(any(Plugin.class))).thenReturn(-1);
1754 Collection<ModuleDescriptor<?>> mods = new ArrayList<ModuleDescriptor<?>>();
1755 MockModuleDescriptor<String> moduleDescriptor = new MockModuleDescriptor<String>(plugin, "foo", "foo");
1756 mods.add(moduleDescriptor);
1757 when(plugin.getModuleDescriptors()).thenReturn(mods);
1758 when(plugin.getModuleDescriptor("foo")).thenReturn((ModuleDescriptor)moduleDescriptor);
1759 when (pluginLoader.loadAllPlugins(any(ModuleDescriptorFactory.class))).thenReturn(asList(plugin));
1760 pluginLoaders.add(pluginLoader);
1761 manager.init();
1762
1763 PluginDisabledListener listener = new PluginDisabledListener();
1764 PluginModuleDisabledListener moduleDisabledListener = new PluginModuleDisabledListener();
1765 pluginEventManager.register(listener);
1766 pluginEventManager.register(moduleDisabledListener);
1767 when(plugin.getPluginState()).thenReturn(PluginState.DISABLED);
1768 pluginEventManager.broadcast(new PluginContainerUnavailableEvent("dynPlugin"));
1769
1770 assertFalse(getPluginAccessor().isPluginEnabled("dynPlugin"));
1771 assertFalse(listener.called);
1772 assertFalse(moduleDisabledListener.called);
1773 }
1774
1775 public void testUninstallPluginWithDependencies() throws PluginException, IOException
1776 {
1777 PluginLoader pluginLoader = mock(PluginLoader.class);
1778 when(pluginLoader.supportsRemoval()).thenReturn(true);
1779 Plugin child = mock(Plugin.class);
1780 when(child.getKey()).thenReturn("child");
1781 when(child.isEnabledByDefault()).thenReturn(true);
1782 when(child.getPluginState()).thenReturn(PluginState.ENABLED);
1783 when(child.getRequiredPlugins()).thenReturn(singleton("parent"));
1784 when(child.compareTo(any(Plugin.class))).thenReturn(-1);
1785 Plugin parent = mock(Plugin.class);
1786 when(parent.getKey()).thenReturn("parent");
1787 when(parent.isEnabledByDefault()).thenReturn(true);
1788 when(parent.isDeleteable()).thenReturn(true);
1789 when(parent.isUninstallable()).thenReturn(true);
1790 when(parent.getPluginState()).thenReturn(PluginState.ENABLED);
1791 when(parent.compareTo(any(Plugin.class))).thenReturn(-1);
1792 when (pluginLoader.loadAllPlugins(any(ModuleDescriptorFactory.class))).thenReturn(asList(child, parent));
1793 pluginLoaders.add(pluginLoader);
1794 manager.init();
1795
1796 manager.uninstall(parent);
1797 verify(parent).enable();
1798 verify(parent).disable();
1799 verify(pluginLoader).removePlugin(parent);
1800
1801 verify(child).enable();
1802 verify(child).disable();
1803 }
1804
1805 public void testNonRemovablePlugins() throws PluginParseException
1806 {
1807 pluginLoaders.add(new SinglePluginLoader("test-atlassian-plugin.xml"));
1808
1809 moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
1810 moduleDescriptorFactory.addModuleDescriptor("mineral", MockMineralModuleDescriptor.class);
1811
1812 manager.init();
1813
1814 final Plugin plugin = getPluginAccessor().getPlugin("test.atlassian.plugin");
1815 assertFalse(plugin.isUninstallable());
1816 assertNotNull(plugin.getResourceAsStream("test-atlassian-plugin.xml"));
1817
1818 try
1819 {
1820 manager.uninstall(plugin);
1821 fail("Where was the exception?");
1822 }
1823 catch (final PluginException p)
1824 {
1825 }
1826 }
1827
1828 public void testNonDeletablePlugins() throws PluginException, IOException
1829 {
1830 createFillAndCleanTempPluginDirectory();
1831
1832 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1833 assertEquals(2, manager.getPlugins().size());
1834
1835
1836 final Plugin pluginToRemove = new AbstractDelegatingPlugin(manager.getPlugin("test.atlassian.plugin.classloaded"))
1837 {
1838 public boolean isDeleteable()
1839 {
1840 return false;
1841 }
1842 };
1843
1844
1845 final MockAnimalModuleDescriptor moduleDescriptor = (MockAnimalModuleDescriptor) manager.getPluginModule("test.atlassian.plugin.classloaded:paddington");
1846 assertFalse(moduleDescriptor.disabled);
1847
1848 manager.uninstall(pluginToRemove);
1849
1850 assertTrue("Module must have had disable() called before being removed", moduleDescriptor.disabled);
1851 assertEquals(1, manager.getPlugins().size());
1852 assertNull(manager.getPlugin("test.atlassian.plugin.classloaded"));
1853 assertEquals(2, pluginsTestDir.listFiles().length);
1854 }
1855
1856
1857
1858 public void testComparePluginNewer()
1859 {
1860
1861 final Plugin p1 = createPluginWithVersion("1.1");
1862 final Plugin p2 = createPluginWithVersion("1.0");
1863 assertTrue(p1.compareTo(p2) == 1);
1864
1865 p1.getPluginInformation().setVersion("1.10");
1866 p2.getPluginInformation().setVersion("1.2");
1867 assertTrue(p1.compareTo(p2) == 1);
1868
1869 p1.getPluginInformation().setVersion("1.2");
1870 p2.getPluginInformation().setVersion("1.01");
1871 assertTrue(p1.compareTo(p2) == 1);
1872
1873 p1.getPluginInformation().setVersion("1.0.1");
1874 p2.getPluginInformation().setVersion("1.0");
1875 assertTrue(p1.compareTo(p2) == 1);
1876
1877 p1.getPluginInformation().setVersion("1.2");
1878 p2.getPluginInformation().setVersion("1.1.1");
1879 assertTrue(p1.compareTo(p2) == 1);
1880 }
1881
1882 public void testComparePluginOlder()
1883 {
1884 final Plugin p1 = createPluginWithVersion("1.0");
1885 final Plugin p2 = createPluginWithVersion("1.1");
1886 assertTrue(p1.compareTo(p2) == -1);
1887
1888 p1.getPluginInformation().setVersion("1.2");
1889 p2.getPluginInformation().setVersion("1.10");
1890 assertTrue(p1.compareTo(p2) == -1);
1891
1892 p1.getPluginInformation().setVersion("1.01");
1893 p2.getPluginInformation().setVersion("1.2");
1894 assertTrue(p1.compareTo(p2) == -1);
1895
1896 p1.getPluginInformation().setVersion("1.0");
1897 p2.getPluginInformation().setVersion("1.0.1");
1898 assertTrue(p1.compareTo(p2) == -1);
1899
1900 p1.getPluginInformation().setVersion("1.1.1");
1901 p2.getPluginInformation().setVersion("1.2");
1902 assertTrue(p1.compareTo(p2) == -1);
1903 }
1904
1905 public void testComparePluginEqual()
1906 {
1907 final Plugin p1 = createPluginWithVersion("1.0");
1908 final Plugin p2 = createPluginWithVersion("1.0");
1909 assertTrue(p1.compareTo(p2) == 0);
1910
1911 p1.getPluginInformation().setVersion("1.1.0.0");
1912 p2.getPluginInformation().setVersion("1.1");
1913 assertTrue(p1.compareTo(p2) == 0);
1914
1915 p1.getPluginInformation().setVersion(" 1 . 1 ");
1916 p2.getPluginInformation().setVersion("1.1");
1917 assertTrue(p1.compareTo(p2) == 0);
1918 }
1919
1920
1921
1922 public void testComparePluginNoVersion()
1923 {
1924 final Plugin p1 = createPluginWithVersion("1.0");
1925 final Plugin p2 = createPluginWithVersion("#$%");
1926 assertEquals(1, p1.compareTo(p2));
1927
1928 p1.getPluginInformation().setVersion("#$%");
1929 p2.getPluginInformation().setVersion("1.0");
1930 assertEquals(-1, p1.compareTo(p2));
1931 }
1932
1933 public void testComparePluginBadPlugin()
1934 {
1935 final Plugin p1 = createPluginWithVersion("1.0");
1936 final Plugin p2 = createPluginWithVersion("1.0");
1937
1938
1939 p2.setKey("bad.key");
1940 assertTrue(p1.compareTo(p2) != 0);
1941 }
1942
1943 public void testInvalidationOfDynamicResourceCache() throws IOException, PluginException
1944 {
1945 createFillAndCleanTempPluginDirectory();
1946
1947 final DefaultPluginManager manager = makeClassLoadingPluginManager();
1948
1949 checkResources(manager, true, true);
1950 manager.disablePlugin("test.atlassian.plugin.classloaded");
1951 checkResources(manager, false, false);
1952 manager.enablePlugin("test.atlassian.plugin.classloaded");
1953 checkResources(manager, true, true);
1954 manager.uninstall(manager.getPlugin("test.atlassian.plugin.classloaded"));
1955 checkResources(manager, false, false);
1956
1957 FileUtils.copyDirectory(pluginsDirectory, pluginsTestDir);
1958 manager.scanForNewPlugins();
1959 checkResources(manager, true, true);
1960
1961
1962
1963 }
1964
1965 public void testValidatePlugin() throws PluginParseException
1966 {
1967 final DefaultPluginManager manager = new DefaultPluginManager(pluginStateStore, pluginLoaders, moduleDescriptorFactory,
1968 new DefaultPluginEventManager());
1969 final Mock mockLoader = new Mock(DynamicPluginLoader.class);
1970 @SuppressWarnings("unchecked")
1971 final PluginLoader loader = (PluginLoader) mockLoader.proxy();
1972 pluginLoaders.add(loader);
1973
1974 final Mock mockPluginJar = new Mock(PluginArtifact.class);
1975 final PluginArtifact pluginArtifact = (PluginArtifact) mockPluginJar.proxy();
1976 mockLoader.expectAndReturn("canLoad", C.args(C.eq(pluginArtifact)), "foo");
1977
1978 final String key = manager.validatePlugin(pluginArtifact);
1979 assertEquals("foo", key);
1980 mockLoader.verify();
1981 }
1982
1983 public void testValidatePluginWithNoDynamicLoaders() throws PluginParseException
1984 {
1985 final DefaultPluginManager manager = new DefaultPluginManager(pluginStateStore, pluginLoaders, moduleDescriptorFactory,
1986 new DefaultPluginEventManager());
1987 final Mock mockLoader = new Mock(PluginLoader.class);
1988 @SuppressWarnings("unchecked")
1989 final PluginLoader loader = (PluginLoader) mockLoader.proxy();
1990 pluginLoaders.add(loader);
1991
1992 final Mock mockPluginJar = new Mock(PluginArtifact.class);
1993 final PluginArtifact pluginArtifact = (PluginArtifact) mockPluginJar.proxy();
1994 try
1995 {
1996 manager.validatePlugin(pluginArtifact);
1997 fail("Should have thrown exception");
1998 }
1999 catch (final IllegalStateException ex)
2000 {
2001
2002 }
2003 }
2004
2005 public void testInvalidationOfDynamicClassCache() throws IOException, PluginException
2006 {
2007 createFillAndCleanTempPluginDirectory();
2008
2009 final DefaultPluginManager manager = makeClassLoadingPluginManager();
2010
2011 checkClasses(manager, true);
2012 manager.disablePlugin("test.atlassian.plugin.classloaded");
2013 checkClasses(manager, false);
2014 manager.enablePlugin("test.atlassian.plugin.classloaded");
2015 checkClasses(manager, true);
2016 manager.uninstall(manager.getPlugin("test.atlassian.plugin.classloaded"));
2017 checkClasses(manager, false);
2018
2019 FileUtils.copyDirectory(pluginsDirectory, pluginsTestDir);
2020 manager.scanForNewPlugins();
2021 checkClasses(manager, true);
2022 }
2023
2024 public void testInstallPlugin() throws Exception
2025 {
2026 final Mock mockPluginStateStore = new Mock(PluginPersistentStateStore.class);
2027 final Mock mockModuleDescriptorFactory = new Mock(ModuleDescriptorFactory.class);
2028 final Mock mockPluginLoader = new Mock(DynamicPluginLoader.class);
2029 final Mock mockDescriptorParserFactory = new Mock(DescriptorParserFactory.class);
2030 final Mock mockDescriptorParser = new Mock(DescriptorParser.class);
2031 final Mock mockPluginJar = new Mock(PluginArtifact.class);
2032 final Mock mockRepository = new Mock(PluginInstaller.class);
2033 final Mock mockPlugin = new Mock(Plugin.class);
2034
2035 final ModuleDescriptorFactory moduleDescriptorFactory = (ModuleDescriptorFactory) mockModuleDescriptorFactory.proxy();
2036
2037 final DefaultPluginManager pluginManager = new DefaultPluginManager((PluginPersistentStateStore) mockPluginStateStore.proxy(),
2038 Collections.<PluginLoader>singletonList((PluginLoader) mockPluginLoader.proxy()), moduleDescriptorFactory, pluginEventManager);
2039
2040 final Plugin plugin = (Plugin) mockPlugin.proxy();
2041 final PluginArtifact pluginArtifact = (PluginArtifact) mockPluginJar.proxy();
2042
2043 mockPluginStateStore.expectAndReturn("load", new DefaultPluginPersistentState());
2044 mockPluginStateStore.expectAndReturn("load", new DefaultPluginPersistentState());
2045 mockPluginStateStore.expectAndReturn("load", new DefaultPluginPersistentState());
2046 mockPluginStateStore.expect("save", C.ANY_ARGS);
2047 mockDescriptorParser.matchAndReturn("getKey", "test");
2048 mockRepository.expect("installPlugin", C.args(C.eq("test"), C.eq(pluginArtifact)));
2049 mockPluginLoader.expectAndReturn("loadAllPlugins", C.eq(moduleDescriptorFactory), Collections.emptyList());
2050 mockPluginLoader.expectAndReturn("supportsAddition", true);
2051 mockPluginLoader.expectAndReturn("addFoundPlugins", moduleDescriptorFactory, Collections.singletonList(plugin));
2052 mockPluginLoader.expectAndReturn("canLoad", C.args(C.eq(pluginArtifact)), "test");
2053 mockPlugin.matchAndReturn("getKey", "test");
2054 mockPlugin.matchAndReturn("hashCode", mockPlugin.hashCode());
2055 mockPlugin.expectAndReturn("getModuleDescriptors", new ArrayList<Object>());
2056 mockPlugin.expectAndReturn("getModuleDescriptors", new ArrayList<Object>());
2057 mockPlugin.expectAndReturn("isEnabledByDefault", true);
2058 mockPlugin.expect("install");
2059 mockPlugin.expect("enable");
2060 mockPlugin.expectAndReturn("isSystemPlugin", false);
2061 mockPlugin.expectAndReturn("isEnabledByDefault", true);
2062 mockPlugin.matchAndReturn("isEnabled", true);
2063 mockPlugin.matchAndReturn("getPluginState", PluginState.ENABLED);
2064 mockPlugin.matchAndReturn("compareTo", mockPlugin.proxy(), 0);
2065
2066 pluginManager.setPluginInstaller((PluginInstaller) mockRepository.proxy());
2067 pluginManager.init();
2068 final PassListener enabledListener = new PassListener(PluginEnabledEvent.class);
2069 pluginEventManager.register(enabledListener);
2070 pluginManager.installPlugin(pluginArtifact);
2071
2072 assertEquals(plugin, pluginManager.getPlugin("test"));
2073 assertTrue(pluginManager.isPluginEnabled("test"));
2074
2075 mockPlugin.verify();
2076 mockRepository.verify();
2077 mockPluginJar.verify();
2078 mockDescriptorParser.verify();
2079 mockDescriptorParserFactory.verify();
2080 mockPluginLoader.verify();
2081 mockPluginStateStore.verify();
2082 enabledListener.assertCalled();
2083 }
2084
2085 public void testInstallPluginsWithOne()
2086 {
2087 DynamicPluginLoader loader = mock(DynamicPluginLoader.class);
2088 ModuleDescriptorFactory descriptorFactory = mock(ModuleDescriptorFactory.class);
2089 PluginEventManager eventManager = mock(PluginEventManager.class);
2090 PluginInstaller installer = mock(PluginInstaller.class);
2091 DefaultPluginManager pm = new DefaultPluginManager(new MemoryPluginPersistentStateStore(), Collections.<PluginLoader>singletonList(loader), descriptorFactory, eventManager);
2092 pm.setPluginInstaller(installer);
2093 PluginArtifact artifact = mock(PluginArtifact.class);
2094 Plugin plugin = mock(Plugin.class);
2095 when(loader.canLoad(artifact)).thenReturn("foo");
2096 when(loader.addFoundPlugins(descriptorFactory)).thenReturn(Arrays.asList(plugin));
2097
2098 pm.installPlugins(artifact);
2099
2100 verify(loader).canLoad(artifact);
2101 verify(installer).installPlugin("foo", artifact);
2102 }
2103
2104 public void testInstallPluginsWithTwo()
2105 {
2106 DynamicPluginLoader loader = mock(DynamicPluginLoader.class);
2107 ModuleDescriptorFactory descriptorFactory = mock(ModuleDescriptorFactory.class);
2108 PluginEventManager eventManager = mock(PluginEventManager.class);
2109 PluginInstaller installer = mock(PluginInstaller.class);
2110 DefaultPluginManager pm = new DefaultPluginManager(new MemoryPluginPersistentStateStore(), Collections.<PluginLoader>singletonList(loader), descriptorFactory, eventManager);
2111 pm.setPluginInstaller(installer);
2112 PluginArtifact artifactA = mock(PluginArtifact.class);
2113 Plugin pluginA = mock(Plugin.class);
2114 when(loader.canLoad(artifactA)).thenReturn("a");
2115 PluginArtifact artifactB = mock(PluginArtifact.class);
2116 Plugin pluginB = mock(Plugin.class);
2117 when(loader.canLoad(artifactB)).thenReturn("b");
2118
2119 when(loader.addFoundPlugins(descriptorFactory)).thenReturn(Arrays.asList(pluginA, pluginB));
2120
2121 pm.installPlugins(artifactA, artifactB);
2122
2123 verify(loader).canLoad(artifactA);
2124 verify(loader).canLoad(artifactB);
2125 verify(installer).installPlugin("a", artifactA);
2126 verify(installer).installPlugin("b", artifactB);
2127 }
2128
2129 public void testInstallPluginsWithTwoButOneFailsValidation()
2130 {
2131 DynamicPluginLoader loader = mock(DynamicPluginLoader.class);
2132 ModuleDescriptorFactory descriptorFactory = mock(ModuleDescriptorFactory.class);
2133 PluginEventManager eventManager = mock(PluginEventManager.class);
2134 PluginInstaller installer = mock(PluginInstaller.class);
2135 DefaultPluginManager pm = new DefaultPluginManager(new MemoryPluginPersistentStateStore(), Collections.<PluginLoader>singletonList(loader), descriptorFactory, eventManager);
2136 pm.setPluginInstaller(installer);
2137 PluginArtifact artifactA = mock(PluginArtifact.class);
2138 Plugin pluginA = mock(Plugin.class);
2139 when(loader.canLoad(artifactA)).thenReturn("a");
2140 PluginArtifact artifactB = mock(PluginArtifact.class);
2141 Plugin pluginB = mock(Plugin.class);
2142 when(loader.canLoad(artifactB)).thenReturn(null);
2143
2144 when(loader.addFoundPlugins(descriptorFactory)).thenReturn(Arrays.asList(pluginA, pluginB));
2145
2146 try
2147 {
2148 pm.installPlugins(artifactA, artifactB);
2149 fail("Should have not installed plugins");
2150 }
2151 catch (PluginParseException ex)
2152 {
2153
2154 }
2155
2156 verify(loader).canLoad(artifactA);
2157 verify(loader).canLoad(artifactB);
2158 verify(installer, never()).installPlugin("a", artifactA);
2159 verify(installer, never()).installPlugin("b", artifactB);
2160 }
2161
2162 public void testInstallPluginsWithTwoButOneFailsValidationWithException()
2163 {
2164 DynamicPluginLoader loader = mock(DynamicPluginLoader.class);
2165 ModuleDescriptorFactory descriptorFactory = mock(ModuleDescriptorFactory.class);
2166 PluginEventManager eventManager = mock(PluginEventManager.class);
2167 PluginInstaller installer = mock(PluginInstaller.class);
2168 DefaultPluginManager pm = new DefaultPluginManager(new MemoryPluginPersistentStateStore(), Collections.<PluginLoader>singletonList(loader), descriptorFactory, eventManager);
2169 pm.setPluginInstaller(installer);
2170 PluginArtifact artifactA = mock(PluginArtifact.class);
2171 Plugin pluginA = mock(Plugin.class);
2172 when(loader.canLoad(artifactA)).thenReturn("a");
2173 PluginArtifact artifactB = mock(PluginArtifact.class);
2174 Plugin pluginB = mock(Plugin.class);
2175 doThrow(new PluginParseException()).when(loader).canLoad(artifactB);
2176
2177 when(loader.addFoundPlugins(descriptorFactory)).thenReturn(Arrays.asList(pluginA, pluginB));
2178
2179 try
2180 {
2181 pm.installPlugins(artifactA, artifactB);
2182 fail("Should have not installed plugins");
2183 }
2184 catch (PluginParseException ex)
2185 {
2186
2187 }
2188
2189 verify(loader).canLoad(artifactA);
2190 verify(loader).canLoad(artifactB);
2191 verify(installer, never()).installPlugin("a", artifactA);
2192 verify(installer, never()).installPlugin("b", artifactB);
2193 }
2194
2195
2196 private <T> void checkResources(final PluginAccessor manager, final boolean canGetGlobal, final boolean canGetModule) throws IOException
2197 {
2198 InputStream is = manager.getDynamicResourceAsStream("icon.gif");
2199 assertEquals(canGetGlobal, is != null);
2200 IOUtils.closeQuietly(is);
2201 is = manager.getDynamicResourceAsStream("bear/paddington.vm");
2202 assertEquals(canGetModule, is != null);
2203 IOUtils.closeQuietly(is);
2204 }
2205
2206 private <T> void checkClasses(final PluginAccessor manager, final boolean canGet)
2207 {
2208 try
2209 {
2210 manager.getDynamicPluginClass("com.atlassian.plugin.mock.MockPaddington");
2211 if (!canGet)
2212 {
2213 fail("Class in plugin was successfully loaded");
2214 }
2215 }
2216 catch (final ClassNotFoundException e)
2217 {
2218 if (canGet)
2219 {
2220 fail(e.getMessage());
2221 }
2222 }
2223 }
2224
2225 public void testAddPluginsThatThrowExceptionOnEnabled() throws Exception
2226 {
2227 final Plugin plugin = new CannotEnablePlugin();
2228
2229 manager.addPlugins(null, Arrays.asList(plugin));
2230
2231 assertFalse(plugin.getPluginState() == PluginState.ENABLED);
2232 }
2233
2234 public void testUninstallPluginClearsState() throws IOException
2235 {
2236 createFillAndCleanTempPluginDirectory();
2237
2238 final DefaultPluginManager manager = makeClassLoadingPluginManager();
2239
2240 checkClasses(manager, true);
2241 final Plugin plugin = manager.getPlugin("test.atlassian.plugin.classloaded");
2242
2243 final ModuleDescriptor<?> module = plugin.getModuleDescriptor("paddington");
2244 assertTrue(manager.isPluginModuleEnabled(module.getCompleteKey()));
2245 manager.disablePluginModule(module.getCompleteKey());
2246 assertFalse(manager.isPluginModuleEnabled(module.getCompleteKey()));
2247 manager.uninstall(plugin);
2248 assertFalse(manager.isPluginModuleEnabled(module.getCompleteKey()));
2249 assertTrue(pluginStateStore.load().getPluginStateMap(plugin).isEmpty());
2250 }
2251
2252 public void testCannotInitTwice() throws PluginParseException
2253 {
2254 manager.init();
2255 try
2256 {
2257 manager.init();
2258 fail("IllegalStateException expected");
2259 }
2260 catch (final IllegalStateException expected)
2261 {
2262 }
2263 }
2264
2265 public void testCannotShutdownTwice() throws PluginParseException
2266 {
2267 manager.init();
2268 manager.shutdown();
2269 try
2270 {
2271 manager.shutdown();
2272 fail("IllegalStateException expected");
2273 }
2274 catch (final IllegalStateException expected)
2275 {
2276 }
2277 }
2278
2279 public void testGetPluginWithNullKey()
2280 {
2281 manager.init();
2282 try
2283 {
2284 getPluginAccessor().getPlugin(null);
2285 fail();
2286 }
2287 catch (IllegalArgumentException ex)
2288 {
2289
2290 }
2291 }
2292
2293 public void testShutdownHandlesException()
2294 {
2295 final ThingsAreWrongListener listener = new ThingsAreWrongListener();
2296 pluginEventManager.register(listener);
2297 manager.init();
2298 try
2299 {
2300
2301 manager.shutdown();
2302 }
2303 catch (Exception e)
2304 {
2305 fail("Should not have thrown an exception!");
2306 }
2307 assertTrue(listener.isCalled());
2308 }
2309
2310 private void writeToFile(String file, String line) throws IOException
2311 {
2312 final String resourceName = ClasspathFilePluginMetadata.class.getPackage().getName().replace(".", "/") + "/" + file;
2313 URL resource = getClass().getClassLoader().getResource(resourceName);
2314
2315 FileOutputStream fout = new FileOutputStream(resource.getFile(), false);
2316 fout.write(line.getBytes(), 0, line.length());
2317 fout.close();
2318
2319 }
2320
2321 public void testExceptionOnRequiredPluginNotEnabling() throws Exception
2322 {
2323 try
2324 {
2325 writeToFile("application-required-modules.txt", "foo.required:bar");
2326 writeToFile("application-required-plugins.txt", "foo.required");
2327
2328 final Mock mockPluginLoader = new Mock(PluginLoader.class);
2329 final ModuleDescriptor<Object> badModuleDescriptor = new AbstractModuleDescriptor<Object>(ModuleFactory.LEGACY_MODULE_FACTORY)
2330 {
2331 @Override
2332 public String getKey()
2333 {
2334 return "bar";
2335 }
2336
2337 @Override
2338 public String getCompleteKey()
2339 {
2340 return "foo.required:bar";
2341 }
2342
2343 @Override
2344 public void enabled()
2345 {
2346 throw new IllegalArgumentException("Cannot enable");
2347 }
2348
2349 @Override
2350 public Object getModule()
2351 {
2352 return null;
2353 }
2354 };
2355
2356 final AbstractModuleDescriptor goodModuleDescriptor = mock(AbstractModuleDescriptor.class);
2357 when(goodModuleDescriptor.getKey()).thenReturn("baz");
2358 when(goodModuleDescriptor.getCompleteKey()).thenReturn("foo.required:baz");
2359
2360 Plugin plugin = new StaticPlugin()
2361 {
2362 @Override
2363 public Collection<ModuleDescriptor<?>> getModuleDescriptors()
2364 {
2365 return Arrays.<ModuleDescriptor<?>>asList(goodModuleDescriptor, badModuleDescriptor);
2366 }
2367
2368 @Override
2369 public ModuleDescriptor<Object> getModuleDescriptor(final String key)
2370 {
2371 return badModuleDescriptor;
2372 }
2373 };
2374 plugin.setKey("foo.required");
2375 plugin.setEnabledByDefault(true);
2376 plugin.setPluginInformation(new PluginInformation());
2377
2378 mockPluginLoader.expectAndReturn("loadAllPlugins", C.ANY_ARGS, Collections.singletonList(plugin));
2379
2380 @SuppressWarnings("unchecked")
2381 final PluginLoader loader = (PluginLoader) mockPluginLoader.proxy();
2382 pluginLoaders.add(loader);
2383
2384 try
2385 {
2386 manager.init();
2387 }
2388 catch(PluginException e)
2389 {
2390
2391 assertEquals("Unable to validate required plugins or modules", e.getMessage());
2392 return;
2393 }
2394 fail("A PluginException is expected when trying to initialize the plugins system with required plugins that do not load.");
2395 }
2396 finally
2397 {
2398
2399 writeToFile("application-required-modules.txt", "");
2400 writeToFile("application-required-plugins.txt", "");
2401 }
2402 }
2403
2404 public static class ThingsAreWrongListener
2405 {
2406 private volatile boolean called = false;
2407
2408 @PluginEventListener
2409 public void onFrameworkShutdown(final PluginFrameworkShutdownEvent event)
2410 {
2411 called = true;
2412 throw new NullPointerException("AAAH!");
2413 }
2414
2415 public boolean isCalled()
2416 {
2417 return called;
2418 }
2419 }
2420
2421 public Plugin createPluginWithVersion(final String version)
2422 {
2423 final Plugin p = new StaticPlugin();
2424 p.setKey("test.default.plugin");
2425 final PluginInformation pInfo = p.getPluginInformation();
2426 pInfo.setVersion(version);
2427 return p;
2428 }
2429
2430
2431
2432
2433
2434 private static class SinglePluginLoaderWithRemoval extends SinglePluginLoader
2435 {
2436 public SinglePluginLoaderWithRemoval(final String resource)
2437 {
2438 super(resource);
2439 }
2440
2441 public boolean supportsRemoval()
2442 {
2443
2444 return true;
2445 }
2446
2447 public void removePlugin(final Plugin plugin) throws PluginException
2448 {
2449 plugins = Collections.emptyList();
2450 }
2451
2452 protected StaticPlugin getNewPlugin()
2453 {
2454 return new StaticPlugin()
2455 {
2456 public boolean isUninstallable()
2457 {
2458 return true;
2459 }
2460 };
2461 }
2462 }
2463
2464 class NothingModuleDescriptor extends MockUnusedModuleDescriptor
2465 {
2466 }
2467
2468 @RequiresRestart
2469 public static class RequiresRestartModuleDescriptor extends MockUnusedModuleDescriptor
2470 {
2471 }
2472
2473
2474 public static class RequiresRestartSubclassModuleDescriptor extends RequiresRestartModuleDescriptor
2475 {
2476 }
2477
2478 private class MultiplePluginLoader implements PluginLoader
2479 {
2480 private final String[] descriptorPaths;
2481
2482 public MultiplePluginLoader(final String... descriptorPaths)
2483 {
2484 this.descriptorPaths = descriptorPaths;
2485 }
2486
2487 public Collection<Plugin> loadAllPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
2488 {
2489 final List<Plugin> result = new ArrayList<Plugin>(descriptorPaths.length);
2490 for (final String path : descriptorPaths)
2491 {
2492 final SinglePluginLoader loader = new SinglePluginLoader(path);
2493 result.addAll(loader.loadAllPlugins(moduleDescriptorFactory));
2494 }
2495 return result;
2496 }
2497
2498 public boolean supportsAddition()
2499 {
2500 return false;
2501 }
2502
2503 public boolean supportsRemoval()
2504 {
2505 return false;
2506 }
2507
2508 public Collection<Plugin> addFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
2509 {
2510 throw new UnsupportedOperationException("This PluginLoader does not support addition.");
2511 }
2512
2513 public void removePlugin(final Plugin plugin) throws PluginException
2514 {
2515 throw new UnsupportedOperationException("This PluginLoader does not support addition.");
2516 }
2517 }
2518
2519 private static class DynamicSinglePluginLoader extends SinglePluginLoader implements DynamicPluginLoader
2520 {
2521 private final String key;
2522
2523 public DynamicSinglePluginLoader(final String key, final String resource)
2524 {
2525 super(resource);
2526 this.key = key;
2527 }
2528
2529 public String canLoad(final PluginArtifact pluginArtifact) throws PluginParseException
2530 {
2531 return key;
2532 }
2533
2534 public boolean supportsAddition()
2535 {
2536 return true;
2537 }
2538
2539 @Override
2540 public Collection<Plugin> addFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory)
2541 {
2542 return super.loadAllPlugins(moduleDescriptorFactory);
2543 }
2544 }
2545
2546 private static class CannotEnablePlugin extends StaticPlugin
2547 {
2548 public CannotEnablePlugin()
2549 {
2550 setKey("foo");
2551 }
2552
2553 @Override
2554 protected PluginState enableInternal()
2555 {
2556 throw new RuntimeException("boo");
2557 }
2558
2559 public void disabled()
2560 {
2561 }
2562 }
2563
2564 public static class PluginModuleEnabledListener
2565 {
2566 public volatile boolean called;
2567 @PluginEventListener
2568 public void onEnable(PluginModuleEnabledEvent event)
2569 {
2570 called = true;
2571 }
2572 }
2573
2574 public static class PluginModuleDisabledListener
2575 {
2576 public volatile boolean called;
2577 @PluginEventListener
2578 public void onDisable(PluginModuleDisabledEvent event)
2579 {
2580 called = true;
2581 }
2582 }
2583
2584 public static class PluginDisabledListener
2585 {
2586 public volatile boolean called;
2587 @PluginEventListener
2588 public void onDisable(PluginDisabledEvent event)
2589 {
2590 called = true;
2591 }
2592 }
2593 }