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