PageRenderTime 67ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/atlassian-plugins-osgi/src/test/java/it/com/atlassian/plugin/osgi/TestPluginInstall.java

https://bitbucket.org/atlassian/atlassian-plugins
Java | 987 lines | 840 code | 115 blank | 32 comment | 8 complexity | 95e83e98348de8f46bbf77a460b402ea MD5 | raw file
  1. package it.com.atlassian.plugin.osgi;
  2. import com.atlassian.plugin.DefaultModuleDescriptorFactory;
  3. import com.atlassian.plugin.JarPluginArtifact;
  4. import com.atlassian.plugin.Plugin;
  5. import com.atlassian.plugin.PluginState;
  6. import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
  7. import com.atlassian.plugin.impl.UnloadablePlugin;
  8. import com.atlassian.plugin.osgi.AnotherInterface;
  9. import com.atlassian.plugin.osgi.BasicWaitCondition;
  10. import com.atlassian.plugin.osgi.BooleanFlag;
  11. import com.atlassian.plugin.osgi.Callable2;
  12. import com.atlassian.plugin.osgi.Callable3;
  13. import com.atlassian.plugin.osgi.DefaultBooleanFlag;
  14. import com.atlassian.plugin.osgi.DummyModuleDescriptor;
  15. import com.atlassian.plugin.osgi.HostClassUsingHostComponentConstructor;
  16. import com.atlassian.plugin.osgi.HostClassUsingHostComponentSetter;
  17. import com.atlassian.plugin.osgi.ObjectModuleDescriptor;
  18. import com.atlassian.plugin.osgi.PluginInContainerTestBase;
  19. import com.atlassian.plugin.osgi.SomeInterface;
  20. import com.atlassian.plugin.osgi.StubServletModuleDescriptor;
  21. import com.atlassian.plugin.osgi.external.SingleModuleDescriptorFactory;
  22. import com.atlassian.plugin.osgi.factory.OsgiPlugin;
  23. import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
  24. import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
  25. import com.atlassian.plugin.servlet.DefaultServletModuleManager;
  26. import com.atlassian.plugin.servlet.ServletModuleManager;
  27. import com.atlassian.plugin.servlet.descriptors.ServletModuleDescriptor;
  28. import com.atlassian.plugin.test.PluginJarBuilder;
  29. import com.atlassian.plugin.util.PluginUtils;
  30. import com.atlassian.plugin.util.WaitUntil;
  31. import com.google.common.collect.ImmutableMap;
  32. import org.junit.Rule;
  33. import org.junit.Test;
  34. import org.junit.contrib.java.lang.system.RestoreSystemProperties;
  35. import org.osgi.framework.Bundle;
  36. import org.osgi.framework.Constants;
  37. import javax.servlet.ServletConfig;
  38. import javax.servlet.ServletContext;
  39. import javax.servlet.http.HttpServlet;
  40. import java.io.File;
  41. import java.util.Collections;
  42. import java.util.concurrent.TimeUnit;
  43. import java.util.concurrent.locks.Lock;
  44. import java.util.concurrent.locks.ReentrantLock;
  45. import static com.atlassian.plugin.PluginState.DISABLED;
  46. import static com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager.ATLASSIAN_BOOTDELEGATION_EXTRA;
  47. import static org.hamcrest.Matchers.empty;
  48. import static org.hamcrest.Matchers.instanceOf;
  49. import static org.hamcrest.Matchers.lessThan;
  50. import static org.hamcrest.Matchers.notNullValue;
  51. import static org.hamcrest.core.Is.is;
  52. import static org.junit.Assert.assertEquals;
  53. import static org.junit.Assert.assertFalse;
  54. import static org.junit.Assert.assertNotNull;
  55. import static org.junit.Assert.assertThat;
  56. import static org.junit.Assert.assertTrue;
  57. import static org.junit.Assert.fail;
  58. import static org.mockito.Mockito.mock;
  59. import static org.mockito.Mockito.when;
  60. public final class TestPluginInstall extends PluginInContainerTestBase {
  61. @Rule
  62. public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
  63. private static final String SPRING_CONFIG_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  64. + "<beans xmlns=\"http://www.springframework.org/schema/beans\"\n"
  65. + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
  66. + " xmlns:osgi=\"http://www.eclipse.org/gemini/blueprint/schema/blueprint\"\n"
  67. + " xsi:schemaLocation=\""
  68. + " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n"
  69. + " http://www.eclipse.org/gemini/blueprint/schema/blueprint http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd\"\n"
  70. + ">\n";
  71. private static final String SPRING_CONFIG_FOOTER = "</beans>\n";
  72. private static void assertExists(File f) {
  73. assertTrue("File should exist: " + f, f.exists());
  74. }
  75. private static void assertDoesNotExist(File f) {
  76. assertFalse("File should not exist: " + f, f.exists());
  77. }
  78. @Test
  79. public void testUpgradeOfBundledPlugin() throws Exception {
  80. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(hostContainer);
  81. factory.addModuleDescriptor("object", ObjectModuleDescriptor.class);
  82. final File pluginJar = new PluginJarBuilder("testUpgradeOfBundledPlugin")
  83. .addFormattedResource("atlassian-plugin.xml",
  84. "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
  85. " <plugin-info>",
  86. " <version>1.0</version>",
  87. " </plugin-info>",
  88. " <object key='obj' class='my.Foo'/>",
  89. "</atlassian-plugin>")
  90. .addFormattedJava("my.Foo",
  91. "package my;",
  92. "public class Foo {}")
  93. .build();
  94. initBundlingPluginManager(factory, pluginJar);
  95. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  96. assertEquals("Test", pluginAccessor.getPlugin("test.bundled.plugin").getName());
  97. assertEquals("my.Foo", pluginAccessor.getPlugin("test.bundled.plugin").getModuleDescriptor("obj").getModule().getClass().getName());
  98. final File pluginJar2 = new PluginJarBuilder("testUpgradeOfBundledPlugin")
  99. .addFormattedResource("atlassian-plugin.xml",
  100. "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
  101. " <plugin-info>",
  102. " <version>1.0</version>",
  103. " </plugin-info>",
  104. " <object key='obj' class='my.Bar'/>",
  105. "</atlassian-plugin>")
  106. .addFormattedJava("my.Bar",
  107. "package my;",
  108. "public class Bar {}")
  109. .build();
  110. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  111. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  112. assertEquals("Test", pluginAccessor.getPlugin("test.bundled.plugin").getName());
  113. assertEquals("my.Bar", pluginAccessor.getPlugin("test.bundled.plugin").getModuleDescriptor("obj").getModule().getClass().getName());
  114. }
  115. @Test
  116. public void testUpgradeOfBadPlugin() throws Exception {
  117. new PluginJarBuilder("testUpgradeOfBundledPlugin-old")
  118. .addFormattedResource("atlassian-plugin.xml",
  119. "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
  120. " <plugin-info>",
  121. " <version>1.0</version>",
  122. " </plugin-info>",
  123. " <component key='obj' class='my.Foo'/>",
  124. "</atlassian-plugin>")
  125. .addFormattedJava("my.Foo",
  126. "package my;",
  127. "public class Foo {",
  128. " public Foo() { throw new RuntimeException('bad plugin');}",
  129. "}")
  130. .build(pluginsDir);
  131. new PluginJarBuilder("testUpgradeOfBundledPlugin-new")
  132. .addFormattedResource("atlassian-plugin.xml",
  133. "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
  134. " <plugin-info>",
  135. " <version>2.0</version>",
  136. " </plugin-info>",
  137. " <component key='obj' class='my.Foo'/>",
  138. "</atlassian-plugin>")
  139. .addFormattedJava("my.Foo",
  140. "package my;",
  141. "public class Foo {",
  142. " public Foo() {}",
  143. "}")
  144. .build(pluginsDir);
  145. initPluginManager();
  146. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  147. assertEquals("Test", pluginAccessor.getPlugin("test.bundled.plugin").getName());
  148. assertEquals("2.0", pluginAccessor.getPlugin("test.bundled.plugin").getPluginInformation().getVersion());
  149. }
  150. @Test
  151. public void testUpgradeWithNewComponentImports() throws Exception {
  152. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
  153. factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
  154. initPluginManager(new HostComponentProvider() {
  155. public void provide(final ComponentRegistrar registrar) {
  156. registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
  157. });
  158. registrar.register(AnotherInterface.class).forInstance(new AnotherInterface() {
  159. });
  160. }
  161. }, factory);
  162. final File pluginJar = new PluginJarBuilder("first")
  163. .addFormattedResource("atlassian-plugin.xml",
  164. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  165. " <plugin-info>",
  166. " <version>1.0</version>",
  167. " </plugin-info>",
  168. " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
  169. " <dummy key='dum1'/>", "</atlassian-plugin>")
  170. .build();
  171. final File pluginJar2 = new PluginJarBuilder("second")
  172. .addFormattedResource("atlassian-plugin.xml",
  173. "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
  174. " <plugin-info>",
  175. " <version>1.0</version>",
  176. " </plugin-info>",
  177. " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
  178. " <component-import key='comp2' interface='com.atlassian.plugin.osgi.AnotherInterface' />",
  179. " <dummy key='dum1'/>",
  180. " <dummy key='dum2'/>",
  181. "</atlassian-plugin>")
  182. .build();
  183. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  184. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  185. assertEquals("Test", pluginAccessor.getPlugin("test.plugin").getName());
  186. assertEquals(2, pluginAccessor.getPlugin("test.plugin").getModuleDescriptors().size());
  187. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  188. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  189. assertEquals(4, pluginAccessor.getPlugin("test.plugin").getModuleDescriptors().size());
  190. assertEquals("Test 2", pluginAccessor.getPlugin("test.plugin").getName());
  191. }
  192. @Test
  193. public void testInstallWithClassConstructorReferencingHostClassWithHostComponent() throws Exception {
  194. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(hostContainer);
  195. factory.addModuleDescriptor("object", ObjectModuleDescriptor.class);
  196. initPluginManager(new HostComponentProvider() {
  197. public void provide(final ComponentRegistrar registrar) {
  198. registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
  199. });
  200. }
  201. }, factory);
  202. final File pluginJar = new PluginJarBuilder("testUpgradeOfBundledPlugin")
  203. .addFormattedResource("atlassian-plugin.xml",
  204. "<atlassian-plugin name='Test' key='hostClass' pluginsVersion='2'>",
  205. " <plugin-info>",
  206. " <version>1.0</version>",
  207. " </plugin-info>",
  208. " <object key='hostClass' class='com.atlassian.plugin.osgi.HostClassUsingHostComponentConstructor'/>",
  209. "</atlassian-plugin>")
  210. .build();
  211. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  212. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  213. assertEquals("Test", pluginAccessor.getPlugin("hostClass").getName());
  214. assertEquals(1, pluginAccessor.getPlugin("hostClass").getModuleDescriptors().size());
  215. HostClassUsingHostComponentConstructor module = (HostClassUsingHostComponentConstructor) pluginAccessor.getPlugin("hostClass").getModuleDescriptor("hostClass").getModule();
  216. assertNotNull(module);
  217. }
  218. @Test
  219. public void testInstallWithClassSetterReferencingHostClassWithHostComponent() throws Exception {
  220. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(hostContainer);
  221. factory.addModuleDescriptor("object", ObjectModuleDescriptor.class);
  222. initPluginManager(new HostComponentProvider() {
  223. public void provide(final ComponentRegistrar registrar) {
  224. registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
  225. });
  226. }
  227. }, factory);
  228. final File pluginJar = new PluginJarBuilder("testUpgradeOfBundledPlugin")
  229. .addFormattedResource("atlassian-plugin.xml",
  230. "<atlassian-plugin name='Test' key='hostClass' pluginsVersion='2'>",
  231. " <plugin-info>",
  232. " <version>1.0</version>",
  233. " </plugin-info>",
  234. " <object key='hostClass' class='com.atlassian.plugin.osgi.HostClassUsingHostComponentSetter'/>",
  235. "</atlassian-plugin>")
  236. .build();
  237. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  238. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  239. assertEquals("Test", pluginAccessor.getPlugin("hostClass").getName());
  240. assertEquals(1, pluginAccessor.getPlugin("hostClass").getModuleDescriptors().size());
  241. HostClassUsingHostComponentSetter module = (HostClassUsingHostComponentSetter) pluginAccessor.getPlugin("hostClass").getModuleDescriptor("hostClass").getModule();
  242. assertNotNull(module);
  243. assertNotNull(module.getSomeInterface());
  244. }
  245. /* Enable for manual memory leak profiling
  246. @Test
  247. public void testNoMemoryLeak() throws Exception
  248. {
  249. DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
  250. factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
  251. for (int x=0; x<100; x++)
  252. {
  253. pluginEventManager = new DefaultPluginEventManager();
  254. initPluginManager(new HostComponentProvider(){
  255. public void provide(ComponentRegistrar registrar)
  256. {
  257. registrar.register(SomeInterface.class).forInstance(new SomeInterface(){});
  258. registrar.register(AnotherInterface.class).forInstance(new AnotherInterface(){});
  259. }
  260. }, factory);
  261. pluginSystemLifecycle.shutdown();
  262. }
  263. System.out.println("Gentlement, start your profilers!");
  264. System.in.read();
  265. }
  266. */
  267. @Test
  268. public void testUpgradeWithNoAutoDisable() throws Exception {
  269. DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
  270. factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
  271. initPluginManager(new HostComponentProvider() {
  272. public void provide(ComponentRegistrar registrar) {
  273. registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
  274. });
  275. registrar.register(AnotherInterface.class).forInstance(new AnotherInterface() {
  276. });
  277. }
  278. }, factory);
  279. File pluginJar = new PluginJarBuilder("first")
  280. .addFormattedResource("atlassian-plugin.xml",
  281. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  282. " <plugin-info>",
  283. " <version>1.0</version>",
  284. " </plugin-info>",
  285. " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
  286. " <dummy key='dum1'/>",
  287. "</atlassian-plugin>")
  288. .build();
  289. final File pluginJar2 = new PluginJarBuilder("second")
  290. .addFormattedResource("atlassian-plugin.xml",
  291. "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
  292. " <plugin-info>",
  293. " <version>1.0</version>",
  294. " </plugin-info>",
  295. " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
  296. " <dummy key='dum1'/>",
  297. " <dummy key='dum2'/>",
  298. "</atlassian-plugin>")
  299. .build();
  300. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  301. assertTrue(pluginAccessor.isPluginEnabled("test.plugin"));
  302. final Lock lock = new ReentrantLock();
  303. Thread upgradeThread = new Thread() {
  304. public void run() {
  305. lock.lock();
  306. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  307. lock.unlock();
  308. }
  309. };
  310. Thread isEnabledThread = new Thread() {
  311. public void run() {
  312. try {
  313. while (!lock.tryLock(10, TimeUnit.SECONDS))
  314. pluginAccessor.isPluginEnabled("test.plugin");
  315. } catch (InterruptedException e) {
  316. fail();
  317. }
  318. }
  319. };
  320. upgradeThread.start();
  321. isEnabledThread.start();
  322. upgradeThread.join(10000);
  323. assertTrue(pluginAccessor.isPluginEnabled("test.plugin"));
  324. }
  325. @Test
  326. public void testUpgradeTestingForCachedXml() throws Exception {
  327. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
  328. factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
  329. initPluginManager(new HostComponentProvider() {
  330. public void provide(final ComponentRegistrar registrar) {
  331. registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
  332. });
  333. registrar.register(AnotherInterface.class).forInstance(new AnotherInterface() {
  334. });
  335. }
  336. }, factory);
  337. final File pluginJar = new PluginJarBuilder("first").addFormattedResource("atlassian-plugin.xml",
  338. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>", " <plugin-info>", " <version>1.0</version>",
  339. " </plugin-info>", " <component key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' class='my.ServiceImpl' />",
  340. "</atlassian-plugin>").addFormattedJava("my.ServiceImpl", "package my;",
  341. "public class ServiceImpl implements com.atlassian.plugin.osgi.SomeInterface {}").build();
  342. final File pluginJar2 = new PluginJarBuilder("second").addFormattedResource("atlassian-plugin.xml",
  343. "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>", " <plugin-info>", " <version>1.0</version>",
  344. " </plugin-info>", "</atlassian-plugin>").build();
  345. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  346. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  347. assertEquals("Test", pluginAccessor.getPlugin("test.plugin").getName());
  348. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  349. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  350. assertEquals("Test 2", pluginAccessor.getPlugin("test.plugin").getName());
  351. }
  352. @Test
  353. public void testPluginDependentOnPackageImport() throws Exception {
  354. HostComponentProvider prov = new HostComponentProvider() {
  355. public void provide(final ComponentRegistrar registrar) {
  356. registrar.register(ServletConfig.class).forInstance(new HttpServlet() {
  357. });
  358. }
  359. };
  360. File servletJar = new PluginJarBuilder("first")
  361. .addFormattedResource("META-INF/MANIFEST.MF",
  362. "Export-Package: javax.servlet.http;version='4.0.0',javax.servlet;version='4.0.0'",
  363. "Import-Package: javax.servlet.http;version='4.0.0',javax.servlet;version='4.0.0'",
  364. "Bundle-SymbolicName: first",
  365. "Bundle-Version: 4.0.0",
  366. "Manifest-Version: 1.0",
  367. "")
  368. .addFormattedJava("javax.servlet.Servlet",
  369. "package javax.servlet;",
  370. "public interface Servlet {}")
  371. .addFormattedJava("javax.servlet.http.HttpServlet",
  372. "package javax.servlet.http;",
  373. "public abstract class HttpServlet implements javax.servlet.Servlet{}")
  374. .build();
  375. File pluginJar = new PluginJarBuilder("asecond")
  376. .addFormattedResource("atlassian-plugin.xml",
  377. "<atlassian-plugin name='Test' key='second' pluginsVersion='2'>",
  378. " <plugin-info>",
  379. " <version>1.0</version>",
  380. " <bundle-instructions><Import-Package>javax.servlet.http;version='3.0',javax.servlet;version='3.0',*</Import-Package></bundle-instructions>",
  381. " </plugin-info>",
  382. "</atlassian-plugin>")
  383. .addFormattedJava("second.MyImpl",
  384. "package second;",
  385. "public class MyImpl {",
  386. " public MyImpl(javax.servlet.ServletConfig config) {",
  387. " }",
  388. "}")
  389. .build();
  390. initPluginManager(prov);
  391. pluginController.installPlugins(new JarPluginArtifact(servletJar));
  392. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  393. WaitUntil.invoke(new BasicWaitCondition() {
  394. public boolean isFinished() {
  395. return pluginAccessor.getEnabledPlugins().size() == 2;
  396. }
  397. });
  398. assertEquals(2, pluginAccessor.getEnabledPlugins().size());
  399. assertNotNull(pluginAccessor.getPlugin("first-4.0.0"));
  400. assertNotNull(pluginAccessor.getPlugin("second"));
  401. }
  402. @Test
  403. public void testPluginWithHostComponentUsingOldPackageImport() throws Exception {
  404. final PluginJarBuilder firstBuilder = new PluginJarBuilder("oldpkgfirst");
  405. firstBuilder
  406. .addFormattedResource("atlassian-plugin.xml",
  407. "<atlassian-plugin name='Test' key='first' pluginsVersion='2'>",
  408. " <plugin-info>",
  409. " <version>1.0</version>",
  410. " <bundle-instructions>",
  411. " <Export-Package>first</Export-Package>",
  412. " </bundle-instructions>",
  413. " </plugin-info>",
  414. " <servlet key='foo' class='second.MyServlet'>",
  415. " <url-pattern>/foo</url-pattern>",
  416. " </servlet>",
  417. "</atlassian-plugin>")
  418. .addFormattedJava("first.MyInterface",
  419. "package first;",
  420. "public interface MyInterface {}")
  421. .build(pluginsDir);
  422. new PluginJarBuilder("oldpkgsecond", firstBuilder.getClassLoader())
  423. .addPluginInformation("second", "Some name", "1.0")
  424. .addFormattedJava("second.MyImpl",
  425. "package second;",
  426. "public class MyImpl implements first.MyInterface {}")
  427. .build(pluginsDir);
  428. initPluginManager();
  429. assertEquals(2, pluginAccessor.getEnabledPlugins().size());
  430. assertNotNull(pluginAccessor.getPlugin("first"));
  431. assertNotNull(pluginAccessor.getPlugin("second"));
  432. }
  433. @Test
  434. public void testPluginWithServletDependentOnPackageImport() throws Exception {
  435. final PluginJarBuilder firstBuilder = new PluginJarBuilder("first");
  436. firstBuilder
  437. .addPluginInformation("first", "Some name", "1.0")
  438. .addFormattedJava("first.MyInterface",
  439. "package first;",
  440. "public interface MyInterface {}")
  441. .addFormattedResource("META-INF/MANIFEST.MF",
  442. "Manifest-Version: 1.0",
  443. "Bundle-SymbolicName: first",
  444. "Bundle-Version: 1.0",
  445. "Export-Package: first",
  446. "")
  447. .build(pluginsDir);
  448. new PluginJarBuilder("asecond", firstBuilder.getClassLoader())
  449. .addFormattedResource("atlassian-plugin.xml",
  450. "<atlassian-plugin name='Test' key='asecond' pluginsVersion='2'>",
  451. " <plugin-info>",
  452. " <version>1.0</version>",
  453. " </plugin-info>",
  454. " <servlet key='foo' class='second.MyServlet'>",
  455. " <url-pattern>/foo</url-pattern>",
  456. " </servlet>",
  457. "</atlassian-plugin>")
  458. .addFormattedJava("second.MyServlet",
  459. "package second;",
  460. "public class MyServlet extends javax.servlet.http.HttpServlet implements first.MyInterface {}")
  461. .build(pluginsDir);
  462. initPluginManager(null, new SingleModuleDescriptorFactory(new DefaultHostContainer(), "servlet", StubServletModuleDescriptor.class));
  463. assertEquals(2, pluginAccessor.getEnabledPlugins().size());
  464. assertTrue(pluginAccessor.getPlugin("first").getPluginState() == PluginState.ENABLED);
  465. assertNotNull(pluginAccessor.getPlugin("asecond").getPluginState() == PluginState.ENABLED);
  466. }
  467. @Test
  468. public void testPluginWithServletRefreshedAfterOtherPluginUpgraded() throws Exception {
  469. final PluginJarBuilder firstBuilder = new PluginJarBuilder("first");
  470. firstBuilder
  471. .addPluginInformation("first", "Some name", "1.0")
  472. .addFormattedJava("first.MyInterface",
  473. "package first;",
  474. "public interface MyInterface {}")
  475. .addFormattedResource("META-INF/MANIFEST.MF",
  476. "Manifest-Version: 1.0",
  477. "Bundle-SymbolicName: first",
  478. "Bundle-Version: 1.0",
  479. "Export-Package: first",
  480. "")
  481. .build(pluginsDir);
  482. new PluginJarBuilder("asecond", firstBuilder.getClassLoader())
  483. .addFormattedResource("atlassian-plugin.xml",
  484. "<atlassian-plugin name='Test' key='asecond' pluginsVersion='2'>",
  485. " <plugin-info>",
  486. " <version>1.0</version>",
  487. " </plugin-info>",
  488. " <servlet key='foo' class='second.MyServlet'>",
  489. " <url-pattern>/foo</url-pattern>",
  490. " </servlet>",
  491. "</atlassian-plugin>")
  492. .addFormattedJava("second.MyServlet",
  493. "package second;",
  494. "import com.atlassian.plugin.osgi.Callable2;",
  495. "public class MyServlet extends javax.servlet.http.HttpServlet implements first.MyInterface {",
  496. " private Callable2 callable;",
  497. " public MyServlet(Callable2 cal) { this.callable = cal; }",
  498. " public String getServletInfo() {",
  499. " try {return callable.call() + ' bob';} catch (Exception ex) { throw new RuntimeException(ex);}",
  500. " }",
  501. "}")
  502. .build(pluginsDir);
  503. HostComponentProvider prov = new HostComponentProvider() {
  504. public void provide(ComponentRegistrar registrar) {
  505. registrar.register(Callable2.class).forInstance(new Callable2() {
  506. public String call() {
  507. return "hi";
  508. }
  509. });
  510. }
  511. };
  512. ServletContext ctx = mock(ServletContext.class);
  513. when(ctx.getInitParameterNames()).thenReturn(Collections.<String>enumeration(Collections.<String>emptyList()));
  514. ServletConfig servletConfig = mock(ServletConfig.class);
  515. when(servletConfig.getServletContext()).thenReturn(ctx);
  516. ServletModuleManager mgr = new DefaultServletModuleManager(pluginEventManager);
  517. hostContainer = createHostContainer(Collections.<Class<?>, Object>singletonMap(ServletModuleManager.class, mgr));
  518. initPluginManager(prov, new SingleModuleDescriptorFactory(
  519. hostContainer,
  520. "servlet",
  521. ServletModuleDescriptor.class));
  522. assertEquals(2, pluginAccessor.getEnabledPlugins().size());
  523. assertTrue(pluginAccessor.getPlugin("first").getPluginState() == PluginState.ENABLED);
  524. assertNotNull(pluginAccessor.getPlugin("asecond").getPluginState() == PluginState.ENABLED);
  525. assertEquals("hi bob", mgr.getServlet("/foo", servletConfig).getServletInfo());
  526. final File updatedJar = new PluginJarBuilder("first-updated")
  527. .addPluginInformation("foo", "Some name", "1.0")
  528. .addFormattedJava("first.MyInterface",
  529. "package first;",
  530. "public interface MyInterface {}")
  531. .addFormattedResource("META-INF/MANIFEST.MF",
  532. "Manifest-Version: 1.0",
  533. "Bundle-SymbolicName: foo",
  534. "Bundle-Version: 1.0",
  535. "Export-Package: first",
  536. "")
  537. .build();
  538. pluginController.installPlugins(new JarPluginArtifact(updatedJar));
  539. WaitUntil.invoke(new BasicWaitCondition() {
  540. public boolean isFinished() {
  541. return pluginAccessor.isPluginEnabled("asecond");
  542. }
  543. });
  544. assertEquals("hi bob", mgr.getServlet("/foo", servletConfig).getServletInfo());
  545. }
  546. // PLUG-760
  547. @Test
  548. public void testModuleDescriptorWithNamespace() throws Exception {
  549. new PluginJarBuilder("asecond")
  550. .addFormattedResource("atlassian-plugin.xml",
  551. "<atlassian-plugin name='Test' key='asecond' pluginsVersion='2'",
  552. " xmlns='http://www.atlassian.com/schema/plugins'",
  553. " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'",
  554. " xsi:schemaLocation='http://www.atlassian.com/schema/plugins http://schema.atlassian.com/refapp/refapp-2.9.xsd'>",
  555. " <plugin-info>",
  556. " <version>1.0</version>",
  557. " </plugin-info>",
  558. " <servlet key='foo' class='second.MyServlet'>",
  559. " <url-pattern>/foo</url-pattern>",
  560. " </servlet>",
  561. "</atlassian-plugin>")
  562. .addFormattedJava("second.MyServlet",
  563. "package second;",
  564. "public class MyServlet extends javax.servlet.http.HttpServlet {}")
  565. .build(pluginsDir);
  566. ServletContext ctx = mock(ServletContext.class);
  567. when(ctx.getInitParameterNames()).thenReturn(Collections.<String>enumeration(Collections.<String>emptyList()));
  568. ServletConfig servletConfig = mock(ServletConfig.class);
  569. when(servletConfig.getServletContext()).thenReturn(ctx);
  570. ServletModuleManager mgr = new DefaultServletModuleManager(pluginEventManager);
  571. hostContainer = createHostContainer(Collections.<Class<?>, Object>singletonMap(ServletModuleManager.class, mgr));
  572. initPluginManager(null, new SingleModuleDescriptorFactory(
  573. hostContainer,
  574. "servlet",
  575. ServletModuleDescriptor.class));
  576. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  577. assertNotNull(pluginAccessor.getPlugin("asecond").getPluginState() == PluginState.ENABLED);
  578. }
  579. @Test
  580. public void testLotsOfHostComponents() throws Exception {
  581. new PluginJarBuilder("first")
  582. .addFormattedResource("atlassian-plugin.xml",
  583. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  584. " <plugin-info>",
  585. " <version>1.0</version>",
  586. " </plugin-info>",
  587. " <dummy key='dum1'/>",
  588. "</atlassian-plugin>")
  589. .build(pluginsDir);
  590. new PluginJarBuilder("second")
  591. .addFormattedResource("atlassian-plugin.xml",
  592. "<atlassian-plugin name='Test 2' key='test.plugin2' pluginsVersion='2'>",
  593. " <plugin-info>",
  594. " <version>1.0</version>",
  595. " </plugin-info>",
  596. " <dummy key='dum1'/>",
  597. " <dummy key='dum2'/>",
  598. "</atlassian-plugin>")
  599. .build(pluginsDir);
  600. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
  601. factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
  602. initPluginManager(new HostComponentProvider() {
  603. public void provide(final ComponentRegistrar registrar) {
  604. for (int x = 0; x < 100; x++) {
  605. registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
  606. }).withName("some" + x);
  607. registrar.register(AnotherInterface.class).forInstance(new AnotherInterface() {
  608. }).withName("another" + x);
  609. }
  610. }
  611. }, factory);
  612. assertEquals(2, pluginAccessor.getEnabledPlugins().size());
  613. }
  614. @Test
  615. public void testInstallWithManifestNoSpringContextAndComponents() throws Exception {
  616. final BooleanFlag flag = new DefaultBooleanFlag(false);
  617. new PluginJarBuilder("first")
  618. .addFormattedResource("atlassian-plugin.xml",
  619. "<atlassian-plugin name='Test' key='first' pluginsVersion='2'>",
  620. " <plugin-info>",
  621. " <version>1.0</version>",
  622. " </plugin-info>",
  623. " <component key='foo' class='first.MyClass' interface='first.MyInterface' public='true'/>",
  624. "</atlassian-plugin>")
  625. .addFormattedJava("first.MyInterface",
  626. "package first;",
  627. "public interface MyInterface {}")
  628. .addFormattedJava("first.MyClass",
  629. "package first;",
  630. "public class MyClass implements MyInterface{",
  631. " public MyClass(com.atlassian.plugin.osgi.BooleanFlag bool) { bool.set(true); }",
  632. "}")
  633. .addFormattedResource("META-INF/MANIFEST.MF",
  634. "Manifest-Version: 1.0",
  635. "Bundle-SymbolicName: foo",
  636. "Bundle-Version: 1.0",
  637. "Export-Package: first",
  638. "")
  639. .build(pluginsDir);
  640. initPluginManager(registrar -> registrar.register(BooleanFlag.class)
  641. .forInstance(flag)
  642. .withName("bob"));
  643. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  644. assertNotNull(pluginAccessor.getPlugin("first"));
  645. assertTrue(flag.get());
  646. }
  647. @Test
  648. public void testInstallWithManifestNoDescriptorWithSpringXml() throws Exception {
  649. new PluginJarBuilder("nodesc")
  650. .manifest(new ImmutableMap.Builder<String, String>()
  651. .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "nodesc")
  652. .put(Constants.BUNDLE_VERSION, "1.0")
  653. .build())
  654. .addResource("META-INF/spring/foo.xml", SPRING_CONFIG_HEADER + SPRING_CONFIG_FOOTER)
  655. .build(pluginsDir);
  656. initPluginManager();
  657. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  658. Plugin plugin = pluginAccessor.getPlugin("nodesc");
  659. assertNotNull(plugin);
  660. assertEquals("1.0", plugin.getPluginInformation().getVersion());
  661. assertEquals("nodesc", plugin.getKey());
  662. assertEquals(0, plugin.getModuleDescriptors().size());
  663. }
  664. @Test
  665. public void testInstallWithManifestNoDescriptorWithSpringHeader() throws Exception {
  666. new PluginJarBuilder("nodesc")
  667. .manifest(new ImmutableMap.Builder<String, String>()
  668. .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "nodesc")
  669. .put(Constants.BUNDLE_VERSION, "1.0")
  670. .put("Spring-Context", "*;timeout:=60")
  671. .build())
  672. .build(pluginsDir);
  673. initPluginManager();
  674. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  675. Plugin plugin = pluginAccessor.getPlugin("nodesc");
  676. assertNotNull(plugin);
  677. assertEquals("1.0", plugin.getPluginInformation().getVersion());
  678. assertEquals("nodesc", plugin.getKey());
  679. assertEquals(0, plugin.getModuleDescriptors().size());
  680. }
  681. @Test
  682. public void testInstallWithSpringContainerFail() throws Exception {
  683. System.setProperty(PluginUtils.ATLASSIAN_PLUGINS_ENABLE_WAIT, "10");
  684. new PluginJarBuilder("fail-spring-container")
  685. .manifest(new ImmutableMap.Builder<String, String>()
  686. .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "fail-spring-container")
  687. .put(Constants.BUNDLE_VERSION, "1.0")
  688. .put("Spring-Context", "*")
  689. .build())
  690. .addResource("META-INF/spring/fail.xml",
  691. SPRING_CONFIG_HEADER + "<osgi:reference id=\"notFound\" interface=\"some.class.NotFound\"/>" + SPRING_CONFIG_FOOTER)
  692. .build(pluginsDir);
  693. final long beforeStarting = System.currentTimeMillis();
  694. initPluginManager();
  695. final long startupDuration = System.currentTimeMillis() - beforeStarting;
  696. assertThat(pluginAccessor.getEnabledPlugins(), empty());
  697. final Plugin plugin = pluginAccessor.getPlugin("fail-spring-container");
  698. assertThat(plugin, notNullValue());
  699. assertThat(plugin, instanceOf(OsgiPlugin.class));
  700. final OsgiPlugin osgiPlugin = (OsgiPlugin) plugin;
  701. assertThat(osgiPlugin.getPluginState(), is(DISABLED));
  702. assertThat(osgiPlugin.getBundle().getState(), is(Bundle.RESOLVED));
  703. assertThat("fail-spring-container failed due to plugin system timeout rather than immediately via PluginContainerFailedEvent", startupDuration, lessThan(10000L));
  704. }
  705. // TODO: turn this back on PLUG-682
  706. // @Test
  707. public void testInstallWithComponentBeanNameConflictedWithHostComponent() throws Exception {
  708. new PluginJarBuilder("first")
  709. .addFormattedResource("atlassian-plugin.xml",
  710. "<atlassian-plugin name='Test' key='first' pluginsVersion='2'>",
  711. " <plugin-info>",
  712. " <version>1.0</version>",
  713. " </plugin-info>",
  714. " <component key='host_component1' class='first.MyClass' interface='first.MyInterface'/>",
  715. "</atlassian-plugin>")
  716. .addFormattedJava("com.atlassian.plugin.osgi.SomeInterface",
  717. "package com.atlassian.plugin.osgi;",
  718. "public interface SomeInterface {}")
  719. .addFormattedJava("first.MyClass",
  720. "package first;",
  721. "import com.atlassian.plugin.osgi.SomeInterface;",
  722. "public class MyClass implements SomeInterface{",
  723. "}")
  724. .build(pluginsDir);
  725. initPluginManager(registrar -> registrar.register(SomeInterface.class)
  726. .forInstance(new SomeInterface() {})
  727. .withName("host_component1"));
  728. // there is a name conflict therefore this plugin should not have been enabled.
  729. assertEquals(0, pluginAccessor.getEnabledPlugins().size());
  730. assertTrue(pluginAccessor.getPlugins().toArray()[0] instanceof UnloadablePlugin);
  731. // the error message has to mention the problematic component name otherwise users won't be able to figure out.
  732. assertTrue(pluginAccessor.getPlugins().toArray(new UnloadablePlugin[1])[0].getErrorText().contains("host_component1"));
  733. }
  734. @Test
  735. public void testInstallWithStrangePath() throws Exception {
  736. File strangeDir = new File(tmpDir, "20%time");
  737. strangeDir.mkdir();
  738. File oldTmp = tmpDir;
  739. try {
  740. tmpDir = strangeDir;
  741. cacheDir = new File(tmpDir, "felix-cache");
  742. cacheDir.mkdir();
  743. pluginsDir = new File(tmpDir, "plugins");
  744. pluginsDir.mkdir();
  745. new PluginJarBuilder("strangePath")
  746. .addFormattedResource("atlassian-plugin.xml",
  747. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  748. " <plugin-info>",
  749. " <version>1.0</version>",
  750. " </plugin-info>",
  751. "</atlassian-plugin>")
  752. .build(pluginsDir);
  753. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
  754. factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
  755. initPluginManager(new HostComponentProvider() {
  756. public void provide(final ComponentRegistrar registrar) {
  757. }
  758. }, factory);
  759. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  760. } finally {
  761. tmpDir = oldTmp;
  762. }
  763. }
  764. @Test
  765. public void testInstallWithUnsatisifedDependency() throws Exception {
  766. File plugin = new PluginJarBuilder("unsatisifiedDependency")
  767. .addFormattedResource("atlassian-plugin.xml",
  768. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  769. " <plugin-info>",
  770. " <version>1.0</version>",
  771. " </plugin-info>",
  772. " <component-import key='foo' interface='java.util.concurrent.Callable' />",
  773. "</atlassian-plugin>")
  774. .build(pluginsDir);
  775. long start = System.currentTimeMillis();
  776. // Set dev mode temporarily
  777. System.setProperty("atlassian.dev.mode", "true");
  778. System.setProperty(PluginUtils.ATLASSIAN_PLUGINS_ENABLE_WAIT, "7");
  779. initPluginManager();
  780. assertTrue(start + (60 * 1000) > System.currentTimeMillis());
  781. }
  782. @Test
  783. public void testInstallSimplePluginNoSpring() throws Exception {
  784. File jar = new PluginJarBuilder("strangePath")
  785. .addPluginInformation("no-spring", "foo", "1.0")
  786. .build();
  787. initPluginManager();
  788. pluginController.installPlugins(new JarPluginArtifact(jar));
  789. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  790. }
  791. @Test
  792. public void testInstallSimplePluginWithNoManifest() throws Exception {
  793. File jar = new PluginJarBuilder("strangePath")
  794. .addPluginInformation("no-spring", "foo", "1.0")
  795. .buildWithNoManifest();
  796. initPluginManager();
  797. pluginController.installPlugins(new JarPluginArtifact(jar));
  798. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  799. }
  800. @Test
  801. public void testInstallPluginTakesTooLong() throws Exception {
  802. System.setProperty(PluginUtils.ATLASSIAN_PLUGINS_ENABLE_WAIT, "3");
  803. final PluginJarBuilder builder = new PluginJarBuilder("first")
  804. .addFormattedResource("atlassian-plugin.xml",
  805. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  806. " <plugin-info>",
  807. " <version>1.0</version>",
  808. " </plugin-info>",
  809. " <component key='svc' class='my.ServiceImpl' public='true'>",
  810. " <interface>my.Service</interface>",
  811. " </component>",
  812. "</atlassian-plugin>")
  813. .addFormattedJava("my.Service",
  814. "package my;",
  815. "public interface Service {",
  816. " public Object call() throws Exception;",
  817. "}")
  818. .addFormattedJava("my.ServiceImpl",
  819. "package my;",
  820. "public class ServiceImpl implements Service {",
  821. "public ServiceImpl(){",
  822. "try{",
  823. "Thread.sleep(10000);",
  824. "}catch(Exception e){}",
  825. "}",
  826. " public Object call() throws Exception { ",
  827. " return 'hi';}",
  828. "}");
  829. final File jar = builder.build();
  830. initPluginManager();
  831. pluginController.installPlugins(new JarPluginArtifact(jar));
  832. assertEquals(0, pluginAccessor.getEnabledPlugins().size());
  833. }
  834. @Test
  835. public void testInstallPluginVersion3() throws Exception {
  836. initPluginManager();
  837. final File v3plugin = new PluginJarBuilder("v3-plugin")
  838. .addFormattedResource("atlassian-plugin.xml",
  839. "<atlassian-plugin name='V3 Plugin' key='v3-plugin' pluginsVersion='3'>",
  840. " <plugin-info>",
  841. " <version>1.0</version>",
  842. " <permissions>",
  843. " <permission>execute_java</permission>",
  844. " </permissions>",
  845. " </plugin-info>",
  846. "</atlassian-plugin>")
  847. .addFormattedResource("META-INF/MANIFEST.MF",
  848. "Bundle-SymbolicName: v3-plugin",
  849. // need the key because of com.atlassian.plugin.osgi.factory.OsgiPluginUninstalledHelper#install,
  850. // and the comparison of keys, using com.atlassian.plugin.osgi.util.OsgiHeaderUtil#getPluginKey !
  851. OsgiPlugin.ATLASSIAN_PLUGIN_KEY + ": v3-plugin",
  852. "Bundle-Version: 1.0.0",
  853. "Manifest-Version: 1.0",
  854. "Spring-Context: *;timeout:=60", // we still need a container, add this to trigger spring.
  855. "")
  856. .build();
  857. pluginController.installPlugins(new JarPluginArtifact(v3plugin));
  858. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  859. assertNotNull(pluginAccessor.getEnabledPlugin("v3-plugin"));
  860. }
  861. public static class Callable3Aware {
  862. private final Callable3 callable;
  863. public Callable3Aware(Callable3 callable) {
  864. this.callable = callable;
  865. }
  866. public String call() throws Exception {
  867. return callable.call();
  868. }
  869. }
  870. }