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 17import logging 18import mock 19import os 20import shutil 21import tempfile 22import unittest 23 24from acts import logger 25from acts.controllers import android_device 26 27# Mock log path for a test run. 28MOCK_LOG_PATH = "/tmp/logs/MockTest/xx-xx-xx_xx-xx-xx/" 29 30# Mock start and end time of the adb cat. 31MOCK_ADB_LOGCAT_BEGIN_TIME = "1970-01-02 21:03:20.123" 32MOCK_ADB_LOGCAT_END_TIME = "1970-01-02 21:22:02.000" 33MOCK_ADB_EPOCH_BEGIN_TIME = 191000123 34 35MOCK_SERIAL = 1 36MOCK_RELEASE_BUILD_ID = "ABC1.123456.007" 37MOCK_DEV_BUILD_ID = "ABC-MR1" 38MOCK_NYC_BUILD_ID = "N4F27P" 39 40 41def 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 58def mock_get_all_instances(): 59 return get_mock_ads(5) 60 61 62def mock_list_adb_devices(): 63 return [ad.serial for ad in get_mock_ads(5)] 64 65 66class 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 134class 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 151class 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 508if __name__ == "__main__": 509 unittest.main() 510