1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.web

File DownloadActionTest.java

 

Code metrics

6
246
41
1
645
473
45
0.18
6
41
1.1

Classes

Class Line # Actions
DownloadActionTest 65 246 0% 45 3
0.989761199%
 

Contributing tests

This file is covered by 31 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.web;
21   
22    import java.io.ByteArrayInputStream;
23    import java.io.IOException;
24    import java.io.UnsupportedEncodingException;
25    import java.util.Date;
26   
27    import javax.servlet.ServletOutputStream;
28    import javax.servlet.http.HttpServletResponse;
29   
30    import org.junit.Before;
31    import org.junit.Rule;
32    import org.junit.Test;
33    import org.mockito.ArgumentMatcher;
34    import org.xwiki.model.reference.AttachmentReference;
35    import org.xwiki.model.reference.DocumentReference;
36    import org.xwiki.resource.ResourceReference;
37    import org.xwiki.resource.ResourceReferenceManager;
38    import org.xwiki.resource.entity.EntityResourceAction;
39    import org.xwiki.resource.entity.EntityResourceReference;
40   
41    import com.xpn.xwiki.XWiki;
42    import com.xpn.xwiki.XWikiContext;
43    import com.xpn.xwiki.XWikiException;
44    import com.xpn.xwiki.doc.XWikiAttachment;
45    import com.xpn.xwiki.doc.XWikiDocument;
46    import com.xpn.xwiki.plugin.XWikiPluginManager;
47    import com.xpn.xwiki.test.MockitoOldcoreRule;
48   
49    import static org.junit.Assert.assertEquals;
50    import static org.junit.Assert.assertNull;
51    import static org.junit.Assert.fail;
52    import static org.mockito.ArgumentMatchers.any;
53    import static org.mockito.ArgumentMatchers.argThat;
54    import static org.mockito.ArgumentMatchers.eq;
55    import static org.mockito.Mockito.doReturn;
56    import static org.mockito.Mockito.mock;
57    import static org.mockito.Mockito.verify;
58    import static org.mockito.Mockito.when;
59   
60    /**
61    * Validate {@link DownloadAction}.
62    *
63    * @version $Id: b25c2cf5870495425da1b3f35603ed4d61bad4eb $
64    */
 
