1*6777b538SAndroid Build Coastguard Worker /* 2*6777b538SAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project 3*6777b538SAndroid Build Coastguard Worker * 4*6777b538SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*6777b538SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*6777b538SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*6777b538SAndroid Build Coastguard Worker * 8*6777b538SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*6777b538SAndroid Build Coastguard Worker * 10*6777b538SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*6777b538SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*6777b538SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6777b538SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*6777b538SAndroid Build Coastguard Worker * limitations under the License. 15*6777b538SAndroid Build Coastguard Worker */ 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker package com.android.tests.chromium.host; 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.COMMAND_LINE_FLAGS_KEY; 20*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.DUMP_COVERAGE_KEY; 21*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.EXTRA_SHARD_NANO_TIMEOUT_KEY; 22*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.LIBRARY_TO_LOAD_ACTIVITY_KEY; 23*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.NATIVE_TEST_ACTIVITY_KEY; 24*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.NATIVE_UNIT_TEST_ACTIVITY_KEY; 25*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.RUN_IN_SUBTHREAD_KEY; 26*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.STDOUT_FILE_KEY; 27*6777b538SAndroid Build Coastguard Worker import static com.android.tests.chromium.host.InstrumentationFlags.TEST_RUNNER; 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard Worker import android.annotation.NonNull; 30*6777b538SAndroid Build Coastguard Worker 31*6777b538SAndroid Build Coastguard Worker import com.android.ddmlib.MultiLineReceiver; 32*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.config.Option; 33*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.device.CollectingOutputReceiver; 34*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.device.DeviceNotAvailableException; 35*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.device.ITestDevice; 36*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.invoker.TestInformation; 37*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.log.LogUtil; 38*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.result.ITestInvocationListener; 39*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.result.LogDataType; 40*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.result.FileInputStreamSource; 41*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.testtype.GTestListTestParser; 42*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.testtype.GTestResultParser; 43*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.testtype.IDeviceTest; 44*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.testtype.IRemoteTest; 45*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.testtype.ITestCollector; 46*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.testtype.ITestFilterReceiver; 47*6777b538SAndroid Build Coastguard Worker import com.android.tradefed.util.FileUtil; 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Worker import com.google.common.base.Joiner; 50*6777b538SAndroid Build Coastguard Worker import com.google.common.base.Strings; 51*6777b538SAndroid Build Coastguard Worker 52*6777b538SAndroid Build Coastguard Worker import java.io.File; 53*6777b538SAndroid Build Coastguard Worker import java.io.IOException; 54*6777b538SAndroid Build Coastguard Worker import java.nio.file.Files; 55*6777b538SAndroid Build Coastguard Worker import java.time.Duration; 56*6777b538SAndroid Build Coastguard Worker import java.util.LinkedHashSet; 57*6777b538SAndroid Build Coastguard Worker import java.util.Set; 58*6777b538SAndroid Build Coastguard Worker import java.util.concurrent.TimeUnit; 59*6777b538SAndroid Build Coastguard Worker 60*6777b538SAndroid Build Coastguard Worker /** 61*6777b538SAndroid Build Coastguard Worker * A host-side test-runner capable of running Chromium unit-tests. 62*6777b538SAndroid Build Coastguard Worker */ 63*6777b538SAndroid Build Coastguard Worker public class ChromiumHostDrivenTest implements IRemoteTest, IDeviceTest, ITestCollector, 64*6777b538SAndroid Build Coastguard Worker ITestFilterReceiver { 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker private static final String CLEAR_CLANG_COVERAGE_FILES = 67*6777b538SAndroid Build Coastguard Worker "find /data/misc/trace -name '*.profraw' -delete"; 68*6777b538SAndroid Build Coastguard Worker private static final Duration TESTS_TIMEOUT = Duration.ofMinutes(30); 69*6777b538SAndroid Build Coastguard Worker private static final String GTEST_FLAG_PRINT_TIME = "--gtest_print_time"; 70*6777b538SAndroid Build Coastguard Worker private static final String GTEST_FLAG_FILTER = "--gtest_filter"; 71*6777b538SAndroid Build Coastguard Worker private static final String GTEST_FLAG_LIST_TESTS = "--gtest_list_tests"; 72*6777b538SAndroid Build Coastguard Worker private static final String GTEST_FLAG_FILE = "--gtest_flagfile"; 73*6777b538SAndroid Build Coastguard Worker @Option( 74*6777b538SAndroid Build Coastguard Worker name = "include-filter", 75*6777b538SAndroid Build Coastguard Worker description = "The set of annotations a test must have to be run.") 76*6777b538SAndroid Build Coastguard Worker private Set<String> includeFilters = new LinkedHashSet<>(); 77*6777b538SAndroid Build Coastguard Worker @Option( 78*6777b538SAndroid Build Coastguard Worker name = "exclude-filter", 79*6777b538SAndroid Build Coastguard Worker description = 80*6777b538SAndroid Build Coastguard Worker "The set of annotations to exclude tests from running. A test must have " 81*6777b538SAndroid Build Coastguard Worker + "none of the annotations in this list to run.") 82*6777b538SAndroid Build Coastguard Worker private Set<String> excludeFilters = new LinkedHashSet<>(); 83*6777b538SAndroid Build Coastguard Worker private boolean collectTestsOnly = false; 84*6777b538SAndroid Build Coastguard Worker private ITestDevice device = null; 85*6777b538SAndroid Build Coastguard Worker 86*6777b538SAndroid Build Coastguard Worker @Option( 87*6777b538SAndroid Build Coastguard Worker name = "dump-native-coverage", 88*6777b538SAndroid Build Coastguard Worker description = "Force APK under test to dump native test coverage upon exit" 89*6777b538SAndroid Build Coastguard Worker ) 90*6777b538SAndroid Build Coastguard Worker private boolean isCoverageEnabled = false; 91*6777b538SAndroid Build Coastguard Worker @Option( 92*6777b538SAndroid Build Coastguard Worker name = "library-to-load", 93*6777b538SAndroid Build Coastguard Worker description = "Name of the .so file under test" 94*6777b538SAndroid Build Coastguard Worker ) 95*6777b538SAndroid Build Coastguard Worker private String libraryToLoad = ""; 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker /** 99*6777b538SAndroid Build Coastguard Worker * Creates a temporary file on the host machine then push it to the device in a temporary 100*6777b538SAndroid Build Coastguard Worker * location It is necessary to create a temp file for output for each instrumentation run and 101*6777b538SAndroid Build Coastguard Worker * not module invocation. This is preferred over using 102*6777b538SAndroid Build Coastguard Worker * {@link com.android.tradefed.targetprep.RunCommandTargetPreparer} 103*6777b538SAndroid Build Coastguard Worker * because RunCommandTargetPreparer is only run once before the test invocation which leads to 104*6777b538SAndroid Build Coastguard Worker * incorrect parsing as the retries will all use the same file for test result outputs. 105*6777b538SAndroid Build Coastguard Worker */ 106*6777b538SAndroid Build Coastguard Worker @NonNull createTempResultFileOnDevice()107*6777b538SAndroid Build Coastguard Worker private String createTempResultFileOnDevice() throws DeviceNotAvailableException { 108*6777b538SAndroid Build Coastguard Worker File resultFile = null; 109*6777b538SAndroid Build Coastguard Worker String deviceFileDestination; 110*6777b538SAndroid Build Coastguard Worker try { 111*6777b538SAndroid Build Coastguard Worker resultFile = FileUtil.createTempFile("gtest_results", ".txt"); 112*6777b538SAndroid Build Coastguard Worker deviceFileDestination = String.format("/data/local/tmp/%s", resultFile.getName()); 113*6777b538SAndroid Build Coastguard Worker getDevice().pushFile(resultFile, deviceFileDestination); 114*6777b538SAndroid Build Coastguard Worker FileUtil.deleteFile(resultFile); 115*6777b538SAndroid Build Coastguard Worker } catch (IOException e) { 116*6777b538SAndroid Build Coastguard Worker throw new FailedChromiumGTestException( 117*6777b538SAndroid Build Coastguard Worker "Failed to create temp file for result on the device.", e); 118*6777b538SAndroid Build Coastguard Worker } finally { 119*6777b538SAndroid Build Coastguard Worker FileUtil.deleteFile(resultFile); 120*6777b538SAndroid Build Coastguard Worker } 121*6777b538SAndroid Build Coastguard Worker return deviceFileDestination; 122*6777b538SAndroid Build Coastguard Worker } 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Worker /** 125*6777b538SAndroid Build Coastguard Worker * This creates the gtest filter string which indicates which test should be run. 126*6777b538SAndroid Build Coastguard Worker * Sometimes the gtest filter is long (> 500 character) which results in creating 127*6777b538SAndroid Build Coastguard Worker * a temporary flag file and have gtest result the filter from the flag file. 128*6777b538SAndroid Build Coastguard Worker * 129*6777b538SAndroid Build Coastguard Worker * @return A gtest argument for flag file or --gtest_filter directly. 130*6777b538SAndroid Build Coastguard Worker */ 131*6777b538SAndroid Build Coastguard Worker @NonNull getGTestFilters()132*6777b538SAndroid Build Coastguard Worker private String getGTestFilters() throws DeviceNotAvailableException { 133*6777b538SAndroid Build Coastguard Worker StringBuilder filter = new StringBuilder(); 134*6777b538SAndroid Build Coastguard Worker if (!includeFilters.isEmpty() || !excludeFilters.isEmpty()) { 135*6777b538SAndroid Build Coastguard Worker filter.append(GTEST_FLAG_FILTER); 136*6777b538SAndroid Build Coastguard Worker filter.append('='); 137*6777b538SAndroid Build Coastguard Worker Joiner joiner = Joiner.on(":").skipNulls(); 138*6777b538SAndroid Build Coastguard Worker if (!includeFilters.isEmpty()) { 139*6777b538SAndroid Build Coastguard Worker joiner.appendTo(filter, includeFilters); 140*6777b538SAndroid Build Coastguard Worker } 141*6777b538SAndroid Build Coastguard Worker if (!excludeFilters.isEmpty()) { 142*6777b538SAndroid Build Coastguard Worker filter.append("-"); 143*6777b538SAndroid Build Coastguard Worker joiner.appendTo(filter, excludeFilters); 144*6777b538SAndroid Build Coastguard Worker } 145*6777b538SAndroid Build Coastguard Worker } 146*6777b538SAndroid Build Coastguard Worker String filterFlag = filter.toString(); 147*6777b538SAndroid Build Coastguard Worker // Handle long args 148*6777b538SAndroid Build Coastguard Worker if (filterFlag.length() > 500) { 149*6777b538SAndroid Build Coastguard Worker String tmpFlag = createFlagFileOnDevice(filterFlag); 150*6777b538SAndroid Build Coastguard Worker return String.format("%s=%s", GTEST_FLAG_FILE, tmpFlag); 151*6777b538SAndroid Build Coastguard Worker } 152*6777b538SAndroid Build Coastguard Worker return filterFlag; 153*6777b538SAndroid Build Coastguard Worker } 154*6777b538SAndroid Build Coastguard Worker 155*6777b538SAndroid Build Coastguard Worker /** 156*6777b538SAndroid Build Coastguard Worker * Helper method for getGTestFilters which creates a temporary flag file and push it to device. 157*6777b538SAndroid Build Coastguard Worker * 158*6777b538SAndroid Build Coastguard Worker * If it fails to create a file then it will directly use the filter in the adb command. 159*6777b538SAndroid Build Coastguard Worker * 160*6777b538SAndroid Build Coastguard Worker * @param filter the string to append to the flag file. 161*6777b538SAndroid Build Coastguard Worker * @return path to the flag file on device or null if it could not be created. 162*6777b538SAndroid Build Coastguard Worker */ 163*6777b538SAndroid Build Coastguard Worker @NonNull createFlagFileOnDevice(@onNull String filter)164*6777b538SAndroid Build Coastguard Worker private String createFlagFileOnDevice(@NonNull String filter) 165*6777b538SAndroid Build Coastguard Worker throws DeviceNotAvailableException { 166*6777b538SAndroid Build Coastguard Worker File tmpFlagFile = null; 167*6777b538SAndroid Build Coastguard Worker String devicePath; 168*6777b538SAndroid Build Coastguard Worker try { 169*6777b538SAndroid Build Coastguard Worker tmpFlagFile = FileUtil.createTempFile("flagfile", ".txt"); 170*6777b538SAndroid Build Coastguard Worker FileUtil.writeToFile(filter, tmpFlagFile); 171*6777b538SAndroid Build Coastguard Worker devicePath = String.format("/data/local/tmp/%s", tmpFlagFile.getName()); 172*6777b538SAndroid Build Coastguard Worker getDevice().pushFile(tmpFlagFile, devicePath); 173*6777b538SAndroid Build Coastguard Worker } catch (IOException e) { 174*6777b538SAndroid Build Coastguard Worker throw new FailedChromiumGTestException( 175*6777b538SAndroid Build Coastguard Worker "Failed to create temp file for gtest filter flag on the device.", e); 176*6777b538SAndroid Build Coastguard Worker } finally { 177*6777b538SAndroid Build Coastguard Worker FileUtil.deleteFile(tmpFlagFile); 178*6777b538SAndroid Build Coastguard Worker } 179*6777b538SAndroid Build Coastguard Worker return devicePath; 180*6777b538SAndroid Build Coastguard Worker } 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard Worker @NonNull getAllGTestFlags()183*6777b538SAndroid Build Coastguard Worker private String getAllGTestFlags() throws DeviceNotAvailableException { 184*6777b538SAndroid Build Coastguard Worker String flags = String.format("%s %s", GTEST_FLAG_PRINT_TIME, getGTestFilters()); 185*6777b538SAndroid Build Coastguard Worker if (isCollectTestsOnly()) { 186*6777b538SAndroid Build Coastguard Worker flags = String.format("%s %s", flags, GTEST_FLAG_LIST_TESTS); 187*6777b538SAndroid Build Coastguard Worker } 188*6777b538SAndroid Build Coastguard Worker return flags; 189*6777b538SAndroid Build Coastguard Worker } 190*6777b538SAndroid Build Coastguard Worker 191*6777b538SAndroid Build Coastguard Worker /** 192*6777b538SAndroid Build Coastguard Worker * The flags all exist in Chromium's instrumentation APK 193*6777b538SAndroid Build Coastguard Worker * {@link org.chromium.build.gtest_apk.NativeTestInstrumentationTestRunner} and 194*6777b538SAndroid Build Coastguard Worker * {@link org.chromium.native_test.NativeTest}. 195*6777b538SAndroid Build Coastguard Worker * 196*6777b538SAndroid Build Coastguard Worker * The following is a brief explanation for each flag 197*6777b538SAndroid Build Coastguard Worker * <ul> 198*6777b538SAndroid Build Coastguard Worker * <li> NATIVE_TEST_ACTIVITY_KEY: Indicates the name of the activity which should be 199*6777b538SAndroid Build Coastguard Worker * started by the instrumentation APK. This activity is responsible for executing gtests. 200*6777b538SAndroid Build Coastguard Worker * <li> RUN_IN_SUBTHREAD_KEY: Whether to run the tests in the main-thread or a sub-thread. 201*6777b538SAndroid Build Coastguard Worker * <li> EXTRA_SHARD_NANO_TIMEOUT_KEY: Shard timeout (Equal to the test timeout and not 202*6777b538SAndroid Build Coastguard Worker * important as we only use a single shard). 203*6777b538SAndroid Build Coastguard Worker * <li> LIBRARY_TO_LOAD_ACTIVITY_KEY: Name of the native library which has the code under 204*6777b538SAndroid Build Coastguard Worker * test. System.LoadLibrary will be invoked on the value of this flag 205*6777b538SAndroid Build Coastguard Worker * <li> STDOUT_FILE_KEY: Path to the file where stdout/stderr will be redirected to.</li> 206*6777b538SAndroid Build Coastguard Worker * <li> COMMAND_LINE_FLAGS_KEY: Command line flags delegated to the gtest executor. This is 207*6777b538SAndroid Build Coastguard Worker * mostly used for gtest flags 208*6777b538SAndroid Build Coastguard Worker * <li> DUMP_COVERAGE_KEY: Flag used to indicate that the apk should not exit before dumping 209*6777b538SAndroid Build Coastguard Worker * native coverage. 210*6777b538SAndroid Build Coastguard Worker * </ul> 211*6777b538SAndroid Build Coastguard Worker * 212*6777b538SAndroid Build Coastguard Worker * @param resultFilePath path to a temporary file on the device which the gtest result will be 213*6777b538SAndroid Build Coastguard Worker * directed to 214*6777b538SAndroid Build Coastguard Worker * @return an instrumentation command that can be executed using adb shell am instrument. 215*6777b538SAndroid Build Coastguard Worker */ 216*6777b538SAndroid Build Coastguard Worker @NonNull createRunAllTestsCommand(@onNull String resultFilePath)217*6777b538SAndroid Build Coastguard Worker private String createRunAllTestsCommand(@NonNull String resultFilePath) 218*6777b538SAndroid Build Coastguard Worker throws DeviceNotAvailableException { 219*6777b538SAndroid Build Coastguard Worker InstrumentationCommandBuilder builder = new InstrumentationCommandBuilder(TEST_RUNNER) 220*6777b538SAndroid Build Coastguard Worker .addArgument(NATIVE_TEST_ACTIVITY_KEY, NATIVE_UNIT_TEST_ACTIVITY_KEY) 221*6777b538SAndroid Build Coastguard Worker .addArgument(RUN_IN_SUBTHREAD_KEY, "1") 222*6777b538SAndroid Build Coastguard Worker .addArgument(EXTRA_SHARD_NANO_TIMEOUT_KEY, String.valueOf(TESTS_TIMEOUT.toNanos())) 223*6777b538SAndroid Build Coastguard Worker .addArgument(LIBRARY_TO_LOAD_ACTIVITY_KEY, libraryToLoad) 224*6777b538SAndroid Build Coastguard Worker .addArgument(STDOUT_FILE_KEY, resultFilePath) 225*6777b538SAndroid Build Coastguard Worker .addArgument(COMMAND_LINE_FLAGS_KEY, 226*6777b538SAndroid Build Coastguard Worker String.format("'%s'", getAllGTestFlags())); 227*6777b538SAndroid Build Coastguard Worker if (isCoverageEnabled) { 228*6777b538SAndroid Build Coastguard Worker builder.addArgument(DUMP_COVERAGE_KEY, "true"); 229*6777b538SAndroid Build Coastguard Worker } 230*6777b538SAndroid Build Coastguard Worker return builder.build(); 231*6777b538SAndroid Build Coastguard Worker } 232*6777b538SAndroid Build Coastguard Worker 233*6777b538SAndroid Build Coastguard Worker /** 234*6777b538SAndroid Build Coastguard Worker * Those logs can be found in host_log_%s.txt which is bundled with test execution. 235*6777b538SAndroid Build Coastguard Worker * 236*6777b538SAndroid Build Coastguard Worker * @param cmd Command used to instrumentation, this has all the flags which can help debugging 237*6777b538SAndroid Build Coastguard Worker * unusual behaviour. 238*6777b538SAndroid Build Coastguard Worker */ printHostLogs(@onNull String cmd)239*6777b538SAndroid Build Coastguard Worker private void printHostLogs(@NonNull String cmd) { 240*6777b538SAndroid Build Coastguard Worker LogUtil.CLog.i(String.format("[Cronet] Library to be loaded: %s\n", libraryToLoad)); 241*6777b538SAndroid Build Coastguard Worker LogUtil.CLog.i(String.format("[Cronet] Command used to run gtests: adb shell %s\n", cmd)); 242*6777b538SAndroid Build Coastguard Worker LogUtil.CLog.i(String.format("[Cronet] Native-Coverage = %b", isCoverageEnabled)); 243*6777b538SAndroid Build Coastguard Worker } 244*6777b538SAndroid Build Coastguard Worker 245*6777b538SAndroid Build Coastguard Worker /** 246*6777b538SAndroid Build Coastguard Worker * This is automatically invoked by the {@link com.android.tradefed.testtype.HostTest}. 247*6777b538SAndroid Build Coastguard Worker * 248*6777b538SAndroid Build Coastguard Worker * @param testInfo The {@link TestInformation} object containing useful information to run 249*6777b538SAndroid Build Coastguard Worker * tests. 250*6777b538SAndroid Build Coastguard Worker * @param listener the {@link ITestInvocationListener} of test results 251*6777b538SAndroid Build Coastguard Worker */ 252*6777b538SAndroid Build Coastguard Worker @Override run(TestInformation testInfo, ITestInvocationListener listener)253*6777b538SAndroid Build Coastguard Worker public void run(TestInformation testInfo, ITestInvocationListener listener) 254*6777b538SAndroid Build Coastguard Worker throws DeviceNotAvailableException { 255*6777b538SAndroid Build Coastguard Worker if (Strings.isNullOrEmpty(libraryToLoad)) { 256*6777b538SAndroid Build Coastguard Worker throw new IllegalStateException("No library provided to be loaded."); 257*6777b538SAndroid Build Coastguard Worker } 258*6777b538SAndroid Build Coastguard Worker String resultFilePath = createTempResultFileOnDevice(); 259*6777b538SAndroid Build Coastguard Worker String cmd = createRunAllTestsCommand(resultFilePath); 260*6777b538SAndroid Build Coastguard Worker printHostLogs(cmd); 261*6777b538SAndroid Build Coastguard Worker getDevice().executeShellCommand(CLEAR_CLANG_COVERAGE_FILES); 262*6777b538SAndroid Build Coastguard Worker ITestInvocationListener listenerWithTime = new TestListenerWithTime( 263*6777b538SAndroid Build Coastguard Worker System.currentTimeMillis(), listener); 264*6777b538SAndroid Build Coastguard Worker getDevice().executeShellCommand(cmd, new CollectingOutputReceiver(), 265*6777b538SAndroid Build Coastguard Worker /* maxTimeBeforeTimeOut */ TESTS_TIMEOUT.toMinutes(), 266*6777b538SAndroid Build Coastguard Worker /* timeUnit */ TimeUnit.MINUTES, 267*6777b538SAndroid Build Coastguard Worker /* retryAttempts */ 1); 268*6777b538SAndroid Build Coastguard Worker parseAndReport(resultFilePath, listenerWithTime); 269*6777b538SAndroid Build Coastguard Worker } 270*6777b538SAndroid Build Coastguard Worker parseAndReport(@onNull String resultFilePath, @NonNull ITestInvocationListener listener)271*6777b538SAndroid Build Coastguard Worker private void parseAndReport(@NonNull String resultFilePath, 272*6777b538SAndroid Build Coastguard Worker @NonNull ITestInvocationListener listener) throws DeviceNotAvailableException { 273*6777b538SAndroid Build Coastguard Worker File resultFile = device.pullFile(resultFilePath); 274*6777b538SAndroid Build Coastguard Worker if (resultFile == null) { 275*6777b538SAndroid Build Coastguard Worker throw new FailedChromiumGTestException( 276*6777b538SAndroid Build Coastguard Worker "Failed to retrieve gtest results file from device."); 277*6777b538SAndroid Build Coastguard Worker } 278*6777b538SAndroid Build Coastguard Worker try (FileInputStreamSource data = new FileInputStreamSource(resultFile)) { 279*6777b538SAndroid Build Coastguard Worker listener.testLog( 280*6777b538SAndroid Build Coastguard Worker String.format("gtest_output_%s", resultFile.getName()), LogDataType.TEXT, data); 281*6777b538SAndroid Build Coastguard Worker } 282*6777b538SAndroid Build Coastguard Worker // Loading all the lines is fine since this is done on the host-machine. 283*6777b538SAndroid Build Coastguard Worker String[] lines; 284*6777b538SAndroid Build Coastguard Worker try { 285*6777b538SAndroid Build Coastguard Worker lines = Files.readAllLines(resultFile.toPath()).toArray(String[]::new); 286*6777b538SAndroid Build Coastguard Worker } catch (IOException e) { 287*6777b538SAndroid Build Coastguard Worker throw new FailedChromiumGTestException( 288*6777b538SAndroid Build Coastguard Worker "Failed to read gtest results file on host machine.", e); 289*6777b538SAndroid Build Coastguard Worker } 290*6777b538SAndroid Build Coastguard Worker MultiLineReceiver parser; 291*6777b538SAndroid Build Coastguard Worker // the parser automatically reports the test result back to the infra through the listener. 292*6777b538SAndroid Build Coastguard Worker if (isCollectTestsOnly()) { 293*6777b538SAndroid Build Coastguard Worker parser = new GTestListTestParser(libraryToLoad, listener); 294*6777b538SAndroid Build Coastguard Worker } else { 295*6777b538SAndroid Build Coastguard Worker parser = new GTestResultParser(libraryToLoad, listener); 296*6777b538SAndroid Build Coastguard Worker } 297*6777b538SAndroid Build Coastguard Worker parser.processNewLines(lines); 298*6777b538SAndroid Build Coastguard Worker parser.done(); 299*6777b538SAndroid Build Coastguard Worker } 300*6777b538SAndroid Build Coastguard Worker 301*6777b538SAndroid Build Coastguard Worker // ------- Everything below is called by HostTest and should not be invoked manually ----- isCollectTestsOnly()302*6777b538SAndroid Build Coastguard Worker public boolean isCollectTestsOnly() { 303*6777b538SAndroid Build Coastguard Worker return collectTestsOnly; 304*6777b538SAndroid Build Coastguard Worker } 305*6777b538SAndroid Build Coastguard Worker 306*6777b538SAndroid Build Coastguard Worker @Override setCollectTestsOnly(boolean shouldCollectTest)307*6777b538SAndroid Build Coastguard Worker public void setCollectTestsOnly(boolean shouldCollectTest) { 308*6777b538SAndroid Build Coastguard Worker collectTestsOnly = shouldCollectTest; 309*6777b538SAndroid Build Coastguard Worker } 310*6777b538SAndroid Build Coastguard Worker cleanFilter(String filter)311*6777b538SAndroid Build Coastguard Worker public String cleanFilter(String filter) { 312*6777b538SAndroid Build Coastguard Worker return filter.replace('#', '.'); 313*6777b538SAndroid Build Coastguard Worker } 314*6777b538SAndroid Build Coastguard Worker 315*6777b538SAndroid Build Coastguard Worker @Override addIncludeFilter(String filter)316*6777b538SAndroid Build Coastguard Worker public void addIncludeFilter(String filter) { 317*6777b538SAndroid Build Coastguard Worker includeFilters.add(cleanFilter(filter)); 318*6777b538SAndroid Build Coastguard Worker } 319*6777b538SAndroid Build Coastguard Worker 320*6777b538SAndroid Build Coastguard Worker @Override addAllIncludeFilters(Set<String> filters)321*6777b538SAndroid Build Coastguard Worker public void addAllIncludeFilters(Set<String> filters) { 322*6777b538SAndroid Build Coastguard Worker for (String filter : filters) { 323*6777b538SAndroid Build Coastguard Worker includeFilters.add(cleanFilter(filter)); 324*6777b538SAndroid Build Coastguard Worker } 325*6777b538SAndroid Build Coastguard Worker } 326*6777b538SAndroid Build Coastguard Worker 327*6777b538SAndroid Build Coastguard Worker @Override addExcludeFilter(String filter)328*6777b538SAndroid Build Coastguard Worker public void addExcludeFilter(String filter) { 329*6777b538SAndroid Build Coastguard Worker excludeFilters.add(cleanFilter(filter)); 330*6777b538SAndroid Build Coastguard Worker } 331*6777b538SAndroid Build Coastguard Worker 332*6777b538SAndroid Build Coastguard Worker @Override addAllExcludeFilters(Set<String> filters)333*6777b538SAndroid Build Coastguard Worker public void addAllExcludeFilters(Set<String> filters) { 334*6777b538SAndroid Build Coastguard Worker for (String filter : filters) { 335*6777b538SAndroid Build Coastguard Worker excludeFilters.add(cleanFilter(filter)); 336*6777b538SAndroid Build Coastguard Worker } 337*6777b538SAndroid Build Coastguard Worker } 338*6777b538SAndroid Build Coastguard Worker 339*6777b538SAndroid Build Coastguard Worker @Override clearIncludeFilters()340*6777b538SAndroid Build Coastguard Worker public void clearIncludeFilters() { 341*6777b538SAndroid Build Coastguard Worker includeFilters.clear(); 342*6777b538SAndroid Build Coastguard Worker } 343*6777b538SAndroid Build Coastguard Worker 344*6777b538SAndroid Build Coastguard Worker @Override getIncludeFilters()345*6777b538SAndroid Build Coastguard Worker public Set<String> getIncludeFilters() { 346*6777b538SAndroid Build Coastguard Worker return includeFilters; 347*6777b538SAndroid Build Coastguard Worker } 348*6777b538SAndroid Build Coastguard Worker 349*6777b538SAndroid Build Coastguard Worker @Override getExcludeFilters()350*6777b538SAndroid Build Coastguard Worker public Set<String> getExcludeFilters() { 351*6777b538SAndroid Build Coastguard Worker return excludeFilters; 352*6777b538SAndroid Build Coastguard Worker } 353*6777b538SAndroid Build Coastguard Worker 354*6777b538SAndroid Build Coastguard Worker @Override clearExcludeFilters()355*6777b538SAndroid Build Coastguard Worker public void clearExcludeFilters() { 356*6777b538SAndroid Build Coastguard Worker excludeFilters.clear(); 357*6777b538SAndroid Build Coastguard Worker } 358*6777b538SAndroid Build Coastguard Worker 359*6777b538SAndroid Build Coastguard Worker @Override getDevice()360*6777b538SAndroid Build Coastguard Worker public ITestDevice getDevice() { 361*6777b538SAndroid Build Coastguard Worker return device; 362*6777b538SAndroid Build Coastguard Worker } 363*6777b538SAndroid Build Coastguard Worker 364*6777b538SAndroid Build Coastguard Worker @Override setDevice(ITestDevice device)365*6777b538SAndroid Build Coastguard Worker public void setDevice(ITestDevice device) { 366*6777b538SAndroid Build Coastguard Worker this.device = device; 367*6777b538SAndroid Build Coastguard Worker } 368*6777b538SAndroid Build Coastguard Worker }