View Javadoc

1   package com.atlassian.plugin.osgi.factory;
2   
3   import com.atlassian.plugin.Application;
4   import com.atlassian.plugin.JarPluginArtifact;
5   import com.atlassian.plugin.ModuleDescriptorFactory;
6   import com.atlassian.plugin.Plugin;
7   import com.atlassian.plugin.PluginAccessor;
8   import com.atlassian.plugin.PluginInformation;
9   import com.atlassian.plugin.PluginParseException;
10  import com.atlassian.plugin.XmlPluginArtifact;
11  import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
12  import com.atlassian.plugin.osgi.container.OsgiContainerManager;
13  import com.atlassian.plugin.osgi.container.impl.DefaultOsgiPersistentCache;
14  import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
15  import com.atlassian.plugin.test.PluginJarBuilder;
16  import com.atlassian.plugin.test.PluginTestUtils;
17  
18  import com.google.common.collect.ImmutableList;
19  import com.google.common.collect.ImmutableMap;
20  import com.mockobjects.dynamic.C;
21  import com.mockobjects.dynamic.Mock;
22  import junit.framework.TestCase;
23  import org.apache.commons.io.FileUtils;
24  import org.osgi.framework.Bundle;
25  import org.osgi.framework.BundleContext;
26  import org.osgi.framework.Constants;
27  import org.osgi.service.packageadmin.PackageAdmin;
28  import org.osgi.util.tracker.ServiceTracker;
29  
30  import java.io.File;
31  import java.io.IOException;
32  import java.net.URISyntaxException;
33  import java.util.ArrayList;
34  import java.util.Collections;
35  import java.util.Dictionary;
36  import java.util.Hashtable;
37  
38  import static org.hamcrest.Matchers.instanceOf;
39  import static org.hamcrest.Matchers.sameInstance;
40  import static org.hamcrest.core.IsEqual.equalTo;
41  import static org.junit.Assert.assertThat;
42  import static org.mockito.Matchers.any;
43  import static org.mockito.Matchers.eq;
44  import static org.mockito.Mockito.mock;
45  import static org.mockito.Mockito.verify;
46  import static org.mockito.Mockito.when;
47  import static org.mockito.Mockito.withSettings;
48  
49  public class TestOsgiPluginFactory extends TestCase
50  {
51      OsgiPluginFactory factory;
52  
53      private File tmpDir;
54      private File jar;
55      OsgiContainerManager osgiContainerManager;
56      private Mock mockBundle;
57      private Mock mockSystemBundle;
58  
59      @Override
60      public void setUp() throws IOException, URISyntaxException
61      {
62          tmpDir = PluginTestUtils.createTempDirectory(TestOsgiPluginFactory.class);
63          osgiContainerManager = mock(
64                  OsgiContainerManager.class,
65                  withSettings().extraInterfaces(OsgiContainerManager.AllowsReferenceInstall.class));
66  
67          ServiceTracker tracker = mock(ServiceTracker.class);
68          when(tracker.getServices()).thenReturn(new Object[0]);
69          when(osgiContainerManager.getServiceTracker(ModuleDescriptorFactory.class.getName())).thenReturn(tracker);
70  
71          factory = new OsgiPluginFactory(PluginAccessor.Descriptor.FILENAME, Collections.<Application>emptySet(), new DefaultOsgiPersistentCache(tmpDir), osgiContainerManager, new DefaultPluginEventManager());
72          jar = new PluginJarBuilder("someplugin").addPluginInformation("plugin.key", "My Plugin", "1.0").build();
73  
74          mockBundle = new Mock(Bundle.class);
75          final Dictionary<String, String> dict = new Hashtable<String, String>();
76          dict.put(Constants.BUNDLE_DESCRIPTION, "desc");
77          dict.put(Constants.BUNDLE_VERSION, "1.0");
78          mockBundle.matchAndReturn("getHeaders", dict);
79  
80          mockSystemBundle = new Mock(Bundle.class);
81          final Dictionary<String, String> sysDict = new Hashtable<String, String>();
82          sysDict.put(Constants.BUNDLE_DESCRIPTION, "desc");
83          sysDict.put(Constants.BUNDLE_VERSION, "1.0");
84          mockSystemBundle.matchAndReturn("getHeaders", sysDict);
85          mockSystemBundle.matchAndReturn("getLastModified", System.currentTimeMillis());
86          mockSystemBundle.matchAndReturn("getSymbolicName", "system.bundle");
87  
88          Mock mockSysContext = new Mock(BundleContext.class);
89          mockSystemBundle.matchAndReturn("getBundleContext", mockSysContext.proxy());
90  
91          mockSysContext.matchAndReturn("getServiceReference", C.ANY_ARGS, null);
92          mockSysContext.matchAndReturn("getService", C.ANY_ARGS, new Mock(PackageAdmin.class).proxy());
93      }
94  
95      @Override
96      public void tearDown() throws IOException
97      {
98          factory = null;
99          FileUtils.cleanDirectory(tmpDir);
100         jar.delete();
101     }
102 
103     public void testCreateOsgiPlugin() throws PluginParseException
104     {
105         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
106         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
107         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
108         final Plugin plugin = factory.create(new JarPluginArtifact(jar), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
109         assertNotNull(plugin);
110         assertTrue(plugin instanceof OsgiPlugin);
111     }
112 
113     public void testCreateOsgiPluginWithBadVersion() throws PluginParseException, IOException
114     {
115         jar = new PluginJarBuilder("someplugin").addPluginInformation("plugin.key", "My Plugin", "beta.1.0").build();
116         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
117         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
118         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
119         try
120         {
121             factory.create(new JarPluginArtifact(jar), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
122             fail("Should have complained about osgi version");
123         }
124         catch (PluginParseException ex)
125         {
126             // expected
127         }
128     }
129 
130     public void testCreateOsgiPluginWithBadVersion2() throws PluginParseException, IOException
131     {
132         jar = new PluginJarBuilder("someplugin").addPluginInformation("plugin.key", "My Plugin", "3.2-rc1").build();
133         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
134         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
135         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
136         Plugin plugin = factory.create(new JarPluginArtifact(jar), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
137         assertTrue(plugin instanceof OsgiPlugin);
138     }
139 
140     public void testCreateOsgiPluginWithManifestKey() throws PluginParseException, IOException
141     {
142         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
143         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
144         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
145 
146         final File pluginFile = new PluginJarBuilder("loadwithxml")
147                 .manifest(new ImmutableMap.Builder<String, String>()
148                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "somekey")
149                         .put(Constants.BUNDLE_VERSION, "1.0")
150                         .put(Constants.BUNDLE_NAME,"My awesome plugin")
151                         .put(Constants.BUNDLE_DESCRIPTION,"Bundle Description")
152                         .put(Constants.BUNDLE_VENDOR,"My vendor Name")
153                         .build())
154                 .build();
155 
156         final Plugin plugin = factory.create(new JarPluginArtifact(pluginFile), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
157         assertNotNull(plugin);
158         assertTrue(plugin instanceof OsgiPlugin);
159     }
160 
161     public void testCreateOsgiPluginWithManifestKeyAndDescriptorSkippingTransform() throws PluginParseException, IOException
162     {
163         File jar = new PluginJarBuilder("someplugin")
164                 .addPluginInformation("plugin.key", "My Plugin", "1.0")
165                 .manifest(new ImmutableMap.Builder<String, String>()
166                                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "somekey")
167                                         .put(Constants.BUNDLE_VERSION, "1.0")
168                                         .build())
169                 .build();
170         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
171         mockBundle.expectAndReturn("getHeaders", new Hashtable() {{
172             put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "plugin.key");
173             put(Constants.BUNDLE_VERSION, "1.0");
174         }});
175         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(
176                 Collections.<HostComponentRegistration>emptyList());
177         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
178         when(((OsgiContainerManager.AllowsReferenceInstall)osgiContainerManager).installBundle(jar, false)).thenReturn((Bundle) mockBundle.proxy());
179         final Plugin plugin = factory.create(new JarPluginArtifact(jar), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
180         assertNotNull(plugin);
181         assertTrue(plugin instanceof OsgiPlugin);
182 
183         plugin.install();
184         verify((OsgiContainerManager.AllowsReferenceInstall)osgiContainerManager).installBundle(jar, false);
185     }
186 
187     public void testPluginInformationAndPluginNameIsExtractedFromManifest() throws IOException
188     {
189         PluginInformation expectedPluginInformation = createPluginInformation("My Description", "My Awesome Vendor Name", "1.0");
190         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
191         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
192 
193         String pluginName = "My awesome plugin";
194 
195         final Plugin plugin = createPlugin(pluginName, expectedPluginInformation);
196         assertNotNull(plugin);
197         assertTrue(plugin instanceof OsgiPlugin);
198 
199         assertThat(plugin.getName(),equalTo(pluginName));
200 
201         PluginInformation actualPluginInformation = plugin.getPluginInformation();
202         assertThat(actualPluginInformation.getDescription(), equalTo(expectedPluginInformation.getDescription()));
203         assertThat(actualPluginInformation.getVendorName(),equalTo(expectedPluginInformation.getVendorName()));
204         assertThat(actualPluginInformation.getVersion(), equalTo(expectedPluginInformation.getVersion()));
205     }
206 
207     public void testShouldLoadPluginIfManifestDoesNotHaveOptionalInformation() throws IOException
208     {
209         PluginInformation pluginInformation = createPluginInformation("", "", "1.0");
210         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
211         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
212 
213         String pluginName = "My Awesome Plugin";
214         Plugin plugin = createPlugin(pluginName, pluginInformation);
215 
216         assertNotNull(plugin);
217         assertTrue(plugin instanceof OsgiPlugin);
218         assertThat(plugin.getName(), equalTo(pluginName));
219     }
220 
221     private Plugin createPlugin(String pluginName, PluginInformation pluginInformation) throws IOException
222     {
223         final File pluginFile = new PluginJarBuilder("loadwithxml")
224                 .manifest(new ImmutableMap.Builder<String, String>()
225                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, pluginName)
226                         .put(Constants.BUNDLE_VERSION, pluginInformation.getVersion())
227                         .put(Constants.BUNDLE_NAME, pluginName)
228                         .put(Constants.BUNDLE_DESCRIPTION, pluginInformation.getDescription())
229                         .put(Constants.BUNDLE_VENDOR, pluginInformation.getVendorName())
230                         .build())
231                 .build();
232 
233         return factory.create(new JarPluginArtifact(pluginFile), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
234     }
235 
236     private PluginInformation createPluginInformation(String description, String vendorName, String version)
237     {
238         PluginInformation pluginInformation = new PluginInformation();
239         pluginInformation.setDescription(description);
240         pluginInformation.setVendorName(vendorName);
241         pluginInformation.setVersion(version);
242         return pluginInformation;
243     }
244 
245     public void testCreateOsgiPluginWithManifestKeyNoVersion() throws PluginParseException, IOException
246     {
247         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
248         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(new ArrayList());
249         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
250 
251         final File pluginFile = new PluginJarBuilder("loadwithxml")
252                 .manifest(new ImmutableMap.Builder<String, String>()
253                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "somekey")
254                         .build())
255                 .build();
256 
257         try
258         {
259             factory.create(new JarPluginArtifact(pluginFile), (ModuleDescriptorFactory) new Mock(ModuleDescriptorFactory.class).proxy());
260             fail("Should have failed due to no version");
261         }
262         catch (NullPointerException ex)
263         {
264             // test passed
265         }
266     }
267 
268     public void testCanLoadWithXml() throws PluginParseException, IOException
269     {
270         final File plugin = new PluginJarBuilder("loadwithxml").addPluginInformation("foo.bar", "", "1.0").build();
271         final String key = factory.canCreate(new JarPluginArtifact(plugin));
272         assertEquals("foo.bar", key);
273     }
274 
275     public void testCanLoadWithXmlArtifact() throws PluginParseException, IOException
276     {
277         File xmlFile = new File(tmpDir, "plugin.xml");
278         FileUtils.writeStringToFile(xmlFile, "<somexml />");
279         final String key = factory.canCreate(new XmlPluginArtifact(xmlFile));
280         assertNull(key);
281     }
282 
283     public void testCanLoadJarWithNoManifest() throws PluginParseException, IOException
284     {
285         final File plugin = new PluginJarBuilder("loadwithxml")
286                 .addResource("foo.xml", "<foo/>")
287                 .buildWithNoManifest();
288         final String key = factory.canCreate(new JarPluginArtifact(plugin));
289         assertNull(key);
290     }
291 
292     public void testCanLoadNoXml() throws PluginParseException, IOException
293     {
294         final File plugin = new PluginJarBuilder("loadwithxml").build();
295         final String key = factory.canCreate(new JarPluginArtifact(plugin));
296         assertNull(key);
297     }
298 
299     public void testCanLoadNoXmlButWithManifestEntry() throws PluginParseException, IOException
300     {
301         final File plugin = new PluginJarBuilder("loadwithxml")
302                 .manifest(new ImmutableMap.Builder<String, String>()
303                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "somekey")
304                         .put(Constants.BUNDLE_VERSION, "1.0")
305                         .build())
306                 .build();
307         final String key = factory.canCreate(new JarPluginArtifact(plugin));
308         assertEquals("somekey", key);
309     }
310 
311     public void testCanLoadNoXmlButWithManifestEntryNoVersion() throws PluginParseException, IOException
312     {
313         final File plugin = new PluginJarBuilder("loadwithxml")
314                 .manifest(new ImmutableMap.Builder<String, String>()
315                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "somekey")
316                         .build())
317                 .build();
318         final String key = factory.canCreate(new JarPluginArtifact(plugin));
319         assertNull(key);
320     }
321 
322     public void testCanLoadWithXmlVersion3() throws Exception
323     {
324         final File plugin = new PluginJarBuilder("loadwithxml").addPluginInformation("foo.bar", "", "1.0", 3).build();
325         final String key = factory.canCreate(new JarPluginArtifact(plugin));
326         assertNull(key);
327     }
328 
329     public void testTransformedArtifactAllowsReferenceInstall()
330     {
331         mockBundle.expectAndReturn("getSymbolicName", "plugin.key");
332         // We need to insert the Atlassian-Plugin-Key header that transformation would for installation to work
333         ((Bundle) mockBundle.proxy()).getHeaders().put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "plugin.key");
334 
335         when(osgiContainerManager.getHostComponentRegistrations()).thenReturn(ImmutableList.<HostComponentRegistration>of());
336         when(osgiContainerManager.getBundles()).thenReturn(new Bundle[] {(Bundle) mockSystemBundle.proxy()});
337         // Have our mock OsgiContainerManager respond only to a reference install (the true in the next line)
338         when(((OsgiContainerManager.AllowsReferenceInstall) osgiContainerManager).installBundle(any(File.class), eq(true)))
339                 .thenReturn((Bundle) mockBundle.proxy());
340         final ModuleDescriptorFactory moduleDescriptorFactory = mock(ModuleDescriptorFactory.class);
341         final Plugin plugin = factory.create(new JarPluginArtifact(jar), moduleDescriptorFactory);
342         plugin.install();
343         assertThat(plugin, instanceOf(OsgiPlugin.class));
344         final Bundle actualBundle = ((OsgiPlugin) plugin).getBundle();
345         assertThat(actualBundle, sameInstance(mockBundle.proxy()));
346         verify((OsgiContainerManager.AllowsReferenceInstall) osgiContainerManager).installBundle(any(File.class), eq(true));
347     }
348 }