1 /* 2 * Copyright (C) 2016 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.content.pm.cts.shortcuthost; 17 18 import static org.junit.Assert.assertNotNull; 19 import static org.junit.Assert.assertNull; 20 import static org.junit.Assert.assertTrue; 21 import static org.junit.Assert.fail; 22 23 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 24 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 25 import com.android.ddmlib.testrunner.TestResult.TestStatus; 26 import com.android.tradefed.device.DeviceNotAvailableException; 27 import com.android.tradefed.log.LogUtil.CLog; 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 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 33 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions; 34 35 import org.junit.After; 36 import org.junit.Before; 37 38 import java.io.FileNotFoundException; 39 import java.util.ArrayList; 40 import java.util.Collections; 41 import java.util.Map; 42 import java.util.regex.MatchResult; 43 import java.util.regex.Matcher; 44 import java.util.regex.Pattern; 45 46 import javax.annotation.Nullable; 47 48 abstract public class BaseShortcutManagerHostTest extends BaseHostJUnit4Test { 49 protected static final boolean DUMPSYS_IN_TEARDOWN = false; // DO NOT SUBMIT WITH TRUE 50 51 protected static final boolean NO_UNINSTALL_IN_TEARDOWN = false; // DO NOT SUBMIT WITH TRUE 52 53 private static final String RUNNER = "androidx.test.runner.AndroidJUnitRunner"; 54 55 protected boolean mIsMultiuserSupported; 56 protected boolean mIsManagedUserSupported; 57 58 private int mInitialUserId; 59 private ArrayList<Integer> mOriginalUsers; 60 61 @Before setUp()62 public void setUp() throws Exception { 63 assertNotNull(getBuild()); // ensure build has been set before test is run. 64 65 mIsMultiuserSupported = getDevice().isMultiUserSupported(); 66 if (!mIsMultiuserSupported) { 67 CLog.w("Multi user not supporeted"); 68 } 69 mIsManagedUserSupported = getDevice().hasFeature("android.software.managed_users"); 70 if (!mIsManagedUserSupported) { 71 CLog.w("Managed users not supporeted"); 72 } 73 74 if (mIsMultiuserSupported) { 75 mInitialUserId = getDevice().getCurrentUser(); 76 mOriginalUsers = new ArrayList<>(getDevice().listUsers()); 77 } 78 } 79 80 @After tearDown()81 public void tearDown() throws Exception { 82 removeTestUsers(); 83 } 84 dumpsys(String label)85 protected void dumpsys(String label) throws DeviceNotAvailableException { 86 CLog.w("dumpsys shortcuts #" + label); 87 88 CLog.w(getDevice().executeShellCommand("dumpsys shortcut")); 89 } 90 executeShellCommandWithLog(String command)91 protected String executeShellCommandWithLog(String command) throws DeviceNotAvailableException { 92 CLog.i("Executing command: " + command); 93 final String output = getDevice().executeShellCommand(command); 94 CLog.i(output); 95 return output; 96 } 97 clearShortcuts(String packageName, int userId)98 protected void clearShortcuts(String packageName, int userId) throws Exception { 99 assertContainsRegex("Success", 100 getDevice().executeShellCommand("cmd shortcut clear-shortcuts --user " + userId 101 + " " + packageName)); 102 } 103 installAppAsUser(String appFileName, int userId)104 protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException, 105 DeviceNotAvailableException { 106 CLog.i("Installing app " + appFileName + " for user " + userId); 107 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); 108 String result = getDevice().installPackageForUser( 109 buildHelper.getTestFile(appFileName), true, true, userId, "-t"); 110 assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result, 111 result); 112 } 113 getPrimaryUserId()114 protected int getPrimaryUserId() throws DeviceNotAvailableException { 115 return getDevice().getPrimaryUserId(); 116 } 117 118 /** Returns true if the specified tests passed. Tests are run as given user. */ runDeviceTestsAsUser( String pkgName, @Nullable String testClassName, int userId)119 protected void runDeviceTestsAsUser( 120 String pkgName, @Nullable String testClassName, int userId) 121 throws DeviceNotAvailableException { 122 runDeviceTestsAsUser(pkgName, testClassName, null /*testMethodName*/, userId); 123 } 124 125 /** Returns true if the specified tests passed. Tests are run as given user. */ runDeviceTestsAsUser( String pkgName, @Nullable String testClassName, String testMethodName, int userId)126 protected void runDeviceTestsAsUser( 127 String pkgName, @Nullable String testClassName, String testMethodName, int userId) 128 throws DeviceNotAvailableException { 129 130 final DeviceTestRunOptions opts = new DeviceTestRunOptions(pkgName); 131 if (testClassName != null) { 132 if (testClassName.startsWith(".")) { 133 testClassName = pkgName + testClassName; 134 } 135 opts.setTestClassName(testClassName); 136 } 137 if (testMethodName != null) { 138 opts.setTestMethodName(testMethodName); 139 } 140 opts.setUserId(userId); 141 142 runDeviceTests(opts); 143 } 144 removeTestUsers()145 private void removeTestUsers() throws Exception { 146 if (!mIsMultiuserSupported) { 147 return; 148 } 149 getDevice().switchUser(mInitialUserId); 150 for (int userId : getDevice().listUsers()) { 151 if (!mOriginalUsers.contains(userId)) { 152 getDevice().removeUser(userId); 153 } 154 } 155 } 156 getOrCreateSecondaryUser()157 protected int getOrCreateSecondaryUser() throws Exception { 158 if (getDevice().isUserSecondary(mInitialUserId)) { 159 return mInitialUserId; 160 } 161 for (int userId : getDevice().listUsers()) { 162 if (getDevice().isUserSecondary(userId)) { 163 return userId; 164 } 165 } 166 return createUser(); 167 } 168 createUser()169 protected int createUser() throws Exception{ 170 return getDevice().createUser("TestUser_" + System.currentTimeMillis()); 171 } 172 createProfile(int parentUserId)173 protected int createProfile(int parentUserId) throws Exception{ 174 final String command = "pm create-user --profileOf " + parentUserId 175 + " --managed TestUser_" + System.currentTimeMillis(); 176 CLog.d("Starting command: " + command); 177 final String output = getDevice().executeShellCommand(command); 178 CLog.d("Output for command " + command + ": " + output); 179 180 if (output.startsWith("Success")) { 181 try { 182 return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()); 183 } catch (NumberFormatException e) { 184 CLog.e("Failed to parse result: %s", output); 185 } 186 } else { 187 CLog.e("Failed to create user: %s", output); 188 } 189 throw new IllegalStateException(); 190 } 191 192 /** 193 * Variant of {@link #assertContainsRegex(String,String,String)} using a 194 * generic message. 195 */ assertContainsRegex( String expectedRegex, String actual)196 public MatchResult assertContainsRegex( 197 String expectedRegex, String actual) { 198 return assertContainsRegex(null, expectedRegex, actual); 199 } 200 201 /** 202 * Asserts that {@code expectedRegex} matches any substring of {@code actual} 203 * and fails with {@code message} if it does not. The Matcher is returned in 204 * case the test needs access to any captured groups. Note that you can also 205 * use this for a literal string, by wrapping your expected string in 206 * {@link Pattern#quote}. 207 */ assertContainsRegex( String message, String expectedRegex, String actual)208 public MatchResult assertContainsRegex( 209 String message, String expectedRegex, String actual) { 210 if (actual == null) { 211 failNotContains(message, expectedRegex, actual); 212 } 213 Matcher matcher = getMatcher(expectedRegex, actual); 214 if (!matcher.find()) { 215 failNotContains(message, expectedRegex, actual); 216 } 217 return matcher; 218 } 219 220 /** 221 * Asserts that {@code expectedRegex} does not exactly match {@code actual}, 222 * and fails with {@code message} if it does. Note that you can also use 223 * this for a literal string, by wrapping your expected string in 224 * {@link Pattern#quote}. 225 */ assertNotMatchesRegex( String message, String expectedRegex, String actual)226 public void assertNotMatchesRegex( 227 String message, String expectedRegex, String actual) { 228 Matcher matcher = getMatcher(expectedRegex, actual); 229 if (matcher.matches()) { 230 failMatch(message, expectedRegex, actual); 231 } 232 } 233 getMatcher(String expectedRegex, String actual)234 private Matcher getMatcher(String expectedRegex, String actual) { 235 Pattern pattern = Pattern.compile(expectedRegex); 236 return pattern.matcher(actual); 237 } 238 failMatch( String message, String expectedRegex, String actual)239 private void failMatch( 240 String message, String expectedRegex, String actual) { 241 failWithMessage(message, "expected not to match regex:<" + expectedRegex 242 + "> but was:<" + actual + '>'); 243 } 244 failWithMessage(String userMessage, String ourMessage)245 private void failWithMessage(String userMessage, String ourMessage) { 246 fail((userMessage == null) 247 ? ourMessage 248 : userMessage + ' ' + ourMessage); 249 } 250 failNotContains( String message, String expectedRegex, String actual)251 private void failNotContains( 252 String message, String expectedRegex, String actual) { 253 String actualDesc = (actual == null) ? "null" : ('<' + actual + '>'); 254 failWithMessage(message, "expected to contain regex:<" + expectedRegex 255 + "> but was:" + actualDesc); 256 } 257 } 258