1 #!/usr/bin/env python3 2 # 3 # Copyright 2016 - The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 import logging 18 import mock 19 import os 20 import shutil 21 import tempfile 22 import unittest 23 24 from acts import logger 25 from acts.controllers import android_device 26 27 # Mock log path for a test run. 28 MOCK_LOG_PATH = "/tmp/logs/MockTest/xx-xx-xx_xx-xx-xx/" 29 30 # Mock start and end time of the adb cat. 31 MOCK_ADB_LOGCAT_BEGIN_TIME = "1970-01-02 21:03:20.123" 32 MOCK_ADB_LOGCAT_END_TIME = "1970-01-02 21:22:02.000" 33 MOCK_ADB_EPOCH_BEGIN_TIME = 191000123 34 35 MOCK_SERIAL = 1 36 MOCK_RELEASE_BUILD_ID = "ABC1.123456.007" 37 MOCK_DEV_BUILD_ID = "ABC-MR1" 38 MOCK_NYC_BUILD_ID = "N4F27P" 39 40 41 def get_mock_ads(num): 42 """Generates a list of mock AndroidDevice objects. 43 44 The serial number of each device will be integer 0 through num - 1. 45 46 Args: 47 num: An integer that is the number of mock AndroidDevice objects to 48 create. 49 """ 50 ads = [] 51 for i in range(num): 52 ad = mock.MagicMock(name="AndroidDevice", serial=i, h_port=None) 53 ad.ensure_screen_on = mock.MagicMock(return_value=True) 54 ads.append(ad) 55 return ads 56 57 58 def mock_get_all_instances(): 59 return get_mock_ads(5) 60 61 62 def mock_list_adb_devices(): 63 return [ad.serial for ad in get_mock_ads(5)] 64 65 66 class MockAdbProxy(object): 67 """Mock class that swaps out calls to adb with mock calls.""" 68 69 def __init__(self, 70 serial, 71 fail_br=False, 72 fail_br_before_N=False, 73 build_id=MOCK_RELEASE_BUILD_ID): 74 self.serial = serial 75 self.fail_br = fail_br 76 self.fail_br_before_N = fail_br_before_N 77 self.return_value = None 78 self.return_multiple = False 79 self.build_id = build_id 80 81 def shell(self, params, ignore_status=False, timeout=60): 82 if params == "id -u": 83 return "root" 84 elif params == "bugreportz": 85 if self.fail_br: 86 return "OMG I died!\n" 87 return "OK:/path/bugreport.zip\n" 88 elif params == "bugreportz -v": 89 if self.fail_br_before_N: 90 return "/system/bin/sh: bugreportz: not found" 91 return "1.1" 92 else: 93 if self.return_multiple: 94 return self.return_value.pop(0) 95 else: 96 return self.return_value 97 98 def getprop(self, params): 99 if params == "ro.build.id": 100 return self.build_id 101 elif params == "ro.build.version.incremental": 102 return "123456789" 103 elif params == "ro.build.type": 104 return "userdebug" 105 elif params == "ro.build.product" or params == "ro.product.name": 106 return "FakeModel" 107 elif params == "sys.boot_completed": 108 return "1" 109 110 def devices(self): 111 return "\t".join([str(self.serial), "device"]) 112 113 def bugreport(self, params, timeout=android_device.BUG_REPORT_TIMEOUT): 114 expected = os.path.join( 115 logging.log_path, "AndroidDevice%s" % self.serial, 116 "test_something", "AndroidDevice%s_%s" % 117 (self.serial, 118 logger.normalize_log_line_timestamp(MOCK_ADB_LOGCAT_BEGIN_TIME))) 119 assert expected in params, "Expected '%s', got '%s'." % (expected, 120 params) 121 122 def __getattr__(self, name): 123 """All calls to the none-existent functions in adb proxy would 124 simply return the adb command string. 125 """ 126 127 def adb_call(*args, **kwargs): 128 arg_str = ' '.join(str(elem) for elem in args) 129 return arg_str 130 131 return adb_call 132 133 134 class MockFastbootProxy(): 135 """Mock class that swaps out calls to adb with mock calls.""" 136 137 def __init__(self, serial): 138 self.serial = serial 139 140 def devices(self): 141 return "xxxx\tdevice\nyyyy\tdevice" 142 143 def __getattr__(self, name): 144 def fastboot_call(*args): 145 arg_str = ' '.join(str(elem) for elem in args) 146 return arg_str 147 148 return fastboot_call 149 150 151 class ActsAndroidDeviceTest(unittest.TestCase): 152 """This test class has unit tests for the implementation of everything 153 under acts.controllers.android_device. 154 """ 155 156 def setUp(self): 157 # Set log_path to logging since acts logger setup is not called. 158 if not hasattr(logging, "log_path"): 159 setattr(logging, "log_path", "/tmp/logs") 160 # Creates a temp dir to be used by tests in this test class. 161 self.tmp_dir = tempfile.mkdtemp() 162 163 def tearDown(self): 164 """Removes the temp dir. 165 """ 166 shutil.rmtree(self.tmp_dir) 167 168 # Tests for android_device module functions. 169 # These tests use mock AndroidDevice instances. 170 171 @mock.patch.object( 172 android_device, "get_all_instances", new=mock_get_all_instances) 173 @mock.patch.object( 174 android_device, "list_adb_devices", new=mock_list_adb_devices) 175 def test_create_with_pickup_all(self): 176 pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN 177 actual_ads = android_device.create(pick_all_token) 178 for actual, expected in zip(actual_ads, get_mock_ads(5)): 179 self.assertEqual(actual.serial, expected.serial) 180 181 def test_create_with_empty_config(self): 182 expected_msg = android_device.ANDROID_DEVICE_EMPTY_CONFIG_MSG 183 with self.assertRaisesRegex(android_device.AndroidDeviceError, 184 expected_msg): 185 android_device.create([]) 186 187 def test_create_with_not_list_config(self): 188 expected_msg = android_device.ANDROID_DEVICE_NOT_LIST_CONFIG_MSG 189 with self.assertRaisesRegex(android_device.AndroidDeviceError, 190 expected_msg): 191 android_device.create("HAHA") 192 193 def test_get_device_success_with_serial(self): 194 ads = get_mock_ads(5) 195 expected_serial = 0 196 ad = android_device.get_device(ads, serial=expected_serial) 197 self.assertEqual(ad.serial, expected_serial) 198 199 def test_get_device_success_with_serial_and_extra_field(self): 200 ads = get_mock_ads(5) 201 expected_serial = 1 202 expected_h_port = 5555 203 ads[1].h_port = expected_h_port 204 ad = android_device.get_device( 205 ads, serial=expected_serial, h_port=expected_h_port) 206 self.assertEqual(ad.serial, expected_serial) 207 self.assertEqual(ad.h_port, expected_h_port) 208 209 def test_get_device_no_match(self): 210 ads = get_mock_ads(5) 211 expected_msg = ("Could not find a target device that matches condition" 212 ": {'serial': 5}.") 213 with self.assertRaisesRegex(android_device.AndroidDeviceError, 214 expected_msg): 215 ad = android_device.get_device(ads, serial=len(ads)) 216 217 def test_get_device_too_many_matches(self): 218 ads = get_mock_ads(5) 219 target_serial = ads[1].serial = ads[0].serial 220 expected_msg = "More than one device matched: \[0, 0\]" 221 with self.assertRaisesRegex(android_device.AndroidDeviceError, 222 expected_msg): 223 ad = android_device.get_device(ads, serial=target_serial) 224 225 def test_start_services_on_ads(self): 226 """Makes sure when an AndroidDevice fails to start some services, all 227 AndroidDevice objects get cleaned up. 228 """ 229 msg = "Some error happened." 230 ads = get_mock_ads(3) 231 ads[0].start_services = mock.MagicMock() 232 ads[0].clean_up = mock.MagicMock() 233 ads[1].start_services = mock.MagicMock() 234 ads[1].clean_up = mock.MagicMock() 235 ads[2].start_services = mock.MagicMock( 236 side_effect=android_device.AndroidDeviceError(msg)) 237 ads[2].clean_up = mock.MagicMock() 238 with self.assertRaisesRegex(android_device.AndroidDeviceError, msg): 239 android_device._start_services_on_ads(ads) 240 ads[0].clean_up.assert_called_once_with() 241 ads[1].clean_up.assert_called_once_with() 242 ads[2].clean_up.assert_called_once_with() 243 244 # Tests for android_device.AndroidDevice class. 245 # These tests mock out any interaction with the OS and real android device 246 # in AndroidDeivce. 247 248 @mock.patch( 249 'acts.controllers.adb.AdbProxy', 250 return_value=MockAdbProxy(MOCK_SERIAL)) 251 @mock.patch( 252 'acts.controllers.fastboot.FastbootProxy', 253 return_value=MockFastbootProxy(MOCK_SERIAL)) 254 def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy): 255 """Verifies the AndroidDevice object's basic attributes are correctly 256 set after instantiation. 257 """ 258 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 259 self.assertEqual(ad.serial, 1) 260 self.assertEqual(ad.model, "fakemodel") 261 self.assertIsNone(ad.adb_logcat_process) 262 self.assertIsNone(ad.adb_logcat_file_path) 263 expected_lp = os.path.join(logging.log_path, 264 "AndroidDevice%s" % MOCK_SERIAL) 265 self.assertEqual(ad.log_path, expected_lp) 266 267 @mock.patch( 268 'acts.controllers.adb.AdbProxy', 269 return_value=MockAdbProxy(MOCK_SERIAL)) 270 @mock.patch( 271 'acts.controllers.fastboot.FastbootProxy', 272 return_value=MockFastbootProxy(MOCK_SERIAL)) 273 def test_AndroidDevice_build_info_release(self, MockFastboot, 274 MockAdbProxy): 275 """Verifies the AndroidDevice object's basic attributes are correctly 276 set after instantiation. 277 """ 278 ad = android_device.AndroidDevice(serial=1) 279 build_info = ad.build_info 280 self.assertEqual(build_info["build_id"], "ABC1.123456.007") 281 self.assertEqual(build_info["build_type"], "userdebug") 282 283 @mock.patch( 284 'acts.controllers.adb.AdbProxy', 285 return_value=MockAdbProxy(MOCK_SERIAL, build_id=MOCK_DEV_BUILD_ID)) 286 @mock.patch( 287 'acts.controllers.fastboot.FastbootProxy', 288 return_value=MockFastbootProxy(MOCK_SERIAL)) 289 def test_AndroidDevice_build_info_release(self, MockFastboot, 290 MockAdbProxy): 291 """Verifies the AndroidDevice object's basic attributes are correctly 292 set after instantiation. 293 """ 294 global MOCK_BUILD_ID 295 ad = android_device.AndroidDevice(serial=1) 296 old_mock_build_id = MOCK_BUILD_ID 297 MOCK_BUILD_ID = "ABC-MR1" 298 build_info = ad.build_info 299 self.assertEqual(build_info["build_id"], "123456789") 300 self.assertEqual(build_info["build_type"], "userdebug") 301 MOCK_BUILD_ID = old_mock_build_id 302 303 @mock.patch( 304 'acts.controllers.adb.AdbProxy', 305 return_value=MockAdbProxy(MOCK_SERIAL)) 306 @mock.patch( 307 'acts.controllers.fastboot.FastbootProxy', 308 return_value=MockFastbootProxy(MOCK_SERIAL)) 309 def test_AndroidDevice_build_info_dev(self, MockFastboot, MockAdbProxy): 310 """Verifies the AndroidDevice object's basic attributes are correctly 311 set after instantiation. 312 """ 313 ad = android_device.AndroidDevice(serial=1) 314 build_info = ad.build_info 315 self.assertEqual(build_info["build_id"], "123456789") 316 self.assertEqual(build_info["build_type"], "userdebug") 317 318 @mock.patch( 319 'acts.controllers.adb.AdbProxy', 320 return_value=MockAdbProxy(MOCK_SERIAL, build_id=MOCK_NYC_BUILD_ID)) 321 @mock.patch( 322 'acts.controllers.fastboot.FastbootProxy', 323 return_value=MockFastbootProxy(MOCK_SERIAL)) 324 def test_AndroidDevice_build_info_nyc(self, MockFastboot, MockAdbProxy): 325 """Verifies the AndroidDevice object's build id is set correctly for 326 NYC releases. 327 """ 328 ad = android_device.AndroidDevice(serial=1) 329 build_info = ad.build_info 330 self.assertEqual(build_info["build_id"], MOCK_NYC_BUILD_ID) 331 332 @mock.patch( 333 'acts.controllers.adb.AdbProxy', 334 return_value=MockAdbProxy(MOCK_SERIAL)) 335 @mock.patch( 336 'acts.controllers.fastboot.FastbootProxy', 337 return_value=MockFastbootProxy(MOCK_SERIAL)) 338 339 @mock.patch('acts.utils.create_dir') 340 @mock.patch('acts.utils.exe_cmd') 341 def test_AndroidDevice_take_bug_report(self, exe_mock, create_dir_mock, 342 FastbootProxy, MockAdbProxy): 343 """Verifies AndroidDevice.take_bug_report calls the correct adb command 344 and writes the bugreport file to the correct path. 345 """ 346 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 347 ad.take_bug_report("test_something", 234325.32) 348 expected_path = os.path.join( 349 logging.log_path, "AndroidDevice%s" % ad.serial, "test_something") 350 create_dir_mock.assert_called_with(expected_path) 351 352 @mock.patch( 353 'acts.controllers.adb.AdbProxy', 354 return_value=MockAdbProxy(MOCK_SERIAL, fail_br=True)) 355 @mock.patch( 356 'acts.controllers.fastboot.FastbootProxy', 357 return_value=MockFastbootProxy(MOCK_SERIAL)) 358 @mock.patch('acts.utils.create_dir') 359 @mock.patch('acts.utils.exe_cmd') 360 def test_AndroidDevice_take_bug_report_fail( 361 self, exe_mock, create_dir_mock, FastbootProxy, MockAdbProxy): 362 """Verifies AndroidDevice.take_bug_report writes out the correct message 363 when taking bugreport fails. 364 """ 365 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 366 expected_msg = "Failed to take bugreport on 1: OMG I died!" 367 with self.assertRaisesRegex(android_device.AndroidDeviceError, 368 expected_msg): 369 ad.take_bug_report("test_something", 4346343.23) 370 371 @mock.patch( 372 'acts.controllers.adb.AdbProxy', 373 return_value=MockAdbProxy(MOCK_SERIAL, fail_br_before_N=True)) 374 @mock.patch( 375 'acts.controllers.fastboot.FastbootProxy', 376 return_value=MockFastbootProxy(MOCK_SERIAL)) 377 @mock.patch('acts.utils.create_dir') 378 @mock.patch('acts.utils.exe_cmd') 379 def test_AndroidDevice_take_bug_report_fallback( 380 self, exe_mock, create_dir_mock, FastbootProxy, MockAdbProxy): 381 """Verifies AndroidDevice.take_bug_report falls back to traditional 382 bugreport on builds that do not have bugreportz. 383 """ 384 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 385 ad.take_bug_report("test_something", MOCK_ADB_EPOCH_BEGIN_TIME) 386 expected_path = os.path.join( 387 logging.log_path, "AndroidDevice%s" % ad.serial, "test_something") 388 create_dir_mock.assert_called_with(expected_path) 389 390 @mock.patch( 391 'acts.controllers.adb.AdbProxy', 392 return_value=MockAdbProxy(MOCK_SERIAL)) 393 @mock.patch( 394 'acts.controllers.fastboot.FastbootProxy', 395 return_value=MockFastbootProxy(MOCK_SERIAL)) 396 @mock.patch('acts.utils.create_dir') 397 @mock.patch('acts.utils.start_standing_subprocess', return_value="process") 398 @mock.patch('acts.utils.stop_standing_subprocess') 399 @mock.patch('acts.utils._assert_subprocess_running') 400 def test_AndroidDevice_take_logcat(self, check_proc_mock, stop_proc_mock, 401 start_proc_mock, creat_dir_mock, 402 FastbootProxy, MockAdbProxy): 403 """Verifies the steps of collecting adb logcat on an AndroidDevice 404 object, including various function calls and the expected behaviors of 405 the calls. 406 """ 407 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 408 expected_msg = ("Android device .* does not have an ongoing adb logcat" 409 " collection.") 410 # Expect error if stop is called before start. 411 with self.assertRaisesRegex(android_device.AndroidDeviceError, 412 expected_msg): 413 ad.stop_adb_logcat() 414 ad.start_adb_logcat() 415 # Verify start did the correct operations. 416 self.assertTrue(ad.adb_logcat_process) 417 expected_log_path = os.path.join(logging.log_path, 418 "AndroidDevice%s" % ad.serial, 419 "adblog,fakemodel,%s.txt" % ad.serial) 420 creat_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) 421 adb_cmd = 'adb -s %s logcat -T 1 -v year -b all >> %s' 422 start_proc_mock.assert_called_with(adb_cmd % (ad.serial, 423 expected_log_path)) 424 self.assertEqual(ad.adb_logcat_file_path, expected_log_path) 425 expected_msg = ("Android device .* already has an adb logcat thread " 426 "going on. Cannot start another one.") 427 # Expect error if start is called back to back. 428 with self.assertRaisesRegex(android_device.AndroidDeviceError, 429 expected_msg): 430 ad.start_adb_logcat() 431 # Verify stop did the correct operations. 432 ad.stop_adb_logcat() 433 stop_proc_mock.assert_called_with("process") 434 self.assertIsNone(ad.adb_logcat_process) 435 self.assertEqual(ad.adb_logcat_file_path, expected_log_path) 436 437 @mock.patch( 438 'acts.controllers.adb.AdbProxy', 439 return_value=MockAdbProxy(MOCK_SERIAL)) 440 @mock.patch( 441 'acts.controllers.fastboot.FastbootProxy', 442 return_value=MockFastbootProxy(MOCK_SERIAL)) 443 @mock.patch('acts.utils.create_dir') 444 @mock.patch('acts.utils.start_standing_subprocess', return_value="process") 445 @mock.patch('acts.utils.stop_standing_subprocess') 446 @mock.patch('acts.utils._assert_subprocess_running') 447 def test_AndroidDevice_take_logcat_with_user_param( 448 self, check_proc_mock, stop_proc_mock, start_proc_mock, 449 creat_dir_mock, FastbootProxy, MockAdbProxy): 450 """Verifies the steps of collecting adb logcat on an AndroidDevice 451 object, including various function calls and the expected behaviors of 452 the calls. 453 """ 454 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 455 ad.adb_logcat_param = "-b radio" 456 expected_msg = ("Android device .* does not have an ongoing adb logcat" 457 " collection.") 458 # Expect error if stop is called before start. 459 with self.assertRaisesRegex(android_device.AndroidDeviceError, 460 expected_msg): 461 ad.stop_adb_logcat() 462 ad.start_adb_logcat() 463 # Verify start did the correct operations. 464 self.assertTrue(ad.adb_logcat_process) 465 expected_log_path = os.path.join(logging.log_path, 466 "AndroidDevice%s" % ad.serial, 467 "adblog,fakemodel,%s.txt" % ad.serial) 468 creat_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) 469 adb_cmd = 'adb -s %s logcat -T 1 -v year -b radio >> %s' 470 start_proc_mock.assert_called_with(adb_cmd % (ad.serial, 471 expected_log_path)) 472 self.assertEqual(ad.adb_logcat_file_path, expected_log_path) 473 474 @mock.patch( 475 'acts.controllers.adb.AdbProxy', 476 return_value=MockAdbProxy(MOCK_SERIAL)) 477 def test_get_apk_process_id_process_cannot_find(self, adb_proxy): 478 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 479 ad.adb.return_value = "does_not_contain_value" 480 self.assertEqual(None, ad.get_package_pid("some_package")) 481 482 @mock.patch( 483 'acts.controllers.adb.AdbProxy', 484 return_value=MockAdbProxy(MOCK_SERIAL)) 485 def test_get_apk_process_id_process_exists_second_try(self, adb_proxy): 486 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 487 ad.adb.return_multiple = True 488 ad.adb.return_value = ["", "system 1 2 3 4 S com.some_package"] 489 self.assertEqual(1, ad.get_package_pid("some_package")) 490 491 @mock.patch( 492 'acts.controllers.adb.AdbProxy', 493 return_value=MockAdbProxy(MOCK_SERIAL)) 494 def test_get_apk_process_id_bad_return(self, adb_proxy): 495 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 496 ad.adb.return_value = "bad_return_index_error" 497 self.assertEqual(None, ad.get_package_pid("some_package")) 498 499 @mock.patch( 500 'acts.controllers.adb.AdbProxy', 501 return_value=MockAdbProxy(MOCK_SERIAL)) 502 def test_get_apk_process_id_bad_return(self, adb_proxy): 503 ad = android_device.AndroidDevice(serial=MOCK_SERIAL) 504 ad.adb.return_value = "bad return value error" 505 self.assertEqual(None, ad.get_package_pid("some_package")) 506 507 508 if __name__ == "__main__": 509 unittest.main() 510