1 /* 2 * Copyright (C) 2019 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.compatibility.common.tradefed.targetprep; 18 19 import static org.junit.Assert.fail; 20 import static org.mockito.Mockito.when; 21 22 import com.android.tradefed.build.BuildInfo; 23 import com.android.tradefed.config.OptionSetter; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.invoker.IInvocationContext; 27 import com.android.tradefed.invoker.InvocationContext; 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.util.AaptParser; 32 import com.android.tradefed.util.FileUtil; 33 34 import org.easymock.EasyMock; 35 import org.junit.Before; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 import org.junit.runners.JUnit4; 39 import org.mockito.Mockito; 40 41 import java.io.File; 42 import java.io.FileNotFoundException; 43 import java.io.IOException; 44 import java.util.HashMap; 45 import java.util.Map; 46 47 /** Unit tests for {@link DeviceInteractionHelperInstaller} */ 48 @RunWith(JUnit4.class) 49 public class DeviceInteractionHelperInstallerTest { 50 private DeviceInteractionHelperInstaller mPreparer = null; 51 private ITestDevice mMockDevice = null; 52 private OptionSetter mOptionSetter = null; 53 54 private Map<File, AaptParser> mAaptParsers = new HashMap<File, AaptParser>(); 55 56 @Before setUp()57 public void setUp() throws Exception { 58 mMockDevice = EasyMock.createStrictMock(ITestDevice.class); 59 EasyMock.expect(mMockDevice.getDeviceDescriptor()).andStubReturn(null); 60 EasyMock.expect(mMockDevice.getSerialNumber()).andStubReturn("SERIAL"); 61 mPreparer = 62 new DeviceInteractionHelperInstaller() { 63 @Override 64 protected AaptParser parseApk(File apkFile) { 65 return mAaptParsers.getOrDefault(apkFile, AaptParser.parse(apkFile)); 66 } 67 }; 68 mOptionSetter = new OptionSetter(mPreparer); 69 } 70 expectHelperInstall(File file)71 private void expectHelperInstall(File file) throws DeviceNotAvailableException { 72 EasyMock.expect(mMockDevice.isAppEnumerationSupported()).andReturn(true); 73 EasyMock.expect( 74 mMockDevice.installPackage( 75 EasyMock.eq(file), EasyMock.anyBoolean(), EasyMock.anyObject())) 76 .andReturn(null); 77 } 78 expectDeviceProperty(String value)79 private void expectDeviceProperty(String value) throws DeviceNotAvailableException { 80 EasyMock.expect(mMockDevice.getProperty("ro.vendor.cts_interaction_helper_packages")) 81 .andReturn(value); 82 } 83 84 /** Creates a local file in dir and makes testInfo.getDependencyFile() return it. */ createFindableFile(File dir, String name, TestInformation testInfo)85 private File createFindableFile(File dir, String name, TestInformation testInfo) 86 throws FileNotFoundException, IOException { 87 File f = new File(dir, name); 88 f.createNewFile(); 89 if (testInfo != null) { 90 testInfo.executionFiles().put(name, f); 91 } 92 return f; 93 } 94 95 /** Creates a mock AaptParser that will return a desired package name for a file. */ mockApkPackage(File apk, String packageName)96 private void mockApkPackage(File apk, String packageName) { 97 AaptParser mockParser = Mockito.mock(AaptParser.class); 98 when(mockParser.getPackageName()).thenReturn(packageName); 99 mAaptParsers.put(apk, mockParser); 100 } 101 makeTestInfo(ITestDevice device)102 private TestInformation makeTestInfo(ITestDevice device) { 103 IInvocationContext context = new InvocationContext(); 104 context.addAllocatedDevice("device", device); 105 context.addDeviceBuildInfo("device", new BuildInfo()); 106 return TestInformation.newBuilder().setInvocationContext(context).build(); 107 } 108 109 // With no options or device property, only the default helpers should be installed. 110 @Test testNoOptionsNoDeviceProperty()111 public void testNoOptionsNoDeviceProperty() throws Exception { 112 File testsDir = FileUtil.createTempDir("tests_dir"); 113 try { 114 TestInformation testInfo = makeTestInfo(mMockDevice); 115 File baseApk = 116 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 117 118 expectHelperInstall(baseApk); 119 expectDeviceProperty(null); 120 121 EasyMock.replay(mMockDevice); 122 mPreparer.setUp(testInfo); 123 EasyMock.verify(mMockDevice); 124 } finally { 125 FileUtil.recursiveDelete(testsDir); 126 } 127 } 128 129 // With no options and an empty device property, only the default helpers should be installed. 130 @Test testNoOptionsEmptyDeviceProperty()131 public void testNoOptionsEmptyDeviceProperty() throws Exception { 132 File testsDir = FileUtil.createTempDir("tests_dir"); 133 try { 134 TestInformation testInfo = makeTestInfo(mMockDevice); 135 File baseApk = 136 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 137 138 expectHelperInstall(baseApk); 139 expectDeviceProperty(""); 140 141 EasyMock.replay(mMockDevice); 142 mPreparer.setUp(testInfo); 143 EasyMock.verify(mMockDevice); 144 } finally { 145 FileUtil.recursiveDelete(testsDir); 146 } 147 } 148 149 // With no options and a valid device property, the default helpers and the helpers listed in 150 // the property should all be installed. 151 @Test testNoOptionsValidDeviceProperty()152 public void testNoOptionsValidDeviceProperty() throws Exception { 153 File testsDir = FileUtil.createTempDir("tests_dir"); 154 try { 155 TestInformation testInfo = makeTestInfo(mMockDevice); 156 File baseApk = 157 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 158 159 // Extra apks should be found based on device property. 160 File extraApk = createFindableFile(testsDir, "com.helper1.apk", testInfo); 161 mockApkPackage(extraApk, "com.helper1"); 162 File extraApk2 = createFindableFile(testsDir, "com.helper2.apk", testInfo); 163 mockApkPackage(extraApk2, "com.helper2"); 164 165 expectHelperInstall(baseApk); 166 expectDeviceProperty("com.helper1:com.helper2"); 167 EasyMock.checkOrder(mMockDevice, false); // Package install order is nondeterministic. 168 expectHelperInstall(extraApk); 169 expectHelperInstall(extraApk2); 170 171 EasyMock.replay(mMockDevice); 172 mPreparer.setUp(testInfo); 173 EasyMock.verify(mMockDevice); 174 } finally { 175 FileUtil.recursiveDelete(testsDir); 176 } 177 } 178 179 // If an explicit default package name is passed, it should be used to install the default 180 // helpers instead of the default name. 181 @Test testFallbackPackageOptionOverridesDefault()182 public void testFallbackPackageOptionOverridesDefault() throws Exception { 183 mOptionSetter.setOptionValue("default-package", "com.fallback"); 184 File testsDir = FileUtil.createTempDir("tests_dir"); 185 try { 186 TestInformation testInfo = makeTestInfo(mMockDevice); 187 File baseApk = 188 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 189 File otherApk = createFindableFile(testsDir, "com.fallback.apk", testInfo); 190 mockApkPackage(otherApk, "com.fallback"); 191 192 expectHelperInstall(otherApk); 193 expectDeviceProperty(null); 194 195 EasyMock.replay(mMockDevice); 196 mPreparer.setUp(testInfo); 197 EasyMock.verify(mMockDevice); 198 } finally { 199 FileUtil.recursiveDelete(testsDir); 200 } 201 } 202 203 // If an explicit device property name is passed, that property should be read instead of the 204 // default. The default helpers will still be installed. 205 @Test testDevicePropertyOptionOverridesDefault()206 public void testDevicePropertyOptionOverridesDefault() throws Exception { 207 mOptionSetter.setOptionValue("property-name", "ro.other_property"); 208 File testsDir = FileUtil.createTempDir("tests_dir"); 209 try { 210 TestInformation testInfo = makeTestInfo(mMockDevice); 211 File baseApk = 212 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 213 214 // Extra apks should be found based on device property. 215 File extraApk = createFindableFile(testsDir, "com.helper1.apk", testInfo); 216 mockApkPackage(extraApk, "com.helper1"); 217 File extraApk2 = createFindableFile(testsDir, "com.helper2.apk", testInfo); 218 mockApkPackage(extraApk2, "com.helper2"); 219 220 expectHelperInstall(baseApk); 221 EasyMock.expect(mMockDevice.getProperty("ro.other_property")) 222 .andReturn("com.helper1:com.helper2"); 223 EasyMock.checkOrder(mMockDevice, false); // Package install order is nondeterministic. 224 expectHelperInstall(extraApk); 225 expectHelperInstall(extraApk2); 226 227 EasyMock.replay(mMockDevice); 228 mPreparer.setUp(testInfo); 229 EasyMock.verify(mMockDevice); 230 } finally { 231 FileUtil.recursiveDelete(testsDir); 232 } 233 } 234 235 // Attempting to install an apk that can't be parsed will throw BuildError. 236 @Test testInvalidApkWontInstall()237 public void testInvalidApkWontInstall() throws Exception { 238 File testsDir = FileUtil.createTempDir("tests_dir"); 239 240 try { 241 TestInformation testInfo = makeTestInfo(mMockDevice); 242 File baseApk = 243 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 244 File extraApk = createFindableFile(testsDir, "MyCtsHelpers.apk", testInfo); 245 246 expectHelperInstall(baseApk); 247 expectDeviceProperty("MyCtsHelpers"); 248 249 EasyMock.replay(mMockDevice); 250 try { 251 mPreparer.setUp(testInfo); 252 fail("BuildError not thrown"); 253 } catch (BuildError e) { 254 // expected 255 } 256 257 EasyMock.verify(mMockDevice); 258 } finally { 259 FileUtil.recursiveDelete(testsDir); 260 } 261 } 262 263 // Attempting to install an apk that doesn't contain a package name will throw BuildError. 264 @Test testApkWithoutPackageWontInstall()265 public void testApkWithoutPackageWontInstall() throws Exception { 266 File testsDir = FileUtil.createTempDir("tests_dir"); 267 268 try { 269 TestInformation testInfo = makeTestInfo(mMockDevice); 270 File baseApk = 271 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 272 File extraApk = createFindableFile(testsDir, "MyCtsHelpers.apk", testInfo); 273 mockApkPackage(extraApk, ""); 274 275 expectHelperInstall(baseApk); 276 expectDeviceProperty("MyCtsHelpers"); 277 278 EasyMock.replay(mMockDevice); 279 try { 280 mPreparer.setUp(testInfo); 281 fail("BuildError not thrown"); 282 } catch (BuildError e) { 283 // expected 284 } 285 286 EasyMock.verify(mMockDevice); 287 } finally { 288 FileUtil.recursiveDelete(testsDir); 289 } 290 } 291 292 // Attempting to install an apk with a package name that doesn't match the file name will 293 // throw BuildError because the file name came from the device search path. 294 @Test testApkWithBadPackageWontInstall()295 public void testApkWithBadPackageWontInstall() throws Exception { 296 File testsDir = FileUtil.createTempDir("tests_dir"); 297 298 try { 299 TestInformation testInfo = makeTestInfo(mMockDevice); 300 File baseApk = 301 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 302 File extraApk = createFindableFile(testsDir, "MyCtsHelpers.apk", testInfo); 303 mockApkPackage(extraApk, "NotMyCtsHelpers"); 304 305 expectHelperInstall(baseApk); 306 expectDeviceProperty("MyCtsHelpers"); 307 308 EasyMock.replay(mMockDevice); 309 try { 310 mPreparer.setUp(testInfo); 311 fail("BuildError not thrown"); 312 } catch (BuildError e) { 313 // expected 314 } 315 EasyMock.verify(mMockDevice); 316 } finally { 317 FileUtil.recursiveDelete(testsDir); 318 } 319 } 320 321 // If a package listed in the device's search path is not found, the default helpers and other 322 // requested packages will still be installed. No exception is thrown. 323 @Test testMissingPackageFromDevicePropertyDoesntAbort()324 public void testMissingPackageFromDevicePropertyDoesntAbort() throws Exception { 325 File testsDir = FileUtil.createTempDir("tests_dir"); 326 try { 327 TestInformation testInfo = makeTestInfo(mMockDevice); 328 File baseApk = 329 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 330 File extraApk = createFindableFile(testsDir, "com.helper2.apk", testInfo); 331 mockApkPackage(extraApk, "com.helper2"); 332 333 expectHelperInstall(baseApk); 334 expectDeviceProperty("MyMissingHelpers:com.helper2"); 335 // Skips installing MyMissingHelpers and installs remaining packages in the list. 336 expectHelperInstall(extraApk); 337 338 EasyMock.replay(mMockDevice); 339 mPreparer.setUp(testInfo); 340 EasyMock.verify(mMockDevice); 341 } finally { 342 FileUtil.recursiveDelete(testsDir); 343 } 344 } 345 346 // If the fallback helpers cannot be found, BuildError is thrown and no other packages 347 // will be installed. 348 @Test testDefaultHelpersNotFound()349 public void testDefaultHelpersNotFound() throws Exception { 350 File testsDir = FileUtil.createTempDir("tests_dir"); 351 try { 352 TestInformation testInfo = makeTestInfo(mMockDevice); 353 354 // Should throw TargetSetupError after failing to find the default helpers. 355 // No search for other files. 356 357 EasyMock.replay(mMockDevice); 358 try { 359 mPreparer.setUp(testInfo); 360 fail("BuildError not thrown"); 361 } catch (BuildError e) { 362 // expected 363 } 364 EasyMock.verify(mMockDevice); 365 } finally { 366 FileUtil.recursiveDelete(testsDir); 367 } 368 } 369 370 // If a package can't be installed, TargetSetupError is thrown. 371 @Test testFailedInstallAborts()372 public void testFailedInstallAborts() throws Exception { 373 File testsDir = FileUtil.createTempDir("tests_dir"); 374 try { 375 TestInformation testInfo = makeTestInfo(mMockDevice); 376 File baseApk = 377 createFindableFile(testsDir, "com.android.cts.helpers.aosp.apk", testInfo); 378 379 EasyMock.expect(mMockDevice.isAppEnumerationSupported()).andReturn(true); 380 EasyMock.expect( 381 mMockDevice.installPackage( 382 EasyMock.eq(baseApk), 383 EasyMock.anyBoolean(), 384 EasyMock.anyObject())) 385 .andReturn("Install failed"); 386 // Should throw TargetSetupError after failing to install and not do any further steps. 387 388 EasyMock.replay(mMockDevice); 389 try { 390 mPreparer.setUp(testInfo); 391 fail("TargetSetupError not thrown"); 392 } catch (TargetSetupError e) { 393 // expected 394 } 395 EasyMock.verify(mMockDevice); 396 } finally { 397 FileUtil.recursiveDelete(testsDir); 398 } 399 } 400 } 401