View Javadoc
1   package com.atlassian.plugin.osgi.util;
2   
3   import com.atlassian.plugin.JarPluginArtifact;
4   import com.atlassian.plugin.PluginArtifact;
5   import com.atlassian.plugin.PluginParseException;
6   import com.atlassian.plugin.osgi.factory.OsgiPlugin;
7   import com.atlassian.plugin.osgi.factory.transform.StubHostComponentRegistration;
8   import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
9   import com.atlassian.plugin.test.CapturedLogging;
10  import com.atlassian.plugin.test.PluginJarBuilder;
11  import com.google.common.collect.Sets;
12  import org.junit.Assert;
13  import org.junit.Rule;
14  import org.junit.Test;
15  import org.osgi.framework.Bundle;
16  import org.osgi.framework.Constants;
17  import org.osgi.framework.Version;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.Dictionary;
26  import java.util.HashMap;
27  import java.util.Hashtable;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.jar.JarFile;
31  import java.util.jar.Manifest;
32  
33  import static com.atlassian.plugin.test.CapturedLogging.didLogWarn;
34  import static org.hamcrest.Matchers.notNullValue;
35  import static org.hamcrest.Matchers.nullValue;
36  import static org.hamcrest.core.Is.is;
37  import static org.hamcrest.core.IsEqual.equalTo;
38  import static org.junit.Assert.assertEquals;
39  import static org.junit.Assert.assertFalse;
40  import static org.junit.Assert.assertThat;
41  import static org.junit.Assert.assertTrue;
42  import static org.mockito.Mockito.mock;
43  import static org.mockito.Mockito.when;
44  
45  public class TestOsgiHeaderUtil {
46  
47      @Rule
48      public final CapturedLogging capturedLogging = new CapturedLogging(OsgiHeaderUtil.class);
49  
50      @Test(expected = NullPointerException.class)
51      public void shouldAssertValueShouldNotBeNull() {
52          Manifest manifest = new Manifest();
53          OsgiHeaderUtil.getValidatedAttribute(manifest, "some-random-key");
54      }
55  
56      @Test(expected = IllegalArgumentException.class)
57      public void shouldAssertValueShouldNotBeEmpty() throws IOException {
58          Manifest manifest = generateManifest();
59          OsgiHeaderUtil.getValidatedAttribute(manifest, "Some-other");
60      }
61  
62      @Test(expected = IllegalArgumentException.class)
63      public void shouldRaiseAnExceptionWhenValueIsMissing() throws IOException {
64          Manifest manifest = generateManifest();
65          OsgiHeaderUtil.getNonEmptyAttribute(manifest, "Some-other");
66      }
67  
68      @Test
69      public void shouldGetValidatedAttribute() throws IOException {
70          Manifest manifestFile = generateManifest();
71          assertThat(OsgiHeaderUtil.getValidatedAttribute(manifestFile, "Import-Package"), equalTo("javax.swing"));
72      }
73  
74      @Test
75      public void shouldGetEmptyAttributeWithoutValidation() throws IOException {
76          Manifest manifest = generateManifest();
77          assertThat(OsgiHeaderUtil.getAttributeWithoutValidation(manifest, "Some-other"), is(""));
78      }
79  
80      @Test
81      public void shouldGetNullAttributeWithoutValidation() throws IOException {
82          Manifest manifest = generateManifest();
83          Assert.assertNull(OsgiHeaderUtil.getAttributeWithoutValidation(manifest, "some-random"));
84      }
85  
86      private Manifest generateManifest() throws IOException {
87          File bundle = new PluginJarBuilder("someplugin")
88                  .addResource("META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n" +
89                          "Import-Package: javax.swing\n" +
90                          "Bundle-SymbolicName: my.foo.symbolicName\n" +
91                          "Some-other: \n" +
92                          "Bundle-Version: 1.0\n")
93                  .build();
94          JarPluginArtifact jarPluginArtifact = new JarPluginArtifact(bundle);
95          InputStream descriptorClassStream = jarPluginArtifact.getResourceAsStream("META-INF/MANIFEST.MF");
96          return new Manifest(descriptorClassStream);
97      }
98  
99      @Test
100     public void testFindReferredPackages() throws IOException {
101         Set<String> foundPackages = OsgiHeaderUtil.findReferredPackageNames(Collections.singleton(OsgiHeaderUtil.class));
102 
103         assertTrue(foundPackages.contains(HostComponentRegistration.class.getPackage().getName()));
104     }
105 
106     @Test
107     public void testFindReferredPackagesMustNotReturnJavaPackages() throws IOException {
108         DummyClass dummy = mock(DummyClass.class);
109         Set<String> foundPackages = OsgiHeaderUtil.findReferredPackageNames(Collections.singleton(dummy.getClass()));
110 
111         assertFalse(foundPackages.contains("java.lang"));
112     }
113 
114     @Test
115     public void testFindReferredPackagesWithVersion() throws IOException {
116         Map<String, String> foundPackages = OsgiHeaderUtil.findReferredPackageVersions(new ArrayList<HostComponentRegistration>() {{
117             add(new StubHostComponentRegistration(OsgiHeaderUtil.class));
118         }}, Collections.singletonMap(HostComponentRegistration.class.getPackage().getName(), "1.0.45"));
119 
120         assertTrue(foundPackages.containsKey(HostComponentRegistration.class.getPackage().getName()));
121         assertEquals(foundPackages.get(HostComponentRegistration.class.getPackage().getName()), "1.0.45");
122     }
123 
124     @Test
125     public void testGetPluginKeyBundle() {
126         Dictionary<String, String> headers = new Hashtable<>();
127         headers.put(Constants.BUNDLE_VERSION, "1.0");
128         headers.put(Constants.BUNDLE_SYMBOLICNAME, "foo");
129 
130         Bundle bundle = mock(Bundle.class);
131         when(bundle.getSymbolicName()).thenReturn("foo");
132         when(bundle.getHeaders()).thenReturn(headers);
133 
134         assertEquals("foo-1.0", OsgiHeaderUtil.getPluginKey(bundle));
135 
136         headers.put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "bar");
137         assertEquals("bar", OsgiHeaderUtil.getPluginKey(bundle));
138     }
139 
140     @Test
141     public void testGetPluginKeyBundleWithDirectives() {
142         Dictionary<String, String> headers = new Hashtable<>();
143         headers.put(Constants.BUNDLE_VERSION, "1.0");
144         headers.put(Constants.BUNDLE_SYMBOLICNAME, "foo;singleton:=true");
145 
146         Bundle bundle = mock(Bundle.class);
147         when(bundle.getSymbolicName()).thenReturn("foo;singleton:=true");
148         when(bundle.getHeaders()).thenReturn(headers);
149 
150         assertThat("foo-1.0", equalTo(OsgiHeaderUtil.getPluginKey(bundle)));
151 
152         headers.put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "bar");
153         assertThat("bar", equalTo(OsgiHeaderUtil.getPluginKey(bundle)));
154     }
155 
156     @Test
157     public void testGetPluginKeyManifest() {
158         Manifest mf = new Manifest();
159         mf.getMainAttributes().putValue(Constants.BUNDLE_VERSION, "1.0");
160         mf.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, "foo");
161 
162         assertEquals("foo-1.0", OsgiHeaderUtil.getPluginKey(mf));
163 
164         mf.getMainAttributes().putValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "bar");
165         assertEquals("bar", OsgiHeaderUtil.getPluginKey(mf));
166     }
167 
168     @Test
169     public void testGetPluginKeyManifestWithDirectives() {
170         Manifest mf = new Manifest();
171         mf.getMainAttributes().putValue(Constants.BUNDLE_VERSION, "1.0");
172         mf.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, "foo;singleton:=true");
173 
174         assertThat("foo-1.0", equalTo(OsgiHeaderUtil.getPluginKey(mf)));
175 
176         mf.getMainAttributes().putValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "bar");
177         assertThat("bar", equalTo(OsgiHeaderUtil.getPluginKey(mf)));
178     }
179 
180     @Test
181     public void testGeneratePackageVersionString() {
182         Map<String, String> input = new HashMap<>();
183         input.put("foo.bar", "1.2");
184         input.put("foo.baz", Version.emptyVersion.toString());
185 
186         String output = OsgiHeaderUtil.generatePackageVersionString(input);
187 
188         Set<String> set = Sets.newHashSet(output.split("[,]"));
189 
190         assertTrue(set.contains("foo.bar;version=1.2"));
191         assertTrue(set.contains("foo.baz"));
192         assertEquals(2, set.size());
193     }
194 
195     @Test
196     public void getManifestGetsManifest() {
197         final String manifestString = "Manifest-Version: 1.0\r\nSome-Header: some value\r\n";
198         final PluginArtifact pluginArtifact = getPluginArtifactWithManifest(manifestString);
199         final Manifest manifest = OsgiHeaderUtil.getManifest(pluginArtifact);
200         assertThat(manifest, notNullValue());
201         assertThat(manifest.getMainAttributes().getValue("Some-Header"), is("some value"));
202     }
203 
204     @Test
205     public void getManifestReturnsNullIfManifestIsMissing() {
206         final PluginArtifact pluginArtifact = mock(PluginArtifact.class);
207         // Mockito defaults return null, which is correct for missing resource
208         final Manifest manifest = OsgiHeaderUtil.getManifest(pluginArtifact);
209         assertThat(manifest, nullValue());
210     }
211 
212     @Test
213     public void getManifestReturnsNullIfGetResourceAsStreamFails() {
214         final PluginArtifact pluginArtifact = mock(PluginArtifact.class);
215         when(pluginArtifact.getResourceAsStream(JarFile.MANIFEST_NAME))
216                 .thenThrow(new PluginParseException("Intentional test fail"));
217         final Manifest manifest = OsgiHeaderUtil.getManifest(pluginArtifact);
218         assertThat(manifest, nullValue());
219     }
220 
221     @Test
222     public void getManifestReturnsNullIfResourceStreamThrowsWhenRead() {
223         final InputStream inputStream = new InputStream() {
224             @Override
225             public int read() throws IOException {
226                 throw new IOException("Intentional test fail");
227             }
228         };
229         final PluginArtifact pluginArtifact = mock(PluginArtifact.class);
230         when(pluginArtifact.getResourceAsStream(JarFile.MANIFEST_NAME)).thenReturn(inputStream);
231         final Manifest manifest = OsgiHeaderUtil.getManifest(pluginArtifact);
232         assertThat(manifest, nullValue());
233     }
234 
235     @Test
236     public void getManifestReturnsNullIfManifestIsCorrupt() {
237         // Malformed, because you need a ' ' after the header ':'
238         final String manifestString = "Manifest-Version: 1.0\r\nSome-Header:some value\r\n";
239         final PluginArtifact pluginArtifact = getPluginArtifactWithManifest(manifestString);
240         final Manifest manifest = OsgiHeaderUtil.getManifest(pluginArtifact);
241         assertThat(manifest, nullValue());
242     }
243 
244     @Test
245     public void moveStarPackagesToEndComplex() {
246 
247         final Map<String, Map<String, String>> input = new HashMap<>();
248         input.put("javax.servlet*", new HashMap<>());
249         input.put("javax.servlet*~", new HashMap<>());
250         input.put("*", new HashMap<>());
251         input.put("*~", new HashMap<>());
252         input.put("javax.servlet", new HashMap<>());
253         input.put("javax.servlet~", new HashMap<>());
254         input.put("org.apache.lucene.search", new HashMap<>());
255 
256         final Map<String, Map<String, String>> output = new HashMap<>();
257         output.put("javax.servlet", new HashMap<>());
258         output.put("javax.servlet~", new HashMap<>());
259         output.put("org.apache.lucene.search", new HashMap<>());
260         output.put("javax.servlet*", new HashMap<>());
261         output.put("javax.servlet*~", new HashMap<>());
262         output.put("*", new HashMap<>());
263         output.put("*~", new HashMap<>());
264 
265         assertThat(OsgiHeaderUtil.moveStarPackageToEnd(input, "myplugin"), is(output));
266     }
267 
268     @Test
269     public void moveStarPackagesToEndEmpty() {
270         final Map<String, Map<String, String>> input = new HashMap<>();
271         final Map<String, Map<String, String>> output = new HashMap<>();
272         assertThat(OsgiHeaderUtil.moveStarPackageToEnd(input, "myplugin"), is(output));
273     }
274 
275     @Test
276     public void stripDuplicatePackagesWithDuplicates() {
277 
278         final Map<String, Map<String, String>> input = new HashMap<>();
279         input.put("some.package", new HashMap<>());
280         input.put("some.package~", new HashMap<>());
281         input.put("some.other.package~", new HashMap<>());
282 
283         final Map<String, Map<String, String>> output = new HashMap<>();
284         output.put("some.package", new HashMap<>());
285 
286         assertThat(OsgiHeaderUtil.stripDuplicatePackages(input, "myplugin", "myaction"), is(output));
287 
288         assertThat(capturedLogging, didLogWarn("removing duplicate", "myplugin", "myaction", "some.package~"));
289     }
290 
291     @Test
292     public void stripDuplicatePackagesEmpty() {
293         final Map<String, Map<String, String>> input = new HashMap<>();
294         final Map<String, Map<String, String>> output = new HashMap<>();
295         assertThat(OsgiHeaderUtil.stripDuplicatePackages(input, "myplugin", "myaction"), is(output));
296     }
297 
298     private PluginArtifact getPluginArtifactWithManifest(final String manifestString) {
299         final PluginArtifact pluginArtifact = mock(PluginArtifact.class);
300         final ByteArrayInputStream manifestStream = new ByteArrayInputStream(manifestString.getBytes());
301         when(pluginArtifact.getResourceAsStream(JarFile.MANIFEST_NAME)).thenReturn(manifestStream);
302         return pluginArtifact;
303     }
304 
305     private interface DummyClass {
306         void doSomething(Object obj);
307     }
308 
309 }