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