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