1 /* 2 * Copyright (C) 2024 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 17 package com.android.cts.netpolicy; 18 19 import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL; 20 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.fail; 24 25 import com.android.ddmlib.Log; 26 import com.android.tradefed.config.Option; 27 import com.android.tradefed.device.DeviceNotAvailableException; 28 import com.android.tradefed.invoker.TestInformation; 29 import com.android.tradefed.targetprep.BuildError; 30 import com.android.tradefed.targetprep.TargetSetupError; 31 import com.android.tradefed.targetprep.suite.SuiteApkInstaller; 32 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 33 import com.android.tradefed.testtype.junit4.AfterClassWithInfo; 34 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 35 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo; 36 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions; 37 import com.android.tradefed.util.RunUtil; 38 39 import org.junit.runner.RunWith; 40 41 import java.util.Map; 42 43 @RunWith(DeviceJUnit4ClassRunner.class) 44 abstract class HostsideNetworkPolicyTestCase extends BaseHostJUnit4Test { 45 protected static final boolean DEBUG = false; 46 protected static final String TAG = "HostsideNetworkPolicyTests"; 47 protected static final String TEST_PKG = "com.android.cts.netpolicy.hostside"; 48 protected static final String TEST_APK = "CtsHostsideNetworkPolicyTestsApp.apk"; 49 protected static final String TEST_APP2_PKG = "com.android.cts.netpolicy.hostside.app2"; 50 protected static final String TEST_APP2_APK = "CtsHostsideNetworkPolicyTestsApp2.apk"; 51 52 @Option(name = "custom-url", importance = Option.Importance.IF_UNSET, 53 description = "A custom url to use for testing network connections") 54 protected String mCustomUrl; 55 56 @BeforeClassWithInfo setUpOnceBase(TestInformation testInfo)57 public static void setUpOnceBase(TestInformation testInfo) throws Exception { 58 uninstallPackage(testInfo, TEST_PKG, false); 59 installPackage(testInfo, TEST_APK); 60 } 61 62 @AfterClassWithInfo tearDownOnceBase(TestInformation testInfo)63 public static void tearDownOnceBase(TestInformation testInfo) 64 throws DeviceNotAvailableException { 65 uninstallPackage(testInfo, TEST_PKG, true); 66 } 67 68 // Custom static method to install the specified package, this is used to bypass auto-cleanup 69 // per test in BaseHostJUnit4. installPackage(TestInformation testInfo, String apk)70 protected static void installPackage(TestInformation testInfo, String apk) 71 throws DeviceNotAvailableException, TargetSetupError { 72 assertNotNull(testInfo); 73 final int userId = testInfo.getDevice().getCurrentUser(); 74 final SuiteApkInstaller installer = new SuiteApkInstaller(); 75 // Force the apk clean up 76 installer.setCleanApk(true); 77 installer.addTestFileName(apk); 78 installer.setUserId(userId); 79 installer.setShouldGrantPermission(true); 80 installer.addInstallArg("-t"); 81 try { 82 installer.setUp(testInfo); 83 } catch (BuildError e) { 84 throw new TargetSetupError( 85 e.getMessage(), e, testInfo.getDevice().getDeviceDescriptor(), e.getErrorId()); 86 } 87 } 88 installPackage(String apk)89 protected void installPackage(String apk) throws DeviceNotAvailableException, TargetSetupError { 90 installPackage(getTestInformation(), apk); 91 } 92 uninstallPackage(TestInformation testInfo, String packageName, boolean shouldSucceed)93 protected static void uninstallPackage(TestInformation testInfo, String packageName, 94 boolean shouldSucceed) 95 throws DeviceNotAvailableException { 96 assertNotNull(testInfo); 97 final String result = testInfo.getDevice().uninstallPackage(packageName); 98 if (shouldSucceed) { 99 assertNull("uninstallPackage(" + packageName + ") failed: " + result, result); 100 } 101 } 102 uninstallPackage(String packageName, boolean shouldSucceed)103 protected void uninstallPackage(String packageName, 104 boolean shouldSucceed) 105 throws DeviceNotAvailableException { 106 uninstallPackage(getTestInformation(), packageName, shouldSucceed); 107 } 108 assertPackageUninstalled(String packageName)109 protected void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException { 110 final String command = "cmd package list packages " + packageName; 111 final int max_tries = 5; 112 for (int i = 1; i <= max_tries; i++) { 113 final String result = runCommand(command); 114 if (result.trim().isEmpty()) { 115 return; 116 } 117 // 'list packages' filters by substring, so we need to iterate with the results 118 // and check one by one, otherwise 'com.android.cts.netpolicy.hostside' could return 119 // 'com.android.cts.netpolicy.hostside.app2' 120 boolean found = false; 121 for (String line : result.split("[\\r\\n]+")) { 122 if (line.endsWith(packageName)) { 123 found = true; 124 break; 125 } 126 } 127 if (!found) { 128 return; 129 } 130 Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result 131 + "); sleeping 1s before polling again"); 132 RunUtil.getDefault().sleep(1000); 133 } 134 fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); 135 } 136 getUid(String packageName)137 protected int getUid(String packageName) throws DeviceNotAvailableException { 138 final int currentUser = getDevice().getCurrentUser(); 139 final String uidLines = runCommand( 140 "cmd package list packages -U --user " + currentUser + " " + packageName); 141 for (String uidLine : uidLines.split("\n")) { 142 if (uidLine.startsWith("package:" + packageName + " uid:")) { 143 final String[] uidLineParts = uidLine.split(":"); 144 // 3rd entry is package uid 145 return Integer.parseInt(uidLineParts[2].trim()); 146 } 147 } 148 throw new IllegalStateException("Failed to find the test app on the device; pkg=" 149 + packageName + ", u=" + currentUser); 150 } 151 runDeviceTestsWithCustomOptions(String packageName, String className)152 protected boolean runDeviceTestsWithCustomOptions(String packageName, String className) 153 throws DeviceNotAvailableException { 154 return runDeviceTestsWithCustomOptions(packageName, className, null); 155 } 156 runDeviceTestsWithCustomOptions(String packageName, String className, String methodName)157 protected boolean runDeviceTestsWithCustomOptions(String packageName, String className, 158 String methodName) throws DeviceNotAvailableException { 159 return runDeviceTestsWithCustomOptions(packageName, className, methodName, null); 160 } 161 runDeviceTestsWithCustomOptions(String packageName, String className, String methodName, Map<String, String> testArgs)162 protected boolean runDeviceTestsWithCustomOptions(String packageName, String className, 163 String methodName, Map<String, String> testArgs) throws DeviceNotAvailableException { 164 final DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(packageName) 165 .setTestClassName(className) 166 .setTestMethodName(methodName); 167 168 // Currently there is only one custom option that the test exposes. 169 if (mCustomUrl != null) { 170 deviceTestRunOptions.addInstrumentationArg(ARG_CONNECTION_CHECK_CUSTOM_URL, mCustomUrl); 171 } 172 // Pass over any test specific arguments. 173 if (testArgs != null) { 174 for (Map.Entry<String, String> arg : testArgs.entrySet()) { 175 deviceTestRunOptions.addInstrumentationArg(arg.getKey(), arg.getValue()); 176 } 177 } 178 return runDeviceTests(deviceTestRunOptions); 179 } 180 runCommand(String command)181 protected String runCommand(String command) throws DeviceNotAvailableException { 182 Log.d(TAG, "Command: '" + command + "'"); 183 final String output = getDevice().executeShellCommand(command); 184 if (DEBUG) Log.v(TAG, "Output: " + output.trim()); 185 return output; 186 } 187 } 188