blob: 0542b9498b577b7d0b525c01cf6d3450d6cf9eb6 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm.cts.shortcuthost;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestResult.TestStatus;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.result.TestResult;
import com.android.tradefed.result.TestRunResult;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import org.junit.After;
import org.junit.Before;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
abstract public class BaseShortcutManagerHostTest extends BaseHostJUnit4Test {
protected static final boolean DUMPSYS_IN_TEARDOWN = false; // DO NOT SUBMIT WITH TRUE
protected static final boolean NO_UNINSTALL_IN_TEARDOWN = false; // DO NOT SUBMIT WITH TRUE
private static final String RUNNER = "androidx.test.runner.AndroidJUnitRunner";
protected boolean mIsMultiuserSupported;
protected boolean mIsManagedUserSupported;
private int mInitialUserId;
private ArrayList<Integer> mOriginalUsers;
@Before
public void setUp() throws Exception {
assertNotNull(getBuild()); // ensure build has been set before test is run.
mIsMultiuserSupported = getDevice().isMultiUserSupported();
if (!mIsMultiuserSupported) {
CLog.w("Multi user not supporeted");
}
mIsManagedUserSupported = getDevice().hasFeature("android.software.managed_users");
if (!mIsManagedUserSupported) {
CLog.w("Managed users not supporeted");
}
if (mIsMultiuserSupported) {
mInitialUserId = getDevice().getCurrentUser();
mOriginalUsers = new ArrayList<>(getDevice().listUsers());
}
}
@After
public void tearDown() throws Exception {
removeTestUsers();
}
protected void dumpsys(String label) throws DeviceNotAvailableException {
CLog.w("dumpsys shortcuts #" + label);
CLog.w(getDevice().executeShellCommand("dumpsys shortcut"));
}
protected String executeShellCommandWithLog(String command) throws DeviceNotAvailableException {
CLog.i("Executing command: " + command);
final String output = getDevice().executeShellCommand(command);
CLog.i(output);
return output;
}
protected void clearShortcuts(String packageName, int userId) throws Exception {
assertContainsRegex("Success",
getDevice().executeShellCommand("cmd shortcut clear-shortcuts --user " + userId
+ " " + packageName));
}
protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
DeviceNotAvailableException {
CLog.i("Installing app " + appFileName + " for user " + userId);
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
String result = getDevice().installPackageForUser(
buildHelper.getTestFile(appFileName), true, true, userId, "-t");
assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
result);
}
protected int getPrimaryUserId() throws DeviceNotAvailableException {
return getDevice().getPrimaryUserId();
}
/** Returns true if the specified tests passed. Tests are run as given user. */
protected void runDeviceTestsAsUser(
String pkgName, @Nullable String testClassName, int userId)
throws DeviceNotAvailableException {
runDeviceTestsAsUser(pkgName, testClassName, null /*testMethodName*/, userId);
}
/** Returns true if the specified tests passed. Tests are run as given user. */
protected void runDeviceTestsAsUser(
String pkgName, @Nullable String testClassName, String testMethodName, int userId)
throws DeviceNotAvailableException {
final DeviceTestRunOptions opts = new DeviceTestRunOptions(pkgName);
if (testClassName != null) {
if (testClassName.startsWith(".")) {
testClassName = pkgName + testClassName;
}
opts.setTestClassName(testClassName);
}
if (testMethodName != null) {
opts.setTestMethodName(testMethodName);
}
opts.setUserId(userId);
runDeviceTests(opts);
}
private void removeTestUsers() throws Exception {
if (!mIsMultiuserSupported) {
return;
}
getDevice().switchUser(mInitialUserId);
for (int userId : getDevice().listUsers()) {
if (!mOriginalUsers.contains(userId)) {
getDevice().removeUser(userId);
}
}
}
protected int getOrCreateSecondaryUser() throws Exception {
if (getDevice().isUserSecondary(mInitialUserId)) {
return mInitialUserId;
}
for (int userId : getDevice().listUsers()) {
if (getDevice().isUserSecondary(userId)) {
return userId;
}
}
return createUser();
}
protected int createUser() throws Exception{
return getDevice().createUser("TestUser_" + System.currentTimeMillis());
}
protected int createProfile(int parentUserId) throws Exception{
final String command = "pm create-user --profileOf " + parentUserId
+ " --managed TestUser_" + System.currentTimeMillis();
CLog.d("Starting command: " + command);
final String output = getDevice().executeShellCommand(command);
CLog.d("Output for command " + command + ": " + output);
if (output.startsWith("Success")) {
try {
return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
} catch (NumberFormatException e) {
CLog.e("Failed to parse result: %s", output);
}
} else {
CLog.e("Failed to create user: %s", output);
}
throw new IllegalStateException();
}
/**
* Variant of {@link #assertContainsRegex(String,String,String)} using a
* generic message.
*/
public MatchResult assertContainsRegex(
String expectedRegex, String actual) {
return assertContainsRegex(null, expectedRegex, actual);
}
/**
* Asserts that {@code expectedRegex} matches any substring of {@code actual}
* and fails with {@code message} if it does not. The Matcher is returned in
* case the test needs access to any captured groups. Note that you can also
* use this for a literal string, by wrapping your expected string in
* {@link Pattern#quote}.
*/
public MatchResult assertContainsRegex(
String message, String expectedRegex, String actual) {
if (actual == null) {
failNotContains(message, expectedRegex, actual);
}
Matcher matcher = getMatcher(expectedRegex, actual);
if (!matcher.find()) {
failNotContains(message, expectedRegex, actual);
}
return matcher;
}
/**
* Asserts that {@code expectedRegex} does not exactly match {@code actual},
* and fails with {@code message} if it does. Note that you can also use
* this for a literal string, by wrapping your expected string in
* {@link Pattern#quote}.
*/
public void assertNotMatchesRegex(
String message, String expectedRegex, String actual) {
Matcher matcher = getMatcher(expectedRegex, actual);
if (matcher.matches()) {
failMatch(message, expectedRegex, actual);
}
}
private Matcher getMatcher(String expectedRegex, String actual) {
Pattern pattern = Pattern.compile(expectedRegex);
return pattern.matcher(actual);
}
private void failMatch(
String message, String expectedRegex, String actual) {
failWithMessage(message, "expected not to match regex:<" + expectedRegex
+ "> but was:<" + actual + '>');
}
private void failWithMessage(String userMessage, String ourMessage) {
fail((userMessage == null)
? ourMessage
: userMessage + ' ' + ourMessage);
}
private void failNotContains(
String message, String expectedRegex, String actual) {
String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
failWithMessage(message, "expected to contain regex:<" + expectedRegex
+ "> but was:" + actualDesc);
}
protected void waitForBroadcastIdle() throws Exception {
runCommand("am wait-for-broadcast-idle");
}
private String runCommand(String command) throws Exception {
return runCommand(command, "", true);
}
private String runCommand(String command, String expectedOutputPattern) throws Exception {
return runCommand(command, expectedOutputPattern, true);
}
private String runCommandAndNotMatch(String command, String expectedOutputPattern)
throws Exception {
return runCommand(command, expectedOutputPattern, false);
}
private String runCommand(String command, String expectedOutputPattern,
boolean shouldMatch) throws Exception {
CLog.d("Executing command: " + command);
final String output = getDevice().executeShellCommand(command);
CLog.d("Output:\n"
+ "====================\n"
+ output
+ "====================");
final Pattern pat = Pattern.compile(
expectedOutputPattern, Pattern.MULTILINE | Pattern.COMMENTS);
if (pat.matcher(output.trim()).find() != shouldMatch) {
fail("Output from \"" + command + "\" "
+ (shouldMatch ? "didn't match" : "unexpectedly matched")
+ " \"" + expectedOutputPattern + "\"");
}
return output;
}
}