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