Merge "Resolve dynamic File in maps"
diff --git a/src/com/android/tradefed/config/DynamicRemoteFileResolver.java b/src/com/android/tradefed/config/DynamicRemoteFileResolver.java
index a10b6c7..d10317e 100644
--- a/src/com/android/tradefed/config/DynamicRemoteFileResolver.java
+++ b/src/com/android/tradefed/config/DynamicRemoteFileResolver.java
@@ -28,7 +28,9 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -118,8 +120,35 @@
                                 }
                             }
                         }
+                    } else if (value instanceof Map) {
+                        Map<Object, Object> m = (Map<Object, Object>) value;
+                        Map<Object, Object> copy = new LinkedHashMap<>(m);
+                        for (Entry<Object, Object> entry : copy.entrySet()) {
+                            Object key = entry.getKey();
+                            Object val = entry.getValue();
+
+                            Object finalKey = key;
+                            Object finalVal = val;
+                            if (key instanceof File) {
+                                key = resolveRemoteFiles((File) key, option);
+                                if (key != null) {
+                                    downloadedFiles.add((File) key);
+                                    finalKey = key;
+                                }
+                            }
+                            if (val instanceof File) {
+                                val = resolveRemoteFiles((File) val, option);
+                                if (val != null) {
+                                    downloadedFiles.add((File) val);
+                                    finalVal = val;
+                                }
+                            }
+
+                            m.remove(entry.getKey());
+                            m.put(finalKey, finalVal);
+                        }
                     }
-                    // TODO: Handle Map of files
+                    // TODO: add support for multimap
                 }
             }
         } catch (ConfigurationException e) {
diff --git a/tests/src/com/android/tradefed/config/DynamicRemoteFileResolverTest.java b/tests/src/com/android/tradefed/config/DynamicRemoteFileResolverTest.java
index 544cd72..113aaf0 100644
--- a/tests/src/com/android/tradefed/config/DynamicRemoteFileResolverTest.java
+++ b/tests/src/com/android/tradefed/config/DynamicRemoteFileResolverTest.java
@@ -32,7 +32,9 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
@@ -47,6 +49,9 @@
 
         @Option(name = "remote-file-list")
         public Collection<File> remoteFileList = new ArrayList<>();
+
+        @Option(name = "remote-map")
+        public Map<File, File> remoteMap = new HashMap<>();
     }
 
     @OptionClass(alias = "option-class-alias", global_namespace = false)
@@ -200,6 +205,51 @@
     }
 
     @Test
+    public void testResolve_remoteMap() throws Exception {
+        RemoteFileOption object = new RemoteFileOption();
+        OptionSetter setter =
+                new OptionSetter(object) {
+                    @Override
+                    DynamicRemoteFileResolver createResolver() {
+                        return mResolver;
+                    }
+                };
+
+        File fake = FileUtil.createTempFile("gs-option-setter-test", "txt");
+        File fake2 = FileUtil.createTempFile("gs-option-setter-test", "txt");
+
+        setter.setOptionValue("remote-map", "gs://fake/path", "value");
+        setter.setOptionValue("remote-map", "fake/file", "gs://fake/path2");
+        setter.setOptionValue("remote-map", "key", "val");
+        assertEquals(3, object.remoteMap.size());
+
+        EasyMock.expect(
+                        mMockResolver.resolveRemoteFiles(
+                                EasyMock.eq(new File("gs:/fake/path")), EasyMock.anyObject()))
+                .andReturn(fake);
+        EasyMock.expect(
+                        mMockResolver.resolveRemoteFiles(
+                                EasyMock.eq(new File("gs:/fake/path2")), EasyMock.anyObject()))
+                .andReturn(fake2);
+        EasyMock.replay(mMockResolver);
+
+        Set<File> downloadedFile = setter.validateRemoteFilePath();
+        try {
+            assertEquals(2, downloadedFile.size());
+            // The file has been replaced by the downloaded one.
+            assertEquals(3, object.remoteMap.size());
+            assertEquals(new File("value"), object.remoteMap.get(fake));
+            assertEquals(fake2, object.remoteMap.get(new File("fake/file")));
+            assertEquals(new File("val"), object.remoteMap.get(new File("key")));
+        } finally {
+            for (File f : downloadedFile) {
+                FileUtil.recursiveDelete(f);
+            }
+        }
+        EasyMock.verify(mMockResolver);
+    }
+
+    @Test
     public void testResolve_withNoGlobalNameSpace() throws Exception {
         RemoteFileOptionWithOptionClass object = new RemoteFileOptionWithOptionClass();
         OptionSetter setter =