1 package com.atlassian.plugin.osgi.factory.transform.stage;
2
3 import com.atlassian.plugin.PluginAccessor;
4 import com.atlassian.plugin.PluginParseException;
5 import com.atlassian.plugin.JarPluginArtifact;
6 import com.atlassian.plugin.util.PluginUtils;
7 import com.atlassian.plugin.osgi.factory.transform.TransformContext;
8 import com.atlassian.plugin.osgi.factory.transform.model.SystemExports;
9 import com.atlassian.plugin.osgi.factory.OsgiPlugin;
10 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
11 import com.atlassian.plugin.test.PluginJarBuilder;
12
13 import org.apache.log4j.Logger;
14 import org.apache.log4j.spi.Filter;
15 import org.apache.commons.logging.Log;
16 import org.osgi.framework.Constants;
17 import static org.mockito.Mockito.mock;
18 import static org.mockito.Mockito.verify;
19 import static org.mockito.Matchers.contains;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.PrintStream;
25 import java.io.ByteArrayOutputStream;
26 import java.net.URISyntaxException;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.jar.Attributes;
31 import java.util.jar.Manifest;
32 import java.lang.reflect.Field;
33
34 import javax.print.attribute.AttributeSet;
35
36 import junit.framework.TestCase;
37
38 public class TestGenerateManifestStage extends TestCase
39 {
40 private GenerateManifestStage stage;
41
42 @Override
43 public void setUp()
44 {
45 stage = new GenerateManifestStage();
46 }
47
48 public void testGenerateManifest() throws Exception
49 {
50 final File file = new PluginJarBuilder()
51 .addFormattedResource(
52 "atlassian-plugin.xml",
53 "<atlassian-plugin key='com.atlassian.plugins.example' name='Example Plugin'>",
54 " <plugin-info>",
55 " <description>",
56 " A sample plugin for demonstrating the file format.",
57 " </description>",
58 " <version>1.1</version>",
59 " <vendor name='Atlassian Software Systems Pty Ltd' url='http://www.atlassian.com'/>",
60 " </plugin-info>",
61 "</atlassian-plugin>")
62 .addFormattedJava(
63 "com.mycompany.myapp.Foo",
64 "package com.mycompany.myapp; public class Foo {}")
65 .build();
66
67 final TransformContext context = new TransformContext(Collections.<HostComponentRegistration> emptyList(), SystemExports.NONE, new JarPluginArtifact(file),
68 null, PluginAccessor.Descriptor.FILENAME);
69 context.setShouldRequireSpring(true);
70
71 final Attributes attrs = executeStage(context);
72
73 assertEquals("1.1", attrs.getValue(Constants.BUNDLE_VERSION));
74 assertEquals("com.atlassian.plugins.example", attrs.getValue(Constants.BUNDLE_SYMBOLICNAME));
75 assertEquals("A sample plugin for demonstrating the file format.", attrs.getValue(Constants.BUNDLE_DESCRIPTION));
76 assertEquals("Atlassian Software Systems Pty Ltd", attrs.getValue(Constants.BUNDLE_VENDOR));
77 assertEquals("http://www.atlassian.com", attrs.getValue(Constants.BUNDLE_DOCURL));
78 assertEquals(null, attrs.getValue(Constants.EXPORT_PACKAGE));
79 assertEquals(".", attrs.getValue(Constants.BUNDLE_CLASSPATH));
80 assertEquals("com.atlassian.plugins.example", attrs.getValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY));
81 assertEquals("*;timeout:=60", attrs.getValue("Spring-Context"));
82 assertEquals(null, attrs.getValue(Constants.IMPORT_PACKAGE));
83
84 }
85
86 public void testGenerateManifestWithProperInferredImports() throws Exception
87 {
88
89 final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0").build();
90 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(file), null, PluginAccessor.Descriptor.FILENAME);
91 context.getExtraImports().add(AttributeSet.class.getPackage().getName());
92 final Attributes attrs = executeStage(context);
93
94 assertTrue(attrs.getValue(Constants.IMPORT_PACKAGE).contains(AttributeSet.class.getPackage().getName()));
95
96 }
97
98 public void testGenerateManifestWithCustomTimeout() throws Exception
99 {
100 try
101 {
102 System.setProperty(PluginUtils.ATLASSIAN_PLUGINS_ENABLE_WAIT, "333");
103 stage = new GenerateManifestStage();
104 final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0").build();
105 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(file), null, PluginAccessor.Descriptor.FILENAME);
106 context.setShouldRequireSpring(true);
107 final Attributes attrs = executeStage(context);
108
109 assertEquals("*;timeout:=333", attrs.getValue("Spring-Context"));
110 }
111 finally
112 {
113 System.clearProperty(PluginUtils.ATLASSIAN_PLUGINS_ENABLE_WAIT);
114 }
115
116 }
117
118 public void testGenerateManifestMergeHostComponentImportsWithExisting() throws Exception
119 {
120 final File plugin = new PluginJarBuilder("plugin")
121 .addFormattedResource("META-INF/MANIFEST.MF",
122 "Manifest-Version: 1.0",
123 "Import-Package: javax.swing",
124 "Bundle-SymbolicName: my.foo.symbolicName",
125 "Bundle-ClassPath: .,foo")
126 .addResource("foo/bar.txt", "Something")
127 .addPluginInformation("innerjarcp", "Some name", "1.0")
128 .build();
129
130 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
131 context.getExtraImports().add(AttributeSet.class.getPackage().getName());
132 final Attributes attrs = executeStage(context);
133 assertEquals("my.foo.symbolicName", attrs.getValue(Constants.BUNDLE_SYMBOLICNAME));
134 assertEquals(".,foo", attrs.getValue(Constants.BUNDLE_CLASSPATH));
135 assertEquals("innerjarcp", attrs.getValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY));
136 final String importPackage = attrs.getValue(Constants.IMPORT_PACKAGE);
137 assertTrue(importPackage.contains(AttributeSet.class.getPackage().getName()+","));
138 assertTrue(importPackage.contains("javax.swing"));
139
140 }
141
142 public void testGenerateManifestNoSpring() throws Exception
143 {
144 final File plugin = new PluginJarBuilder("plugin")
145 .addFormattedResource("META-INF/MANIFEST.MF",
146 "Manifest-Version: 1.0",
147 "Bundle-SymbolicName: my.foo.symbolicName",
148 "Bundle-Version: 1.0",
149 "Bundle-ClassPath: .,foo")
150 .addResource("foo/bar.txt", "Something")
151 .addPluginInformation("innerjarcp", "Some name", "1.0")
152 .build();
153
154 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
155 final Attributes attrs = executeStage(context);
156 assertEquals("innerjarcp", attrs.getValue("Atlassian-Plugin-Key"));
157
158 }
159
160 public void testGenerateManifestInvalidVersionWithExisting() throws Exception
161 {
162 final File plugin = new PluginJarBuilder("plugin")
163 .addFormattedResource("META-INF/MANIFEST.MF",
164 "Manifest-Version: 1.0",
165 "Bundle-SymbolicName: my.foo.symbolicName",
166 "Bundle-Version: beta1",
167 "Bundle-ClassPath: .,foo\n")
168 .addResource("foo/bar.txt", "Something")
169 .addPluginInformation("innerjarcp", "Some name", "1.0")
170 .build();
171
172 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
173 try
174 {
175 executeStage(context);
176 fail("Should have complained about bad plugin version");
177 }
178 catch (PluginParseException ex)
179 {
180 ex.printStackTrace();
181
182 }
183 }
184
185 public void testGenerateManifestInvalidVersion() throws Exception
186 {
187 final File plugin = new PluginJarBuilder("plugin")
188 .addPluginInformation("innerjarcp", "Some name", "beta1.0")
189 .build();
190
191 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
192 try
193 {
194 executeStage(context);
195 fail("Should have complained about bad plugin version");
196 }
197 catch (PluginParseException ex)
198 {
199 ex.printStackTrace();
200
201 }
202
203 }
204
205 public void testGenerateManifestSimplePluginNoSpring() throws Exception
206 {
207 final File plugin = new PluginJarBuilder("plugin")
208 .addResource("foo/bar.txt", "Something")
209 .addPluginInformation("innerjarcp", "Some name", "1.0")
210 .build();
211
212 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
213 final Attributes attrs = executeStage(context);
214 assertEquals("innerjarcp", attrs.getValue("Atlassian-Plugin-Key"));
215 assertNull(attrs.getValue("Spring-Context"));
216
217 }
218
219 public void testGenerateManifestWarnNoSpringWithExisting() throws Exception
220 {
221 Log log = mock(Log.class);
222 GenerateManifestStage.log = log;
223
224 final File plugin = new PluginJarBuilder("plugin")
225 .addFormattedResource("META-INF/MANIFEST.MF",
226 "Manifest-Version: 1.0",
227 "Import-Package: javax.swing",
228 "Bundle-SymbolicName: my.foo.symbolicName",
229 "Bundle-ClassPath: .,foo")
230 .addResource("foo/bar.txt", "Something")
231 .addPluginInformation("innerjarcp", "Some name", "1.0")
232 .build();
233
234 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
235 context.setShouldRequireSpring(true);
236 context.getExtraImports().add(AttributeSet.class.getPackage().getName());
237
238 Attributes attrs = executeStage(context);
239 assertEquals("innerjarcp", attrs.getValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY));
240 verify(log).debug(contains("'Spring-Context' is missing"));
241 }
242
243 public void testGenerateManifestWarnNoTimeout() throws Exception
244 {
245 Log log = mock(Log.class);
246 GenerateManifestStage.log = log;
247
248 final File plugin = new PluginJarBuilder("plugin")
249 .addFormattedResource("META-INF/MANIFEST.MF",
250 "Manifest-Version: 1.0",
251 "Import-Package: javax.swing",
252 "Bundle-SymbolicName: my.foo.symbolicName",
253 "Spring-Context: *",
254 "Bundle-ClassPath: .,foo")
255 .addResource("foo/bar.txt", "Something")
256 .addPluginInformation("innerjarcp", "Some name", "1.0")
257 .build();
258
259 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
260 context.setShouldRequireSpring(true);
261 context.getExtraImports().add(AttributeSet.class.getPackage().getName());
262 executeStage(context);
263 verify(log).warn(contains("Please add ';timeout:=60'"));
264 }
265
266
267 public void testGenerateManifest_innerjars() throws URISyntaxException, PluginParseException, IOException
268 {
269 final File innerJar = new PluginJarBuilder("innerjar1").build();
270 final File innerJar2 = new PluginJarBuilder("innerjar2").build();
271 final File plugin = new PluginJarBuilder("plugin")
272 .addFile("META-INF/lib/innerjar.jar", innerJar)
273 .addFile("META-INF/lib/innerjar2.jar", innerJar2)
274 .addPluginInformation("innerjarcp", "Some name", "1.0")
275 .build();
276
277 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
278 final Attributes attrs = executeStage(context);
279
280 final Collection classpathEntries = Arrays.asList(attrs.getValue(Constants.BUNDLE_CLASSPATH).split(","));
281 assertEquals(3, classpathEntries.size());
282 assertTrue(classpathEntries.contains("."));
283 assertTrue(classpathEntries.contains("META-INF/lib/innerjar.jar"));
284 assertTrue(classpathEntries.contains("META-INF/lib/innerjar2.jar"));
285 }
286
287 public void testGenerateManifest_innerjarsInImports() throws Exception, PluginParseException, IOException
288 {
289 final File innerJar = new PluginJarBuilder("innerjar")
290 .addFormattedJava("my.Foo",
291 "package my;",
292 "import org.apache.log4j.Logger;",
293 "public class Foo{",
294 " Logger log;",
295 "}")
296 .build();
297 assertNotNull(innerJar);
298 final File plugin = new PluginJarBuilder("plugin")
299 .addJava("my.Bar", "package my;import org.apache.log4j.spi.Filter; public class Bar{Filter log;}")
300 .addFile("META-INF/lib/innerjar.jar", innerJar)
301 .addPluginInformation("innerjarcp", "Some name", "1.0")
302 .build();
303
304 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
305 final Attributes attrs = executeStage(context);
306
307 assertEquals("1.0", attrs.getValue(Constants.BUNDLE_VERSION));
308 assertEquals("innerjarcp", attrs.getValue(Constants.BUNDLE_SYMBOLICNAME));
309
310 final Collection classpathEntries = Arrays.asList(attrs.getValue(Constants.BUNDLE_CLASSPATH).split(","));
311 assertEquals(2, classpathEntries.size());
312 assertTrue(classpathEntries.contains("."));
313 assertTrue(classpathEntries.contains("META-INF/lib/innerjar.jar"));
314
315 final Collection imports = Arrays.asList(attrs.getValue("Import-Package").split(","));
316 assertEquals(2, imports.size());
317 assertTrue(imports.contains(Logger.class.getPackage().getName() + ";resolution:=\"optional\""));
318 assertTrue(imports.contains(Filter.class.getPackage().getName() + ";resolution:=\"optional\""));
319 }
320
321 public void testGenerateManifestWithBundleInstructions() throws Exception
322 {
323 final File plugin = new PluginJarBuilder("plugin")
324 .addPluginInformation("test.plugin", "test.plugin", "1.0")
325 .addJava("foo.MyClass", "package foo; public class MyClass{}")
326 .addJava("foo.internal.MyPrivateClass", "package foo.internal; public class MyPrivateClass{}")
327 .build();
328
329 final TransformContext context = new TransformContext(null, SystemExports.NONE, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
330 context.getBndInstructions().put("Export-Package", "!*.internal.*,*");
331 final Attributes attrs = executeStage(context);
332 assertEquals("test.plugin", attrs.getValue(Constants.BUNDLE_SYMBOLICNAME));
333 assertEquals("foo", attrs.getValue(Constants.EXPORT_PACKAGE));
334 }
335
336 public void testGenerateManifestWithHostAndExternalImports() throws Exception
337 {
338 final File plugin = new PluginJarBuilder("plugin")
339 .addPluginInformation("test.plugin", "test.plugin", "1.0")
340 .build();
341
342 SystemExports exports = new SystemExports("foo.bar,foo.baz;version=\"1.0\"");
343 final TransformContext context = new TransformContext(null, exports, new JarPluginArtifact(plugin), null, PluginAccessor.Descriptor.FILENAME);
344 context.getBndInstructions().put("Import-Package", "foo.bar,foo.baz");
345 final Attributes attrs = executeStage(context);
346 assertEquals("test.plugin", attrs.getValue(Constants.BUNDLE_SYMBOLICNAME));
347
348 String imports = attrs.getValue(Constants.IMPORT_PACKAGE);
349 assertTrue(imports.contains("foo.baz;version=\"[1.0,1.0]\""));
350 assertTrue(imports.contains("foo.bar"));
351 }
352
353 private Attributes executeStage(final TransformContext context) throws IOException
354 {
355 stage.execute(context);
356 final Manifest mf = new Manifest(new ByteArrayInputStream(context.getFileOverrides().get("META-INF/MANIFEST.MF")));
357 final Attributes attrs = mf.getMainAttributes();
358 return attrs;
359 }
360 }