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