View Javadoc

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