Home | History | Annotate | Download | only in shortcuthost
      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 com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
     19 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
     20 import com.android.ddmlib.testrunner.TestResult.TestStatus;
     21 import com.android.tradefed.build.IBuildInfo;
     22 import com.android.tradefed.device.DeviceNotAvailableException;
     23 import com.android.tradefed.log.LogUtil.CLog;
     24 import com.android.tradefed.result.CollectingTestListener;
     25 import com.android.tradefed.result.TestDescription;
     26 import com.android.tradefed.result.TestResult;
     27 import com.android.tradefed.result.TestRunResult;
     28 import com.android.tradefed.testtype.DeviceTestCase;
     29 import com.android.tradefed.testtype.IBuildReceiver;
     30 
     31 import java.io.FileNotFoundException;
     32 import java.util.ArrayList;
     33 import java.util.Collections;
     34 import java.util.Map;
     35 import java.util.regex.MatchResult;
     36 import java.util.regex.Matcher;
     37 import java.util.regex.Pattern;
     38 
     39 import javax.annotation.Nullable;
     40 
     41 abstract public class BaseShortcutManagerHostTest extends DeviceTestCase implements IBuildReceiver {
     42     protected static final boolean DUMPSYS_IN_TEARDOWN = false; // DO NOT SUBMIT WITH TRUE
     43 
     44     protected static final boolean NO_UNINSTALL_IN_TEARDOWN = false; // DO NOT SUBMIT WITH TRUE
     45 
     46     private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
     47 
     48     private IBuildInfo mCtsBuild;
     49 
     50     protected boolean mIsMultiuserSupported;
     51     protected boolean mIsManagedUserSupported;
     52 
     53     private ArrayList<Integer> mOriginalUsers;
     54 
     55     @Override
     56     public void setBuild(IBuildInfo buildInfo) {
     57         mCtsBuild = buildInfo;
     58     }
     59 
     60     @Override
     61     protected void setUp() throws Exception {
     62         super.setUp();
     63         assertNotNull(mCtsBuild);  // 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             mOriginalUsers = new ArrayList<>(getDevice().listUsers());
     76         }
     77     }
     78 
     79     @Override
     80     protected void tearDown() throws Exception {
     81         removeTestUsers();
     82         super.tearDown();
     83     }
     84 
     85     protected void dumpsys(String label) throws DeviceNotAvailableException {
     86         CLog.w("dumpsys shortcuts #" + label);
     87 
     88         CLog.w(getDevice().executeShellCommand("dumpsys shortcut"));
     89     }
     90 
     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 
     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 
    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(mCtsBuild);
    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 
    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. */
    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. */
    126     protected void runDeviceTestsAsUser(
    127             String pkgName, @Nullable String testClassName, String testMethodName, int userId)
    128             throws DeviceNotAvailableException {
    129         Map<String, String> params = Collections.emptyMap();
    130         runDeviceTestsAsUser(pkgName, testClassName, testMethodName, userId, params);
    131     }
    132 
    133     protected void runDeviceTestsAsUser(String pkgName, @Nullable String testClassName,
    134             @Nullable String testMethodName, int userId,
    135             Map<String, String> params) throws DeviceNotAvailableException {
    136         if (testClassName != null && testClassName.startsWith(".")) {
    137             testClassName = pkgName + testClassName;
    138         }
    139 
    140         RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
    141                 pkgName, RUNNER, getDevice().getIDevice());
    142         if (testClassName != null && testMethodName != null) {
    143             testRunner.setMethodName(testClassName, testMethodName);
    144         } else if (testClassName != null) {
    145             testRunner.setClassName(testClassName);
    146         }
    147 
    148         for (Map.Entry<String, String> param : params.entrySet()) {
    149             testRunner.addInstrumentationArg(param.getKey(), param.getValue());
    150         }
    151 
    152         CollectingTestListener listener = new CollectingTestListener();
    153         assertTrue(getDevice().runInstrumentationTestsAsUser(testRunner, userId, listener));
    154 
    155         TestRunResult runResult = listener.getCurrentRunResults();
    156         if (runResult.getTestResults().size() == 0) {
    157             fail("No tests have been executed.");
    158             return;
    159         }
    160 
    161         printTestResult(runResult);
    162         if (runResult.hasFailedTests() || runResult.getNumTestsInState(TestStatus.PASSED) == 0) {
    163             fail("Some tests have been failed.");
    164         }
    165     }
    166 
    167     private void printTestResult(TestRunResult runResult) {
    168         for (Map.Entry<TestDescription, TestResult> testEntry :
    169                 runResult.getTestResults().entrySet()) {
    170             TestResult testResult = testEntry.getValue();
    171 
    172             final String message = "Test " + testEntry.getKey() + ": " + testResult.getStatus();
    173             if (testResult.getStatus() == TestStatus.PASSED) {
    174                 CLog.i(message);
    175             } else {
    176                 CLog.e(message);
    177                 CLog.e(testResult.getStackTrace());
    178             }
    179         }
    180     }
    181 
    182     private void removeTestUsers() throws Exception {
    183         if (!mIsMultiuserSupported) {
    184             return;
    185         }
    186         getDevice().switchUser(getPrimaryUserId());
    187         for (int userId : getDevice().listUsers()) {
    188             if (!mOriginalUsers.contains(userId)) {
    189                 getDevice().removeUser(userId);
    190             }
    191         }
    192     }
    193 
    194     protected int createUser() throws Exception{
    195         return getDevice().createUser("TestUser_" + System.currentTimeMillis());
    196     }
    197 
    198     protected int createProfile(int parentUserId) throws Exception{
    199         final String command = "pm create-user --profileOf " + parentUserId
    200                 + " --managed TestUser_" + System.currentTimeMillis();
    201         CLog.d("Starting command: " + command);
    202         final String output = getDevice().executeShellCommand(command);
    203         CLog.d("Output for command " + command + ": " + output);
    204 
    205         if (output.startsWith("Success")) {
    206             try {
    207                 return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
    208             } catch (NumberFormatException e) {
    209                 CLog.e("Failed to parse result: %s", output);
    210             }
    211         } else {
    212             CLog.e("Failed to create user: %s", output);
    213         }
    214         throw new IllegalStateException();
    215     }
    216 
    217     /**
    218      * Variant of {@link #assertContainsRegex(String,String,String)} using a
    219      * generic message.
    220      */
    221     public MatchResult assertContainsRegex(
    222             String expectedRegex, String actual) {
    223         return assertContainsRegex(null, expectedRegex, actual);
    224     }
    225 
    226     /**
    227      * Asserts that {@code expectedRegex} matches any substring of {@code actual}
    228      * and fails with {@code message} if it does not.  The Matcher is returned in
    229      * case the test needs access to any captured groups.  Note that you can also
    230      * use this for a literal string, by wrapping your expected string in
    231      * {@link Pattern#quote}.
    232      */
    233     public MatchResult assertContainsRegex(
    234             String message, String expectedRegex, String actual) {
    235         if (actual == null) {
    236             failNotContains(message, expectedRegex, actual);
    237         }
    238         Matcher matcher = getMatcher(expectedRegex, actual);
    239         if (!matcher.find()) {
    240             failNotContains(message, expectedRegex, actual);
    241         }
    242         return matcher;
    243     }
    244 
    245     /**
    246      * Asserts that {@code expectedRegex} does not exactly match {@code actual},
    247      * and fails with {@code message} if it does. Note that you can also use
    248      * this for a literal string, by wrapping your expected string in
    249      * {@link Pattern#quote}.
    250      */
    251     public void assertNotMatchesRegex(
    252             String message, String expectedRegex, String actual) {
    253         Matcher matcher = getMatcher(expectedRegex, actual);
    254         if (matcher.matches()) {
    255             failMatch(message, expectedRegex, actual);
    256         }
    257     }
    258 
    259     private Matcher getMatcher(String expectedRegex, String actual) {
    260         Pattern pattern = Pattern.compile(expectedRegex);
    261         return pattern.matcher(actual);
    262     }
    263 
    264     private void failMatch(
    265             String message, String expectedRegex, String actual) {
    266         failWithMessage(message, "expected not to match regex:<" + expectedRegex
    267                 + "> but was:<" + actual + '>');
    268     }
    269 
    270     private void failWithMessage(String userMessage, String ourMessage) {
    271         fail((userMessage == null)
    272                 ? ourMessage
    273                 : userMessage + ' ' + ourMessage);
    274     }
    275 
    276     private void failNotContains(
    277             String message, String expectedRegex, String actual) {
    278         String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
    279         failWithMessage(message, "expected to contain regex:<" + expectedRegex
    280                 + "> but was:" + actualDesc);
    281     }
    282 }
    283