65    public class DownloadActionTest
66    {
67    /** The name of the attachment being downloaded in most of the tests. */
68    private static final String DEFAULT_FILE_NAME = "file.txt";
69   
70    /** The URI requested in most of the tests. */
71    private static final String DEFAULT_URI = "/xwiki/bin/download/space/page/file.txt";
72   
73    @Rule
74    public MockitoOldcoreRule oldcore = new MockitoOldcoreRule();
75   
76    /** Mocked context document. */
77    private XWikiDocument document;
78   
79    /** Mocked client request. */
80    private XWikiRequest request;
81   
82    /** Mocked client response. */
83    private XWikiResponse response;
84   
85    /** Mocked engine context. */
86    private XWikiEngineContext ec;
87   
88    /** A mocked output stream where the output file data is being written. */
89    private ServletOutputStream out;
90   
91    /** The action being tested. */
92    private DownloadAction action = new DownloadAction();
93   
94    /** The content of the file being downloaded in most of the tests. */
95    private byte[] fileContent = "abcdefghijklmn".getBytes(XWiki.DEFAULT_ENCODING);
96   
97    private ResourceReferenceManager resourceReferenceManager;
98   
99    private DocumentReference documentReference;
100   
101    /**
102    * Default constructor.
103    *
104    * @throws UnsupportedEncodingException if UTF-8 is not available, so never
105    */
 
106  31 toggle public DownloadActionTest() throws UnsupportedEncodingException
107    {
108    // Empty, needed for declaring the exception thrown while initializing fileContent
109    }
110   
 
111  31 toggle @Before
112    public void before() throws Exception
113    {
114  31 this.oldcore.registerMockEnvironment();
115   
116  31 this.request = mock(XWikiRequest.class);
117  31 this.oldcore.getXWikiContext().setRequest(this.request);
118  31 this.response = mock(XWikiResponse.class);
119  31 this.oldcore.getXWikiContext().setResponse(this.response);
120  31 this.ec = mock(XWikiEngineContext.class);
121  31 this.oldcore.getXWikiContext().setEngineContext(this.ec);
122  31 this.out = mock(ServletOutputStream.class);
123   
124  31 XWikiPluginManager pluginManager = new XWikiPluginManager();
125  31 pluginManager.initInterface();
126   
127  31 this.documentReference = new DocumentReference("wiki", "space", "page");
128  31 this.document = new XWikiDocument(this.documentReference);
129  31 this.oldcore.getXWikiContext().setDoc(this.document);
130   
131  31 doReturn(pluginManager).when(this.oldcore.getSpyXWiki()).getPluginManager();
132  31 when(this.ec.getMimeType("file.txt")).thenReturn("text/plain");
133  31 when(this.response.getOutputStream()).thenReturn(this.out);
134  31 when(this.oldcore.getMockRightService().hasAccessLevel(eq("programming"), any(), any(),
135    any(XWikiContext.class))).thenReturn(false);
136   
137    // Mock what's needed for extracting the filename from the URL
138  31 this.resourceReferenceManager = this.oldcore.getMocker().registerMockComponent(ResourceReferenceManager.class);
139    }
140   
 
141  1 toggle @Test
142    public void downloadNormal() throws XWikiException, IOException
143    {
144  1 Date d = new Date();
145  1 createAttachment(d, DEFAULT_FILE_NAME);
146  1 setRequestExpectations(DEFAULT_URI, null, null, null, -1l, DEFAULT_FILE_NAME);
147   
148  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
149   
150  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
151  1 verifyOutputExpectations(0, this.fileContent.length);
152    }
153   
 
154  1 toggle @Test
155    public void downloadWhenIfModifiedSinceBefore() throws XWikiException, IOException
156    {
157  1 Date d = new Date();
158  1 createAttachment(d, DEFAULT_FILE_NAME);
159  1 setRequestExpectations(DEFAULT_URI, null, null, null, d.getTime() - 1000l, DEFAULT_FILE_NAME);
160   
161  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
162   
163  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
164  1 verifyOutputExpectations(0, this.fileContent.length);
165    }
166   
 
167  1 toggle @Test
168    public void downloadWhenIfModifiedSinceSame() throws XWikiException, IOException
169    {
170  1 Date d = new Date();
171  1 createAttachment(d, DEFAULT_FILE_NAME);
172  1 setRequestExpectations(DEFAULT_URI, null, null, null, d.getTime(), DEFAULT_FILE_NAME);
173   
174  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
175    }
176   
 
177  1 toggle @Test
178    public void downloadWhenIfModifiedSinceAfter() throws XWikiException, IOException
179    {
180  1 Date d = new Date();
181  1 createAttachment(d, DEFAULT_FILE_NAME);
182  1 setRequestExpectations(DEFAULT_URI, null, null, null, d.getTime() + 1000l, DEFAULT_FILE_NAME);
183   
184  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
185    }
186   
 
187  1 toggle @Test(expected = XWikiException.class)
188    public void downloadWhenMissingFile() throws XWikiException
189    {
190  1 setRequestExpectations("/xwiki/bin/download/space/page/nofile.txt", null, null, null, -1l, DEFAULT_FILE_NAME);
191   
192  1 this.action.render(this.oldcore.getXWikiContext());
193    }
194   
 
195  1 toggle @Test
196    public void downloadWhenURLNotPointingToAttachment() throws XWikiException
197    {
198  1 ResourceReference rr = new EntityResourceReference(this.documentReference, EntityResourceAction.VIEW);
199  1 when(this.resourceReferenceManager.getResourceReference()).thenReturn(rr);
200   
201  1 when(this.request.getRequestURI()).thenReturn("/xwiki/bin/download/space/page");
202   
203  1 try {
204  1 this.action.render(this.oldcore.getXWikiContext());
205  0 fail("Should have thrown an exception before reaching here");
206    } catch (XWikiException expected) {
207  1 assertEquals("Error number 11003 in 11: Attachment not found", expected.getMessage());
208    }
209    }
210   
 
211  1 toggle @Test
212    public void downloadById() throws XWikiException, IOException
213    {
214  1 Date d = new Date();
215  1 XWikiAttachment att;
216  11 for (byte i = 0; i < 10; ++i) {
217  10 att = new XWikiAttachment(this.document, "file." + i + ".txt");
218  10 byte[] content = new byte[1];
219  10 content[0] = (byte) ('0' + i);
220  10 att.setContent(new ByteArrayInputStream(content));
221  10 att.setDate(d);
222  10 this.document.getAttachmentList().add(att);
223    }
224   
225  1 when(this.ec.getMimeType("file.5.txt")).thenReturn("text/plain");
226   
227  1 setRequestExpectations("/xwiki/bin/download/space/page/file.2.txt", "5", null, null, -1l, DEFAULT_FILE_NAME);
228   
229  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
230   
231  1 verifyResponseExpectations(d.getTime(), 1, "text/plain", "inline; filename*=utf-8''file.5.txt");
232  1 verify(this.out).write(argThat(new ArgumentMatcher<byte[]>()
233    {
 
234  2 toggle @Override
235    public boolean matches(byte[] argument)
236    {
237  2 return argument[0] == '5';
238    }
239    }), eq(0), eq(1));
240  1 verify(this.out).write(argThat(new ArgumentMatcher<byte[]>()
241    {
 
242  2 toggle @Override
243    public boolean matches(byte[] argument)
244    {
245  2 return argument[0] == '5';
246    }
247    }), eq(0), eq(1));
248    }
249   
 
250  1 toggle @Test(expected = XWikiException.class)
251    public void testDownloadByWrongId() throws XWikiException, IOException
252    {
253  1 Date d = new Date();
254  1 createAttachment(d, DEFAULT_FILE_NAME);
255  1 setRequestExpectations(DEFAULT_URI, "42", null, null, -1l, DEFAULT_FILE_NAME);
256   
257  1 this.action.render(this.oldcore.getXWikiContext());
258    }
259   
 
260  1 toggle @Test
261    public void downloadWhenInvalidId() throws XWikiException, IOException
262    {
263  1 Date d = new Date();
264  1 createAttachment(d, DEFAULT_FILE_NAME);
265  1 setRequestExpectations(DEFAULT_URI, "two", null, null, -1l, DEFAULT_FILE_NAME);
266   
267  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
268   
269  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
270  1 verifyOutputExpectations(0, this.fileContent.length);
271    }
272   
 
273  1 toggle @Test(expected = XWikiException.class)
274    public void downloadWhenIncompletePath() throws XWikiException
275    {
276  1 setRequestExpectations("/xwiki/bin/download/", null, null, null, -1l, DEFAULT_FILE_NAME);
277   
278  1 this.action.render(this.oldcore.getXWikiContext());
279    }
280   
 
281  1 toggle @Test
282    public void downloadWhenDifferentMimeType() throws XWikiException, IOException
283    {
284  1 Date d = new Date();
285  1 createAttachment(d, "file.png");
286  1 when(this.ec.getMimeType("file.png")).thenReturn("image/png");
287  1 setRequestExpectations("/xwiki/bin/download/space/page/file.png", null, null, null, -1l, "file.png");
288   
289  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
290   
291  1 verifyResponseExpectations(d.getTime(), this.fileContent.length, "image/png",
292    "inline; filename*=utf-8''file.png");
293  1 verifyOutputExpectations(0, this.fileContent.length);
294    }
295   
 
296  1 toggle @Test
297    public void downloadWhenForce() throws XWikiException, IOException
298    {
299  1 Date d = new Date();
300  1 createAttachment(d, DEFAULT_FILE_NAME);
301  1 setRequestExpectations(DEFAULT_URI, null, "1", null, -1l, DEFAULT_FILE_NAME);
302   
303  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
304   
305  1 verifyResponseExpectations(d.getTime(), this.fileContent.length, "text/plain",
306    "attachment; filename*=utf-8''file.txt");
307  1 verifyOutputExpectations(0, this.fileContent.length);
308    }
309   
 
310  1 toggle @Test
311    public void downloadWithRealDate() throws XWikiException, IOException
312    {
313  1 Date d = new Date(411757300000l);
314  1 createAttachment(d, DEFAULT_FILE_NAME);
315  1 setRequestExpectations(DEFAULT_URI, null, null, null, -1l, DEFAULT_FILE_NAME);
316   
317  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
318   
319  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
320  1 verifyOutputExpectations(0, this.fileContent.length);
321    }
322   
 
323  1 toggle @Test
324    public void downloadWhenNameWithSpacesEncodedWithPlus() throws XWikiException, IOException
325    {
326  1 Date d = new Date();
327  1 createAttachment(d, "file name.txt");
328  1 when(this.ec.getMimeType("file name.txt")).thenReturn("text/plain");
329  1 setRequestExpectations("/xwiki/bin/download/space/page/file+name.txt", null, null, null, -1l, "file name.txt");
330   
331  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
332   
333  1 verifyResponseExpectations(d.getTime(), this.fileContent.length, "text/plain",
334    "inline; filename*=utf-8''file%20name.txt");
335  1 verifyOutputExpectations(0, this.fileContent.length);
336    }
337   
 
338  1 toggle @Test
339    public void downloadWhenNameWithSpacesEncodedWithPercent() throws XWikiException, IOException
340    {
341  1 Date d = new Date();
342  1 createAttachment(d, "file name.txt");
343  1 when(this.ec.getMimeType("file name.txt")).thenReturn("text/plain");
344  1 setRequestExpectations("/xwiki/bin/download/space/page/file%20name.txt", null, "1", null, -1l, "file name.txt");
345   
346  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
347   
348  1 verifyResponseExpectations(d.getTime(), this.fileContent.length, "text/plain",
349    "attachment; filename*=utf-8''file%20name.txt");
350  1 verifyOutputExpectations(0, this.fileContent.length);
351    }
352   
 
353  1 toggle @Test
354    public void downloadWhenNameWithNonAsciiChars() throws XWikiException, IOException
355    {
356  1 Date d = new Date();
357  1 createAttachment(d, "file\u021B.txt");
358   
359  1 when(this.ec.getMimeType("file\u021B.txt")).thenReturn("text/plain");
360  1 setRequestExpectations("/xwiki/bin/download/space/page/file%C8%9B.txt", null, "1", null, -1l, "file\u021B.txt");
361   
362  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
363   
364  1 verifyResponseExpectations(d.getTime(), this.fileContent.length, "text/plain",
365    "attachment; filename*=utf-8''file%C8%9B.txt");
366  1 verifyOutputExpectations(0, this.fileContent.length);
367    }
368   
 
369  1 toggle @Test
370    public void downloadWhenValidStartRange() throws XWikiException, IOException
371    {
372    // This test expects bytes 0, 1, 2 and 3 from the file.
373  1 Date d = new Date();
374  1 createAttachment(d, DEFAULT_FILE_NAME);
375  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=0-3", -1l, DEFAULT_FILE_NAME);
376   
377  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
378   
379  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
380  1 verify(this.response).setHeader("Content-Range", "bytes 0-3/" + DownloadActionTest.this.fileContent.length);
381  1 verifyResponseExpectations(d.getTime(), 4);
382  1 verifyOutputExpectations(0, 4);
383    }
384   
 
385  1 toggle @Test
386    public void downloadWhenValidMiddleRange() throws XWikiException, IOException
387    {
388    // This test expects bytes 3, 4 and 5 from the file.
389  1 Date d = new Date();
390  1 createAttachment(d, DEFAULT_FILE_NAME);
391  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=3-5", -1l, DEFAULT_FILE_NAME);
392   
393  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
394   
395  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
396  1 verify(this.response).setHeader("Content-Range", "bytes 3-5/" + DownloadActionTest.this.fileContent.length);
397  1 verifyResponseExpectations(d.getTime(), 3);
398  1 verifyOutputExpectations(3, 6);
399    }
400   
 
401  1 toggle @Test
402    public void downloadWhenValidEndRange() throws XWikiException, IOException
403    {
404    // This test expects bytes 9, 10, 11, 12 and 13 from the file.
405  1 Date d = new Date();
406  1 createAttachment(d, DEFAULT_FILE_NAME);
407  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=9-13", -1l, DEFAULT_FILE_NAME);
408   
409  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
410   
411  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
412  1 verify(this.response).setHeader("Content-Range", "bytes 9-13/" + DownloadActionTest.this.fileContent.length);
413  1 verifyResponseExpectations(d.getTime(), this.fileContent.length - 9);
414  1 verifyOutputExpectations(9, this.fileContent.length);
415    }
416   
 
417  1 toggle @Test
418    public void downloadWhenOneByteRange() throws XWikiException, IOException
419    {
420    // This test expects the last four bytes (10, 11, 12 and 13) from the file
421  1 Date d = new Date();
422  1 createAttachment(d, DEFAULT_FILE_NAME);
423  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=0-0", -1l, DEFAULT_FILE_NAME);
424   
425  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
426   
427  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
428  1 verify(this.response).setHeader("Content-Range", "bytes 0-0/" + DownloadActionTest.this.fileContent.length);
429  1 verifyResponseExpectations(d.getTime(), 1);
430  1 verifyOutputExpectations(0, 1);
431    }
432   
 
433  1 toggle @Test
434    public void downloadWhenRestRange() throws XWikiException, IOException
435    {
436    // This test expects bytes from 11 to the end of the file (11, 12 and 13)
437  1 Date d = new Date();
438  1 createAttachment(d, DEFAULT_FILE_NAME);
439  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=11-", -1l, DEFAULT_FILE_NAME);
440   
441  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
442   
443  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
444  1 verify(this.response).setHeader("Content-Range", "bytes 11-13/" + DownloadActionTest.this.fileContent.length);
445  1 verifyResponseExpectations(d.getTime(), this.fileContent.length - 11);
446  1 verifyOutputExpectations(11, this.fileContent.length);
447    }
448   
 
449  1 toggle @Test
450    public void downloadWhenFullRestRange() throws XWikiException, IOException
451    {
452    // This test expects the whole file
453  1 Date d = new Date();
454  1 createAttachment(d, DEFAULT_FILE_NAME);
455  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=0-", -1l, DEFAULT_FILE_NAME);
456   
457  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
458   
459  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
460  1 verify(this.response).setHeader("Content-Range", "bytes 0-13/" + DownloadActionTest.this.fileContent.length);
461  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
462  1 verifyOutputExpectations(0, this.fileContent.length);
463    }
464   
 
465  1 toggle @Test
466    public void downloadWhenTailRange() throws XWikiException, IOException
467    {
468    // This test expects the last four bytes (10, 11, 12 and 13) from the file
469  1 Date d = new Date();
470  1 createAttachment(d, DEFAULT_FILE_NAME);
471  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=-4", -1l, DEFAULT_FILE_NAME);
472   
473  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
474   
475  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
476  1 verify(this.response).setHeader("Content-Range", "bytes 10-13/" + DownloadActionTest.this.fileContent.length);
477  1 verifyResponseExpectations(d.getTime(), this.fileContent.length - 10);
478  1 verifyOutputExpectations(10, this.fileContent.length);
479    }
480   
 
481  1 toggle @Test
482    public void downloadWhenFullTailRange() throws XWikiException, IOException
483    {
484    // This test expects the whole file
485  1 Date d = new Date();
486  1 createAttachment(d, DEFAULT_FILE_NAME);
487  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=-14", -1l, DEFAULT_FILE_NAME);
488   
489  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
490   
491  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
492  1 verify(this.response).setHeader("Content-Range", "bytes 0-13/" + DownloadActionTest.this.fileContent.length);
493  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
494  1 verifyOutputExpectations(0, this.fileContent.length);
495    }
496   
 
497  1 toggle @Test
498    public void downloadWhenOverflowingTailRange() throws XWikiException, IOException
499    {
500    // This test expects the whole file, although the client requested more
501  1 Date d = new Date();
502  1 createAttachment(d, DEFAULT_FILE_NAME);
503  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=-40", -1l, DEFAULT_FILE_NAME);
504   
505  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
506   
507  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
508  1 verify(this.response).setHeader("Content-Range", "bytes 0-13/" + DownloadActionTest.this.fileContent.length);
509  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
510  1 verifyOutputExpectations(0, this.fileContent.length);
511    }
512   
 
513  1 toggle @Test
514    public void downloadWhenValidOverflowingRange() throws XWikiException, IOException
515    {
516    // This test expects bytes 9, 10, 11, 12 and 13 from the file, although 14 and 15 are requested as well.
517  1 Date d = new Date();
518  1 createAttachment(d, DEFAULT_FILE_NAME);
519  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=9-15", -1l, DEFAULT_FILE_NAME);
520   
521  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
522   
523  1 verify(this.response).setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
524  1 verify(this.response).setHeader("Content-Range", "bytes 9-13/" + DownloadActionTest.this.fileContent.length);
525  1 verifyResponseExpectations(d.getTime(), this.fileContent.length - 9);
526  1 verifyOutputExpectations(9, this.fileContent.length);
527    }
528   
 
529  1 toggle @Test
530    public void downloadWhenInvalidSwappedRange() throws XWikiException, IOException
531    {
532  1 Date d = new Date();
533  1 createAttachment(d, DEFAULT_FILE_NAME);
534  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=9-5", -1l, DEFAULT_FILE_NAME);
535   
536  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
537   
538  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
539  1 verifyOutputExpectations(0, this.fileContent.length);
540    }
541   
 
542  1 toggle @Test
543    public void downloadWhenInvalidRange() throws XWikiException, IOException
544    {
545  1 Date d = new Date();
546  1 createAttachment(d, DEFAULT_FILE_NAME);
547  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=all", -1l, DEFAULT_FILE_NAME);
548   
549  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
550   
551  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
552  1 verifyOutputExpectations(0, this.fileContent.length);
553    }
554   
 
555  1 toggle @Test
556    public void downloadWhenOutsideRange() throws XWikiException, IOException
557    {
558    // This test expects a 416 response
559  1 Date d = new Date();
560  1 createAttachment(d, DEFAULT_FILE_NAME);
561  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=129-145", -1l, DEFAULT_FILE_NAME);
562   
563  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
564   
565  1 verify(this.response).setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
566    }
567   
 
568  1 toggle @Test
569    public void downloadWhenOutsideRestRange() throws XWikiException, IOException
570    {
571    // This test expects a 416 response
572  1 Date d = new Date();
573  1 createAttachment(d, DEFAULT_FILE_NAME);
574  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=129-", -1L, DEFAULT_FILE_NAME);
575   
576  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
577   
578  1 verify(this.response).setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
579    }
580   
 
581  1 toggle @Test
582    public void downloadWhenEmptyRange() throws XWikiException, IOException
583    {
584  1 Date d = new Date();
585  1 createAttachment(d, DEFAULT_FILE_NAME);
586  1 setRequestExpectations(DEFAULT_URI, null, null, "bytes=-", -1L, DEFAULT_FILE_NAME);
587  1 assertNull(this.action.render(this.oldcore.getXWikiContext()));
588   
589  1 verifyOutputExpectations(0, this.fileContent.length);
590  1 verifyResponseExpectations(d.getTime(), this.fileContent.length);
591    }
592   
 
593  27 toggle private void createAttachment(Date d, String name) throws IOException
594    {
595  27 XWikiAttachment filetxt = new XWikiAttachment(this.document, name);
596  27 filetxt.setContent(new ByteArrayInputStream(this.fileContent));
597  27 filetxt.setDate(d);
598  27 this.document.getAttachmentList().add(filetxt);
599    }
600   
 
601  30 toggle private void setRequestExpectations(String uri, String id, String forceDownload, String range, long modifiedSince,
602    String attachmentName)
603    {
604  30 ResourceReference rr = new EntityResourceReference(
605    new AttachmentReference(attachmentName, this.documentReference), EntityResourceAction.VIEW);
606   
607  30 when(this.request.getRequestURI()).thenReturn(uri);
608  30 when(this.request.getParameter("id")).thenReturn(id);
609  30 when(this.request.getDateHeader("If-Modified-Since")).thenReturn(modifiedSince);
610  30 when(this.request.getParameter("force-download")).thenReturn(forceDownload);
611  30 when(this.request.getHeader("Range")).thenReturn(range);
612  30 when(this.resourceReferenceManager.getResourceReference()).thenReturn(rr);
613    }
614   
 
615  17 toggle private void verifyResponseExpectations(long modified, int length)
616    {
617  17 verifyResponseExpectations(modified, length, "text/plain", "inline; filename*=utf-8''file.txt");
618    }
619   
 
620  23 toggle private void verifyResponseExpectations(long modified, int length, String mime, String disposition)
621    {
622  23 verify(this.response).setContentType(mime);
623  23 verify(this.response).setHeader("Accept-Ranges", "bytes");
624  23 verify(this.response).addHeader("Content-disposition", disposition);
625  23 verify(this.response).setDateHeader("Last-Modified", modified);
626  23 verify(this.response).setContentLength(length);
627    }
628   
 
629  22 toggle private void verifyOutputExpectations(final int start, final int end) throws IOException
630    {
631  22 verify(this.out).write(argThat(new ArgumentMatcher<byte[]>()
632    {
 
633  44 toggle @Override
634    public boolean matches(byte[] argument)
635    {
636  514 for (int i = start; i < end; ++i) {
637  470 if (argument[i - start] != DownloadActionTest.this.fileContent[i]) {
638  0 return false;
639    }
640    }
641  44 return true;
642    }
643    }), eq(0), eq(end - start));
644    }
645    }