Merge "Add CtsStatsdHostTestCases to cts-sim plan"
diff --git a/build/tradefed_binary.go b/build/tradefed_binary.go
index cd56f5e..4881aa3 100644
--- a/build/tradefed_binary.go
+++ b/build/tradefed_binary.go
@@ -73,6 +73,7 @@
 		// Add dependencies required by all tradefed_binary modules.
 		props.Libs = []string{
 			"tradefed",
+			"tradefed-test-framework",
 			"loganalysis",
 			"hosttestlib",
 			"compatibility-host-util",
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
index 87beb75..774cc40 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
@@ -37,6 +37,12 @@
     public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
         return super.resolveRelativeFilePath(
                 buildInfo,
-                String.format("%s%s", fileName, mAppendBitness ? getAbi().getBitness() : ""));
+                String.format(
+                        "%s%s", fileName, shouldAppendBitness() ? getAbi().getBitness() : ""));
+    }
+
+    /** Whether or not to append bitness to the file name. */
+    public boolean shouldAppendBitness() {
+        return mAppendBitness;
     }
 }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java
index cf0c27e..c65618a 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java
@@ -298,10 +298,13 @@
             } catch (IOException e) {
                 FileUtil.recursiveDelete(mediaFolder);
                 throw new TargetSetupError(
-                        "Failed to download and open media files on host, the"
-                                + " device requires these media files for compatibility tests",
+                        String.format(
+                                "Failed to download and open media files on host machine at '%s'."
+                                        + " These media files are required for compatibility tests.",
+                                mediaFolderZip),
                         e,
-                        device.getDeviceDescriptor());
+                        device.getDeviceDescriptor(),
+                        /* device side */ false);
             } finally {
                 FileUtil.deleteFile(mediaFolderZip);
             }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
index e870577..b50c906 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
@@ -19,10 +19,12 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import com.android.compatibility.common.tradefed.targetprep.FilePusher;
 import com.android.tradefed.config.ConfigurationException;
 import com.android.tradefed.config.ConfigurationFactory;
 import com.android.tradefed.config.IConfiguration;
 import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.PushFilePreparer;
 import com.android.tradefed.targetprep.TestAppInstallSetup;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.InstrumentationTest;
@@ -83,15 +85,48 @@
             IConfiguration c = ConfigurationFactory.getInstance()
                     .createConfigurationFromArgs(new String[] {config.getAbsolutePath()});
             // For each config, we check all the apk it's going to install
-            List<String> apkNames = new ArrayList<>();
+            List<File> apkNames = new ArrayList<>();
             List<String> packageListNames = new ArrayList<>();
             for (ITargetPreparer prep : c.getTargetPreparers()) {
                 if (prep instanceof TestAppInstallSetup) {
                     apkNames.addAll(((TestAppInstallSetup) prep).getTestsFileName());
                 }
+                // Ensure the files requested to be pushed exist.
+                if (prep instanceof FilePusher && ((FilePusher) prep).shouldAppendBitness()) {
+                    for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) {
+                        String path = f.getPath();
+                        if (!new File(testcases, path + "32").exists()
+                                || !new File(testcases, path + "64").exists()) {
+                            // TODO: Enforce should abort on failure is True in CTS
+                            if (((FilePusher) prep).shouldAbortOnFailure()) {
+                                fail(
+                                        String.format(
+                                                "File %s[32/64] wasn't found in testcases/ while "
+                                                        + "it's expected to be pushed as part of "
+                                                        + "%s",
+                                                path, config.getName()));
+                            }
+                        }
+                    }
+                } else if (prep instanceof PushFilePreparer) {
+                    for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) {
+                        String path = f.getPath();
+                        if (!new File(testcases, path).exists()) {
+                            // TODO: Enforce should abort on failure is True in CTS
+                            if (((PushFilePreparer) prep).shouldAbortOnFailure()) {
+                                fail(
+                                        String.format(
+                                                "File %s wasn't found in testcases/ while it's "
+                                                        + "expected to be pushed as part of %s",
+                                                path, config.getName()));
+                            }
+                        }
+                    }
+                }
             }
 
-            for (String apkName : apkNames) {
+            for (File apk : apkNames) {
+                String apkName = apk.getName();
                 File apkFile = new File(testcases, apkName);
                 if (!apkFile.exists()) {
                     fail(String.format("Module %s is trying to install %s which does not "
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
index 31d7aa8..f50e59d 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
@@ -19,6 +19,8 @@
 
 import com.android.tradefed.config.ConfigurationException;
 
+import com.google.common.collect.ImmutableSet;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -31,6 +33,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
@@ -43,7 +46,10 @@
 
     // We ignore directories part of the common java and google packages.
     private static final String[] IGNORE_DIRS =
-            new String[] {"android/", "javax/annotation/", "com/google/protobuf/"};
+            new String[] {"android/", "javax/annotation/", "com/google/protobuf/", "kotlin/"};
+
+    // Temporarily exclude some Tradefed jar while we work on unbundling them.
+    private static final Set<String> IGNORE_JARS = ImmutableSet.of("tradefed-test-framework.jar");
 
     /** test if there are duplicate files in different jars. */
     @Test
@@ -82,6 +88,9 @@
         List<String> jarFileList;
         // Map all the files from all the jars.
         for (File jar : jars) {
+            if (IGNORE_JARS.contains(jar.getName())) {
+                continue;
+            }
             jarFile = new JarFile(jar);
             jarFileList = getListOfFiles(jarFile);
             jarFile.close();
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java
index 12e8199..517ca34 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java
@@ -171,7 +171,8 @@
             fail("Should have thrown an exception.");
         } catch (TargetSetupError expected) {
             // expected
-            assertEquals("Cannot get local dynamic config file from test directory null",
+            assertEquals(
+                    "Cannot get local dynamic config file from test directory",
                     expected.getMessage());
         }
         EasyMock.verify(mMockDevice, mMockBuildInfo);
@@ -191,8 +192,9 @@
             fail("Should have thrown an exception.");
         } catch (TargetSetupError expected) {
             // expected
-            assertEquals("Fail to unpack 'not-an-existing-resource-name.dynamic' from resources "
-                    + "null", expected.getMessage());
+            assertEquals(
+                    "Fail to unpack 'not-an-existing-resource-name.dynamic' from resources",
+                    expected.getMessage());
         }
         EasyMock.verify(mMockDevice, mMockBuildInfo);
     }
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 830c395..9e5708c 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -86,6 +86,7 @@
 
 JAR_DIR=${CTS_ROOT}/android-cts/tools
 JARS="tradefed
+  tradefed-test-harness
   loganalysis
   hosttestlib
   compatibility-host-util
diff --git a/tools/cts-tradefed/res/config/cts-meerkat.xml b/tools/cts-tradefed/res/config/cts-meerkat.xml
index 732675c..5dd552a 100644
--- a/tools/cts-tradefed/res/config/cts-meerkat.xml
+++ b/tools/cts-tradefed/res/config/cts-meerkat.xml
@@ -22,8 +22,9 @@
     <!-- Disable instant tests -->
     <option name="compatibility:enable-parameterized-modules" value="false" />
 
-    <!-- Restrict SAW intent -->
+    <!-- System Alert Window (SAW) -->
     <option name="compatibility:include-filter" value="CtsSystemIntentTestCases"/>
+    <option name="compatibility:include-filter" value="CtsMediaTestCases android.media.cts.MediaProjectionTest"/>
 
     <!-- Toasts -->
     <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.ToastWindowTest"/>