1   package com.atlassian.plugin.servlet;
2   
3   import com.atlassian.plugin.elements.ResourceLocation;
4   import com.atlassian.plugin.servlet.util.CapturingHttpServletResponse;
5   import com.atlassian.plugin.util.PluginUtils;
6   
7   import java.io.ByteArrayInputStream;
8   import java.io.ByteArrayOutputStream;
9   import java.io.InputStream;
10  
11  import junit.framework.AssertionFailedError;
12  import junit.framework.TestCase;
13  
14  /**
15   * A test for AbstractDownloadableResource
16   */
17  public class TestAbstractDownloadableResource extends TestCase
18  {
19      private static final String MINIFIED_CONTENT = "minified content";
20      private static final String PLAIN_CONTENT = "plain content";
21      private static final String NEVER_MINIFIED_CONTENT = "never minified content";
22  
23      private class MinifiedFileServingDownloableResource extends AbstractDownloadableResource
24      {
25  
26          public MinifiedFileServingDownloableResource(final ResourceLocation resourceLocation)
27          {
28              super(null, resourceLocation, null);
29          }
30  
31          @Override
32          protected String getLocation()
33          {
34              return "somecode.js";
35          }
36  
37          @Override
38          public String getContentType()
39          {
40              return "minified/content";
41          }
42  
43          @Override
44          protected InputStream getResourceAsStream(final String resourceLocation)
45          {
46              if (resourceLocation.contains("-min."))
47              {
48                  assertEquals("somecode-min.js", resourceLocation);
49                  return newStream(MINIFIED_CONTENT);
50              }
51              assertEquals("somecode.js", resourceLocation);
52              return newStream(PLAIN_CONTENT);
53          }
54  
55          private InputStream newStream(final String s)
56          {
57              return new ByteArrayInputStream(s.getBytes());
58          }
59      }
60  
61      private class MyDownloableResource extends AbstractDownloadableResource
62      {
63          public String getPassedResourceLocation()
64          {
65              return passedResourceLocation;
66          }
67  
68          private String passedResourceLocation;
69  
70          public MyDownloableResource(final ResourceLocation resourceLocation, final boolean disableMinification)
71          {
72              super(null, resourceLocation, "", disableMinification);
73          }
74  
75          @Override
76          protected InputStream getResourceAsStream(final String resourceLocation)
77          {
78              passedResourceLocation = resourceLocation;
79              return newStream(resourceLocation);
80          }
81  
82          private InputStream newStream(final String s)
83          {
84              return new ByteArrayInputStream(s.getBytes());
85          }
86      }
87  
88      private class NotMinifiedFileServingDownloableResouce extends AbstractDownloadableResource
89      {
90          public NotMinifiedFileServingDownloableResouce()
91          {
92              super(null, new ResourceLocation("/flintstone/fred.jpg", "fred.jpg", "stuff", "stuff", "stuff", null), null);
93          }
94  
95          @Override
96          protected String getLocation()
97          {
98              return "somemorecode.js";
99          }
100 
101         @Override
102         public String getContentType()
103         {
104             return "plain/content";
105         }
106 
107         @Override
108         protected InputStream getResourceAsStream(final String resourceLocation)
109         {
110             if (resourceLocation.contains("-min."))
111             {
112                 assertEquals("somemorecode-min.js", resourceLocation);
113                 return null;
114             }
115             assertEquals("somemorecode.js", resourceLocation);
116             return newStream(PLAIN_CONTENT);
117         }
118 
119         private InputStream newStream(final String s)
120         {
121             return new ByteArrayInputStream(s.getBytes());
122         }
123 
124     }
125 
126     private class NeverMinifiedFileServingDownloableResouce extends AbstractDownloadableResource
127     {
128         public NeverMinifiedFileServingDownloableResouce()
129         {
130             super(null, new ResourceLocation("/flintstone/fred.jpg", "fred.jpg", "stuff", "stuff", "stuff", null), null);
131         }
132 
133         @Override
134         protected String getLocation()
135         {
136             return "neverminified.js";
137         }
138 
139         @Override
140         public String getContentType()
141         {
142             return "neverminified/content";
143         }
144 
145         @Override
146         protected InputStream getResourceAsStream(final String resourceLocation)
147         {
148             if (resourceLocation.contains("-min."))
149             {
150                 fail("it should never ask for this");
151             }
152             assertEquals("neverminified.js", resourceLocation);
153             return newStream(NEVER_MINIFIED_CONTENT);
154         }
155 
156         private InputStream newStream(final String s)
157         {
158             return new ByteArrayInputStream(s.getBytes());
159         }
160     }
161 
162     public void testMinificationStrategyWrongFileType() throws Exception
163     {
164         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred.jpg", "fred.jpg", "stuff", "stuff", "stuff", null);
165         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
166         myDownloableResource.streamResource(new ByteArrayOutputStream());
167 
168         assertEquals("/flintstone/fred.jpg", myDownloableResource.passedResourceLocation);
169     }
170 
171     public void testMinificationStrategyCss() throws Exception
172     {
173         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred.css", "fred.css", "stuff", "stuff", "stuff", null);
174         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
175         myDownloableResource.streamResource(new ByteArrayOutputStream());
176 
177         assertEquals("/flintstone/fred-min.css", myDownloableResource.passedResourceLocation);
178     }
179 
180     public void testMinificationStrategyWithTwoMinsInName() throws Exception
181     {
182         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone-min./fred-min.js", "fred-min.js", "stuff", "stuff", "stuff", null);
183         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
184         myDownloableResource.streamResource(new ByteArrayOutputStream());
185 
186         assertEquals("/flintstone-min./fred-min.js", myDownloableResource.passedResourceLocation);
187     }
188 
189     public void testMinificationStrategyAlreadyMinimised() throws Exception
190     {
191         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred-min.js", "fred-min.js", "stuff", "stuff", "stuff", null);
192         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
193         myDownloableResource.streamResource(new ByteArrayOutputStream());
194 
195         assertEquals("/flintstone/fred-min.js", myDownloableResource.passedResourceLocation);
196     }
197 
198     public void testMinificationStrategyNotMinimisedAndEnabled() throws Exception
199     {
200         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred.js", "fred.js", "stuff", "stuff", "stuff", null);
201         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
202         myDownloableResource.streamResource(new ByteArrayOutputStream());
203 
204         assertEquals("/flintstone/fred-min.js", myDownloableResource.passedResourceLocation);
205     }
206 
207     public void testMinificationStrategyNotMinimisedAndDisabled() throws Exception
208     {
209         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred.js", "fred.js", "stuff", "stuff", "stuff", null);
210         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, true);
211         myDownloableResource.streamResource(new ByteArrayOutputStream());
212 
213         assertEquals("/flintstone/fred.js", myDownloableResource.passedResourceLocation);
214     }
215 
216     public void testMinificationStrategyNotMinimisedAndSystemDisabled() throws Exception
217     {
218         System.setProperty("atlassian.webresource.disable.minification", "true");
219 
220         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred.js", "fred.js", "stuff", "stuff", "stuff", null);
221         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
222         myDownloableResource.streamResource(new ByteArrayOutputStream());
223 
224         assertEquals("/flintstone/fred.js", myDownloableResource.passedResourceLocation);
225     }
226 
227     public void testMinificationStrategyNotMinimisedAndSystemEnabled() throws Exception
228     {
229         System.setProperty("atlassian.webresource.disable.minification", "false");
230 
231         final ResourceLocation resourceLocation = new ResourceLocation("/flintstone/fred.js", "fred.js", "stuff", "stuff", "stuff", null);
232         final MyDownloableResource myDownloableResource = new MyDownloableResource(resourceLocation, false);
233         myDownloableResource.streamResource(new ByteArrayOutputStream());
234 
235         assertEquals("/flintstone/fred-min.js", myDownloableResource.passedResourceLocation);
236     }
237 
238     public void testWithMinifiedStrategyInPlay() throws DownloadException
239     {
240         // it should ask for -min files first and in this case get content back
241         final MinifiedFileServingDownloableResource minifiedFileServingDownloableResource = new MinifiedFileServingDownloableResource(new ResourceLocation("/flintstone/fred.jpg", "fred.jpg", "stuff", "stuff", "stuff", null));
242         assertContent(minifiedFileServingDownloableResource, MINIFIED_CONTENT);
243 
244         // it should ask for -min files first but get null and hence move on to the plain old content case.
245         final NotMinifiedFileServingDownloableResouce notMinifiedFileServingDownloableResouce = new NotMinifiedFileServingDownloableResouce();
246         assertContent(notMinifiedFileServingDownloableResouce, PLAIN_CONTENT);
247 
248     }
249 
250     public void testWhenSystemPropertyIsSet() throws DownloadException
251     {
252         verifySystemPropertyRespected("atlassian.webresource.disable.minification");
253     }
254 
255     public void testWhenDevModeSystemPropertyIsSet() throws DownloadException
256     {
257         verifySystemPropertyRespected(PluginUtils.ATLASSIAN_DEV_MODE);
258     }
259 
260     private void verifySystemPropertyRespected(String sysprop)
261             throws DownloadException
262     {
263         try
264         {
265             System.setProperty(sysprop, "true");
266 
267             // now in this case it must never ask for minified files.  This class used will assert that.
268             final NeverMinifiedFileServingDownloableResouce neverMinifiedFileServingDownloableResouce = new NeverMinifiedFileServingDownloableResouce();
269             assertContent(neverMinifiedFileServingDownloableResouce, NEVER_MINIFIED_CONTENT);
270 
271             final MinifiedFileServingDownloableResource minifiedFileServingDownloableResouce = new MinifiedFileServingDownloableResource(new ResourceLocation("/flintstone/fred.jpg", "fred.jpg", "stuff", "stuff", "stuff", null));
272             assertContent(minifiedFileServingDownloableResouce, PLAIN_CONTENT);
273 
274             // it should ask for -min files first but get null and hence move on to the plain old content case.
275             final NotMinifiedFileServingDownloableResouce notMinifiedFileServingDownloableResouce = new NotMinifiedFileServingDownloableResouce();
276             assertContent(notMinifiedFileServingDownloableResouce, PLAIN_CONTENT);
277 
278             System.setProperty(sysprop, "false");
279 
280             // it should ask for -min files first and in this case get content back
281             assertContent(minifiedFileServingDownloableResouce, MINIFIED_CONTENT);
282 
283             // it should ask for -min files first but get null and hence move on to the plain old content case.
284             assertContent(notMinifiedFileServingDownloableResouce, PLAIN_CONTENT);
285 
286             //
287             // now this test is wierd but hey.  If I call back on a never minified resource class object it should
288             // throw an assertion exception that it doesnt expect it.  This proves that it odes indeed get called
289             // with a -min version of itself
290             try
291             {
292                 assertContent(neverMinifiedFileServingDownloableResouce, "doesnt matter");
293 
294                 fail("This should have barfed in NeverMinifiedFileServingDownloableResouce");
295             }
296             catch (final AssertionFailedError expected)
297             {
298                 // this is expected since the test class asserts tgat a -min file should never be called on it.
299                 // and hence by inference the atlassian.webresource.disable.minification property is not taking effect
300             }
301         }
302         finally
303         {
304             // reset for this test
305             System.setProperty(sysprop, "false");
306         }
307     }
308 
309     private void assertContent(final AbstractDownloadableResource downloadableResource, final String content) throws DownloadException
310     {
311         final CapturingHttpServletResponse httpServletResponse = new CapturingHttpServletResponse();
312         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
313 
314         try
315         {
316             downloadableResource.serveResource(null, httpServletResponse);
317         }
318         catch (final DownloadException e)
319         {
320             throw new RuntimeException(e);
321         }
322         downloadableResource.streamResource(baos);
323 
324         assertEquals(content, httpServletResponse.toString());
325         assertEquals(content, baos.toString());
326     }
327 }