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