View Javadoc

1   package com.atlassian.plugin.webresource;
2   
3   import static java.util.Arrays.asList;
4   import static org.mockito.Mockito.mock;
5   import static org.mockito.Mockito.times;
6   import static org.mockito.Mockito.verify;
7   import static org.mockito.Mockito.when;
8   
9   import com.atlassian.plugin.ModuleDescriptor;
10  import com.atlassian.plugin.Plugin;
11  import com.atlassian.plugin.PluginAccessor;
12  import com.atlassian.plugin.PluginInformation;
13  import com.atlassian.plugin.elements.ResourceDescriptor;
14  import com.atlassian.plugin.elements.ResourceLocation;
15  import com.atlassian.plugin.event.PluginEventManager;
16  import com.atlassian.plugin.servlet.DownloadableClasspathResource;
17  import com.atlassian.plugin.servlet.DownloadableResource;
18  import com.atlassian.plugin.servlet.ForwardableResource;
19  import com.atlassian.plugin.servlet.ServletContextFactory;
20  import com.atlassian.plugin.webresource.transformer.WebResourceTransformer;
21  import com.atlassian.plugin.webresource.transformer.WebResourceTransformerModuleDescriptor;
22  
23  import org.dom4j.DocumentHelper;
24  import org.dom4j.Element;
25  import org.mockito.Mock;
26  import org.mockito.MockitoAnnotations;
27  
28  import java.util.Arrays;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.TreeMap;
36  
37  import junit.framework.TestCase;
38  
39  public class TestPluginResourceLocatorImpl extends TestCase
40  {
41      private PluginResourceLocatorImpl pluginResourceLocator;
42      @Mock
43      private WebResourceIntegration mockWebResourceIntegration;
44      @Mock
45      private PluginAccessor mockPluginAccessor;
46      @Mock
47      private ServletContextFactory mockServletContextFactory;
48      @Mock
49      private ResourceBatchingConfiguration mockBatchingConfiguration;
50      @Mock
51      private WebResourceUrlProvider mockWebResourceUrlProvider;
52  
53      @Mock
54      private PluginEventManager mockEventPublisher;
55  
56      private static final String TEST_PLUGIN_KEY = "test.plugin";
57      private static final String TEST_MODULE_KEY = "web-resources";
58      private static final String TEST_MODULE_COMPLETE_KEY = TEST_PLUGIN_KEY + ":" + TEST_MODULE_KEY;
59  
60      @Override
61      protected void setUp() throws Exception
62      {
63          super.setUp();
64  
65          MockitoAnnotations.initMocks(this);
66          when(mockWebResourceIntegration.getPluginAccessor()).thenReturn(mockPluginAccessor);
67  
68          pluginResourceLocator = new PluginResourceLocatorImpl(mockWebResourceIntegration, mockServletContextFactory, mockWebResourceUrlProvider,
69              mockBatchingConfiguration, mockEventPublisher);
70      }
71  
72      @Override
73      protected void tearDown() throws Exception
74      {
75          pluginResourceLocator = null;
76          mockWebResourceIntegration = null;
77          mockPluginAccessor = null;
78          mockServletContextFactory = null;
79          mockBatchingConfiguration = null;
80          mockWebResourceUrlProvider = null;
81          mockEventPublisher = null;
82  
83          super.tearDown();
84      }
85  
86      public void testMatches()
87      {
88          assertTrue(pluginResourceLocator.matches("/download/superbatch/css/batch.css"));
89          assertTrue(pluginResourceLocator.matches("/download/superbatch/css/images/background/blah.gif"));
90          assertTrue(pluginResourceLocator.matches("/download/batch/plugin.key:module-key/plugin.key.js"));
91          assertTrue(pluginResourceLocator.matches("/download/resources/plugin.key:module-key/foo.png"));
92          assertTrue(pluginResourceLocator.matches("/download/contextbatch/css/contexta/batch.css"));
93          assertTrue(pluginResourceLocator.matches("/download/contextbatch/css/contexta/images/blah.png"));
94      }
95  
96      public void testNotMatches()
97      {
98          assertFalse(pluginResourceLocator.matches("/superbatch/batch.css"));
99          assertFalse(pluginResourceLocator.matches("/download/blah.css"));
100     }
101 
102     public void testGetAndParseUrl()
103     {
104         final SinglePluginResource resource = new SinglePluginResource("plugin.key:my-resources", "foo.css", false);
105         final String url = resource.getUrl();
106         assertTrue(pluginResourceLocator.matches(url));
107     }
108 
109     public void testGetPluginResourcesWithoutBatching() throws Exception
110     {
111         final Plugin mockPlugin = mock(Plugin.class);
112         when(mockPlugin.getPluginsVersion()).thenReturn(1);
113 
114         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("master-ie.css", "master.css", "comments.css");
115 
116         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(
117             (ModuleDescriptor) TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, mockPlugin, resourceDescriptors));
118 
119         when(mockBatchingConfiguration.isPluginWebResourceBatchingEnabled()).thenReturn(false);
120         final List<PluginResource> resources = pluginResourceLocator.getPluginResources(TEST_MODULE_COMPLETE_KEY);
121         assertEquals(3, resources.size());
122         // ensure the resources still have their parameters
123         for (final PluginResource resource : resources)
124         {
125             if (resource.getResourceName().contains("ie"))
126             {
127                 assertEquals("true", resource.getParams().get("ieonly"));
128             }
129             else
130             {
131                 assertNull(resource.getParams().get("ieonly"));
132             }
133         }
134     }
135 
136     public void testGetPluginResourcesWithBatching() throws Exception
137     {
138         final Plugin mockPlugin = mock(Plugin.class);
139         when(mockPlugin.getPluginsVersion()).thenReturn(1);
140         
141         final PluginInformation pluginInformation = mock(PluginInformation.class);
142         when(pluginInformation.getVersion()).thenReturn("4.4");
143         when(mockPlugin.getPluginInformation()).thenReturn(pluginInformation);
144 
145         when(mockBatchingConfiguration.isPluginWebResourceBatchingEnabled()).thenReturn(true);
146 
147         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("master-ie.css", "master.css", "comments.css");
148 
149         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(
150             (ModuleDescriptor) TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, mockPlugin, resourceDescriptors));
151 
152         final List<PluginResource> resources = pluginResourceLocator.getPluginResources(TEST_MODULE_COMPLETE_KEY);
153         assertEquals(2, resources.size());
154 
155         final BatchPluginResource ieBatch = (BatchPluginResource) resources.get(0);
156         assertEquals(TEST_MODULE_COMPLETE_KEY, ieBatch.getModuleCompleteKey());
157         assertEquals("css", ieBatch.getType());
158         assertEquals(1, ieBatch.getParams().size());
159         assertEquals("true", ieBatch.getParams().get("ieonly"));
160 
161         final BatchPluginResource batch = (BatchPluginResource) resources.get(1);
162         assertEquals(TEST_MODULE_COMPLETE_KEY, batch.getModuleCompleteKey());
163         assertEquals("css", batch.getType());
164         assertEquals(0, batch.getParams().size());
165     }
166 
167     public void testGetPluginResourcesWithBatchParameter() throws Exception
168     {
169         final Plugin mockPlugin = mock(Plugin.class);
170         when(mockPlugin.getPluginsVersion()).thenReturn(1);
171         
172         final PluginInformation pluginInformation = mock(PluginInformation.class);
173         when(pluginInformation.getVersion()).thenReturn("4.4");
174         when(mockPlugin.getPluginInformation()).thenReturn(pluginInformation);
175 
176         when(mockBatchingConfiguration.isPluginWebResourceBatchingEnabled()).thenReturn(true);
177 
178         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("master.css", "comments.css");
179         final Map<String, String> nonBatchParams = new TreeMap<String, String>();
180         nonBatchParams.put("batch", "false");
181         resourceDescriptors.add(TestUtils.createResourceDescriptor("nonbatch.css", nonBatchParams));
182 
183         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(
184             (ModuleDescriptor) TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, mockPlugin, resourceDescriptors));
185 
186         final List<PluginResource> resources = pluginResourceLocator.getPluginResources(TEST_MODULE_COMPLETE_KEY);
187         assertEquals(2, resources.size());
188 
189         final BatchPluginResource batch = (BatchPluginResource) resources.get(0);
190         assertEquals(TEST_MODULE_COMPLETE_KEY, batch.getModuleCompleteKey());
191         assertEquals("css", batch.getType());
192         assertEquals(0, batch.getParams().size());
193 
194         final SinglePluginResource single = (SinglePluginResource) resources.get(1);
195         assertEquals(TEST_MODULE_COMPLETE_KEY, single.getModuleCompleteKey());
196     }
197 
198     public void testGetPluginResourcesWithForwarding() throws Exception
199     {
200         final Plugin mockPlugin = mock(Plugin.class);
201         when(mockPlugin.getPluginsVersion()).thenReturn(1);
202         
203         final PluginInformation pluginInformation = mock(PluginInformation.class);
204         when(pluginInformation.getVersion()).thenReturn("4.4");
205         when(mockPlugin.getPluginInformation()).thenReturn(pluginInformation);
206 
207         when(mockBatchingConfiguration.isPluginWebResourceBatchingEnabled()).thenReturn(true);
208 
209         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("master.css", "comments.css");
210         final Map<String, String> params = new TreeMap<String, String>();
211         params.put("source", "webContext");
212         resourceDescriptors.add(TestUtils.createResourceDescriptor("forward.css", params));
213 
214         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(
215             (ModuleDescriptor) TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, mockPlugin, resourceDescriptors));
216 
217         final List<PluginResource> resources = pluginResourceLocator.getPluginResources(TEST_MODULE_COMPLETE_KEY);
218         assertEquals(2, resources.size());
219 
220         final BatchPluginResource batch = (BatchPluginResource) resources.get(0);
221         assertEquals(TEST_MODULE_COMPLETE_KEY, batch.getModuleCompleteKey());
222         assertEquals("css", batch.getType());
223         assertEquals(0, batch.getParams().size());
224 
225         final SinglePluginResource single = (SinglePluginResource) resources.get(1);
226         assertEquals(TEST_MODULE_COMPLETE_KEY, single.getModuleCompleteKey());
227     }
228 
229     public void testGetForwardableResource() throws Exception
230     {
231         final String resourceName = "test.css";
232         final String url = "/download/resources/" + TEST_MODULE_COMPLETE_KEY + "/" + resourceName;
233         final Map<String, String> params = new TreeMap<String, String>();
234         params.put("source", "webContext");
235 
236         final Plugin mockPlugin = mock(Plugin.class);
237         final ModuleDescriptor mockModuleDescriptor = mock(ModuleDescriptor.class);
238         when(mockModuleDescriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
239         when(mockModuleDescriptor.getResourceLocation("download", resourceName)).thenReturn(
240             new ResourceLocation("", resourceName, "download", "text/css", "", params));
241 
242         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
243         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
244 
245         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
246 
247         assertTrue(resource instanceof ForwardableResource);
248     }
249 
250     public void testGetDownloadableClasspathResource() throws Exception
251     {
252         final String resourceName = "test.css";
253         final String url = "/download/resources/" + TEST_MODULE_COMPLETE_KEY + "/" + resourceName;
254 
255         final Plugin mockPlugin = mock(Plugin.class);
256         final ModuleDescriptor mockModuleDescriptor = mock(ModuleDescriptor.class);
257         when(mockModuleDescriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
258         when(mockModuleDescriptor.getResourceLocation("download", resourceName)).thenReturn(
259             new ResourceLocation("", resourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
260 
261         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
262         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
263 
264         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
265 
266         assertTrue(resource instanceof DownloadableClasspathResource);
267     }
268 
269     public void testGetTransformedDownloadableClasspathResource() throws Exception
270     {
271         final String resourceName = "test.js";
272         final String url = "/download/resources/" + TEST_MODULE_COMPLETE_KEY + "/" + resourceName;
273 
274         final DownloadableResource transformedResource = mock(DownloadableResource.class);
275         final WebResourceTransformation trans = new WebResourceTransformation(DocumentHelper.parseText(
276             "<transformation extension=\"js\">\n" + "<transformer key=\"foo\" />\n" + "</transformation>").getRootElement());
277         final WebResourceTransformer transformer = new WebResourceTransformer()
278         {
279             public DownloadableResource transform(final Element configElement, final ResourceLocation location, final String filePath, final DownloadableResource nextResource)
280             {
281                 return transformedResource;
282             }
283         };
284 
285         final WebResourceTransformerModuleDescriptor transDescriptor = mock(WebResourceTransformerModuleDescriptor.class);
286         when(transDescriptor.getKey()).thenReturn("foo");
287         when(transDescriptor.getModule()).thenReturn(transformer);
288 
289         final Plugin mockPlugin = mock(Plugin.class);
290         final WebResourceModuleDescriptor descriptor = mock(WebResourceModuleDescriptor.class);
291         when(descriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
292         when(descriptor.getResourceLocation("download", resourceName)).thenReturn(
293             new ResourceLocation("", resourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
294         when(descriptor.getTransformations()).thenReturn(Arrays.asList(trans));
295 
296         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceTransformerModuleDescriptor.class)).thenReturn(
297             Arrays.asList(transDescriptor));
298         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) descriptor);
299         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
300 
301         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
302 
303         assertTrue(resource == transformedResource);
304     }
305 
306     public void testGetUnmatchedTransformDownloadableClasspathResource() throws Exception
307     {
308         final String resourceName = "test.css";
309         final String url = "/download/resources/" + TEST_MODULE_COMPLETE_KEY + "/" + resourceName;
310 
311         final DownloadableResource transformedResource = mock(DownloadableResource.class);
312         final WebResourceTransformation trans = new WebResourceTransformation(DocumentHelper.parseText(
313             "<transformation extension=\"js\">\n" + "<transformer key=\"foo\" />\n" + "</transformation>").getRootElement());
314         final WebResourceTransformer transformer = new WebResourceTransformer()
315         {
316             public DownloadableResource transform(final Element configElement, final ResourceLocation location, final String extraPath, final DownloadableResource nextResource)
317             {
318                 return transformedResource;
319             }
320         };
321 
322         final WebResourceTransformerModuleDescriptor transDescriptor = mock(WebResourceTransformerModuleDescriptor.class);
323         when(transDescriptor.getKey()).thenReturn("foo");
324         when(transDescriptor.getModule()).thenReturn(transformer);
325 
326         final Plugin mockPlugin = mock(Plugin.class);
327         final WebResourceModuleDescriptor descriptor = mock(WebResourceModuleDescriptor.class);
328         when(descriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
329         when(descriptor.getResourceLocation("download", resourceName)).thenReturn(
330             new ResourceLocation("", resourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
331         when(descriptor.getTransformations()).thenReturn(Arrays.asList(trans));
332 
333         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceTransformerModuleDescriptor.class)).thenReturn(
334             Arrays.asList(transDescriptor));
335         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) descriptor);
336         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
337 
338         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
339 
340         assertTrue(resource instanceof DownloadableClasspathResource);
341     }
342 
343     public void testGetMissingTransformerDownloadableClasspathResource() throws Exception
344     {
345         final String resourceName = "test.css";
346         final String url = "/download/resources/" + TEST_MODULE_COMPLETE_KEY + "/" + resourceName;
347 
348         final DownloadableResource transformedResource = mock(DownloadableResource.class);
349         final WebResourceTransformation trans = new WebResourceTransformation(DocumentHelper.parseText(
350             "<transformation extension=\"js\">\n" + "<transformer key=\"foo\" />\n" + "</transformation>").getRootElement());
351         final WebResourceTransformer transformer = new WebResourceTransformer()
352         {
353             public DownloadableResource transform(final Element configElement, final ResourceLocation location, final String extraPath, final DownloadableResource nextResource)
354             {
355                 return transformedResource;
356             }
357         };
358 
359         final WebResourceTransformerModuleDescriptor transDescriptor = mock(WebResourceTransformerModuleDescriptor.class);
360         when(transDescriptor.getKey()).thenReturn("bar");
361         when(transDescriptor.getModule()).thenReturn(transformer);
362 
363         final Plugin mockPlugin = mock(Plugin.class);
364         final WebResourceModuleDescriptor descriptor = mock(WebResourceModuleDescriptor.class);
365         when(descriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
366         when(descriptor.getResourceLocation("download", resourceName)).thenReturn(
367             new ResourceLocation("", resourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
368         when(descriptor.getTransformations()).thenReturn(Arrays.asList(trans));
369 
370         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceTransformerModuleDescriptor.class)).thenReturn(
371             Arrays.asList(transDescriptor));
372         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) descriptor);
373         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
374 
375         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
376 
377         assertTrue(resource instanceof DownloadableClasspathResource);
378     }
379 
380     public void testGetDownloadableBatchResource() throws Exception
381     {
382         final String url = "/download/batch/" + TEST_MODULE_COMPLETE_KEY + "/all.css";
383         final String ieResourceName = "master-ie.css";
384         final Map<String, String> params = new TreeMap<String, String>();
385         params.put("ieonly", "true");
386 
387         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors(ieResourceName, "master.css");
388 
389         final Plugin mockPlugin = mock(Plugin.class);
390         final ModuleDescriptor mockModuleDescriptor = mock(ModuleDescriptor.class);
391         when(mockModuleDescriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
392         when(mockModuleDescriptor.getCompleteKey()).thenReturn(TEST_MODULE_COMPLETE_KEY);
393         when(mockModuleDescriptor.getResourceDescriptors()).thenReturn(resourceDescriptors);
394         when(mockModuleDescriptor.getResourceLocation("download", ieResourceName)).thenReturn(
395             new ResourceLocation("", ieResourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
396 
397         when(mockPluginAccessor.isPluginModuleEnabled(TEST_MODULE_COMPLETE_KEY)).thenReturn(Boolean.TRUE);
398         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
399         when(mockPluginAccessor.getPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
400         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
401 
402         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, params);
403 
404         assertTrue(resource instanceof BatchDownloadableResource);
405     }
406 
407     public void testGetDownloadableBatchResourceWithConditionalComments() throws Exception
408     {
409         final String url = "/download/batch/" + TEST_MODULE_COMPLETE_KEY + "/all.css";
410         final String ieResourceName = "master-conditional.css";
411         final Map<String, String> params = new TreeMap<String, String>();
412         params.put("conditionalComment", "IE");
413 
414         final List<ResourceDescriptor> resourceDescriptors = asList(TestUtils.createResourceDescriptor(ieResourceName, new HashMap<String, String>(
415             params)), TestUtils.createResourceDescriptor(ieResourceName));
416 
417         final Plugin mockPlugin = mock(Plugin.class);
418         final ModuleDescriptor mockModuleDescriptor = mock(ModuleDescriptor.class);
419         when(mockModuleDescriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
420         when(mockModuleDescriptor.getCompleteKey()).thenReturn(TEST_MODULE_COMPLETE_KEY);
421         when(mockModuleDescriptor.getResourceDescriptors()).thenReturn(resourceDescriptors);
422         when(mockModuleDescriptor.getResourceLocation("download", ieResourceName)).thenReturn(
423             new ResourceLocation("", ieResourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
424 
425         when(mockPluginAccessor.isPluginModuleEnabled(TEST_MODULE_COMPLETE_KEY)).thenReturn(Boolean.TRUE);
426         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
427         when(mockPluginAccessor.getPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
428         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
429 
430         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, params);
431 
432         assertTrue(resource instanceof BatchDownloadableResource);
433     }
434 
435     public void testGetDownloadableBatchResourceWhenModuleIsUnkown() throws Exception
436     {
437         final String url = "/download/batch/" + TEST_MODULE_COMPLETE_KEY + "invalid.stuff" + "/all.css";
438         final Map<String, String> params = new TreeMap<String, String>();
439         params.put("ieonly", "true");
440 
441         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY + "invalid.stuff")).thenReturn(null);
442 
443         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, params);
444         assertNull(resource);
445     }
446 
447     public void testGetDownloadableBatchResourceFallbacksToSingle() throws Exception
448     {
449         final String resourceName = "images/foo.png";
450         final String url = "/download/batch/" + TEST_MODULE_COMPLETE_KEY + "/" + resourceName;
451 
452         final Plugin mockPlugin = mock(Plugin.class);
453         final ModuleDescriptor mockModuleDescriptor = mock(ModuleDescriptor.class);
454         when(mockModuleDescriptor.getPluginKey()).thenReturn(TEST_PLUGIN_KEY);
455         when(mockModuleDescriptor.getCompleteKey()).thenReturn(TEST_MODULE_COMPLETE_KEY);
456         when(mockModuleDescriptor.getResourceLocation("download", resourceName)).thenReturn(
457             new ResourceLocation("", resourceName, "download", "text/css", "", Collections.<String, String> emptyMap()));
458 
459         when(mockPluginAccessor.isPluginModuleEnabled(TEST_MODULE_COMPLETE_KEY)).thenReturn(Boolean.TRUE);
460         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
461         when(mockPluginAccessor.getPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn(mockModuleDescriptor);
462         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(mockPlugin);
463 
464         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
465 
466         assertTrue(resource instanceof DownloadableClasspathResource);
467     }
468 
469     public void testGetDownloadableSuperBatchResource() throws Exception
470     {
471         final String url = "/download/superbatch/css/batch.css";
472 
473         final Plugin testPlugin = TestUtils.createTestPlugin(TEST_PLUGIN_KEY, "1");
474         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("atlassian.css", "master.css");
475 
476         final WebResourceModuleDescriptor webModuleDescriptor = TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, testPlugin,
477             resourceDescriptors);
478 
479         when(mockWebResourceIntegration.getSuperBatchVersion()).thenReturn("1.0");
480         when(mockBatchingConfiguration.isSuperBatchingEnabled()).thenReturn(true);
481         when(mockBatchingConfiguration.getSuperBatchModuleCompleteKeys()).thenReturn(Arrays.asList(TEST_MODULE_COMPLETE_KEY));
482 
483         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) webModuleDescriptor);
484         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(testPlugin);
485 
486         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
487         assertTrue(resource instanceof SuperBatchDownloadableResource);
488 
489         final SuperBatchDownloadableResource superBatchPluginResource = (SuperBatchDownloadableResource) resource;
490         assertFalse(superBatchPluginResource.isEmpty());
491     }
492 
493     public void testGetDownloadableSuperBatchSubResource() throws Exception
494     {
495         final String url = "/download/superbatch/css/images/foo.png";
496         final String cssResourcesXml = "<resource name=\"css/\" type=\"download\" location=\"css/images/\" />";
497 
498         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("atlassian.css", "master.css");
499         resourceDescriptors.add(new ResourceDescriptor(DocumentHelper.parseText(cssResourcesXml).getRootElement()));
500 
501         final Plugin testPlugin = TestUtils.createTestPlugin(TEST_PLUGIN_KEY, "1");
502         final WebResourceModuleDescriptor webModuleDescriptor = TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, testPlugin,
503             resourceDescriptors);
504 
505         when(mockWebResourceIntegration.getSuperBatchVersion()).thenReturn("1.0");
506         when(mockBatchingConfiguration.isSuperBatchingEnabled()).thenReturn(true);
507         when(mockBatchingConfiguration.getSuperBatchModuleCompleteKeys()).thenReturn(Arrays.asList(TEST_MODULE_COMPLETE_KEY));
508 
509         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) webModuleDescriptor);
510         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(testPlugin);
511 
512         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
513         assertTrue(resource instanceof DownloadableClasspathResource);
514     }
515 
516     public void testGetDownloadableContextBatchSubResource() throws Exception
517     {
518         final String url = "/download/contextbatch/css/contexta,contextb/images/foo.png";
519         final String cssResourcesXml = "<resource name=\"css/\" type=\"download\" location=\"css/images/\" />";
520 
521         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("atlassian.css", "master.css");
522         resourceDescriptors.add(new ResourceDescriptor(DocumentHelper.parseText(cssResourcesXml).getRootElement()));
523 
524         final String context = "contexta";
525         final Set<String> contexts = new HashSet<String>();
526         contexts.add(context);
527 
528         final Plugin testPlugin = TestUtils.createTestPlugin(TEST_PLUGIN_KEY, "1");
529         final WebResourceModuleDescriptor webModuleDescriptor = TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, testPlugin,
530             resourceDescriptors, Collections.<String> emptyList(), contexts);
531 
532         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceModuleDescriptor.class)).thenReturn(Arrays.asList(webModuleDescriptor));
533         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) webModuleDescriptor);
534         when(mockPluginAccessor.getPlugin(TEST_PLUGIN_KEY)).thenReturn(testPlugin);
535 
536         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
537         assertTrue(resource instanceof DownloadableClasspathResource);
538     }
539 
540     public void testGetDownloadableContextBatchResource() throws Exception
541     {
542         final Set<String> contexts = new HashSet<String>();
543         final String context = "contextA";
544         contexts.add(context);
545         contexts.add("contextB");
546         final String url = "/download/contextbatch/css/contextA/batch.css";
547         final List<ResourceDescriptor> resourceDescriptors = TestUtils.createResourceDescriptors("atlassian.css", "master.css");
548 
549         final Plugin testPlugin = TestUtils.createTestPlugin(TEST_PLUGIN_KEY, "1");
550         final WebResourceModuleDescriptor webModuleDescriptor = TestUtils.createWebResourceModuleDescriptor(TEST_MODULE_COMPLETE_KEY, testPlugin,
551             resourceDescriptors, Collections.<String> emptyList(), contexts);
552 
553         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceModuleDescriptor.class)).thenReturn(Arrays.asList(webModuleDescriptor));
554         when(mockPluginAccessor.getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY)).thenReturn((ModuleDescriptor) webModuleDescriptor);
555 
556         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
557         assertTrue(resource instanceof ContextBatchDownloadableResource);
558 
559         verify(mockPluginAccessor, times(3)).getEnabledPluginModule(TEST_MODULE_COMPLETE_KEY);
560     }
561 
562     public void testGetDownloadableMergedContextBatchResource() throws Exception
563     {
564         final Set<String> contexts1 = new HashSet<String>();
565         final String context1 = "contextA";
566         contexts1.add(context1);
567 
568         final Set<String> contexts2 = new HashSet<String>();
569         final String context2 = "contextB";
570         contexts2.add(context2);
571         final String url = "/download/contextbatch/css/contextA,contextB/batch.css";
572 
573         final Plugin testPlugin = TestUtils.createTestPlugin(TEST_PLUGIN_KEY, "1");
574 
575         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("atlassian.css", "master.css");
576         final String completeKey1 = TEST_PLUGIN_KEY + ":" + "a-resources";
577         final WebResourceModuleDescriptor webModuleDescriptor1 = TestUtils.createWebResourceModuleDescriptor(completeKey1, testPlugin,
578             resourceDescriptors1, Collections.<String> emptyList(), contexts1);
579 
580         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("test.css", "default.css");
581         final String completeKey2 = TEST_PLUGIN_KEY + ":" + "b-resources";
582         final WebResourceModuleDescriptor webModuleDescriptor2 = TestUtils.createWebResourceModuleDescriptor(completeKey2, testPlugin,
583             resourceDescriptors2, Collections.<String> emptyList(), contexts2);
584 
585         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceModuleDescriptor.class)).thenReturn(
586             Arrays.asList(webModuleDescriptor1, webModuleDescriptor2));
587 
588         when(mockPluginAccessor.getEnabledPluginModule(completeKey1)).thenReturn((ModuleDescriptor) webModuleDescriptor1);
589         when(mockPluginAccessor.getEnabledPluginModule(completeKey2)).thenReturn((ModuleDescriptor) webModuleDescriptor2);
590 
591         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
592         assertTrue(resource instanceof ContextBatchDownloadableResource);
593 
594         verify(mockPluginAccessor, times(3)).getEnabledPluginModule(completeKey1);
595         verify(mockPluginAccessor, times(3)).getEnabledPluginModule(completeKey2);
596     }
597 
598     public void testGetDownloadableMergedContextBatchResourceWithOverlap() throws Exception
599     {
600         final Set<String> contexts1 = new HashSet<String>();
601         final String context1 = "contextA";
602         contexts1.add(context1);
603 
604         final Set<String> contexts2 = new HashSet<String>();
605         final String context2 = "contextB";
606         contexts2.add(context2);
607         final String url = "/download/contextbatch/css/contextA,contextB/batch.css";
608 
609         final Plugin testPlugin = TestUtils.createTestPlugin(TEST_PLUGIN_KEY, "1");
610 
611         final List<ResourceDescriptor> parentResourceDescriptors = TestUtils.createResourceDescriptors("parent.css");
612         final String parentKey = TEST_PLUGIN_KEY + ":" + "parent-resources";
613         final WebResourceModuleDescriptor parentWebModuleDescriptor = TestUtils.createWebResourceModuleDescriptor(parentKey, testPlugin,
614             parentResourceDescriptors);
615 
616         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("atlassian.css", "master.css");
617         final String completeKey1 = TEST_PLUGIN_KEY + ":" + "a-resources";
618         final WebResourceModuleDescriptor webModuleDescriptor1 = TestUtils.createWebResourceModuleDescriptor(completeKey1, testPlugin,
619             resourceDescriptors1, Arrays.asList(parentKey), contexts1);
620 
621         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("test.css", "default.css");
622         final String completeKey2 = TEST_PLUGIN_KEY + ":" + "b-resources";
623         final WebResourceModuleDescriptor webModuleDescriptor2 = TestUtils.createWebResourceModuleDescriptor(completeKey2, testPlugin,
624             resourceDescriptors2, Arrays.asList(parentKey), contexts2);
625 
626         when(mockPluginAccessor.getEnabledModuleDescriptorsByClass(WebResourceModuleDescriptor.class)).thenReturn(
627             Arrays.asList(parentWebModuleDescriptor, webModuleDescriptor1, webModuleDescriptor2));
628 
629         when(mockPluginAccessor.getEnabledPluginModule(parentKey)).thenReturn((ModuleDescriptor) parentWebModuleDescriptor);
630         when(mockPluginAccessor.getEnabledPluginModule(completeKey1)).thenReturn((ModuleDescriptor) webModuleDescriptor1);
631         when(mockPluginAccessor.getEnabledPluginModule(completeKey2)).thenReturn((ModuleDescriptor) webModuleDescriptor2);
632 
633         final DownloadableResource resource = pluginResourceLocator.getDownloadableResource(url, Collections.<String, String> emptyMap());
634         assertTrue(resource instanceof ContextBatchDownloadableResource);
635 
636         verify(mockPluginAccessor, times(3)).getEnabledPluginModule(completeKey1);
637         verify(mockPluginAccessor, times(3)).getEnabledPluginModule(completeKey2);
638 
639         // TODO - BN 2.9.0 - work out a better way to ensure that the parent isn't included twice.
640         // 2 for dependency resolution
641         // 1 for resource descriptor download
642         verify(mockPluginAccessor, times(3)).getEnabledPluginModule(parentKey);
643     }
644 
645     public void testSplitLastPathPart()
646     {
647         final String[] parts = pluginResourceLocator.splitLastPathPart("http://localhost:8080/confluence/download/foo/bar/baz");
648         assertEquals(2, parts.length);
649         assertEquals("http://localhost:8080/confluence/download/foo/bar/", parts[0]);
650         assertEquals("baz", parts[1]);
651 
652         final String[] anotherParts = pluginResourceLocator.splitLastPathPart(parts[0]);
653         assertEquals(2, anotherParts.length);
654         assertEquals("http://localhost:8080/confluence/download/foo/", anotherParts[0]);
655         assertEquals("bar/", anotherParts[1]);
656 
657         assertNull(pluginResourceLocator.splitLastPathPart("noslashes"));
658     }
659 }