1 /* 2 * Copyright (C) 2020 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 package android.media.cts; 17 18 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 19 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 20 import com.android.tradefed.build.IBuildInfo; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.log.LogUtil; 23 import com.android.tradefed.result.CollectingTestListener; 24 import com.android.tradefed.result.TestDescription; 25 import com.android.tradefed.result.TestResult; 26 import com.android.tradefed.result.TestRunResult; 27 import com.android.tradefed.testtype.DeviceTestCase; 28 import com.android.tradefed.testtype.IBuildReceiver; 29 30 import java.io.FileNotFoundException; 31 import java.util.Map; 32 import java.util.concurrent.TimeUnit; 33 34 import javax.annotation.Nonnull; 35 import javax.annotation.Nullable; 36 37 /** Base class for host-side tests for media APIs. */ 38 public class BaseMediaHostSideTest extends DeviceTestCase implements IBuildReceiver { 39 private static final String RUNNER = "androidx.test.runner.AndroidJUnitRunner"; 40 41 /** 42 * The defined timeout (in milliseconds) is used as a maximum waiting time when expecting the 43 * command output from the device. At any time, if the shell command does not output anything 44 * for a period longer than the defined timeout the Tradefed run terminates. 45 */ 46 private static final long DEFAULT_SHELL_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5); 47 48 /** Instrumentation test runner argument key used for individual test timeout. */ 49 protected static final String TEST_TIMEOUT_INST_ARGS_KEY = "timeout_msec"; 50 51 /** 52 * Sets timeout (in milliseconds) that will be applied to each test. In the event of a test 53 * timeout it will log the results and proceed with executing the next test. 54 */ 55 private static final long DEFAULT_TEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5); 56 57 protected IBuildInfo mCtsBuild; 58 59 @Override setBuild(IBuildInfo buildInfo)60 public void setBuild(IBuildInfo buildInfo) { 61 mCtsBuild = buildInfo; 62 } 63 64 /** 65 * Runs tests on the device. 66 * 67 * @param pkgName The test package file name that contains the test. 68 * @param testClassName The class name to test within the test package. If {@code null}, runs 69 * all test classes in the package. 70 * @param testMethodName Method name to test within the test class. Ignored if {@code 71 * testClassName} is {@code null}. If {@code null}, runs all test classes in the class. 72 */ runDeviceTests( String pkgName, @Nullable String testClassName, @Nullable String testMethodName)73 protected void runDeviceTests( 74 String pkgName, @Nullable String testClassName, @Nullable String testMethodName) 75 throws DeviceNotAvailableException { 76 RemoteAndroidTestRunner testRunner = getTestRunner(pkgName, testClassName, testMethodName); 77 CollectingTestListener listener = new CollectingTestListener(); 78 assertTrue(getDevice().runInstrumentationTests(testRunner, listener)); 79 assertTestsPassed(listener.getCurrentRunResults()); 80 } 81 82 /** 83 * Excutes shell command and returns the result. 84 * 85 * @param command The command to run. 86 * @return The result from the command. If the result was {@code null}, empty string ("") will 87 * be returned instead. Otherwise, trimmed result will be returned. 88 */ executeShellCommand(String command)89 protected @Nonnull String executeShellCommand(String command) throws Exception { 90 LogUtil.CLog.d("Starting command " + command); 91 String commandOutput = getDevice().executeShellCommand(command); 92 LogUtil.CLog.d("Output for command " + command + ": " + commandOutput); 93 return commandOutput != null ? commandOutput.trim() : ""; 94 } 95 96 /** Installs the app with the given {@code appFileName}. */ installApp(String appFileName)97 protected void installApp(String appFileName) 98 throws FileNotFoundException, DeviceNotAvailableException { 99 LogUtil.CLog.d("Installing app " + appFileName); 100 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); 101 String result = 102 getDevice() 103 .installPackage( 104 buildHelper.getTestFile(appFileName), 105 /* reinstall= */ true, 106 /* grantPermissions= */ true, 107 "-t"); // Signals that this is a test APK. 108 assertNull("Failed to install " + appFileName + ": " + result, result); 109 } 110 111 /** Returns a {@link RemoteAndroidTestRunner} for the given test parameters. */ getTestRunner( String pkgName, String testClassName, String testMethodName)112 protected RemoteAndroidTestRunner getTestRunner( 113 String pkgName, String testClassName, String testMethodName) { 114 if (testClassName != null && testClassName.startsWith(".")) { 115 testClassName = pkgName + testClassName; 116 } 117 118 RemoteAndroidTestRunner testRunner = 119 new RemoteAndroidTestRunner(pkgName, RUNNER, getDevice().getIDevice()); 120 testRunner.setMaxTimeToOutputResponse(DEFAULT_SHELL_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 121 testRunner.addInstrumentationArg( 122 TEST_TIMEOUT_INST_ARGS_KEY, Long.toString(DEFAULT_TEST_TIMEOUT_MILLIS)); 123 if (testClassName != null && testMethodName != null) { 124 testRunner.setMethodName(testClassName, testMethodName); 125 } else if (testClassName != null) { 126 testRunner.setClassName(testClassName); 127 } 128 return testRunner; 129 } 130 131 /** 132 * Asserts that {@code testRunResult} contains at least one test, and that all tests passed. 133 * 134 * <p>If the assertion fails, an {@link AssertionError} with a descriptive message is thrown. 135 */ assertTestsPassed(TestRunResult testRunResult)136 protected void assertTestsPassed(TestRunResult testRunResult) { 137 if (testRunResult.isRunFailure()) { 138 throw new AssertionError( 139 "Failed to successfully run device tests for " 140 + testRunResult.getName() 141 + ": " 142 + testRunResult.getRunFailureMessage()); 143 } 144 if (testRunResult.getNumTests() == 0) { 145 throw new AssertionError("No tests were run on the device"); 146 } 147 148 if (testRunResult.hasFailedTests()) { 149 // Build a meaningful error message 150 StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n"); 151 for (Map.Entry<TestDescription, TestResult> resultEntry : 152 testRunResult.getTestResults().entrySet()) { 153 if (!resultEntry 154 .getValue() 155 .getStatus() 156 .equals(com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) { 157 errorBuilder.append(resultEntry.getKey().toString()); 158 errorBuilder.append(":\n"); 159 errorBuilder.append(resultEntry.getValue().getStackTrace()); 160 } 161 } 162 throw new AssertionError(errorBuilder.toString()); 163 } 164 } 165 } 166