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