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
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
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 }