Support the file/folder use case

GCS allows a file and folder to have the same name so we
need to handle it to avoid NPE at download.

Test: unit/func tests
Bug: 153581184
Change-Id: I47af276fc31df69c03c6296dad155b010c6f50f9
diff --git a/src/com/android/tradefed/util/GCSFileDownloader.java b/src/com/android/tradefed/util/GCSFileDownloader.java
index 303d3b7..08c4990 100644
--- a/src/com/android/tradefed/util/GCSFileDownloader.java
+++ b/src/com/android/tradefed/util/GCSFileDownloader.java
@@ -190,11 +190,16 @@
         }
         for (String subRemoteFolder : subRemoteFolders) {
             String subFolderName = Paths.get(subRemoteFolder).getFileName().toString();
-            if (!recursiveCheckFolderFreshness(
-                    bucketName, subRemoteFolder, new File(localFolder, subFolderName))) {
+            File subFolder = new File(localFolder, subFolderName);
+            if (new File(localFolder, subFolderName).exists()
+                    && !new File(localFolder, subFolderName).isDirectory()) {
+                CLog.w("%s exists as a non-directory.", subFolder);
+                subFolder = new File(localFolder, subFolderName + "_folder");
+            }
+            if (!recursiveCheckFolderFreshness(bucketName, subRemoteFolder, subFolder)) {
                 return false;
             }
-            subFilenames.remove(subFolderName);
+            subFilenames.remove(subFolder.getName());
         }
         return subFilenames.isEmpty();
     }
@@ -310,6 +315,14 @@
         if (!localFolder.exists()) {
             FileUtil.mkdirsRWX(localFolder);
         }
+        if (!localFolder.isDirectory()) {
+            String error =
+                    String.format(
+                            "%s is not a folder. (gs://%s/%s)",
+                            localFolder, bucketName, remoteFolderName);
+            CLog.e(error);
+            throw new IOException(error);
+        }
         Set<String> subFilenames = new HashSet<>(Arrays.asList(localFolder.list()));
         List<String> subRemoteFolders = new ArrayList<>();
         List<StorageObject> subRemoteFiles = new ArrayList<>();
@@ -322,9 +335,14 @@
         }
         for (String subRemoteFolder : subRemoteFolders) {
             String subFolderName = Paths.get(subRemoteFolder).getFileName().toString();
-            recursiveDownloadFolder(
-                    bucketName, subRemoteFolder, new File(localFolder, subFolderName));
-            subFilenames.remove(subFolderName);
+            File subFolder = new File(localFolder, subFolderName);
+            if (new File(localFolder, subFolderName).exists()
+                    && !new File(localFolder, subFolderName).isDirectory()) {
+                CLog.w("%s exists as a non-directory.", subFolder);
+                subFolder = new File(localFolder, subFolderName + "_folder");
+            }
+            recursiveDownloadFolder(bucketName, subRemoteFolder, subFolder);
+            subFilenames.remove(subFolder.getName());
         }
         for (String subFilename : subFilenames) {
             FileUtil.recursiveDelete(new File(localFolder, subFilename));
diff --git a/tests/src/com/android/tradefed/util/GCSFileDownloaderFuncTest.java b/tests/src/com/android/tradefed/util/GCSFileDownloaderFuncTest.java
index c0c5d05..8d97efb 100644
--- a/tests/src/com/android/tradefed/util/GCSFileDownloaderFuncTest.java
+++ b/tests/src/com/android/tradefed/util/GCSFileDownloaderFuncTest.java
@@ -102,6 +102,8 @@
         createFile(mStorage, FILE_CONTENT, BUCKET_NAME, mRemoteRoot, FILE_NAME1);
         createFile(mStorage, FILE_NAME2, BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FILE_NAME2);
         createFile(mStorage, FILE_NAME3, BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FILE_NAME3);
+        // Create a special case condition where folder name is also a file name.
+        createFile(mStorage, FILE_NAME3, BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FOLDER_NAME2);
         createFile(
                 mStorage,
                 FILE_NAME4,
@@ -230,7 +232,7 @@
 
     private void checkDownloadedFolder(File localFile) throws Exception {
         Assert.assertTrue(localFile.isDirectory());
-        Assert.assertEquals(3, localFile.list().length);
+        Assert.assertEquals(4, localFile.list().length);
         for (String filename : localFile.list()) {
             if (filename.equals(FILE_NAME2)) {
                 Assert.assertEquals(
@@ -242,7 +244,7 @@
                         FILE_NAME3,
                         FileUtil.readStringFromFile(
                                 new File(localFile.getAbsolutePath(), filename)));
-            } else if (filename.equals(FOLDER_NAME2)) {
+            } else if (filename.equals(FOLDER_NAME2 + "_folder")) {
                 File subFolder = new File(localFile.getAbsolutePath(), filename);
                 Assert.assertTrue(subFolder.isDirectory());
                 Assert.assertEquals(1, subFolder.list().length);
@@ -250,6 +252,9 @@
                         FILE_NAME4,
                         FileUtil.readStringFromFile(
                                 new File(subFolder.getAbsolutePath(), subFolder.list()[0])));
+            } else if (filename.equals(FOLDER_NAME2)) {
+                File fileWithFolderName = new File(localFile.getAbsolutePath(), filename);
+                Assert.assertTrue(fileWithFolderName.isFile());
             } else {
                 Assert.assertTrue(String.format("Unknonwn file %s", filename), false);
             }