1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.packagemanager.stats.host;
18 
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21 
22 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
23 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
24 import com.android.tradefed.build.IBuildInfo;
25 import com.android.tradefed.device.DeviceNotAvailableException;
26 import com.android.tradefed.device.ITestDevice;
27 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
28 import com.android.tradefed.result.CollectingTestListener;
29 import com.android.tradefed.result.TestDescription;
30 import com.android.tradefed.result.TestResult;
31 import com.android.tradefed.result.TestRunResult;
32 
33 import java.io.File;
34 import java.util.HashMap;
35 import java.util.Map;
36 
37 public final class Utils {
38     public static final String SIGNATURE_FILE_SUFFIX = ".idsig";
39 
pushApkToRemote(String apkName, String remoteDirPath, IBuildInfo ctsBuild, ITestDevice device)40     public static String pushApkToRemote(String apkName, String remoteDirPath, IBuildInfo ctsBuild,
41             ITestDevice device) throws Exception {
42         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(ctsBuild);
43         final File apk = buildHelper.getTestFile(apkName);
44         final File signature = buildHelper.getTestFile(apkName + SIGNATURE_FILE_SUFFIX);
45         assertNotNull(apk);
46         assertNotNull(signature);
47         final String remoteApkPath = remoteDirPath + "/" + apk.getName();
48         final String remoteSignaturePath = remoteApkPath + SIGNATURE_FILE_SUFFIX;
49         assertTrue(device.pushFile(apk, remoteApkPath));
50         assertTrue(device.pushFile(signature, remoteSignaturePath));
51         return remoteApkPath;
52     }
53 
runDeviceTests(ITestDevice device, String packageName, String testClassName, String testMethodName, Map<String, String> testArgs)54     public static Map<String, String> runDeviceTests(ITestDevice device, String packageName,
55             String testClassName, String testMethodName, Map<String, String> testArgs)
56             throws DeviceNotAvailableException {
57         if (testClassName != null && testClassName.startsWith(".")) {
58             testClassName = packageName + testClassName;
59         }
60         RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
61                 "androidx.test.runner.AndroidJUnitRunner", device.getIDevice());
62 
63         if (testClassName != null && testMethodName != null) {
64             testRunner.setMethodName(testClassName, testMethodName);
65         } else if (testClassName != null) {
66             testRunner.setClassName(testClassName);
67         }
68 
69         if (testArgs != null && testArgs.size() > 0) {
70             for (String name : testArgs.keySet()) {
71                 final String value = testArgs.get(name);
72                 testRunner.addInstrumentationArg(name, value);
73             }
74         }
75         final TestResultListener listener = new TestResultListener();
76         assertTrue(device.runInstrumentationTests(testRunner, listener));
77 
78         final TestRunResult result = listener.getCurrentRunResults();
79         if (result.isRunFailure()) {
80             throw new Error("Failed to successfully run device tests for "
81                     + result.getName() + ": " + result.getRunFailureMessage());
82         }
83         if (result.getNumTests() == 0) {
84             throw new Error("No tests were run on the device");
85         }
86         if (result.hasFailedTests()) {
87             StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
88             for (Map.Entry<TestDescription, TestResult> resultEntry :
89                     result.getTestResults().entrySet()) {
90                 if (!resultEntry.getValue().getStatus().equals(
91                         com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) {
92                     errorBuilder.append(resultEntry.getKey().toString());
93                     errorBuilder.append(":\n");
94                     errorBuilder.append(resultEntry.getValue().getStackTrace());
95                 }
96             }
97             throw new AssertionError(errorBuilder.toString());
98         }
99 
100         if (listener.mFailureStackTrace != null) {
101             throw new AssertionError("Failed to successfully run device tests: "
102                     + listener.mFailureStackTrace);
103         }
104         return listener.mMetrics;
105     }
106 
107     /* Special listener for collecting data from the test result */
108     private static class TestResultListener extends CollectingTestListener {
109         private final Map<String, String> mMetrics = new HashMap<>();
110         private String mFailureStackTrace = null;
111 
112         @Override
testEnded(TestDescription test, Map<String, String> metrics)113         public void testEnded(TestDescription test, Map<String, String> metrics) {
114             mMetrics.putAll(metrics);
115         }
116 
117         @Override
testEnded(TestDescription test, HashMap<String, Metric> metrics)118         public void testEnded(TestDescription test, HashMap<String, Metric> metrics) {
119             for (Map.Entry<String, Metric> e: metrics.entrySet()) {
120                 mMetrics.put(e.getKey(), e.getValue().getMeasurements().getSingleString());
121             }
122         }
123 
124         @Override
testFailed(TestDescription test, String trace)125         public void testFailed(TestDescription test, String trace) {
126             mFailureStackTrace = trace;
127         }
128     }
129 
hasIncrementalFeature(ITestDevice device)130     public static boolean hasIncrementalFeature(ITestDevice device) throws Exception {
131         return "true\n".equals(device.executeShellCommand(
132                 "pm has-feature android.software.incremental_delivery"));
133     }
134 }
135