1 package com.atlassian.plugin.parsers;
2
3 import com.atlassian.plugin.Application;
4 import com.atlassian.plugin.InstallationMode;
5 import com.atlassian.plugin.ModuleDescriptorFactory;
6 import com.atlassian.plugin.Plugin;
7 import com.atlassian.plugin.PluginArtifact;
8 import com.atlassian.plugin.PluginInformation;
9 import com.atlassian.plugin.PluginParseException;
10 import com.atlassian.plugin.PluginPermission;
11 import com.atlassian.plugin.classloader.PluginClassLoader;
12 import com.atlassian.plugin.impl.DefaultDynamicPlugin;
13 import com.atlassian.plugin.mock.MockAnimalModuleDescriptor;
14 import com.atlassian.plugin.util.ClassLoaderUtils;
15 import com.google.common.collect.Iterables;
16 import com.mockobjects.dynamic.C;
17 import com.mockobjects.dynamic.Mock;
18 import junit.framework.TestCase;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.InputStream;
25 import java.net.URL;
26 import java.util.Set;
27
28 @SuppressWarnings({"deprecation"})
29 public class TestXmlDescriptorParser extends TestCase
30 {
31 private static final String MISSING_INFO_TEST_FILE = "test-missing-plugin-info.xml";
32 private static final String DUMMY_PLUGIN_FILE = "pooh-test-plugin.jar";
33
34 public TestXmlDescriptorParser(String name)
35 {
36 super(name);
37 }
38
39
40 public void testMissingPluginInfo()
41 {
42
43 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
44 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
45 mockFactory.expect("getModuleDescriptorClass", "unknown-plugin");
46
47
48 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
49
50 try
51 {
52 XmlDescriptorParser parser = new XmlDescriptorParser(new FileInputStream(getTestFile(MISSING_INFO_TEST_FILE)));
53 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
54
55 PluginInformation info = testPlugin.getPluginInformation();
56 assertNotNull("Info should not be null", info);
57 }
58 catch (PluginParseException e)
59 {
60 e.printStackTrace();
61 fail("Plugin information parsing should not fail.");
62 }
63 catch (FileNotFoundException e)
64 {
65 e.printStackTrace();
66
67 fail("Error setting up test");
68 }
69 }
70
71 public void testPluginsApplicationVersionMinMax()
72 {
73 XmlDescriptorParser parser = parse(null,
74 "<atlassian-plugin key='foo'>",
75 " <plugin-info>",
76 " <application-version min='3' max='4' />",
77 " </plugin-info>",
78 "</atlassian-plugin>");
79 assertEquals(3, (int)parser.getPluginInformation().getMinVersion());
80 assertEquals(4, (int)parser.getPluginInformation().getMaxVersion());
81 }
82
83 public void testPluginsApplicationVersionMinMaxWithOnlyMin()
84 {
85 XmlDescriptorParser parser = parse(null,
86 "<atlassian-plugin key='foo'>",
87 " <plugin-info>",
88 " <application-version min='3' />",
89 " </plugin-info>",
90 "</atlassian-plugin>");
91 assertEquals(3, (int)parser.getPluginInformation().getMinVersion());
92 assertEquals(0, (int)parser.getPluginInformation().getMaxVersion());
93 }
94
95 public void testPluginsApplicationVersionMinMaxWithOnlyMax()
96 {
97 XmlDescriptorParser parser = parse(null,
98 "<atlassian-plugin key='foo'>",
99 " <plugin-info>",
100 " <application-version max='3' />",
101 " </plugin-info>",
102 "</atlassian-plugin>");
103 assertEquals(3, (int)parser.getPluginInformation().getMaxVersion());
104 assertEquals(0, (int)parser.getPluginInformation().getMinVersion());
105 }
106
107
108
109 public void testPluginsVersion()
110 {
111 String xml = "<atlassian-plugin key=\"foo\" pluginsVersion=\"2\" />";
112 XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream(xml.getBytes()));
113 assertEquals(2, parser.getPluginsVersion());
114 }
115
116 public void testPluginsVersionAfterConfigure()
117 {
118 XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream("<atlassian-plugin key=\"foo\" plugins-version=\"2\" />".getBytes()));
119
120 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
121 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
122 mockFactory.expect("getModuleDescriptorClass", "unknown-plugin");
123
124
125 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
126 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
127 assertEquals(2, testPlugin.getPluginsVersion());
128 }
129
130 public void testPluginWithModules()
131 {
132 XmlDescriptorParser parser = parse(null,
133 "<atlassian-plugin key='foo'>",
134 " <animal key='bear' />",
135 "</atlassian-plugin>");
136
137 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
138 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
139 mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
140
141
142 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
143 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
144 assertNotNull(testPlugin.getModuleDescriptor("bear"));
145 }
146
147 public void testPluginWithModulesNoApplicationKey()
148 {
149 XmlDescriptorParser parser = parse(null,
150 "<atlassian-plugin key='foo'>",
151 " <animal key='bear' application='foo'/>",
152 "</atlassian-plugin>");
153
154 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
155 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
156 mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
157
158
159 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
160 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
161 assertNull(testPlugin.getModuleDescriptor("bear"));
162 }
163
164 public void testPluginWithSomeNonApplicationModules()
165 {
166 XmlDescriptorParser parser = parse(newApplication("myapp"),
167 "<atlassian-plugin key='foo'>",
168 " <animal key='bear' application='myapp'/>",
169 " <animal key='bear2' application='otherapp'/>",
170 "</atlassian-plugin>");
171
172 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
173 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
174 mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
175
176
177 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
178 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
179 assertNotNull(testPlugin.getModuleDescriptor("bear"));
180 assertNull(testPlugin.getModuleDescriptor("bear2"));
181 }
182
183 public void testPluginWithSomeRestrictionOnModulesNoVersion()
184 {
185 XmlDescriptorParser parser = parse(newApplication("myapp"),
186 "<atlassian-plugin key='foo'>",
187 " <animal key='bear'>",
188 " <restrict application='myapp'/>",
189 " </animal>",
190 " <animal key='bear2' application='otherapp'/>",
191 "</atlassian-plugin>");
192
193 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
194 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
195 mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
196
197
198 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
199 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
200 assertNotNull(testPlugin.getModuleDescriptor("bear"));
201 assertNull(testPlugin.getModuleDescriptor("bear2"));
202 }
203
204 public void testPluginWithSomeRestrictionOnModulesVersionAsAttribute()
205 {
206 XmlDescriptorParser parser = parse(newApplication("myapp", "2.0"),
207 "<atlassian-plugin key='foo'>",
208 " <animal key='bear'>",
209 " <restrict application='myapp' version='[2.0]' />",
210 " </animal>",
211 " <animal key='bear2'>",
212 " <restrict application='myapp' version='[1.0]' />",
213 " </animal>",
214 "</atlassian-plugin>");
215
216 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
217 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
218 mockFactory.matchAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
219
220
221 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
222 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
223 assertNotNull(testPlugin.getModuleDescriptor("bear"));
224 assertNull(testPlugin.getModuleDescriptor("bear2"));
225 }
226
227 public void testPluginWithSomeRestrictionOnModulesVersionAsElement()
228 {
229 XmlDescriptorParser parser = parse(newApplication("myapp", "2.0"),
230 "<atlassian-plugin key='foo'>",
231 " <animal key='bear'>",
232 " <restrict application='myapp'>",
233 " <version>(,3.0)</version>",
234 " <version>[5.0,)</version>",
235 " </restrict>",
236 " </animal>",
237 " <animal key='bear2'>",
238 " <restrict application='myapp'>",
239 " <version>(,2.0)</version>",
240 " <version>[5.0,)</version>",
241 " </restrict>",
242 " </animal>",
243 "</atlassian-plugin>");
244
245 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
246 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
247 mockFactory.matchAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
248
249
250 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
251 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
252 assertNotNull(testPlugin.getModuleDescriptor("bear"));
253 assertNull(testPlugin.getModuleDescriptor("bear2"));
254 }
255
256 public void testPluginWithSystemAttribute()
257 {
258 XmlDescriptorParser parser = parse(null,
259 "<atlassian-plugin key='foo' system='true'>",
260 "</atlassian-plugin>");
261
262
263 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
264 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
265 mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
266
267
268 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
269 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
270
271 assertEquals("This plugin should be a system plugin - bundled plugins2 plugins are system plugins.", true, testPlugin.isSystemPlugin());
272 }
273
274 public void testPluginWithoutSystemAttribute()
275 {
276 XmlDescriptorParser parser = parse(null,
277 "<atlassian-plugin key='foo' >",
278 "</atlassian-plugin>");
279
280
281 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
282 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
283 mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
284
285
286 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
287 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
288 assertEquals("This plugin should not be a system plugin.", false, testPlugin.isSystemPlugin());
289 }
290
291 public void testPluginsVersionWithDash()
292 {
293 String xml = "<atlassian-plugin key=\"foo\" plugins-version=\"2\" />";
294 XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream(xml.getBytes()));
295 assertEquals(2, parser.getPluginsVersion());
296 }
297
298 public void testPluginsVersionMissing()
299 {
300 String xml = "<atlassian-plugin key=\"foo\" />";
301 XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream(xml.getBytes()));
302 assertEquals(1, parser.getPluginsVersion());
303 }
304
305 public void testPluginsResourcesAvailableToModuleDescriptors()
306 {
307 XmlDescriptorParser parser = parse(null,
308 "<atlassian-plugin key='foo'>",
309 " <resource type='velocity' name='edit'>Show an input box here.</resource>",
310 " <animal key='bear' />",
311 "</atlassian-plugin>");
312
313 PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
314 Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
315 MockAnimalModuleDescriptor descriptor = new MockAnimalModuleDescriptor("velocity", "edit");
316 mockFactory.expectAndReturn("getModuleDescriptor", C.args(C.eq("animal")), descriptor);
317
318
319 Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
320 parser.configurePlugin((ModuleDescriptorFactory)mockFactory.proxy(), testPlugin);
321 assertNotNull(testPlugin.getModuleDescriptor("bear"));
322
323 mockFactory.verify();
324 }
325
326 public void testPluginPermissionsIsAllPermissionsForPluginsWithNoVersionByDefault()
327 {
328 XmlDescriptorParser parser = parse(null,
329 "<atlassian-plugin key='foo'>",
330 " <plugin-info>",
331 " </plugin-info>",
332 "</atlassian-plugin>");
333
334 final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
335 assertEquals(1, parsedPermissions.size());
336 assertSame(PluginPermission.ALL, Iterables.get(parsedPermissions, 0));
337 }
338
339 public void testPluginPermissionsIsAllPermissionsForPlugins1ByDefault()
340 {
341 XmlDescriptorParser parser = parse(null,
342 "<atlassian-plugin key='foo' plugins-version='1'>",
343 " <plugin-info>",
344 " </plugin-info>",
345 "</atlassian-plugin>");
346
347 final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
348 assertEquals(1, parsedPermissions.size());
349 assertSame(PluginPermission.ALL, Iterables.get(parsedPermissions, 0));
350 }
351
352 public void testPluginPermissionsIsAllPermissionsForPlugins2ByDefault()
353 {
354 XmlDescriptorParser parser = parse(null,
355 "<atlassian-plugin key='foo' plugins-version='2'>",
356 " <plugin-info>",
357 " </plugin-info>",
358 "</atlassian-plugin>");
359
360 final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
361 assertEquals(1, parsedPermissions.size());
362 assertSame(PluginPermission.ALL, Iterables.get(parsedPermissions, 0));
363 }
364
365 public void testPluginPermissionsIsFilteredByApplications()
366 {
367 XmlDescriptorParser parser = parse(newApplication("my-app"),
368 "<atlassian-plugin key='foo' plugins-version='2'>",
369 " <plugin-info>",
370 " <permissions>",
371 " <permission application='my-other-app'>some_permission</permission>",
372 " <permission application='my-app'>some_other_permission</permission>",
373 " <permission application='my-other-app' installation-mode='local'>yet_another_permission</permission>",
374 " </permissions>",
375 " </plugin-info>",
376 "</atlassian-plugin>");
377
378 final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
379 assertEquals(1, parsedPermissions.size());
380 assertEquals("some_other_permission", Iterables.get(parsedPermissions, 0).getName());
381 }
382
383 public void testPluginPermissions()
384 {
385 XmlDescriptorParser parser = parse(newApplication("my-other-app"),
386 "<atlassian-plugin key='foo' plugins-version='2'>",
387 " <plugin-info>",
388 " <permissions>",
389 " <permission>some_permission</permission>",
390 " <permission application='my-app'>some_other_permission</permission>",
391 " <permission installation-mode='local'>yet_another_permission</permission>",
392 " </permissions>",
393 " </plugin-info>",
394 "</atlassian-plugin>");
395
396 final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
397 assertEquals(2, parsedPermissions.size());
398
399 final PluginPermission firstPermission = Iterables.get(parsedPermissions, 0);
400 assertEquals("some_permission", firstPermission.getName());
401 assertEquals(null, firstPermission.getInstallationMode());
402
403 final PluginPermission secondPermission = Iterables.get(parsedPermissions, 1);
404 assertEquals("yet_another_permission", secondPermission.getName());
405 assertEquals(InstallationMode.LOCAL, secondPermission.getInstallationMode());
406 }
407
408 public void testPluginPermissionsIsEmptyForRemotablePluginByDefault()
409 {
410 XmlDescriptorParser parser = parse(null,
411 "<atlassian-plugin key='foo' plugins-version='3'>",
412 " <plugin-info>",
413 " </plugin-info>",
414 "</atlassian-plugin>");
415
416 assertTrue(parser.getPluginInformation().getPermissions().isEmpty());
417 }
418
419 private String getTestFile(String filename)
420 {
421 final URL url = ClassLoaderUtils.getResource(filename, this.getClass());
422 return url.getFile();
423 }
424
425 private static XmlDescriptorParser parse(Application application, String... lines)
426 {
427 StringBuffer sb = new StringBuffer();
428 for (String line : lines)
429 {
430 sb.append(line.replace('\'', '"')).append('\n');
431 }
432 InputStream in = new ByteArrayInputStream(sb.toString().getBytes());
433 return application != null ? new XmlDescriptorParser(in, application) : new XmlDescriptorParser(in);
434 }
435
436 private Application newApplication(final String appKey)
437 {
438 return newApplication(appKey, null);
439 }
440
441 private Application newApplication(final String appKey, final String version)
442 {
443 return new Application()
444 {
445 @Override
446 public String getKey()
447 {
448 return appKey;
449 }
450
451 @Override
452 public String getVersion()
453 {
454 return version;
455 }
456
457 @Override
458 public String getBuildNumber()
459 {
460 return null;
461 }
462 };
463 }
464 }