View Javadoc

1   package com.atlassian.plugin.webresource;
2   
3   import static com.google.common.collect.Iterables.find;
4   import static com.google.common.collect.Iterables.size;
5   import static org.mockito.Mockito.when;
6   
7   import com.atlassian.plugin.Plugin;
8   import com.atlassian.plugin.elements.ResourceDescriptor;
9   
10  import com.google.common.base.Predicate;
11  
12  import org.mockito.Mock;
13  import org.mockito.MockitoAnnotations;
14  
15  import java.util.ArrayList;
16  import java.util.Arrays;
17  import java.util.Collections;
18  import java.util.List;
19  
20  import junit.framework.TestCase;
21  
22  public class TestContextBatchBuilder extends TestCase
23  {
24  
25      @Mock
26      private ResourceDependencyResolver mockDependencyResolver;
27      @Mock
28      private PluginResourceLocator mockPluginResourceLocator;
29      @Mock
30      private  ResourceBatchingConfiguration mockBatchingConfiguration;
31  
32      private ContextBatchBuilder builder;
33      private Plugin testPlugin;
34      
35      @Override
36      public void setUp() throws Exception
37      {
38          super.setUp();
39          MockitoAnnotations.initMocks(this);
40  
41          builder = new ContextBatchBuilder(mockPluginResourceLocator, mockDependencyResolver, mockBatchingConfiguration);
42          testPlugin = TestUtils.createTestPlugin();
43          when(mockBatchingConfiguration.isContextBatchingEnabled()).thenReturn(true);
44      }
45  
46      @Override
47      public void tearDown() throws Exception
48      {
49          mockPluginResourceLocator = null;
50          mockDependencyResolver = null;
51          mockBatchingConfiguration = null;
52  
53          builder = null;
54          testPlugin = null;
55  
56          super.tearDown();
57      }
58  
59      public void testNoOverlapAndNoDependencies() throws Exception
60      {
61          final String context1 = "xmen";
62          final String context2 = "brotherhood";
63          final List<String> contexts = new ArrayList<String>();
64          contexts.add(context1);
65          contexts.add(context2);
66  
67          final String moduleKey1 = "xavier-resources";
68          final String moduleKey2 = "magneto-resources";
69          final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
70          final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
71  
72          addModuleDescriptor(moduleKey1, resourceDescriptors1);
73          addModuleDescriptor(moduleKey2, resourceDescriptors2);
74          addContext(context1, Arrays.asList(moduleKey1));
75          addContext(context2, Arrays.asList(moduleKey2));
76  
77          final Iterable<PluginResource> resources = builder.build(contexts);
78  
79          assertEquals(4, size(resources));
80          assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen/batch.js")));
81          assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen/batch.css")));
82          assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/brotherhood/batch.js")));
83          assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood/batch.css")));
84  
85          assertEquals(2, size(builder.getAllIncludedResources()));
86      }
87  
88      public void testOverlappingAndNoDependencies() throws Exception
89      {
90          final String context1 = "xmen";
91          final String context2 = "brotherhood";
92          final List<String> contexts = new ArrayList<String>();
93          contexts.add(context1);
94          contexts.add(context2);
95  
96          final String moduleKey1 = "xavier-resources";
97          final String moduleKey2 = "magneto-resources";
98          final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
99          final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
100 
101         addModuleDescriptor(moduleKey1, resourceDescriptors1);
102         addModuleDescriptor(moduleKey2, resourceDescriptors2);
103         addContext(context1, Arrays.asList(moduleKey1, moduleKey2));
104         addContext(context2, Arrays.asList(moduleKey1, moduleKey2));
105 
106         final Iterable<PluginResource> resources = builder.build(contexts);
107 
108         assertEquals(2, size(resources));
109         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen,brotherhood/batch.js")));
110         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen,brotherhood/batch.css")));
111 
112         assertEquals(2, size(builder.getAllIncludedResources()));
113     }
114 
115     public void testDependenciesNoOverlap() throws Exception
116     {
117         final String context1 = "xmen";
118         final String context2 = "brotherhood";
119         final List<String> contexts = new ArrayList<String>();
120         contexts.add(context1);
121         contexts.add(context2);
122 
123         final String moduleKey1 = "xavier-resources";
124         final String moduleKey2 = "magneto-resources";
125         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
126         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
127 
128         final String dependentModule1 = "students-resources";
129         final List<ResourceDescriptor> dependentResourceDescriptors1 = TestUtils.createResourceDescriptors("iceman.js", "iceman.css", "rogue.css");
130         final String dependentModule2 = "evil-students-resources";
131         final List<ResourceDescriptor> dependentResourceDescriptors2 = TestUtils.createResourceDescriptors("pyro.css");
132 
133         addModuleDescriptor(moduleKey1, resourceDescriptors1);
134         addModuleDescriptor(dependentModule1, dependentResourceDescriptors1);
135         addContext(context1, Arrays.asList(moduleKey1, dependentModule1));
136 
137         addModuleDescriptor(moduleKey2, resourceDescriptors2);
138         addModuleDescriptor(dependentModule2, dependentResourceDescriptors2);
139         addContext(context2, Arrays.asList(moduleKey2, dependentModule2));
140 
141         final Iterable<PluginResource> resources = builder.build(contexts);
142 
143         assertEquals(4, size(resources));
144         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen/batch.js")));
145         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen/batch.css")));
146         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/brotherhood/batch.js")));
147         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood/batch.css")));
148 
149         assertEquals(4, size(builder.getAllIncludedResources()));
150     }
151 
152     public void testOverlappingDependencies() throws Exception
153     {
154         final String context1 = "xmen";
155         final String context2 = "government";
156         final String context3 = "brotherhood";
157         final List<String> contexts = new ArrayList<String>();
158         contexts.add(context1);
159         contexts.add(context2);
160 
161         final String moduleKey1 = "xavier-resources";
162         final String moduleKey2 = "magneto-resources";
163         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
164         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
165 
166         final String dependentModule1 = "new-mutants-resources";
167         final List<ResourceDescriptor> dependentResourceDescriptors1 = TestUtils.createResourceDescriptors("iceman.js", "iceman.css", "rogue.css");
168 
169         final String dependentModule2 = "government-resources";
170         final List<ResourceDescriptor> dependentResourceDescriptors2 = TestUtils.createResourceDescriptors("beast.js", "beast.js", "deathstrike.css");
171 
172         addModuleDescriptor(moduleKey1, resourceDescriptors1);
173         addModuleDescriptor(dependentModule1, dependentResourceDescriptors1);
174         addContext(context1, Arrays.asList(moduleKey1, dependentModule1));
175         addModuleDescriptor(dependentModule2, dependentResourceDescriptors2);
176         addContext(context2, Arrays.asList(moduleKey1, dependentModule2));
177 
178         // This shouldn't be added at all
179         addModuleDescriptor(moduleKey2, resourceDescriptors2);
180         addContext(context3, Arrays.asList(moduleKey2));
181 
182         final Iterable<PluginResource> resources = builder.build(contexts);
183 
184         assertEquals(2, size(resources));
185         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen,government/batch.js")));
186         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen,government/batch.css")));
187 
188         assertEquals(3, size(builder.getAllIncludedResources()));
189     }
190 
191     public void testMultipleOverlappingContexts() throws Exception
192     {
193         final String context1 = "xmen";
194         final String context2 = "brotherhood";
195         final String context3 = "rogue";
196         final String context4 = "normals";
197 
198         final List<String> contexts = new ArrayList<String>();
199         contexts.add(context1);
200         contexts.add(context2);
201         contexts.add(context3);
202         contexts.add(context4);
203 
204         final String moduleKey1 = "xavier-resources";
205         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "beast.css");
206 
207         final String moduleKey2 = "magneto-resources";
208         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
209 
210         final String moduleKey3 = "rogue-resources";
211         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("pyro.js", "phoenix.css", "mystique.css");
212 
213         final String moduleKey4 = "normal-resources";
214         final List<ResourceDescriptor> resourceDescriptors4 = TestUtils.createResourceDescriptors("stryker.js", "stryker.css");
215 
216         addModuleDescriptor(moduleKey1, resourceDescriptors1);
217         addModuleDescriptor(moduleKey2, resourceDescriptors2);
218         addModuleDescriptor(moduleKey3, resourceDescriptors3);
219         addModuleDescriptor(moduleKey4, resourceDescriptors4);
220 
221         addContext(context1, Arrays.asList(moduleKey1));
222         addContext(context2, Arrays.asList(moduleKey2));
223         addContext(context3, Arrays.asList(moduleKey1, moduleKey2, moduleKey3));
224 
225         addContext(context4, Arrays.asList(moduleKey4));
226 
227         final Iterable<PluginResource> resources = builder.build(contexts);
228 
229         assertEquals(4, size(resources));
230         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/normals/batch.js")));
231         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/normals/batch.css")));
232         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/brotherhood,xmen,rogue/batch.js")));
233         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood,xmen,rogue/batch.css")));
234 
235         assertEquals(4, size(builder.getAllIncludedResources()));
236     }
237 
238     public void testContextParams() throws Exception
239     {
240         final String context1 = "xmen";
241         final String context2 = "brotherhood";
242         final List<String> contexts = new ArrayList<String>();
243         contexts.add(context1);
244         contexts.add(context2);
245 
246         final String moduleKey1 = "xavier-resources";
247         final String moduleKey2 = "magneto-resources";
248         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "cyclops.css", "storm-ie.css");
249         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "sabretooth.css", "mystigue-ie.css");
250 
251         addModuleDescriptor(moduleKey1, resourceDescriptors1);
252         addContext(context1, Arrays.asList(moduleKey1));
253         addModuleDescriptor(moduleKey2, resourceDescriptors2);
254         addContext(context2, Arrays.asList(moduleKey2));
255 
256         final Iterable<PluginResource> resources = builder.build(contexts);
257 
258         assertEquals(6, size(resources));
259         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen/batch.css?ieonly=true")));
260         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen/batch.js")));
261         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen/batch.css")));
262         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood/batch.css?ieonly=true")));
263         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/brotherhood/batch.js")));
264         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood/batch.css")));
265 
266         assertEquals(2, size(builder.getAllIncludedResources()));
267     }
268 
269     public void testContextParamsInDependencies() throws Exception
270     {
271         final String context1 = "xmen";
272         final String context2 = "brotherhood";
273         final String context3 = "rogue";
274         final List<String> contexts = new ArrayList<String>();
275         contexts.add(context1);
276         contexts.add(context2);
277         contexts.add(context3);
278 
279         final String moduleKey1 = "xavier-resources";
280         final String moduleKey2 = "magneto-resources";
281         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx-ie.css", "cyclops.js");
282         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto-ie.css", "sabretooth.css");
283 
284         final String dependentModule1 = "rogue-resources";
285         final List<ResourceDescriptor> dependentResourceDescriptors1 = TestUtils.createResourceDescriptors("nightcrawler.js", "nightcrawler.css",
286             "gambit.css");
287 
288         addModuleDescriptor(moduleKey1, resourceDescriptors1);
289         addContext(context1, Arrays.asList(moduleKey1));
290         addModuleDescriptor(dependentModule1, dependentResourceDescriptors1);
291         addContext(context3, Arrays.asList(moduleKey1, dependentModule1));
292         addModuleDescriptor(moduleKey2, resourceDescriptors2);
293         addContext(context2, Arrays.asList(moduleKey2));
294 
295         final Iterable<PluginResource> resources = builder.build(contexts);
296 
297         // We currently batch all resource params even if there isn't any overlap in a particular context/param combination
298         assertEquals(6, size(resources));
299         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood/batch.css?ieonly=true")));
300         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/brotherhood/batch.js")));
301         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/brotherhood/batch.css")));
302         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen,rogue/batch.js")));
303         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen,rogue/batch.css?ieonly=true")));
304         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen,rogue/batch.css")));
305 
306         assertEquals(3, size(builder.getAllIncludedResources()));
307     }
308 
309     public void testMultipleContextsWithoutBatching() throws Exception
310     {
311         when(mockBatchingConfiguration.isContextBatchingEnabled()).thenReturn(false);
312         final String context1 = "xmen";
313         final String context2 = "brotherhood";
314         final List<String> contexts = new ArrayList<String>();
315         contexts.add(context1);
316         contexts.add(context2);
317 
318         final String moduleKey1 = "xavier-resources";
319         final String moduleKey2 = "magneto-resources";
320         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
321         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
322 
323         addModuleDescriptor(moduleKey1, resourceDescriptors1);
324         addModuleDescriptor(moduleKey2, resourceDescriptors2);
325         addContext(context1, Arrays.asList(moduleKey1, moduleKey2));
326         addContext(context2, Arrays.asList(moduleKey1, moduleKey2));
327 
328         final Iterable<PluginResource> resources = builder.build(contexts);
329 
330         assertEquals(6, size(resources));
331         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/professorx.js")));
332         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/professorx.css")));
333         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/cyclops.css")));
334         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:magneto-resources/magneto.js")));
335         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:magneto-resources/magneto.css")));
336         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:magneto-resources/sabretooth.css")));
337 
338         assertEquals(2, size(builder.getAllIncludedResources()));
339     }    
340 
341     public void testExcludedContextWithNoOverlap() throws Exception
342     {
343         final String context1 = "xmen";
344         final String context2 = "brotherhood";
345 
346         final String moduleKey1 = "xavier-resources";
347         final String moduleKey2 = "magneto-resources";
348         final String moduleKey3 = "fighting-chimps";
349         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
350         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
351         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("bobo.css", "chobo.css", "hobo.css");
352 
353         addModuleDescriptor(moduleKey1, resourceDescriptors1);
354         addModuleDescriptor(moduleKey2, resourceDescriptors2);
355         addModuleDescriptor(moduleKey3, resourceDescriptors3);
356         addContext(context1, Arrays.asList(moduleKey1, moduleKey3));
357         addContext(context2, Arrays.asList(moduleKey2));
358 
359         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Collections.singletonList(context2));
360 
361         assertEquals(2, size(resources)); 
362         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen/batch.js")));
363         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen/batch.css")));
364 
365         assertEquals(2, size(builder.getAllIncludedResources()));
366     }
367     
368     public void testExcludedContextWithOverlap() throws Exception
369     {
370         final String context1 = "xmen";
371         final String context2 = "brotherhood";
372         final String context3 = "xapes";
373 
374         final String moduleKey1 = "xavier-resources";
375         final String moduleKey2 = "magneto-resources";
376         final String moduleKey3 = "fighting-chimps";
377         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
378         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
379         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("bobo.css", "chobo.css", "hobo.css");
380 
381         addModuleDescriptor(moduleKey1, resourceDescriptors1);
382         addModuleDescriptor(moduleKey2, resourceDescriptors2);
383         addModuleDescriptor(moduleKey3, resourceDescriptors3);
384         addContext(context1, Arrays.asList(moduleKey1, moduleKey2, moduleKey3));
385         addContext(context2, Arrays.asList(moduleKey2));
386         addContext(context3, Arrays.asList(moduleKey3));
387 
388         final Iterable<PluginResource> resources = builder.build(Arrays.asList(context1, context2), Collections.singletonList(context3));
389 
390         assertEquals(2, size(resources));
391         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen,brotherhood,-xapes/batch.js")));
392         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen,brotherhood,-xapes/batch.css")));
393 
394         assertEquals(2, size(builder.getAllIncludedResources()));
395     }
396     
397     public void testMultipleExcludedContextWithOverlap() throws Exception
398     {
399         final String context1 = "xmen";
400         final String context2 = "brotherhood";
401         final String context3 = "xapes";
402 
403         final String moduleKey1 = "xavier-resources";
404         final String moduleKey2 = "magneto-resources";
405         final String moduleKey3 = "fighting-chimps";
406         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "cyclops.js");
407         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
408         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("bobo.css", "chobo.css", "hobo.css");
409 
410         addModuleDescriptor(moduleKey1, resourceDescriptors1);
411         addModuleDescriptor(moduleKey2, resourceDescriptors2);
412         addModuleDescriptor(moduleKey3, resourceDescriptors3);
413         addContext(context1, Arrays.asList(moduleKey1, moduleKey2, moduleKey3));
414         addContext(context2, Arrays.asList(moduleKey2));
415         addContext(context3, Arrays.asList(moduleKey3));
416 
417         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Arrays.asList(context2,context3));
418 
419         assertEquals(1, size(resources));
420         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen,-xapes,-brotherhood/batch.js")));
421 
422         assertEquals(1, size(builder.getAllIncludedResources()));    
423     }
424     
425     public void testMultipleExcludedContextWithPartialOverlap() throws Exception
426     {
427         final String context1 = "xmen";
428         final String context2 = "brotherhood";
429         final String context3 = "xapes";
430 
431         final String moduleKey1 = "xavier-resources";
432         final String moduleKey2 = "magneto-resources";
433         final String moduleKey3 = "fighting-chimps";
434         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
435         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
436         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("bobo.css", "chobo.css", "hobo.css");
437 
438         addModuleDescriptor(moduleKey1, resourceDescriptors1);
439         addModuleDescriptor(moduleKey2, resourceDescriptors2);
440         addModuleDescriptor(moduleKey3, resourceDescriptors3);
441         addContext(context1, Arrays.asList(moduleKey1, moduleKey2));
442         addContext(context2, Arrays.asList(moduleKey2));
443         addContext(context3, Arrays.asList(moduleKey3));
444 
445         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Arrays.asList(context2,context3));
446 
447         assertEquals(2, size(resources));
448         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/js/xmen,-brotherhood/batch.js")));
449         assertNotNull(find(resources, new IsResourceWithUrl("/download/contextbatch/css/xmen,-brotherhood/batch.css")));
450 
451         assertEquals(1, size(builder.getAllIncludedResources()));        
452     }
453     
454     public void testIncludeAndExcludeLeavesNoResourcesInBatch() throws Exception
455     {
456         final String context1 = "xmen";
457         final String context2 = "brotherhood";
458         final String context3 = "xapes";
459 
460         final String moduleKey1 = "xavier-resources";
461         final String moduleKey2 = "magneto-resources";
462         final String moduleKey3 = "fighting-chimps";
463         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
464         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
465         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("bobo.css", "chobo.css", "hobo.css");
466 
467         addModuleDescriptor(moduleKey1, resourceDescriptors1);
468         addModuleDescriptor(moduleKey2, resourceDescriptors2);
469         addModuleDescriptor(moduleKey3, resourceDescriptors3);
470         addContext(context1, Arrays.asList(moduleKey1, moduleKey2, moduleKey3));
471         addContext(context2, Arrays.asList(moduleKey2, moduleKey1));
472         addContext(context3, Arrays.asList(moduleKey3));
473 
474         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Arrays.asList(context2,context3));
475 
476         assertEquals(0, size(resources));
477         assertEquals(0, size(builder.getAllIncludedResources()));    
478     }
479     
480     // You shouldn't be doing this but it could be easily done by accident.
481     public void testIncludeAndExcludeTheSameBatch() throws Exception
482     {
483         final String context1 = "xmen";
484 
485         final String moduleKey1 = "xavier-resources";
486         final String moduleKey2 = "magneto-resources";
487         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
488         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
489 
490         addModuleDescriptor(moduleKey1, resourceDescriptors1);
491         addModuleDescriptor(moduleKey2, resourceDescriptors2);
492         addContext(context1, Arrays.asList(moduleKey1, moduleKey2));
493 
494         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Collections.singletonList(context1));
495 
496         assertEquals(0, size(resources));
497         assertEquals(0, size(builder.getAllIncludedResources()));    
498     }
499             
500     public void testExcludedContextWithNoOverlapUnbatched() throws Exception
501     {
502         when(mockBatchingConfiguration.isContextBatchingEnabled()).thenReturn(false);
503         final String context1 = "xmen";
504         final String context2 = "brotherhood";
505 
506         final String moduleKey1 = "xavier-resources";
507         final String moduleKey2 = "magneto-resources";
508         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
509         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
510 
511         addModuleDescriptor(moduleKey1, resourceDescriptors1);
512         addModuleDescriptor(moduleKey2, resourceDescriptors2);
513         addContext(context1, Arrays.asList(moduleKey1));
514         addContext(context2, Arrays.asList(moduleKey2));
515 
516         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context2), Collections.singletonList(context1));
517 
518         assertEquals(3, size(resources));
519         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:magneto-resources/magneto.js")));
520         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:magneto-resources/magneto.css")));
521         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:magneto-resources/sabretooth.css")));
522 
523         assertEquals(1, size(builder.getAllIncludedResources()));
524     }
525     
526     public void testExcludedContextWithOverlapUnbatched() throws Exception
527     {
528         when(mockBatchingConfiguration.isContextBatchingEnabled()).thenReturn(false);
529         final String context1 = "xmen";
530         final String context2 = "brotherhood";
531 
532         final String moduleKey1 = "xavier-resources";
533         final String moduleKey2 = "magneto-resources";
534         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
535         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
536 
537         addModuleDescriptor(moduleKey1, resourceDescriptors1);
538         addModuleDescriptor(moduleKey2, resourceDescriptors2);
539         addContext(context1, Arrays.asList(moduleKey1, moduleKey2));
540         addContext(context2, Arrays.asList(moduleKey2));
541 
542         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Collections.singletonList(context2));
543 
544         assertEquals(3, size(resources));
545         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/professorx.js")));
546         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/professorx.css")));
547         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/cyclops.css")));
548 
549         assertEquals(1, size(builder.getAllIncludedResources()));
550     }
551     
552     public void testMultipleExcludedContextWithSomeOverlapUnbatched() throws Exception
553     {
554         when(mockBatchingConfiguration.isContextBatchingEnabled()).thenReturn(false);
555         final String context1 = "xmen";
556         final String context2 = "brotherhood";
557         final String context3 = "xapes";
558 
559         final String moduleKey1 = "xavier-resources";
560         final String moduleKey2 = "magneto-resources";
561         final String moduleKey3 = "fighting-chimps";
562         final List<ResourceDescriptor> resourceDescriptors1 = TestUtils.createResourceDescriptors("professorx.js", "professorx.css", "cyclops.css");
563         final List<ResourceDescriptor> resourceDescriptors2 = TestUtils.createResourceDescriptors("magneto.js", "magneto.css", "sabretooth.css");
564         final List<ResourceDescriptor> resourceDescriptors3 = TestUtils.createResourceDescriptors("bobo.css", "chobo.css", "hobo.css");
565 
566         addModuleDescriptor(moduleKey1, resourceDescriptors1);
567         addModuleDescriptor(moduleKey2, resourceDescriptors2);
568         addModuleDescriptor(moduleKey3, resourceDescriptors3);
569         addContext(context1, Arrays.asList(moduleKey1, moduleKey3));
570         addContext(context2, Arrays.asList(moduleKey2, moduleKey3));
571         addContext(context3, Arrays.asList(moduleKey3));
572 
573         final Iterable<PluginResource> resources = builder.build(Collections.singletonList(context1), Arrays.asList(context2,context3));
574 
575         assertEquals(3, size(resources));
576         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/professorx.js")));
577         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/professorx.css")));
578         assertNotNull(find(resources, new IsResourceWithUrl("/download/resources/test.atlassian:xavier-resources/cyclops.css")));
579 
580         assertEquals(1, size(builder.getAllIncludedResources()));
581     }
582     
583     private void addContext(final String context, final List<String> descriptors)
584     {
585         final List<WebResourceModuleDescriptor> moduleDescriptors = new ArrayList<WebResourceModuleDescriptor>();
586 
587         for (final String moduleKey : descriptors)
588         {
589             final String completeKey = testPlugin.getKey() + ":" + moduleKey;
590             moduleDescriptors.add(TestUtils.createWebResourceModuleDescriptor(completeKey, testPlugin));
591         }
592 
593         // cover the bases - some usages of the mockDependencyResolver will supply the 'skippedResources' param.
594         when(mockDependencyResolver.getDependenciesInContext(context)).thenReturn(moduleDescriptors);
595         when(mockDependencyResolver.getDependenciesInContext(context, Collections.<String> emptySet())).thenReturn(moduleDescriptors);
596     }
597 
598     private void addModuleDescriptor(final String moduleKey, final List<ResourceDescriptor> descriptors)
599     {
600         final String completeKey = testPlugin.getKey() + ":" + moduleKey;
601 
602         final List<PluginResource> pluginResources = new ArrayList<PluginResource>();
603         for (final ResourceDescriptor descriptor : descriptors)
604         {
605             pluginResources.add(new SinglePluginResource(descriptor.getName(), completeKey, false, descriptor.getParameters()));
606         }
607 
608         when(mockPluginResourceLocator.getPluginResources(completeKey)).thenReturn(pluginResources);
609     }
610     
611     class IsResourceWithUrl implements Predicate<PluginResource>
612     {
613         private final String url;
614 
615         public IsResourceWithUrl(String url)
616         {
617             this.url = url;
618         }
619 
620         public boolean apply(PluginResource resource)
621         {
622             return  url.equals(resource.getUrl());
623         }
624     }       
625 }