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