PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-plugins-core/src/test/java/com/atlassian/plugin/loaders/TestScanningPluginLoader.java

https://bitbucket.org/atlassian/atlassian-plugins
Java | 545 lines | 435 code | 101 blank | 9 comment | 0 complexity | 5009c4028a88a4669402fd008814850c MD5 | raw file
  1. package com.atlassian.plugin.loaders;
  2. import com.atlassian.annotations.Internal;
  3. import com.atlassian.plugin.InstallationMode;
  4. import com.atlassian.plugin.ModuleDescriptor;
  5. import com.atlassian.plugin.ModuleDescriptorFactory;
  6. import com.atlassian.plugin.Plugin;
  7. import com.atlassian.plugin.PluginArtifact;
  8. import com.atlassian.plugin.PluginArtifactFactory;
  9. import com.atlassian.plugin.PluginDependencies;
  10. import com.atlassian.plugin.PluginException;
  11. import com.atlassian.plugin.PluginInformation;
  12. import com.atlassian.plugin.PluginState;
  13. import com.atlassian.plugin.Resourced;
  14. import com.atlassian.plugin.elements.ResourceDescriptor;
  15. import com.atlassian.plugin.elements.ResourceLocation;
  16. import com.atlassian.plugin.event.PluginEventManager;
  17. import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
  18. import com.atlassian.plugin.factories.PluginFactory;
  19. import com.atlassian.plugin.impl.UnloadablePlugin;
  20. import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
  21. import com.atlassian.plugin.loaders.classloading.Scanner;
  22. import com.google.common.collect.Iterables;
  23. import org.dom4j.Element;
  24. import org.junit.Before;
  25. import org.junit.Rule;
  26. import org.junit.Test;
  27. import org.junit.rules.ExpectedException;
  28. import org.junit.runner.RunWith;
  29. import org.mockito.Mock;
  30. import org.mockito.junit.MockitoJUnitRunner;
  31. import javax.annotation.Nonnull;
  32. import javax.annotation.Nullable;
  33. import java.io.File;
  34. import java.io.InputStream;
  35. import java.net.URL;
  36. import java.util.Arrays;
  37. import java.util.Collection;
  38. import java.util.Collections;
  39. import java.util.Date;
  40. import java.util.List;
  41. import java.util.Optional;
  42. import java.util.Set;
  43. import static org.hamcrest.MatcherAssert.assertThat;
  44. import static org.hamcrest.Matchers.containsInAnyOrder;
  45. import static org.hamcrest.Matchers.is;
  46. import static org.hamcrest.Matchers.nullValue;
  47. import static org.junit.Assert.assertEquals;
  48. import static org.junit.Assert.assertNotNull;
  49. import static org.junit.Assert.assertNotSame;
  50. import static org.junit.Assert.assertSame;
  51. import static org.junit.Assert.assertTrue;
  52. import static org.junit.Assert.fail;
  53. import static org.mockito.ArgumentMatchers.any;
  54. import static org.mockito.Mockito.mock;
  55. import static org.mockito.Mockito.never;
  56. import static org.mockito.Mockito.verify;
  57. import static org.mockito.Mockito.when;
  58. @RunWith(MockitoJUnitRunner.Silent.class)
  59. public class TestScanningPluginLoader {
  60. private static final String PLUGIN_KEY = "plugin-key";
  61. @Rule
  62. public final ExpectedException expectedException = ExpectedException.none();
  63. @Mock
  64. private PluginArtifactFactory pluginArtifactFactory;
  65. @Mock
  66. private PluginArtifact pluginArtifact;
  67. @Mock
  68. private PluginFactory pluginFactory;
  69. @Mock
  70. private ModuleDescriptorFactory moduleDescriptorFactory;
  71. @Mock
  72. private Plugin plugin;
  73. @Mock
  74. private Scanner scanner;
  75. @Mock
  76. private PluginEventManager pluginEventManager;
  77. @Mock
  78. private Element module;
  79. private DeploymentUnit deploymentUnit;
  80. @Before
  81. public void configureMocks() {
  82. deploymentUnit = new DeploymentUnit(new File("foo.jar"));
  83. when(plugin.getKey()).thenReturn(PLUGIN_KEY);
  84. when(pluginArtifactFactory.create(deploymentUnit.getPath().toURI())).thenReturn(pluginArtifact);
  85. when(pluginFactory.canCreate(pluginArtifact)).thenReturn("foo");
  86. when(scanner.getDeploymentUnits()).thenReturn(Arrays.asList(deploymentUnit));
  87. }
  88. @Test
  89. public void loadAllPluginsLoadsPlugin() {
  90. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  91. final ScanningPluginLoader loader = buildScanningPluginLoader();
  92. final Iterable<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
  93. assertThat(plugins, containsInAnyOrder(plugin));
  94. }
  95. @Test
  96. public void removeEnabledPluginFails() {
  97. when(plugin.getPluginState()).thenReturn(PluginState.ENABLED);
  98. final ScanningPluginLoader loader = buildScanningPluginLoader();
  99. expectedException.expect(PluginException.class);
  100. expectedException.expectMessage(PLUGIN_KEY);
  101. loader.removePlugin(plugin);
  102. }
  103. @Test
  104. public void removeNotUninstallablePluginFails() {
  105. when(plugin.isUninstallable()).thenReturn(false);
  106. final ScanningPluginLoader loader = buildScanningPluginLoader();
  107. expectedException.expect(PluginException.class);
  108. expectedException.expectMessage(PLUGIN_KEY);
  109. loader.removePlugin(plugin);
  110. }
  111. @Test
  112. public void removeDeleteablePluginDoesUninstallAndDelete() {
  113. when(plugin.isUninstallable()).thenReturn(true);
  114. when(plugin.isDeleteable()).thenReturn(true);
  115. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  116. final ScanningPluginLoader loader = buildScanningPluginLoader();
  117. final Iterable<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
  118. assertThat(plugins, containsInAnyOrder(plugin));
  119. loader.removePlugin(plugin);
  120. verify(plugin).uninstall();
  121. verify(scanner).remove(deploymentUnit);
  122. }
  123. @Test
  124. public void removeNotDeleteablePluginDoesUninstallButDoesntDelete() {
  125. when(plugin.isUninstallable()).thenReturn(true);
  126. when(plugin.isDeleteable()).thenReturn(false);
  127. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  128. final ScanningPluginLoader loader = buildScanningPluginLoader();
  129. final Iterable<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
  130. assertThat(plugins, containsInAnyOrder(plugin));
  131. loader.removePlugin(plugin);
  132. verify(plugin).uninstall();
  133. verify(scanner, never()).remove(any(DeploymentUnit.class));
  134. }
  135. @Test
  136. public void discardedPluginIsNotTracked() {
  137. when(plugin.isUninstallable()).thenReturn(true);
  138. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  139. final ScanningPluginLoader loader = buildScanningPluginLoader();
  140. final Iterable<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
  141. assertThat(plugins, containsInAnyOrder(plugin));
  142. loader.discardPlugin(plugin);
  143. try {
  144. // Discarded, so removal should fail even though isUninstallable
  145. loader.removePlugin(plugin);
  146. fail();
  147. } catch (final PluginException pe) {
  148. // Expected
  149. }
  150. // Shutdown should not result in uninstall of discarded plugin
  151. loader.onShutdown(mock(PluginFrameworkShutdownEvent.class));
  152. verify(plugin, never()).uninstall();
  153. }
  154. @Test
  155. public void shutdownUninstallsUninstallablePlugin() {
  156. when(plugin.isUninstallable()).thenReturn(true);
  157. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  158. final ScanningPluginLoader loader = buildScanningPluginLoader();
  159. loader.loadAllPlugins(moduleDescriptorFactory);
  160. loader.onShutdown(mock(PluginFrameworkShutdownEvent.class));
  161. verify(plugin).uninstall();
  162. }
  163. @Test
  164. public void shutdownDoesNotUninstallNotUninstallablePlugin() {
  165. when(plugin.isUninstallable()).thenReturn(false);
  166. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  167. final ScanningPluginLoader loader = buildScanningPluginLoader();
  168. loader.loadAllPlugins(moduleDescriptorFactory);
  169. loader.onShutdown(mock(PluginFrameworkShutdownEvent.class));
  170. verify(plugin, never()).uninstall();
  171. }
  172. @Test
  173. public void factoryThrowingRuntimeExceptionYieldsUnloadablePlugin() {
  174. factoryThrowingYieldsUnloadablePlugin(new IllegalArgumentException());
  175. }
  176. @Test
  177. public void factoryThrowingErrorYieldsUnloadablePlugin() {
  178. factoryThrowingYieldsUnloadablePlugin(new NoClassDefFoundError());
  179. }
  180. private void factoryThrowingYieldsUnloadablePlugin(final Throwable throwable) {
  181. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenThrow(throwable);
  182. final ScanningPluginLoader loader = buildScanningPluginLoader();
  183. final Iterable<Plugin> plugins = loader.loadAllPlugins(moduleDescriptorFactory);
  184. assertNotNull(plugins);
  185. assertEquals(1, Iterables.size(plugins));
  186. assertTrue(Iterables.getOnlyElement(plugins) instanceof UnloadablePlugin);
  187. }
  188. @Test
  189. public void pluginLoaderCallsPostProcess() {
  190. when(plugin.isUninstallable()).thenReturn(true);
  191. when(pluginFactory.create(pluginArtifact, moduleDescriptorFactory)).thenReturn(plugin);
  192. final ScanningPluginLoader loader = new ScanningPluginLoader(
  193. scanner, Collections.singletonList(pluginFactory), pluginArtifactFactory, pluginEventManager) {
  194. @Override
  195. protected Plugin postProcess(final Plugin plugin) {
  196. return new WrappedPlugin(plugin);
  197. }
  198. };
  199. final Iterable<Plugin> allPlugins = loader.loadAllPlugins(moduleDescriptorFactory);
  200. assertPluginsIsWrapperFor(allPlugins, plugin);
  201. final DeploymentUnit unitB = new DeploymentUnit(new File("bar.jar"));
  202. final PluginArtifact pluginArtifactB = mock(PluginArtifact.class);
  203. final Plugin pluginB = mock(Plugin.class);
  204. when(scanner.scan()).thenReturn(Arrays.asList(unitB));
  205. when(pluginArtifactFactory.create(unitB.getPath().toURI())).thenReturn(pluginArtifactB);
  206. when(pluginFactory.canCreate(pluginArtifactB)).thenReturn("bar");
  207. when(pluginFactory.create(pluginArtifactB, moduleDescriptorFactory)).thenReturn(pluginB);
  208. final Iterable<Plugin> foundPlugins = loader.loadFoundPlugins(moduleDescriptorFactory);
  209. assertPluginsIsWrapperFor(foundPlugins, pluginB);
  210. }
  211. @Test
  212. public void createModule() {
  213. final ModuleDescriptor moduleDescriptor = mock(ModuleDescriptor.class);
  214. final ScanningPluginLoader scanningPluginLoader = buildScanningPluginLoader();
  215. when(pluginFactory.createModule(plugin, module, moduleDescriptorFactory)).thenReturn(moduleDescriptor);
  216. assertThat(scanningPluginLoader.createModule(plugin, module, moduleDescriptorFactory), is(moduleDescriptor));
  217. }
  218. @Test
  219. public void createModuleNoFactory() {
  220. final ScanningPluginLoader scanningPluginLoader = buildScanningPluginLoader();
  221. when(pluginFactory.createModule(plugin, module, moduleDescriptorFactory)).thenReturn(null);
  222. assertThat(scanningPluginLoader.createModule(plugin, module, moduleDescriptorFactory), nullValue());
  223. }
  224. /**
  225. * A wrapper class for the postProcess test.
  226. *
  227. * By using a wrapper here, we guarantee postProcess is called, because no one else
  228. * could have an instance of this private class.
  229. */
  230. private static class WrappedPlugin implements Plugin {
  231. private final Plugin delegate;
  232. public WrappedPlugin(final Plugin plugin) {
  233. delegate = plugin;
  234. }
  235. @Override
  236. public int getPluginsVersion() {
  237. return delegate.getPluginsVersion();
  238. }
  239. @Override
  240. public void setPluginsVersion(int version) {
  241. delegate.setPluginsVersion(version);
  242. }
  243. @Override
  244. public String getName() {
  245. return delegate.getName();
  246. }
  247. @Override
  248. public void setName(String name) {
  249. delegate.setName(name);
  250. }
  251. @Override
  252. public String getI18nNameKey() {
  253. return delegate.getI18nNameKey();
  254. }
  255. @Override
  256. public void setI18nNameKey(String i18nNameKey) {
  257. delegate.setI18nNameKey(i18nNameKey);
  258. }
  259. @Override
  260. public String getKey() {
  261. return delegate.getKey();
  262. }
  263. @Override
  264. public void setKey(String aPackage) {
  265. delegate.setKey(aPackage);
  266. }
  267. @Override
  268. public void addModuleDescriptor(ModuleDescriptor<?> moduleDescriptor) {
  269. delegate.addModuleDescriptor(moduleDescriptor);
  270. }
  271. @Override
  272. public Collection<ModuleDescriptor<?>> getModuleDescriptors() {
  273. return delegate.getModuleDescriptors();
  274. }
  275. @Override
  276. public ModuleDescriptor<?> getModuleDescriptor(String key) {
  277. return delegate.getModuleDescriptor(key);
  278. }
  279. @Override
  280. public <M> List<ModuleDescriptor<M>> getModuleDescriptorsByModuleClass(Class<M> moduleClass) {
  281. return delegate.getModuleDescriptorsByModuleClass(moduleClass);
  282. }
  283. @Override
  284. public InstallationMode getInstallationMode() {
  285. return delegate.getInstallationMode();
  286. }
  287. @Override
  288. public boolean isEnabledByDefault() {
  289. return delegate.isEnabledByDefault();
  290. }
  291. @Override
  292. public void setEnabledByDefault(boolean enabledByDefault) {
  293. delegate.setEnabledByDefault(enabledByDefault);
  294. }
  295. @Override
  296. public PluginInformation getPluginInformation() {
  297. return delegate.getPluginInformation();
  298. }
  299. @Override
  300. public void setPluginInformation(PluginInformation pluginInformation) {
  301. delegate.setPluginInformation(pluginInformation);
  302. }
  303. @Override
  304. public void setResources(Resourced resources) {
  305. delegate.setResources(resources);
  306. }
  307. @Override
  308. public PluginState getPluginState() {
  309. return delegate.getPluginState();
  310. }
  311. @Override
  312. public boolean isSystemPlugin() {
  313. return delegate.isSystemPlugin();
  314. }
  315. @Override
  316. public void setSystemPlugin(boolean system) {
  317. delegate.setSystemPlugin(system);
  318. }
  319. @Override
  320. public boolean containsSystemModule() {
  321. return delegate.containsSystemModule();
  322. }
  323. @Override
  324. public boolean isBundledPlugin() {
  325. return delegate.isBundledPlugin();
  326. }
  327. @Override
  328. public Date getDateLoaded() {
  329. return delegate.getDateLoaded();
  330. }
  331. @Override
  332. public Date getDateInstalled() {
  333. return delegate.getDateInstalled();
  334. }
  335. @Override
  336. public boolean isUninstallable() {
  337. return delegate.isUninstallable();
  338. }
  339. @Override
  340. public boolean isDeleteable() {
  341. return delegate.isDeleteable();
  342. }
  343. @Override
  344. public boolean isDynamicallyLoaded() {
  345. return delegate.isDynamicallyLoaded();
  346. }
  347. @Override
  348. public <T> Class<T> loadClass(String clazz, Class<?> callingClass) throws ClassNotFoundException {
  349. return delegate.loadClass(clazz, callingClass);
  350. }
  351. @Override
  352. public ClassLoader getClassLoader() {
  353. return delegate.getClassLoader();
  354. }
  355. @Override
  356. public URL getResource(String path) {
  357. return delegate.getResource(path);
  358. }
  359. @Override
  360. public InputStream getResourceAsStream(String name) {
  361. return delegate.getResourceAsStream(name);
  362. }
  363. @Override
  364. public void install() {
  365. delegate.install();
  366. }
  367. @Override
  368. public void uninstall() {
  369. delegate.uninstall();
  370. }
  371. @Override
  372. public void enable() {
  373. delegate.enable();
  374. }
  375. @Override
  376. public void disable() {
  377. delegate.disable();
  378. }
  379. @Override
  380. @Nonnull
  381. public PluginDependencies getDependencies() {
  382. return delegate.getDependencies();
  383. }
  384. @Override
  385. public Set<String> getActivePermissions() {
  386. return delegate.getActivePermissions();
  387. }
  388. @Override
  389. public boolean hasAllPermissions() {
  390. return delegate.hasAllPermissions();
  391. }
  392. @Override
  393. public void resolve() {
  394. delegate.resolve();
  395. }
  396. @Override
  397. @Nullable
  398. public Date getDateEnabling() {
  399. return delegate.getDateEnabling();
  400. }
  401. @Override
  402. @Nullable
  403. public Date getDateEnabled() {
  404. return delegate.getDateEnabled();
  405. }
  406. @Override
  407. @Internal
  408. public PluginArtifact getPluginArtifact() {
  409. return delegate.getPluginArtifact();
  410. }
  411. @Override
  412. public Optional<String> getScopeKey() {
  413. return delegate.getScopeKey();
  414. }
  415. @Override
  416. public List<ResourceDescriptor> getResourceDescriptors() {
  417. return delegate.getResourceDescriptors();
  418. }
  419. @Override
  420. public ResourceDescriptor getResourceDescriptor(String type, String name) {
  421. return delegate.getResourceDescriptor(type, name);
  422. }
  423. @Override
  424. public ResourceLocation getResourceLocation(String type, String name) {
  425. return delegate.getResourceLocation(type, name);
  426. }
  427. @Override
  428. public int compareTo(Plugin o) {
  429. return delegate.compareTo(o);
  430. }
  431. }
  432. private void assertPluginsIsWrapperFor(final Iterable<Plugin> plugins, final Plugin originalPlugin) {
  433. assertNotNull(plugins);
  434. assertEquals(1, Iterables.size(plugins));
  435. final Plugin loadedPlugin = Iterables.getOnlyElement(plugins);
  436. assertNotSame(loadedPlugin, originalPlugin);
  437. assertTrue(loadedPlugin instanceof WrappedPlugin);
  438. final WrappedPlugin wrappedPlugin = (WrappedPlugin) loadedPlugin;
  439. assertSame(wrappedPlugin.delegate, originalPlugin);
  440. }
  441. private ScanningPluginLoader buildScanningPluginLoader() {
  442. return new ScanningPluginLoader(scanner, Collections.singletonList(pluginFactory), pluginArtifactFactory, pluginEventManager);
  443. }
  444. }