View Javadoc

1   package com.atlassian.plugin.osgi.factory.transform.stage;
2   
3   import com.atlassian.plugin.JarPluginArtifact;
4   import com.atlassian.plugin.PluginAccessor;
5   import com.atlassian.plugin.PluginParseException;
6   import com.atlassian.plugin.osgi.container.OsgiContainerManager;
7   import com.atlassian.plugin.osgi.factory.OsgiPlugin;
8   import com.atlassian.plugin.osgi.factory.transform.TransformContext;
9   import com.atlassian.plugin.osgi.factory.transform.model.SystemExports;
10  import com.atlassian.plugin.test.CapturedLogging;
11  import com.atlassian.plugin.test.PluginJarBuilder;
12  import com.google.common.collect.ImmutableMap;
13  import org.apache.log4j.spi.Filter;
14  import org.junit.Before;
15  import org.junit.Rule;
16  import org.junit.Test;
17  import org.junit.contrib.java.lang.system.RestoreSystemProperties;
18  import org.junit.rules.ExpectedException;
19  import org.osgi.framework.Constants;
20  import org.osgi.framework.ServiceReference;
21  
22  import java.io.ByteArrayInputStream;
23  import java.io.File;
24  import java.io.IOException;
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.jar.Attributes;
28  import java.util.jar.Manifest;
29  import javax.print.attribute.AttributeSet;
30  
31  import static com.atlassian.plugin.test.CapturedLogging.didLogWarn;
32  import static com.atlassian.plugin.util.PluginUtils.ATLASSIAN_DEV_MODE;
33  import static com.atlassian.plugin.util.PluginUtils.ATLASSIAN_PLUGINS_ENABLE_WAIT;
34  import static org.hamcrest.MatcherAssert.assertThat;
35  import static org.hamcrest.Matchers.containsInAnyOrder;
36  import static org.hamcrest.Matchers.containsString;
37  import static org.hamcrest.Matchers.is;
38  import static org.hamcrest.Matchers.notNullValue;
39  import static org.hamcrest.Matchers.nullValue;
40  import static org.mockito.Mockito.mock;
41  import static org.mockito.Mockito.when;
42  
43  public class TestGenerateManifestStage
44  {
45      @Rule
46      public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(
47              ATLASSIAN_PLUGINS_ENABLE_WAIT, ATLASSIAN_DEV_MODE
48      );
49  
50      @Rule
51      public ExpectedException expectedException = ExpectedException.none();
52  
53      @Rule
54      public CapturedLogging capturedLogging = new CapturedLogging(GenerateManifestStage.class);
55  
56      private GenerateManifestStage stage;
57      private OsgiContainerManager osgiContainerManager;
58  
59      @Before
60      public void setUp()
61      {
62          stage = new GenerateManifestStage();
63          osgiContainerManager = mock(OsgiContainerManager.class);
64          when(osgiContainerManager.getRegisteredServices()).thenReturn(new ServiceReference[0]);
65      }
66  
67      @Test
68      public void testGenerateManifest() throws Exception
69      {
70          final File file = new PluginJarBuilder()
71                  .addFormattedResource(
72                          "atlassian-plugin.xml",
73                          "<atlassian-plugin key='com.atlassian.plugins.example' name='Example Plugin'>",
74                          "  <plugin-info>",
75                          "    <description>",
76                          "      A sample plugin for demonstrating the file format.",
77                          "    </description>",
78                          "    <version>1.1</version>",
79                          "    <vendor name='Atlassian Software Systems Pty Ltd' url='http://www.atlassian.com'/>",
80                          "  </plugin-info>",
81                          "</atlassian-plugin>")
82                  .addFormattedJava(
83                          "com.mycompany.myapp.Foo",
84                          "package com.mycompany.myapp; public class Foo {}")
85                  .build();
86  
87          final TransformContext context = getTransformContext(file, SystemExports.NONE);
88          context.setShouldRequireSpring(true);
89  
90          final Attributes attrs = executeStage(context);
91  
92          assertThat(attrs.getValue(Constants.BUNDLE_VERSION), is("1.1"));
93          assertThat(attrs.getValue(Constants.BUNDLE_SYMBOLICNAME), is("com.atlassian.plugins.example"));
94          assertThat(attrs.getValue(Constants.BUNDLE_DESCRIPTION), is("A sample plugin for demonstrating the file format."));
95          assertThat(attrs.getValue(Constants.BUNDLE_VENDOR), is("Atlassian Software Systems Pty Ltd"));
96          assertThat(attrs.getValue(Constants.BUNDLE_DOCURL), is("http://www.atlassian.com"));
97          assertThat(attrs.getValue(Constants.EXPORT_PACKAGE), nullValue());
98          assertThat(attrs.getValue(Constants.BUNDLE_CLASSPATH), is("."));
99          assertThat(attrs.getValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY), is("com.atlassian.plugins.example"));
100         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=60"));
101         assertThat(attrs.getValue(Constants.IMPORT_PACKAGE), nullValue());
102     }
103 
104     @Test
105     public void testGenerateManifestWithProperInferredImports() throws Exception
106     {
107 
108         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0").build();
109         final TransformContext context = getTransformContext(file, SystemExports.NONE);
110         context.getExtraImports().add(AttributeSet.class.getPackage().getName());
111         final Attributes attrs = executeStage(context);
112 
113         assertThat(attrs.getValue(Constants.IMPORT_PACKAGE), containsString(AttributeSet.class.getPackage().getName()));
114 
115     }
116 
117     @Test
118     public void testGenerateManifestWithCustomTimeout() throws Exception
119     {
120         System.setProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT, "333");
121         stage = new GenerateManifestStage();
122         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0").build();
123         final TransformContext context = getTransformContext(file, SystemExports.NONE);
124         context.setShouldRequireSpring(true);
125         final Attributes attrs = executeStage(context);
126 
127         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=333"));
128     }
129 
130     @Test
131     public void testGenerateManifestWithExistingSpringContextTimeout() throws Exception
132     {
133         System.setProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT, "333");
134         stage = new GenerateManifestStage();
135         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
136                 .addFormattedResource(
137                         "META-INF/MANIFEST.MF",
138                         "Manifest-Version: 1.0",
139                         "Spring-Context: *;timeout:=60",
140                         "Bundle-Version: 4.2.0.jira40",
141                         "Bundle-SymbolicName: my.foo.symbolicName")
142                 .build();
143         final TransformContext context = getTransformContext(file, SystemExports.NONE);
144         context.setShouldRequireSpring(true);
145         final Attributes attrs = executeStage(context);
146 
147         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=333"));
148     }
149 
150     @Test
151     public void testGenerateManifestWithExistingSpringContextTimeoutNoSystemProperty() throws Exception
152     {
153         stage = new GenerateManifestStage();
154         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
155                 .addFormattedResource("META-INF/MANIFEST.MF",
156                         "Manifest-Version: 1.0",
157                         "Spring-Context: *;timeout:=60",
158                         "Bundle-Version: 4.2.0.jira40",
159                         "Bundle-SymbolicName: my.foo.symbolicName")
160                 .build();
161         final TransformContext context = getTransformContext(file, SystemExports.NONE);
162         context.setShouldRequireSpring(true);
163         final Attributes attrs = executeStage(context);
164 
165         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=60"));
166     }
167 
168     @Test
169     public void testGenerateManifestSpringContextTimeoutNoTimeoutInHeader() throws Exception
170     {
171         System.setProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT, "789");
172         stage = new GenerateManifestStage();
173         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
174                 .addFormattedResource("META-INF/MANIFEST.MF",
175                         "Manifest-Version: 1.0",
176                         "Spring-Context: *;create-asynchronously:=false",
177                         "Bundle-Version: 4.2.0.jira40",
178                         "Bundle-SymbolicName: my.foo.symbolicName")
179                 .build();
180         final TransformContext context = getTransformContext(file, SystemExports.NONE);
181         context.setShouldRequireSpring(true);
182         final Attributes attrs = executeStage(context);
183         assertThat(attrs.getValue("Spring-Context"), is("*;create-asynchronously:=false;timeout:=789"));
184     }
185 
186     @Test
187     public void testGenerateManifestSpringContextTimeoutTimeoutAtTheBeginning() throws Exception
188     {
189         System.setProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT, "789");
190         stage = new GenerateManifestStage();
191         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
192                 .addFormattedResource("META-INF/MANIFEST.MF",
193                         "Manifest-Version: 1.0",
194                         "Spring-Context: timeout:=123;config/account-data-context.xml;create-asynchrously:=false",
195                         "Bundle-Version: 4.2.0.jira40",
196                         "Bundle-SymbolicName: my.foo.symbolicName")
197                 .build();
198         final TransformContext context = getTransformContext(file, SystemExports.NONE);
199         context.setShouldRequireSpring(true);
200         final Attributes attrs = executeStage(context);
201         assertThat(attrs.getValue("Spring-Context"), is("timeout:=789;config/account-data-context.xml;create-asynchrously:=false"));
202     }
203 
204     @Test
205     public void testGenerateManifestSpringContextTimeoutTimeoutInTheMiddle() throws Exception
206     {
207         System.setProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT, "789");
208         stage = new GenerateManifestStage();
209         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
210                 .addFormattedResource("META-INF/MANIFEST.MF",
211                         "Manifest-Version: 1.0",
212                         "Spring-Context: config/account-data-context.xml;timeout:=123;create-asynchrously:=false",
213                         "Bundle-Version: 4.2.0.jira40",
214                         "Bundle-SymbolicName: my.foo.symbolicName")
215                 .build();
216         final TransformContext context = getTransformContext(file, SystemExports.NONE);
217         context.setShouldRequireSpring(true);
218         final Attributes attrs = executeStage(context);
219         assertThat(attrs.getValue("Spring-Context"), is("config/account-data-context.xml;timeout:=789;create-asynchrously:=false"));
220     }
221 
222 
223     @Test
224     public void testGenerateManifestMergeHostComponentImportsWithExisting() throws Exception
225     {
226         final File plugin = new PluginJarBuilder("plugin")
227                 .addFormattedResource("META-INF/MANIFEST.MF",
228                         "Manifest-Version: 1.0",
229                         "Import-Package: javax.swing",
230                         "Bundle-SymbolicName: my.foo.symbolicName",
231                         "Bundle-Version: 1.0",
232                         "Bundle-ClassPath: .,foo")
233                 .addResource("foo/bar.txt", "Something")
234                 .addPluginInformation("innerjarcp", "Some name", "1.0")
235                 .build();
236 
237         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
238         context.getExtraImports().add(AttributeSet.class.getPackage().getName());
239         final Attributes attrs = executeStage(context);
240         assertThat(attrs.getValue(Constants.BUNDLE_SYMBOLICNAME), is("my.foo.symbolicName"));
241         assertThat(attrs.getValue(Constants.BUNDLE_CLASSPATH), is(".,foo"));
242         assertThat(attrs.getValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY), is("innerjarcp"));
243         final String importPackage = attrs.getValue(Constants.IMPORT_PACKAGE);
244         assertThat(importPackage, containsString(AttributeSet.class.getPackage().getName()));
245         assertThat(importPackage, containsString("javax.swing"));
246     }
247 
248     @Test
249     public void testGenerateManifestInvalidVersionWithExisting() throws Exception
250     {
251         final File plugin = new PluginJarBuilder("plugin")
252                 .addFormattedResource("META-INF/MANIFEST.MF",
253                         "Manifest-Version: 1.0",
254                         "Bundle-SymbolicName: my.foo.symbolicName",
255                         "Bundle-Version: beta1",
256                         "Bundle-ClassPath: .,foo\n")
257                 .addResource("foo/bar.txt", "Something")
258                 .addPluginInformation("innerjarcp", "Some name", "1.0")
259                 .build();
260 
261         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
262         expectedException.expect(PluginParseException.class);
263         executeStage(context);
264     }
265 
266     @Test
267     public void testGenerateManifestInvalidVersion() throws Exception
268     {
269         final File plugin = new PluginJarBuilder("plugin")
270                 .addPluginInformation("innerjarcp", "Some name", "beta1.0")
271                 .build();
272 
273         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
274         expectedException.expect(PluginParseException.class);
275         executeStage(context);
276     }
277 
278     @Test
279     public void testGenerateManifestWithExistingManifestNoSpringButDescriptor() throws Exception
280     {
281         final File plugin = new PluginJarBuilder("plugin")
282                 .addFormattedResource("META-INF/MANIFEST.MF",
283                         "Manifest-Version: 1.0",
284                         "Bundle-SymbolicName: my.foo.symbolicName",
285                         "Bundle-Version: 1.0",
286                         "Bundle-ClassPath: .,foo")
287                 .addResource("foo/bar.txt", "Something")
288                 .addPluginInformation("innerjarcp", "Some name", "1.0")
289                 .build();
290 
291         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
292         final Attributes attrs = executeStage(context);
293         assertThat(attrs.getValue("Atlassian-Plugin-Key"), is("innerjarcp"));
294         assertThat(attrs.getValue("Spring-Context"), notNullValue());
295     }
296 
297     @Test
298     public void testThatGeneratingManifestWithExistingManifestWithSimilarSpringAndAtlassianPluginKeyDoesNotRecreateTheManifest()
299             throws Exception
300     {
301         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
302                 .addFormattedResource("META-INF/MANIFEST.MF",
303                         "Manifest-Version: 1.0",
304                         "Spring-Context: *;timeout:=60",
305                         "Atlassian-Plugin-Key: someKey",
306                         "Bundle-Version: 4.2.0.jira40",
307                         "Bundle-SymbolicName: my.foo.symbolicName")
308                 .build();
309 
310         final TransformContext context = getTransformContext(file, SystemExports.NONE);
311         final Attributes attrs = executeStage(context);
312         assertThat(attrs.getValue("Atlassian-Plugin-Key"), is("someKey"));
313         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=60"));
314         assertThat(context.getFileOverrides().get("META-INF/MANIFEST.MF"), nullValue());
315     }
316 
317     @Test
318     public void testThatGeneratingManifestWithExistingManifestWithDifferentSpringTimeoutRecreatesTheManifest() throws Exception
319     {
320         System.setProperty(ATLASSIAN_PLUGINS_ENABLE_WAIT, "333");
321         stage = new GenerateManifestStage();
322         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
323                 .addFormattedResource("META-INF/MANIFEST.MF",
324                         "Manifest-Version: 1.0",
325                         "Spring-Context: *;timeout:=60",
326                         "Atlassian-Plugin-Key: someKey",
327                         "Bundle-Version: 4.2.0.jira40",
328                         "Bundle-SymbolicName: my.foo.symbolicName")
329                 .build();
330 
331         final TransformContext context = getTransformContext(file, SystemExports.NONE);
332         final Attributes attrs = executeStage(context);
333         assertThat(attrs.getValue("Atlassian-Plugin-Key"), is("someKey"));
334         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=333"));
335         assertThat(context.getFileOverrides().get("META-INF/MANIFEST.MF"), notNullValue());
336     }
337 
338     @Test
339     public void testThatGeneratingManifestWithExistingManifestWithDifferentAtlassianPluginKeyRecreatesTheManifest() throws Exception
340     {
341         final File file = new PluginJarBuilder().addPluginInformation("someKey", "someName", "1.0")
342                 .addFormattedResource("META-INF/MANIFEST.MF",
343                         "Manifest-Version: 1.0",
344                         "Spring-Context: *;timeout:=60",
345                         "Atlassian-Plugin-Key: anotherKey",
346                         "Bundle-Version: 4.2.0.jira40",
347                         "Bundle-SymbolicName: my.foo.symbolicName")
348                 .build();
349 
350         final TransformContext context = getTransformContext(file, SystemExports.NONE);
351         final Attributes attrs = executeStage(context);
352         assertThat(attrs.getValue("Atlassian-Plugin-Key"), is("someKey"));
353         assertThat(attrs.getValue("Spring-Context"), is("*;timeout:=60"));
354         assertThat(context.getFileOverrides().get("META-INF/MANIFEST.MF"), notNullValue());
355     }
356 
357     @Test
358     public void testGenerateManifestWithExistingManifestWithSpringWithDescriptor() throws Exception
359     {
360         final File plugin = new PluginJarBuilder("plugin")
361                 .addFormattedResource("META-INF/MANIFEST.MF",
362                         "Manifest-Version: 1.0",
363                         "Bundle-SymbolicName: my.foo.symbolicName",
364                         "Bundle-Version: 1.0",
365                         "Spring-Context: *",
366                         "Bundle-ClassPath: .,foo")
367                 .addResource("foo/bar.txt", "Something")
368                 .addPluginInformation("innerjarcp", "Some name", "1.0")
369                 .build();
370 
371         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
372         final Attributes attrs = executeStage(context);
373         assertThat(attrs.getValue("Atlassian-Plugin-Key"), is("innerjarcp"));
374         assertThat(attrs.getValue("Spring-Context"), is("*"));
375     }
376 
377     @Test
378     public void testGenerateManifestNoExistingManifestButDescriptor() throws Exception
379     {
380         final File plugin = new PluginJarBuilder("plugin")
381                 .addResource("foo/bar.txt", "Something")
382                 .addPluginInformation("innerjarcp", "Some name", "1.0")
383                 .build();
384 
385         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
386         final Attributes attrs = executeStage(context);
387         assertThat(attrs.getValue("Atlassian-Plugin-Key"), is("innerjarcp"));
388         assertThat(attrs.getValue("Spring-Context"), notNullValue());
389     }
390 
391     @Test
392     public void testGenerateManifestWarnIfTimeoutSpecified() throws Exception
393     {
394         System.setProperty(ATLASSIAN_DEV_MODE, "true");
395         final File plugin = new PluginJarBuilder("plugin")
396                 .addFormattedResource("META-INF/MANIFEST.MF",
397                         "Manifest-Version: 1.0",
398                         "Import-Package: javax.swing",
399                         "Bundle-SymbolicName: my.foo.symbolicName",
400                         "Bundle-Version: 1.0",
401                         "Spring-Context: *;timeout:=60",
402                         "Bundle-ClassPath: .,foo")
403                 .addResource("foo/bar.txt", "Something")
404                 .addPluginInformation("innerjarcp", "Some name", "1.0")
405                 .build();
406 
407         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
408         context.setShouldRequireSpring(true);
409         context.getExtraImports().add(AttributeSet.class.getPackage().getName());
410         executeStage(context);
411         final String artifactName = context.getPluginArtifact().getName();
412         assertThat(capturedLogging, didLogWarn("Use the header 'Spring-Context: *'", "*;timeout:=60", artifactName));
413     }
414 
415     @Test
416     public void testGenerateManifest_innerjarsInImports() throws Exception
417     {
418         final File innerJar = new PluginJarBuilder("innerjar")
419                 .addFormattedJava("my.Foo",
420                         "package my;",
421                         "import org.apache.log4j.Logger;",
422                         "public class Foo{",
423                         "   Logger log;",
424                         "}")
425                 .build();
426         assertThat(innerJar, notNullValue());
427         final File plugin = new PluginJarBuilder("plugin")
428                 .addJava("my.Bar", "package my;import org.apache.log4j.spi.Filter; public class Bar{Filter log;}")
429                 .addFile("META-INF/lib/innerjar.jar", innerJar)
430                 .addPluginInformation("innerjarcp", "Some name", "1.0")
431                 .build();
432 
433         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
434         context.addBundleClasspathJar("META-INF/lib/innerjar.jar");
435         final Attributes attrs = executeStage(context);
436 
437         assertThat(attrs.getValue(Constants.BUNDLE_VERSION), is("1.0"));
438         assertThat(attrs.getValue(Constants.BUNDLE_SYMBOLICNAME), is("innerjarcp"));
439 
440         final Collection<String> classpathEntries = Arrays.asList(attrs.getValue(Constants.BUNDLE_CLASSPATH).split(","));
441         assertThat(classpathEntries, containsInAnyOrder(".", "META-INF/lib/innerjar.jar"));
442 
443         final Collection<String> imports = Arrays.asList(attrs.getValue("Import-Package").split(","));
444         assertThat(imports, containsInAnyOrder(
445                 org.apache.log4j.Logger.class.getPackage().getName() + ";resolution:=\"optional\"",
446                 Filter.class.getPackage().getName() + ";resolution:=\"optional\""));
447     }
448 
449     @Test
450     public void testGenerateManifestWithBundleInstructions() throws Exception
451     {
452         final File plugin = new PluginJarBuilder("plugin")
453                 .addPluginInformation("test.plugin", "test.plugin", "1.0")
454                 .addJava("foo.MyClass", "package foo; public class MyClass{}")
455                 .addJava("foo.internal.MyPrivateClass", "package foo.internal; public class MyPrivateClass{}")
456                 .build();
457 
458         final TransformContext context = getTransformContext(plugin, SystemExports.NONE);
459         context.getBndInstructions().put("Export-Package", "!*.internal.*,*");
460         final Attributes attrs = executeStage(context);
461         assertThat(attrs.getValue(Constants.BUNDLE_SYMBOLICNAME), is("test.plugin"));
462         assertThat(attrs.getValue(Constants.EXPORT_PACKAGE), is("foo;version=\"1.0\""));
463     }
464 
465     @Test
466     public void testGenerateManifestWithHostAndExternalImports() throws Exception
467     {
468         final File plugin = new PluginJarBuilder("plugin")
469                 .addPluginInformation("test.plugin", "test.plugin", "1.0")
470                 .build();
471 
472         final SystemExports exports = new SystemExports("foo.bar,foo.baz;version=\"1.0\"");
473         final TransformContext context = getTransformContext(plugin, exports);
474         context.getBndInstructions().put("Import-Package", "foo.bar,foo.baz");
475         final Attributes attrs = executeStage(context);
476         assertThat(attrs.getValue(Constants.BUNDLE_SYMBOLICNAME), is("test.plugin"));
477 
478         final String imports = attrs.getValue(Constants.IMPORT_PACKAGE);
479         assertThat(imports, containsString("foo.baz;version=\"[1.0,1.0]\""));
480         assertThat(imports, containsString("foo.bar"));
481     }
482 
483     @Test
484     public void manifestAttributesArePropagatedForNonOsgiBundlePlugins() throws Exception
485     {
486         final String atlassianBuildDateKey = "Atlassian-Build-Date";
487         final String atlassianBuildDateValue = "2014-05-19T12:48:46-0700";
488         final String nonstandardHeaderKey = "Some-Nonstandard-Header";
489         final String nonstandardHeaderValue = "Value of the nonstandard header";
490         final String pluginKey = "plugin-key";
491         final File file = new PluginJarBuilder()
492                 .addPluginInformation(pluginKey, "plugin name", "1.2.3")
493                 .manifest(ImmutableMap.<String, String>builder()
494                         // This is the actual header of interest in the bug report
495                         .put(atlassianBuildDateKey, atlassianBuildDateValue)
496                         // And this is just something a bit random to check it's not just Atlassian-* or known
497                         .put(nonstandardHeaderKey, nonstandardHeaderValue)
498                         // And this is a value we can't override
499                         .put(OsgiPlugin.ATLASSIAN_PLUGIN_KEY, "not-" + pluginKey)
500                         .build())
501                 .build();
502 
503         final TransformContext context = getTransformContext(file, SystemExports.NONE);
504 
505         final Attributes attributes = executeStage(context);
506 
507         assertThat(attributes.getValue(atlassianBuildDateKey), is(atlassianBuildDateValue));
508         assertThat(attributes.getValue(nonstandardHeaderKey), is(nonstandardHeaderValue));
509         assertThat(attributes.getValue(OsgiPlugin.ATLASSIAN_PLUGIN_KEY), is(pluginKey));
510     }
511 
512     @Test
513     public void testGenerateManifestWithScanningEnabled() throws Exception
514     {
515         final File file = new PluginJarBuilder()
516                 .addFormattedResource(
517                         "atlassian-plugin.xml",
518                         "<atlassian-plugin key='com.atlassian.plugins.example' name='Example Plugin'>",
519                         "  <plugin-info>",
520                         "    <description>",
521                         "      A sample plugin for demonstrating the file format.",
522                         "    </description>",
523                         "    <version>1.1</version>",
524                         "    <vendor name='Atlassian Software Systems Pty Ltd' url='http://www.atlassian.com'/>",
525                         "    <scan-modules/>",
526                         "  </plugin-info>",
527                         "</atlassian-plugin>")
528                 .build();
529 
530         final TransformContext context = getTransformContext(file, SystemExports.NONE);
531         final Attributes attrs = executeStage(context);
532         assertThat(attrs.getValue("Atlassian-Scan-Folders"), is("META-INF/atlassian"));
533     }
534 
535     @Test
536     public void testGenerateManifestWithScanningEnabledAndFoldersSpecified() throws Exception
537     {
538         final File file = new PluginJarBuilder()
539                 .addFormattedResource(
540                         "atlassian-plugin.xml",
541                         "<atlassian-plugin key='com.atlassian.plugins.example' name='Example Plugin'>",
542                         "  <plugin-info>",
543                         "    <description>",
544                         "      A sample plugin for demonstrating the file format.",
545                         "    </description>",
546                         "    <version>1.1</version>",
547                         "    <vendor name='Atlassian Software Systems Pty Ltd' url='http://www.atlassian.com'/>",
548                         "    <scan-modules>",
549                         "       <folder>foo</folder>",
550                         "       <folder>bar</folder>",
551                         "    </scan-modules>",
552                         "  </plugin-info>",
553                         "</atlassian-plugin>")
554                 .build();
555 
556         final TransformContext context = getTransformContext(file, SystemExports.NONE);
557         final Attributes attrs = executeStage(context);
558         assertThat(attrs.getValue("Atlassian-Scan-Folders"), containsString("foo"));
559         assertThat(attrs.getValue("Atlassian-Scan-Folders"), containsString("bar"));
560         assertThat(attrs.getValue("Atlassian-Scan-Folders"), containsString(","));
561     }
562 
563     private TransformContext getTransformContext(final File plugin, final SystemExports exports)
564     {
565         final JarPluginArtifact pluginArtifact = new JarPluginArtifact(plugin);
566         return new TransformContext(null, exports, pluginArtifact, null, PluginAccessor.Descriptor.FILENAME, osgiContainerManager);
567     }
568 
569     private Attributes executeStage(final TransformContext context) throws IOException
570     {
571         stage.execute(context);
572         final Manifest mf;
573         if (context.getFileOverrides().get("META-INF/MANIFEST.MF") != null)
574         {
575             mf = new Manifest(new ByteArrayInputStream(context.getFileOverrides().get("META-INF/MANIFEST.MF")));
576         }
577         else
578         {
579             mf = context.getManifest();
580         }
581         return mf.getMainAttributes();
582     }
583 }