diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java
index f793fea6137f0d2d778425e89cc7b2ec76706f9f..d54a571ad251c47ddcac17e4ef006113c9948b3e 100644
--- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java
+++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/DownloadFileTest.java
@@ -3,6 +3,7 @@ package ch.ethz.sis.openbis.generic.dss.systemtest.api.v3;
 import java.io.InputStream;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.io.IOUtils;
@@ -19,38 +20,141 @@ public class DownloadFileTest extends AbstractFileTest
 {
 
     @Test
-    public void downloadAllFiles() throws Exception
+    public void testDownloadAllFiles() throws Exception
     {
         IDataSetFileId root = new DataSetFilePermId(new DataSetPermId(dataSetCode));
         DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
 
-        InputStream stream = dss.downloadFiles(sessionToken, Arrays.asList(root), options);
+        Map<String, String> contentMap = download(Arrays.asList(root), options);
+
+        assertEquals(filesAndDirectories.size() + 3, contentMap.size());
+        assertEmptyContent(contentMap, getPath("subdir1"));
+        assertContent(contentMap, getPath("subdir1/file3.txt"));
+    }
+
+    @Test
+    public void testDownloadMultipleFiles() throws Exception
+    {
+        IDataSetFileId file1 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("file1.txt"));
+        IDataSetFileId file6 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir3/file6.txt"));
+
+        DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
+
+        Map<String, String> contentMap = download(Arrays.asList(file1, file6), options);
+
+        assertEquals(2, contentMap.size());
+        assertContent(contentMap, getPath("file1.txt"));
+        assertContent(contentMap, getPath("subdir3/file6.txt"));
+    }
+
+    @Test
+    public void testDownloadFolderRecursively() throws Exception
+    {
+        IDataSetFileId folder = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir1/subdir2"));
+        DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
+        options.setRecursive(true);
+
+        Map<String, String> contentMap = download(Arrays.asList(folder), options);
+
+        assertEquals(2, contentMap.size());
+        assertEmptyContent(contentMap, getPath("subdir1/subdir2"));
+        assertContent(contentMap, getPath("subdir1/subdir2/file5.txt"));
+    }
+
+    @Test
+    public void testDownloadFolderOnly() throws Exception
+    {
+        IDataSetFileId folder = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir1/subdir2"));
+        DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
+        options.setRecursive(false);
+
+        Map<String, String> contentMap = download(Arrays.asList(folder), options);
+
+        assertEquals(1, contentMap.size());
+        assertEmptyContent(contentMap, getPath("subdir1/subdir2"));
+    }
+
+    @Test(expectedExceptions = { IllegalStateException.class }, expectedExceptionsMessageRegExp = "Input stream no longer valid")
+    public void testDownloadStreamReturnedByOldRead() throws Exception
+    {
+        IDataSetFileId file1 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("file1.txt"));
+        IDataSetFileId file2 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("file2.txt"));
+        DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
+
+        InputStream stream = dss.downloadFiles(sessionToken, Arrays.asList(file1, file2), options);
+        DataSetFileDownloadReader reader = new DataSetFileDownloadReader(stream);
+
+        DataSetFileDownload download1 = reader.read();
+        reader.read();
+
+        IOUtils.toString(download1.getInputStream());
+    }
+
+    @Test
+    public void testDownloadStreamReturnedAfterUnconsumedReads() throws Exception
+    {
+        IDataSetFileId file1 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("file1.txt"));
+        IDataSetFileId file2 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("file2.txt"));
+        IDataSetFileId file3 = new DataSetFilePermId(new DataSetPermId(dataSetCode), getPath("subdir1/file3.txt"));
+
+        DataSetFileDownloadOptions options = new DataSetFileDownloadOptions();
+
+        InputStream stream = dss.downloadFiles(sessionToken, Arrays.asList(file1, file2, file3), options);
         DataSetFileDownloadReader reader = new DataSetFileDownloadReader(stream);
 
-        Map<String, String> contentMap = new HashMap<>();
-        DataSetFileDownload download = null;
+        reader.read();
+        reader.read();
+        DataSetFileDownload download3 = reader.read();
+
+        assertContent(IOUtils.toString(download3.getInputStream()), getPath("subdir1/file3.txt"));
+    }
+
+    private Map<String, String> download(@SuppressWarnings("hiding")
+    List<IDataSetFileId> files, DataSetFileDownloadOptions options)
+    {
+        try
+        {
+            InputStream stream = dss.downloadFiles(sessionToken, files, options);
+            DataSetFileDownloadReader reader = new DataSetFileDownloadReader(stream);
+
+            Map<String, String> contentMap = new HashMap<>();
+            DataSetFileDownload download = null;
+
+            while ((download = reader.read()) != null)
+            {
+                contentMap.put(download.getDataSetFile().getPath(), IOUtils.toString(download.getInputStream()));
+            }
 
-        while ((download = reader.read()) != null)
+            return contentMap;
+        } catch (Exception e)
         {
-            System.out.println("Downloaded file path: " + download.getDataSetFile().getPath());
-            contentMap.put(download.getDataSetFile().getPath(), IOUtils.toString(download.getInputStream()));
+            throw new RuntimeException(e);
         }
-
-        assertEquals(filesAndDirectories.size() + 3, contentMap.size());
-        assertEmptyContent(contentMap, "subdir1");
-        assertContent(contentMap, "subdir1/file3.txt");
     }
 
     private void assertEmptyContent(Map<String, String> contentMap, String filePath)
     {
-        String theFilePath = "original/" + dataSetCode + "/" + filePath;
-        assertEquals("", contentMap.get(theFilePath));
+        assertEquals("", contentMap.get(filePath));
     }
 
     private void assertContent(Map<String, String> contentMap, String filePath)
     {
-        String theFilePath = "original/" + dataSetCode + "/" + filePath;
-        assertEquals("file content of " + filePath, contentMap.get(theFilePath));
+        assertContent(contentMap.get(filePath), filePath);
+    }
+
+    private void assertContent(String content, String filePath)
+    {
+        String relativePath = filePath.substring(getPathPrefix().length());
+        assertEquals("file content of " + relativePath, content);
     }
 
+    private String getPath(String path)
+    {
+        return getPathPrefix() + path;
+    }
+
+    private String getPathPrefix()
+    {
+        return "original/" + dataSetCode + "/";
+    }
 }
\ No newline at end of file