• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import io
16import logging
17import os
18import shutil
19import tempfile
20import unittest
21from unittest import mock
22
23from mobly import runtime_test_info
24from mobly.controllers import android_device
25from mobly.controllers.android_device_lib import adb
26from mobly.controllers.android_device_lib import errors
27from mobly.controllers.android_device_lib import snippet_client_v2
28from mobly.controllers.android_device_lib.services import base_service
29from mobly.controllers.android_device_lib.services import logcat
30from tests.lib import mock_android_device
31import yaml
32
33MOCK_SNIPPET_PACKAGE_NAME = 'com.my.snippet'
34
35# A mock SnippetClient used for testing snippet management logic.
36MockSnippetClient = mock.MagicMock()
37MockSnippetClient.package = MOCK_SNIPPET_PACKAGE_NAME
38
39
40class AndroidDeviceTest(unittest.TestCase):
41  """This test class has unit tests for the implementation of everything
42  under mobly.controllers.android_device.
43  """
44
45  def setUp(self):
46    # Set log_path to logging since mobly logger setup is not called.
47    if not hasattr(logging, 'log_path'):
48      setattr(logging, 'log_path', '/tmp/logs')
49    # Creates a temp dir to be used by tests in this test class.
50    self.tmp_dir = tempfile.mkdtemp()
51
52  def tearDown(self):
53    """Removes the temp dir."""
54    shutil.rmtree(self.tmp_dir)
55
56  # Tests for android_device module functions.
57  # These tests use mock AndroidDevice instances.
58
59  @mock.patch.object(
60      android_device,
61      'get_all_instances',
62      new=mock_android_device.get_all_instances,
63  )
64  @mock.patch.object(
65      android_device,
66      'list_adb_devices',
67      new=mock_android_device.list_adb_devices,
68  )
69  @mock.patch.object(
70      android_device,
71      'list_adb_devices_by_usb_id',
72      new=mock_android_device.list_adb_devices,
73  )
74  def test_create_with_pickup_all(self):
75    pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN
76    actual_ads = android_device.create(pick_all_token)
77    for actual, expected in zip(
78        actual_ads, mock_android_device.get_mock_ads(5)
79    ):
80      self.assertEqual(actual.serial, expected.serial)
81
82  @mock.patch.object(
83      android_device, 'get_instances', new=mock_android_device.get_instances
84  )
85  @mock.patch.object(
86      android_device,
87      'list_adb_devices',
88      new=mock_android_device.list_adb_devices,
89  )
90  @mock.patch.object(
91      android_device,
92      'list_adb_devices_by_usb_id',
93      new=mock_android_device.list_adb_devices,
94  )
95  def test_create_with_string_list(self):
96    string_list = ['1', '2']
97    actual_ads = android_device.create(string_list)
98    for actual_ad, expected_serial in zip(actual_ads, ['1', '2']):
99      self.assertEqual(actual_ad.serial, expected_serial)
100
101  @mock.patch.object(
102      android_device,
103      'get_instances_with_configs',
104      new=mock_android_device.get_instances_with_configs,
105  )
106  @mock.patch.object(
107      android_device,
108      'list_adb_devices',
109      new=mock_android_device.list_adb_devices,
110  )
111  @mock.patch.object(
112      android_device,
113      'list_adb_devices_by_usb_id',
114      new=mock_android_device.list_adb_devices,
115  )
116  def test_create_with_dict_list(self):
117    string_list = [{'serial': '1'}, {'serial': '2'}]
118    actual_ads = android_device.create(string_list)
119    for actual_ad, expected_serial in zip(actual_ads, ['1', '2']):
120      self.assertEqual(actual_ad.serial, expected_serial)
121
122  @mock.patch.object(
123      android_device,
124      'get_instances_with_configs',
125      new=mock_android_device.get_instances_with_configs,
126  )
127  @mock.patch.object(
128      android_device,
129      'list_adb_devices',
130      new=mock_android_device.list_adb_devices,
131  )
132  @mock.patch.object(
133      android_device, 'list_adb_devices_by_usb_id', return_value=['usb:1']
134  )
135  def test_create_with_usb_id(self, mock_list_adb_devices_by_usb_id):
136    string_list = [{'serial': '1'}, {'serial': '2'}, {'serial': 'usb:1'}]
137    actual_ads = android_device.create(string_list)
138    for actual_ad, expected_serial in zip(actual_ads, ['1', '2', 'usb:1']):
139      self.assertEqual(actual_ad.serial, expected_serial)
140
141  def test_create_with_empty_config(self):
142    expected_msg = android_device.ANDROID_DEVICE_EMPTY_CONFIG_MSG
143    with self.assertRaisesRegex(android_device.Error, expected_msg):
144      android_device.create([])
145
146  def test_create_with_not_list_config(self):
147    expected_msg = android_device.ANDROID_DEVICE_NOT_LIST_CONFIG_MSG
148    with self.assertRaisesRegex(android_device.Error, expected_msg):
149      android_device.create('HAHA')
150
151  def test_create_with_no_valid_config(self):
152    expected_msg = 'No valid config found in: .*'
153    with self.assertRaisesRegex(android_device.Error, expected_msg):
154      android_device.create([1])
155
156  @mock.patch('mobly.controllers.android_device.list_fastboot_devices')
157  @mock.patch('mobly.controllers.android_device.list_adb_devices')
158  @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id')
159  @mock.patch('mobly.controllers.android_device.AndroidDevice')
160  def test_get_instances(
161      self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot
162  ):
163    mock_list_fastboot.return_value = ['0']
164    mock_list_adb.return_value = ['1']
165    mock_list_adb_usb.return_value = []
166    android_device.get_instances(['0', '1'])
167    mock_ad_class.assert_any_call('0')
168    mock_ad_class.assert_any_call('1')
169
170  @mock.patch('mobly.controllers.android_device.list_fastboot_devices')
171  @mock.patch('mobly.controllers.android_device.list_adb_devices')
172  @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id')
173  @mock.patch('mobly.controllers.android_device.AndroidDevice')
174  def test_get_instances_do_not_exist(
175      self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot
176  ):
177    mock_list_fastboot.return_value = []
178    mock_list_adb.return_value = []
179    mock_list_adb_usb.return_value = []
180    with self.assertRaisesRegex(
181        errors.Error,
182        'Android device serial "1" is specified in config but is not reachable',
183    ):
184      android_device.get_instances(['1'])
185
186  @mock.patch('mobly.controllers.android_device.list_fastboot_devices')
187  @mock.patch('mobly.controllers.android_device.list_adb_devices')
188  @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id')
189  @mock.patch('mobly.controllers.android_device.AndroidDevice')
190  def test_get_instances_with_configs(
191      self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot
192  ):
193    mock_list_fastboot.return_value = ['1']
194    mock_list_adb.return_value = ['2']
195    mock_list_adb_usb.return_value = []
196    configs = [{'serial': '1'}, {'serial': '2'}]
197    android_device.get_instances_with_configs(configs)
198    mock_ad_class.assert_any_call('1')
199    mock_ad_class.assert_any_call('2')
200
201  def test_get_instances_with_configs_invalid_config(self):
202    config = {'something': 'random'}
203    with self.assertRaisesRegex(
204        errors.Error,
205        f'Required value "serial" is missing in AndroidDevice config {config}',
206    ):
207      android_device.get_instances_with_configs([config])
208
209  @mock.patch('mobly.controllers.android_device.list_fastboot_devices')
210  @mock.patch('mobly.controllers.android_device.list_adb_devices')
211  @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id')
212  @mock.patch('mobly.controllers.android_device.AndroidDevice')
213  def test_get_instances_with_configsdo_not_exist(
214      self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot
215  ):
216    mock_list_fastboot.return_value = []
217    mock_list_adb.return_value = []
218    mock_list_adb_usb.return_value = []
219    config = {'serial': '1'}
220    with self.assertRaisesRegex(
221        errors.Error,
222        'Android device serial "1" is specified in config but is not reachable',
223    ):
224      android_device.get_instances_with_configs([config])
225
226  def test_get_devices_success_with_extra_field(self):
227    ads = mock_android_device.get_mock_ads(5)
228    expected_label = 'selected'
229    expected_count = 2
230    for ad in ads[:expected_count]:
231      ad.label = expected_label
232    selected_ads = android_device.get_devices(ads, label=expected_label)
233    self.assertEqual(expected_count, len(selected_ads))
234    for ad in selected_ads:
235      self.assertEqual(ad.label, expected_label)
236
237  def test_get_devices_no_match(self):
238    ads = mock_android_device.get_mock_ads(5)
239    expected_msg = (
240        'Could not find a target device that matches condition'
241        ": {'label': 'selected'}."
242    )
243    with self.assertRaisesRegex(android_device.Error, expected_msg):
244      selected_ads = android_device.get_devices(ads, label='selected')
245
246  def test_get_device_success_with_serial(self):
247    ads = mock_android_device.get_mock_ads(5)
248    expected_serial = '0'
249    ad = android_device.get_device(ads, serial=expected_serial)
250    self.assertEqual(ad.serial, expected_serial)
251
252  def test_get_device_success_with_serial_and_extra_field(self):
253    ads = mock_android_device.get_mock_ads(5)
254    expected_serial = '1'
255    expected_h_port = 5555
256    ads[1].h_port = expected_h_port
257    ad = android_device.get_device(
258        ads, serial=expected_serial, h_port=expected_h_port
259    )
260    self.assertEqual(ad.serial, expected_serial)
261    self.assertEqual(ad.h_port, expected_h_port)
262
263  def test_get_device_no_match(self):
264    ads = mock_android_device.get_mock_ads(5)
265    expected_msg = (
266        "Could not find a target device that matches condition: {'serial': 5}."
267    )
268    with self.assertRaisesRegex(android_device.Error, expected_msg):
269      ad = android_device.get_device(ads, serial=len(ads))
270
271  def test_get_device_too_many_matches(self):
272    ads = mock_android_device.get_mock_ads(5)
273    target_serial = ads[1].serial = ads[0].serial
274    expected_msg = r"More than one device matched: \['0', '0'\]"
275    with self.assertRaisesRegex(android_device.Error, expected_msg):
276      android_device.get_device(ads, serial=target_serial)
277
278  def test_start_services_on_ads(self):
279    """Makes sure when an AndroidDevice fails to start some services, all
280    AndroidDevice objects get cleaned up.
281    """
282    msg = 'Some error happened.'
283    ads = mock_android_device.get_mock_ads(3)
284    for ad in ads:
285      ad.services.logcat.start = mock.MagicMock()
286      ad.services.stop_all = mock.MagicMock()
287      ad.skip_logcat = False
288      ad.is_required = True
289    ads[1].services.logcat.start = mock.MagicMock(
290        side_effect=android_device.Error(msg)
291    )
292    with self.assertRaisesRegex(android_device.Error, msg):
293      android_device._start_services_on_ads(ads)
294    ads[0].services.stop_all.assert_called_once_with()
295    ads[1].services.stop_all.assert_called_once_with()
296    ads[2].services.stop_all.assert_called_once_with()
297
298  def test_start_services_on_ads_skip_logcat(self):
299    ads = mock_android_device.get_mock_ads(3)
300    ads[0].services.logcat.start = mock.MagicMock()
301    ads[1].services.logcat.start = mock.MagicMock()
302    ads[2].services.logcat.start = mock.MagicMock(
303        side_effect=Exception('Should not have called this.')
304    )
305    ads[2].skip_logcat = True
306    android_device._start_services_on_ads(ads)
307
308  def test_take_bug_reports(self):
309    ads = mock_android_device.get_mock_ads(3)
310    android_device.take_bug_reports(ads, 'test_something', 'sometime')
311    ads[0].take_bug_report.assert_called_once_with(
312        test_name='test_something', begin_time='sometime', destination=None
313    )
314    ads[1].take_bug_report.assert_called_once_with(
315        test_name='test_something', begin_time='sometime', destination=None
316    )
317    ads[2].take_bug_report.assert_called_once_with(
318        test_name='test_something', begin_time='sometime', destination=None
319    )
320
321  def test_take_bug_reports_with_int_begin_time(self):
322    ads = mock_android_device.get_mock_ads(3)
323    android_device.take_bug_reports(ads, 'test_something', 123)
324    ads[0].take_bug_report.assert_called_once_with(
325        test_name='test_something', begin_time='123', destination=None
326    )
327    ads[1].take_bug_report.assert_called_once_with(
328        test_name='test_something', begin_time='123', destination=None
329    )
330    ads[2].take_bug_report.assert_called_once_with(
331        test_name='test_something', begin_time='123', destination=None
332    )
333
334  @mock.patch('mobly.logger.get_log_file_timestamp')
335  def test_take_bug_reports_with_none_values(self, get_log_file_timestamp_mock):
336    mock_timestamp = '07-22-2019_17-55-30-765'
337    get_log_file_timestamp_mock.return_value = mock_timestamp
338    ads = mock_android_device.get_mock_ads(3)
339    android_device.take_bug_reports(ads)
340    ads[0].take_bug_report.assert_called_once_with(
341        test_name=None, begin_time=mock_timestamp, destination=None
342    )
343    ads[1].take_bug_report.assert_called_once_with(
344        test_name=None, begin_time=mock_timestamp, destination=None
345    )
346    ads[2].take_bug_report.assert_called_once_with(
347        test_name=None, begin_time=mock_timestamp, destination=None
348    )
349
350  # Tests for android_device.AndroidDevice class.
351  # These tests mock out any interaction with the OS and real android device
352  # in AndroidDeivce.
353
354  @mock.patch(
355      'mobly.controllers.android_device_lib.adb.AdbProxy',
356      return_value=mock_android_device.MockAdbProxy('1'),
357  )
358  @mock.patch(
359      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
360      return_value=mock_android_device.MockFastbootProxy('1'),
361  )
362  def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy):
363    """Verifies the AndroidDevice object's basic attributes are correctly
364    set after instantiation.
365    """
366    mock_serial = 1
367    ad = android_device.AndroidDevice(serial=mock_serial)
368    self.assertEqual(ad.serial, '1')
369    self.assertEqual(ad.model, 'fakemodel')
370    expected_lp = os.path.join(
371        logging.log_path, 'AndroidDevice%s' % mock_serial
372    )
373    self.assertEqual(ad.log_path, expected_lp)
374    self.assertIsNotNone(ad.services.logcat)
375    self.assertIsNotNone(ad.services.snippets)
376
377  @mock.patch(
378      'mobly.controllers.android_device_lib.adb.AdbProxy',
379      return_value=mock_android_device.MockAdbProxy(1),
380  )
381  @mock.patch(
382      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
383      return_value=mock_android_device.MockFastbootProxy(1),
384  )
385  @mock.patch('mobly.utils.create_dir')
386  def test_AndroidDevice_load_config(
387      self, create_dir_mock, FastbootProxy, MockAdbProxy
388  ):
389    mock_serial = '1'
390    config = {'space': 'the final frontier', 'number': 1, 'debug_tag': 'my_tag'}
391    ad = android_device.AndroidDevice(serial=mock_serial)
392    ad.load_config(config)
393    self.assertEqual(ad.space, 'the final frontier')
394    self.assertEqual(ad.number, 1)
395    self.assertEqual(ad.debug_tag, 'my_tag')
396
397  @mock.patch(
398      'mobly.controllers.android_device_lib.adb.AdbProxy',
399      return_value=mock_android_device.MockAdbProxy(1),
400  )
401  @mock.patch(
402      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
403      return_value=mock_android_device.MockFastbootProxy(1),
404  )
405  @mock.patch('mobly.utils.create_dir')
406  def test_AndroidDevice_load_config_dup(
407      self, create_dir_mock, FastbootProxy, MockAdbProxy
408  ):
409    mock_serial = '1'
410    config = {'serial': 'new_serial'}
411    ad = android_device.AndroidDevice(serial=mock_serial)
412    with self.assertRaisesRegex(
413        android_device.DeviceError, 'Attribute serial already exists with'
414    ):
415      ad.load_config(config)
416
417  @mock.patch(
418      'mobly.controllers.android_device_lib.adb.AdbProxy',
419      return_value=mock_android_device.MockAdbProxy('1'),
420  )
421  @mock.patch(
422      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
423      return_value=mock_android_device.MockFastbootProxy('1'),
424  )
425  def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy):
426    """Verifies the AndroidDevice object's basic attributes are correctly
427    set after instantiation.
428    """
429    ad = android_device.AndroidDevice(serial='1')
430    build_info = ad.build_info
431    self.assertEqual(build_info['build_id'], 'AB42')
432    self.assertEqual(build_info['build_type'], 'userdebug')
433    self.assertEqual(
434        build_info['build_fingerprint'],
435        'FakeModel:Dessert/AB42/1234567:userdebug/dev-keys',
436    )
437    self.assertEqual(build_info['build_version_codename'], 'Z')
438    self.assertEqual(build_info['build_version_incremental'], '1234567')
439    self.assertEqual(build_info['build_version_sdk'], '28')
440    self.assertEqual(build_info['build_product'], 'FakeModel')
441    self.assertEqual(build_info['build_characteristics'], 'emulator,phone')
442    self.assertEqual(build_info['product_name'], 'FakeModel')
443    self.assertEqual(build_info['debuggable'], '1')
444    self.assertEqual(build_info['hardware'], 'marlin')
445    self.assertEqual(len(build_info), len(android_device.CACHED_SYSTEM_PROPS))
446
447  @mock.patch(
448      'mobly.controllers.android_device_lib.adb.AdbProxy',
449      return_value=mock_android_device.MockAdbProxy(
450          '1',
451          mock_properties={
452              'ro.build.id': 'AB42',
453              'ro.build.type': 'userdebug',
454          },
455      ),
456  )
457  @mock.patch(
458      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
459      return_value=mock_android_device.MockFastbootProxy('1'),
460  )
461  def test_AndroidDevice_build_info_with_minimal_properties(
462      self, MockFastboot, MockAdbProxy
463  ):
464    ad = android_device.AndroidDevice(serial='1')
465    build_info = ad.build_info
466    self.assertEqual(build_info['build_id'], 'AB42')
467    self.assertEqual(build_info['build_type'], 'userdebug')
468    self.assertEqual(build_info['build_fingerprint'], '')
469    self.assertEqual(build_info['build_version_codename'], '')
470    self.assertEqual(build_info['build_version_incremental'], '')
471    self.assertEqual(build_info['build_version_sdk'], '')
472    self.assertEqual(build_info['build_product'], '')
473    self.assertEqual(build_info['build_characteristics'], '')
474    self.assertEqual(build_info['product_name'], '')
475    self.assertEqual(build_info['debuggable'], '')
476    self.assertEqual(build_info['hardware'], '')
477
478  @mock.patch(
479      'mobly.controllers.android_device_lib.adb.AdbProxy',
480      return_value=mock_android_device.MockAdbProxy('1'),
481  )
482  @mock.patch(
483      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
484      return_value=mock_android_device.MockFastbootProxy('1'),
485  )
486  def test_AndroidDevice_build_info_cached(self, MockFastboot, MockAdbProxy):
487    """Verifies the AndroidDevice object's basic attributes are correctly
488    set after instantiation.
489    """
490    ad = android_device.AndroidDevice(serial='1')
491    _ = ad.build_info
492    _ = ad.build_info
493    _ = ad.build_info
494    self.assertEqual(ad.adb.getprops_call_count, 1)
495
496  @mock.patch(
497      'mobly.controllers.android_device_lib.adb.AdbProxy',
498      return_value=mock_android_device.MockAdbProxy('1'),
499  )
500  @mock.patch(
501      'mobly.controllers.android_device.list_fastboot_devices',
502      return_value=mock.MagicMock(),
503  )
504  def test_AndroidDevice_model_property_is_cached(
505      self, mock_list_fastboot_devices, _
506  ):
507    """Accessing `model` a second time shouldn't invoke all the fastboot/adb
508    calls again.
509    """
510    mock_serial = 1
511    # mock returns '2' so the device is not considered in bootloader mode.
512    mock_list_fastboot_devices.return_value = ['2']
513    ad = android_device.AndroidDevice(serial=mock_serial)
514    ad.model
515    mock_count_first = mock_list_fastboot_devices.call_count
516    ad.model  # access `model` again.
517    mock_count_second = mock_list_fastboot_devices.call_count
518    self.assertEqual(mock_count_first, mock_count_second)
519
520  @mock.patch(
521      'mobly.controllers.android_device_lib.adb.AdbProxy',
522      return_value=mock_android_device.MockAdbProxy(
523          '1',
524          mock_properties={
525              'ro.build.id': 'AB42',
526              'ro.build.type': 'userdebug',
527              'ro.debuggable': '1',
528          },
529      ),
530  )
531  @mock.patch(
532      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
533      return_value=mock_android_device.MockFastbootProxy('1'),
534  )
535  def test_AndroidDevice_is_rootable_when_userdebug_device(
536      self, MockFastboot, MockAdbProxy
537  ):
538    ad = android_device.AndroidDevice(serial='1')
539    self.assertTrue(ad.is_rootable)
540
541  @mock.patch(
542      'mobly.controllers.android_device_lib.adb.AdbProxy',
543      return_value=mock_android_device.MockAdbProxy(
544          '1',
545          mock_properties={
546              'ro.build.id': 'AB42',
547              'ro.build.type': 'user',
548              'ro.debuggable': '0',
549          },
550      ),
551  )
552  @mock.patch(
553      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
554      return_value=mock_android_device.MockFastbootProxy('1'),
555  )
556  def test_AndroidDevice_is_rootable_when_user_device(
557      self, MockFastboot, MockAdbProxy
558  ):
559    ad = android_device.AndroidDevice(serial='1')
560    self.assertFalse(ad.is_rootable)
561
562  @mock.patch(
563      'mobly.controllers.android_device_lib.adb.AdbProxy',
564      return_value=mock_android_device.MockAdbProxy('1'),
565  )
566  @mock.patch(
567      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
568      return_value=mock_android_device.MockFastbootProxy('1'),
569  )
570  def test_AndroidDevice_device_info(self, MockFastboot, MockAdbProxy):
571    ad = android_device.AndroidDevice(serial=1)
572    device_info = ad.device_info
573    self.assertEqual(device_info['serial'], '1')
574    self.assertEqual(device_info['model'], 'fakemodel')
575    self.assertEqual(device_info['build_info']['build_id'], 'AB42')
576    self.assertEqual(device_info['build_info']['build_type'], 'userdebug')
577    ad.add_device_info('sim_type', 'Fi')
578    ad.add_device_info('build_id', 'CD42')
579    device_info = ad.device_info
580    self.assertEqual(device_info['user_added_info']['sim_type'], 'Fi')
581    self.assertEqual(device_info['user_added_info']['build_id'], 'CD42')
582
583  @mock.patch(
584      'mobly.controllers.android_device_lib.adb.AdbProxy',
585      return_value=mock_android_device.MockAdbProxy('1'),
586  )
587  @mock.patch(
588      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
589      return_value=mock_android_device.MockFastbootProxy('1'),
590  )
591  def test_AndroidDevice_serial_is_valid(self, MockFastboot, MockAdbProxy):
592    """Verifies that the serial is a primitive string type and serializable."""
593    ad = android_device.AndroidDevice(serial=1)
594    self.assertTrue(isinstance(ad.serial, str))
595    yaml.safe_dump(ad.serial)
596
597  @mock.patch(
598      'mobly.controllers.android_device_lib.adb.AdbProxy',
599      return_value=mock_android_device.MockAdbProxy('1'),
600  )
601  @mock.patch(
602      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
603      return_value=mock_android_device.MockFastbootProxy('1'),
604  )
605  def test_AndroidDevice_is_emulator_when_realish_device(
606      self, MockFastboot, MockAdbProxy
607  ):
608    ad = android_device.AndroidDevice(serial='1')
609    self.assertFalse(ad.is_emulator)
610
611  @mock.patch(
612      'mobly.controllers.android_device_lib.adb.AdbProxy',
613      return_value=mock_android_device.MockAdbProxy('localhost:123'),
614  )
615  @mock.patch(
616      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
617      return_value=mock_android_device.MockFastbootProxy('localhost:123'),
618  )
619  def test_AndroidDevice_is_emulator_when_local_networked_device(
620      self, MockFastboot, MockAdbProxy
621  ):
622    # Although these devices are usually emulators, there might be a reason
623    # to do this with a real device.
624    ad = android_device.AndroidDevice(serial='localhost:123')
625    self.assertFalse(ad.is_emulator)
626
627  @mock.patch(
628      'mobly.controllers.android_device_lib.adb.AdbProxy',
629      return_value=mock_android_device.MockAdbProxy('example.com:123'),
630  )
631  @mock.patch(
632      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
633      return_value=mock_android_device.MockFastbootProxy('example:123'),
634  )
635  def test_AndroidDevice_is_emulator_when_remote_networked_device(
636      self, MockFastboot, MockAdbProxy
637  ):
638    ad = android_device.AndroidDevice(serial='example.com:123')
639    self.assertFalse(ad.is_emulator)
640
641  @mock.patch(
642      'mobly.controllers.android_device_lib.adb.AdbProxy',
643      return_value=mock_android_device.MockAdbProxy(
644          'localhost:5554',
645          mock_properties={
646              'ro.hardware': 'ranchu',
647              'ro.build.id': 'AB42',
648              'ro.build.type': 'userdebug',
649          },
650      ),
651  )
652  @mock.patch(
653      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
654      return_value=mock_android_device.MockFastbootProxy('localhost:5554'),
655  )
656  def test_AndroidDevice_is_emulator_when_ranchu_device(
657      self, MockFastboot, MockAdbProxy
658  ):
659    ad = android_device.AndroidDevice(serial='localhost:5554')
660    self.assertTrue(ad.is_emulator)
661
662  @mock.patch(
663      'mobly.controllers.android_device_lib.adb.AdbProxy',
664      return_value=mock_android_device.MockAdbProxy(
665          '1',
666          mock_properties={
667              'ro.build.id': 'AB42',
668              'ro.build.type': 'userdebug',
669              'ro.hardware': 'goldfish',
670          },
671      ),
672  )
673  @mock.patch(
674      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
675      return_value=mock_android_device.MockFastbootProxy('1'),
676  )
677  def test_AndroidDevice_is_emulator_when_goldfish_device(
678      self, MockFastboot, MockAdbProxy
679  ):
680    ad = android_device.AndroidDevice(serial='1')
681    self.assertTrue(ad.is_emulator)
682
683  @mock.patch(
684      'mobly.controllers.android_device_lib.adb.AdbProxy',
685      return_value=mock_android_device.MockAdbProxy(
686          'example.com:123',
687          mock_properties={
688              'ro.build.id': 'AB42',
689              'ro.build.type': 'userdebug',
690              'ro.build.characteristics': 'emulator',
691          },
692      ),
693  )
694  @mock.patch(
695      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
696      return_value=mock_android_device.MockFastbootProxy('example.com:123'),
697  )
698  def test_AndroidDevice_is_emulator_when_emulator_characteristic(
699      self, MockFastboot, MockAdbProxy
700  ):
701    ad = android_device.AndroidDevice(serial='example.com:123')
702    self.assertTrue(ad.is_emulator)
703
704  @mock.patch(
705      'mobly.controllers.android_device_lib.adb.AdbProxy',
706      return_value=mock_android_device.MockAdbProxy('emulator-5554'),
707  )
708  @mock.patch(
709      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
710      return_value=mock_android_device.MockFastbootProxy('emulator-5554'),
711  )
712  def test_AndroidDevice_is_emulator_when_emulator_serial(
713      self, MockFastboot, MockAdbProxy
714  ):
715    ad = android_device.AndroidDevice(serial='emulator-5554')
716    self.assertTrue(ad.is_emulator)
717
718  @mock.patch(
719      'mobly.controllers.android_device_lib.adb.AdbProxy',
720      return_value=mock_android_device.MockAdbProxy('1'),
721  )
722  @mock.patch(
723      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
724      return_value=mock_android_device.MockFastbootProxy('1'),
725  )
726  @mock.patch(
727      'mobly.controllers.android_device.list_fastboot_devices', return_value='1'
728  )
729  def test_AndroidDevice_is_fastboot(self, _, MockFastboot, MockAdbProxy):
730    ad = android_device.AndroidDevice(serial='1')
731    self.assertTrue(ad.is_bootloader)
732
733  @mock.patch(
734      'mobly.controllers.android_device_lib.adb.AdbProxy',
735      return_value=mock_android_device.MockAdbProxy('1'),
736  )
737  @mock.patch(
738      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
739      return_value=mock_android_device.MockFastbootProxy('1'),
740  )
741  @mock.patch('mobly.logger.get_log_file_timestamp')
742  def test_AndroidDevice_generate_filename_default(
743      self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy
744  ):
745    mock_serial = 1
746    ad = android_device.AndroidDevice(serial=mock_serial)
747    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
748    filename = ad.generate_filename('MagicLog')
749    self.assertEqual(filename, 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450')
750
751  @mock.patch(
752      'mobly.controllers.android_device_lib.adb.AdbProxy',
753      return_value=mock_android_device.MockAdbProxy('1'),
754  )
755  @mock.patch(
756      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
757      return_value=mock_android_device.MockFastbootProxy('1'),
758  )
759  @mock.patch('mobly.logger.get_log_file_timestamp')
760  @mock.patch('mobly.logger.sanitize_filename')
761  def test_AndroidDevice_generate_filename_assert_sanitation(
762      self,
763      sanitize_filename_mock,
764      get_log_file_timestamp_mock,
765      MockFastboot,
766      MockAdbProxy,
767  ):
768    mock_serial = 1
769    sanitize_filename_mock.return_value = '1'
770    ad = android_device.AndroidDevice(serial=mock_serial)
771    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
772    filename = ad.generate_filename('MagicLog')
773    sanitize_filename_mock.assert_called_with(
774        'MagicLog,1,fakemodel,07-22-2019_17-53-34-450'
775    )
776
777  @mock.patch(
778      'mobly.controllers.android_device_lib.adb.AdbProxy',
779      return_value=mock_android_device.MockAdbProxy('1'),
780  )
781  @mock.patch(
782      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
783      return_value=mock_android_device.MockFastbootProxy('1'),
784  )
785  @mock.patch('mobly.logger.get_log_file_timestamp')
786  def test_AndroidDevice_generate_filename_with_ext(
787      self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy
788  ):
789    mock_serial = 1
790    ad = android_device.AndroidDevice(serial=mock_serial)
791    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
792    filename = ad.generate_filename('MagicLog', extension_name='log')
793    self.assertEqual(
794        filename, 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450.log'
795    )
796
797  @mock.patch(
798      'mobly.controllers.android_device_lib.adb.AdbProxy',
799      return_value=mock_android_device.MockAdbProxy('1'),
800  )
801  @mock.patch(
802      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
803      return_value=mock_android_device.MockFastbootProxy('1'),
804  )
805  @mock.patch('mobly.logger.get_log_file_timestamp')
806  def test_AndroidDevice_generate_filename_with_debug_tag(
807      self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy
808  ):
809    mock_serial = 1
810    ad = android_device.AndroidDevice(serial=mock_serial)
811    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
812    ad.debug_tag = 'RoleX'
813    filename = ad.generate_filename('MagicLog')
814    self.assertEqual(
815        filename, 'MagicLog,RoleX,1,fakemodel,07-22-2019_17-53-34-450'
816    )
817
818  @mock.patch(
819      'mobly.controllers.android_device_lib.adb.AdbProxy',
820      return_value=mock_android_device.MockAdbProxy('1'),
821  )
822  @mock.patch(
823      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
824      return_value=mock_android_device.MockFastbootProxy('1'),
825  )
826  @mock.patch('mobly.logger.get_log_file_timestamp')
827  def test_AndroidDevice_generate_filename_with_runtime_info(
828      self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy
829  ):
830    mock_serial = 1
831    ad = android_device.AndroidDevice(serial=mock_serial)
832    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
833    mock_record = mock.MagicMock(
834        test_name='test_xyz', begin_time='1234567', signature='test_xyz-1234567'
835    )
836    mock_test_info = runtime_test_info.RuntimeTestInfo(
837        mock_record.test_name, '/tmp/blah/', mock_record
838    )
839    filename = ad.generate_filename('MagicLog', time_identifier=mock_test_info)
840    self.assertEqual(filename, 'MagicLog,1,fakemodel,test_xyz-1234567')
841
842  @mock.patch(
843      'mobly.controllers.android_device_lib.adb.AdbProxy',
844      return_value=mock_android_device.MockAdbProxy('1'),
845  )
846  @mock.patch(
847      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
848      return_value=mock_android_device.MockFastbootProxy('1'),
849  )
850  @mock.patch('mobly.logger.get_log_file_timestamp')
851  def test_AndroidDevice_generate_filename_with_custom_timestamp(
852      self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy
853  ):
854    mock_serial = 1
855    ad = android_device.AndroidDevice(serial=mock_serial)
856    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
857    filename = ad.generate_filename(
858        'MagicLog', time_identifier='my_special_time'
859    )
860    self.assertEqual(filename, 'MagicLog,1,fakemodel,my_special_time')
861
862  @mock.patch(
863      'mobly.controllers.android_device_lib.adb.AdbProxy',
864      return_value=mock_android_device.MockAdbProxy(1),
865  )
866  @mock.patch(
867      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
868      return_value=mock_android_device.MockFastbootProxy(1),
869  )
870  @mock.patch('mobly.utils.create_dir')
871  def test_AndroidDevice_take_bug_report(
872      self, create_dir_mock, FastbootProxy, MockAdbProxy
873  ):
874    """Verifies AndroidDevice.take_bug_report calls the correct adb command
875    and writes the bugreport file to the correct path.
876    """
877    mock_serial = '1'
878    ad = android_device.AndroidDevice(serial=mock_serial)
879    output_path = ad.take_bug_report(
880        test_name='test_something', begin_time='sometime'
881    )
882    expected_path = os.path.join(
883        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
884    )
885    create_dir_mock.assert_called_with(expected_path)
886    self.assertEqual(
887        output_path,
888        os.path.join(
889            expected_path, 'bugreport,test_something,1,fakemodel,sometime.zip'
890        ),
891    )
892
893  @mock.patch(
894      'mobly.controllers.android_device_lib.adb.AdbProxy',
895      return_value=mock_android_device.MockAdbProxy('1', fail_br=True),
896  )
897  @mock.patch(
898      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
899      return_value=mock_android_device.MockFastbootProxy('1'),
900  )
901  @mock.patch('mobly.utils.create_dir')
902  def test_AndroidDevice_take_bug_report_fail(
903      self, create_dir_mock, FastbootProxy, MockAdbProxy
904  ):
905    """Verifies AndroidDevice.take_bug_report writes out the correct message
906    when taking bugreport fails.
907    """
908    mock_serial = '1'
909    ad = android_device.AndroidDevice(serial=mock_serial)
910    expected_msg = '.* Failed to take bugreport.'
911    with self.assertRaisesRegex(android_device.Error, expected_msg):
912      ad.take_bug_report(test_name='test_something', begin_time='sometime')
913
914  @mock.patch(
915      'mobly.controllers.android_device_lib.adb.AdbProxy',
916      return_value=mock_android_device.MockAdbProxy('1'),
917  )
918  @mock.patch(
919      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
920      return_value=mock_android_device.MockFastbootProxy('1'),
921  )
922  @mock.patch('mobly.utils.create_dir')
923  @mock.patch('mobly.logger.get_log_file_timestamp')
924  def test_AndroidDevice_take_bug_report_without_args(
925      self,
926      get_log_file_timestamp_mock,
927      create_dir_mock,
928      FastbootProxy,
929      MockAdbProxy,
930  ):
931    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
932    mock_serial = '1'
933    ad = android_device.AndroidDevice(serial=mock_serial)
934    output_path = ad.take_bug_report()
935    expected_path = os.path.join(
936        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
937    )
938    self.assertEqual(
939        output_path,
940        os.path.join(
941            expected_path, 'bugreport,1,fakemodel,07-22-2019_17-53-34-450.zip'
942        ),
943    )
944
945  @mock.patch(
946      'mobly.controllers.android_device_lib.adb.AdbProxy',
947      return_value=mock_android_device.MockAdbProxy('1'),
948  )
949  @mock.patch(
950      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
951      return_value=mock_android_device.MockFastbootProxy('1'),
952  )
953  @mock.patch('mobly.utils.create_dir')
954  @mock.patch('mobly.logger.get_log_file_timestamp')
955  def test_AndroidDevice_take_bug_report_with_only_test_name(
956      self,
957      get_log_file_timestamp_mock,
958      create_dir_mock,
959      FastbootProxy,
960      MockAdbProxy,
961  ):
962    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
963    mock_serial = '1'
964    ad = android_device.AndroidDevice(serial=mock_serial)
965    output_path = ad.take_bug_report(test_name='test_something')
966    expected_path = os.path.join(
967        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
968    )
969    create_dir_mock.assert_called_with(expected_path)
970    self.assertEqual(
971        output_path,
972        os.path.join(
973            expected_path,
974            'bugreport,test_something,1,fakemodel,07-22-2019_17-53-34-450.zip',
975        ),
976    )
977
978  @mock.patch(
979      'mobly.controllers.android_device_lib.adb.AdbProxy',
980      return_value=mock_android_device.MockAdbProxy(1),
981  )
982  @mock.patch(
983      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
984      return_value=mock_android_device.MockFastbootProxy(1),
985  )
986  @mock.patch('mobly.utils.create_dir')
987  def test_AndroidDevice_take_bug_report_with_only_begin_time(
988      self, create_dir_mock, FastbootProxy, MockAdbProxy
989  ):
990    mock_serial = '1'
991    ad = android_device.AndroidDevice(serial=mock_serial)
992    output_path = ad.take_bug_report(begin_time='sometime')
993    expected_path = os.path.join(
994        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
995    )
996    create_dir_mock.assert_called_with(expected_path)
997    self.assertEqual(
998        output_path,
999        os.path.join(expected_path, 'bugreport,1,fakemodel,sometime.zip'),
1000    )
1001
1002  @mock.patch(
1003      'mobly.controllers.android_device_lib.adb.AdbProxy',
1004      return_value=mock_android_device.MockAdbProxy(1),
1005  )
1006  @mock.patch(
1007      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1008      return_value=mock_android_device.MockFastbootProxy(1),
1009  )
1010  @mock.patch('mobly.utils.create_dir')
1011  def test_AndroidDevice_take_bug_report_with_int_begin_time(
1012      self, create_dir_mock, FastbootProxy, MockAdbProxy
1013  ):
1014    mock_serial = '1'
1015    ad = android_device.AndroidDevice(serial=mock_serial)
1016    output_path = ad.take_bug_report(begin_time=123)
1017    expected_path = os.path.join(
1018        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
1019    )
1020    create_dir_mock.assert_called_with(expected_path)
1021    self.assertEqual(
1022        output_path,
1023        os.path.join(expected_path, 'bugreport,1,fakemodel,123.zip'),
1024    )
1025
1026  @mock.patch(
1027      'mobly.controllers.android_device_lib.adb.AdbProxy',
1028      return_value=mock_android_device.MockAdbProxy(1),
1029  )
1030  @mock.patch(
1031      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1032      return_value=mock_android_device.MockFastbootProxy(1),
1033  )
1034  @mock.patch('mobly.utils.create_dir')
1035  def test_AndroidDevice_take_bug_report_with_positional_args(
1036      self, create_dir_mock, FastbootProxy, MockAdbProxy
1037  ):
1038    mock_serial = '1'
1039    ad = android_device.AndroidDevice(serial=mock_serial)
1040    output_path = ad.take_bug_report('test_something', 'sometime')
1041    expected_path = os.path.join(
1042        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
1043    )
1044    create_dir_mock.assert_called_with(expected_path)
1045    self.assertEqual(
1046        output_path,
1047        os.path.join(
1048            expected_path, 'bugreport,test_something,1,fakemodel,sometime.zip'
1049        ),
1050    )
1051
1052  @mock.patch(
1053      'mobly.controllers.android_device_lib.adb.AdbProxy',
1054      return_value=mock_android_device.MockAdbProxy('1'),
1055  )
1056  @mock.patch(
1057      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1058      return_value=mock_android_device.MockFastbootProxy('1'),
1059  )
1060  @mock.patch('mobly.utils.create_dir')
1061  def test_AndroidDevice_take_bug_report_with_destination(
1062      self, create_dir_mock, FastbootProxy, MockAdbProxy
1063  ):
1064    mock_serial = '1'
1065    ad = android_device.AndroidDevice(serial=mock_serial)
1066    dest = tempfile.gettempdir()
1067    output_path = ad.take_bug_report(
1068        test_name='test_something', begin_time='sometime', destination=dest
1069    )
1070    expected_path = os.path.join(dest)
1071    create_dir_mock.assert_called_with(expected_path)
1072    self.assertEqual(
1073        output_path,
1074        os.path.join(
1075            expected_path, 'bugreport,test_something,1,fakemodel,sometime.zip'
1076        ),
1077    )
1078
1079  @mock.patch(
1080      'mobly.controllers.android_device_lib.adb.AdbProxy',
1081      return_value=mock_android_device.MockAdbProxy('1', fail_br_before_N=True),
1082  )
1083  @mock.patch(
1084      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1085      return_value=mock_android_device.MockFastbootProxy('1'),
1086  )
1087  @mock.patch('mobly.utils.create_dir')
1088  def test_AndroidDevice_take_bug_report_fallback(
1089      self, create_dir_mock, FastbootProxy, MockAdbProxy
1090  ):
1091    """Verifies AndroidDevice.take_bug_report falls back to traditional
1092    bugreport on builds that do not have bugreportz.
1093    """
1094    mock_serial = '1'
1095    ad = android_device.AndroidDevice(serial=mock_serial)
1096    output_path = ad.take_bug_report(
1097        test_name='test_something', begin_time='sometime'
1098    )
1099    expected_path = os.path.join(
1100        logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports'
1101    )
1102    create_dir_mock.assert_called_with(expected_path)
1103    self.assertEqual(
1104        output_path,
1105        os.path.join(
1106            expected_path, 'bugreport,test_something,1,fakemodel,sometime.txt'
1107        ),
1108    )
1109
1110  @mock.patch(
1111      'mobly.controllers.android_device_lib.adb.AdbProxy',
1112      return_value=mock_android_device.MockAdbProxy('1'),
1113  )
1114  @mock.patch(
1115      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1116      return_value=mock_android_device.MockFastbootProxy('1'),
1117  )
1118  @mock.patch('mobly.utils.create_dir')
1119  @mock.patch('mobly.logger.get_log_file_timestamp')
1120  def test_AndroidDevice_take_screenshot(
1121      self,
1122      get_log_file_timestamp_mock,
1123      create_dir_mock,
1124      FastbootProxy,
1125      MockAdbProxy,
1126  ):
1127    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
1128    mock_serial = '1'
1129    ad = android_device.AndroidDevice(serial=mock_serial)
1130    full_pic_path = ad.take_screenshot(self.tmp_dir)
1131    self.assertEqual(
1132        full_pic_path,
1133        os.path.join(
1134            self.tmp_dir, 'screenshot,1,fakemodel,07-22-2019_17-53-34-450.png'
1135        ),
1136    )
1137
1138  @mock.patch(
1139      'mobly.controllers.android_device_lib.adb.AdbProxy',
1140      return_value=mock_android_device.MockAdbProxy('1'),
1141  )
1142  @mock.patch(
1143      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1144      return_value=mock_android_device.MockFastbootProxy('1'),
1145  )
1146  @mock.patch('mobly.utils.create_dir')
1147  @mock.patch('mobly.logger.get_log_file_timestamp')
1148  def test_AndroidDevice_take_screenshot_with_prefix(
1149      self,
1150      get_log_file_timestamp_mock,
1151      create_dir_mock,
1152      FastbootProxy,
1153      MockAdbProxy,
1154  ):
1155    get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450'
1156    mock_serial = '1'
1157    ad = android_device.AndroidDevice(serial=mock_serial)
1158
1159    full_pic_path = ad.take_screenshot(self.tmp_dir, 'page_a')
1160
1161    self.assertEqual(
1162        full_pic_path,
1163        os.path.join(
1164            self.tmp_dir, 'page_a,1,fakemodel,07-22-2019_17-53-34-450.png'
1165        ),
1166    )
1167
1168  @mock.patch(
1169      'mobly.controllers.android_device_lib.adb.AdbProxy',
1170      return_value=mock_android_device.MockAdbProxy('1'),
1171  )
1172  @mock.patch(
1173      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1174      return_value=mock_android_device.MockFastbootProxy('1'),
1175  )
1176  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1177  @mock.patch('mobly.utils.stop_standing_subprocess')
1178  def test_AndroidDevice_change_log_path(
1179      self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy
1180  ):
1181    ad = android_device.AndroidDevice(serial='1')
1182    old_path = ad.log_path
1183    new_log_path = tempfile.mkdtemp()
1184    ad.log_path = new_log_path
1185    self.assertTrue(os.path.exists(new_log_path))
1186    self.assertFalse(os.path.exists(old_path))
1187
1188  @mock.patch(
1189      'mobly.controllers.android_device_lib.adb.AdbProxy',
1190      return_value=mock_android_device.MockAdbProxy('1'),
1191  )
1192  @mock.patch(
1193      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1194      return_value=mock_android_device.MockFastbootProxy('1'),
1195  )
1196  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1197  @mock.patch('mobly.utils.stop_standing_subprocess')
1198  def test_AndroidDevice_change_log_path_no_log_exists(
1199      self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy
1200  ):
1201    ad = android_device.AndroidDevice(serial='1')
1202    old_path = ad.log_path
1203    new_log_path = tempfile.mkdtemp()
1204    ad.log_path = new_log_path
1205    self.assertTrue(os.path.exists(new_log_path))
1206    self.assertFalse(os.path.exists(old_path))
1207
1208  @mock.patch(
1209      'mobly.controllers.android_device_lib.adb.AdbProxy',
1210      return_value=mock_android_device.MockAdbProxy('127.0.0.1:5557'),
1211  )
1212  @mock.patch(
1213      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1214      return_value=mock_android_device.MockFastbootProxy('127.0.0.1:5557'),
1215  )
1216  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1217  @mock.patch('mobly.utils.stop_standing_subprocess')
1218  def test_AndroidDevice_with_reserved_character_in_serial_log_path(
1219      self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy
1220  ):
1221    ad = android_device.AndroidDevice(serial='127.0.0.1:5557')
1222    base_log_path = os.path.basename(ad.log_path)
1223    self.assertEqual(base_log_path, 'AndroidDevice127.0.0.1-5557')
1224
1225  @mock.patch(
1226      'mobly.controllers.android_device_lib.adb.AdbProxy',
1227      return_value=mock_android_device.MockAdbProxy('1'),
1228  )
1229  @mock.patch(
1230      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1231      return_value=mock_android_device.MockFastbootProxy('1'),
1232  )
1233  @mock.patch('mobly.utils.create_dir')
1234  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1235  @mock.patch('mobly.utils.stop_standing_subprocess')
1236  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1237  def test_AndroidDevice_change_log_path_with_service(
1238      self,
1239      open_logcat_mock,
1240      stop_proc_mock,
1241      start_proc_mock,
1242      creat_dir_mock,
1243      FastbootProxy,
1244      MockAdbProxy,
1245  ):
1246    ad = android_device.AndroidDevice(serial='1')
1247    ad.services.logcat.start()
1248    new_log_path = tempfile.mkdtemp()
1249    expected_msg = '.* Cannot change `log_path` when there is service running.'
1250    with self.assertRaisesRegex(android_device.Error, expected_msg):
1251      ad.log_path = new_log_path
1252
1253  @mock.patch(
1254      'mobly.controllers.android_device_lib.adb.AdbProxy',
1255      return_value=mock_android_device.MockAdbProxy('1'),
1256  )
1257  @mock.patch(
1258      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1259      return_value=mock_android_device.MockFastbootProxy('1'),
1260  )
1261  @mock.patch('mobly.utils.create_dir')
1262  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1263  @mock.patch('mobly.utils.stop_standing_subprocess')
1264  def test_AndroidDevice_change_log_path_with_existing_file(
1265      self,
1266      stop_proc_mock,
1267      start_proc_mock,
1268      creat_dir_mock,
1269      FastbootProxy,
1270      MockAdbProxy,
1271  ):
1272    ad = android_device.AndroidDevice(serial='1')
1273    new_log_path = tempfile.mkdtemp()
1274    new_file_path = os.path.join(new_log_path, 'file.txt')
1275    with io.open(new_file_path, 'w', encoding='utf-8') as f:
1276      f.write('hahah.')
1277    expected_msg = '.* Logs already exist .*'
1278    with self.assertRaisesRegex(android_device.Error, expected_msg):
1279      ad.log_path = new_log_path
1280
1281  @mock.patch(
1282      'mobly.controllers.android_device_lib.adb.AdbProxy',
1283      return_value=mock_android_device.MockAdbProxy('1'),
1284  )
1285  @mock.patch(
1286      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1287      return_value=mock_android_device.MockFastbootProxy('1'),
1288  )
1289  @mock.patch('mobly.utils.create_dir')
1290  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1291  @mock.patch('mobly.utils.stop_standing_subprocess')
1292  def test_AndroidDevice_update_serial(
1293      self,
1294      stop_proc_mock,
1295      start_proc_mock,
1296      creat_dir_mock,
1297      FastbootProxy,
1298      MockAdbProxy,
1299  ):
1300    ad = android_device.AndroidDevice(serial='1')
1301    ad.update_serial('2')
1302    self.assertEqual(ad.serial, '2')
1303    self.assertEqual(ad.debug_tag, ad.serial)
1304    self.assertEqual(ad.adb.serial, ad.serial)
1305    self.assertEqual(ad.fastboot.serial, ad.serial)
1306
1307  @mock.patch(
1308      'mobly.controllers.android_device_lib.adb.AdbProxy',
1309      return_value=mock_android_device.MockAdbProxy('1'),
1310  )
1311  @mock.patch(
1312      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1313      return_value=mock_android_device.MockFastbootProxy('1'),
1314  )
1315  @mock.patch('mobly.utils.create_dir')
1316  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1317  @mock.patch('mobly.utils.stop_standing_subprocess')
1318  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1319  def test_AndroidDevice_update_serial_with_service_running(
1320      self,
1321      open_logcat_mock,
1322      stop_proc_mock,
1323      start_proc_mock,
1324      creat_dir_mock,
1325      FastbootProxy,
1326      MockAdbProxy,
1327  ):
1328    ad = android_device.AndroidDevice(serial='1')
1329    ad.services.logcat.start()
1330    expected_msg = (
1331        '.* Cannot change device serial number when there is service running.'
1332    )
1333    with self.assertRaisesRegex(android_device.Error, expected_msg):
1334      ad.update_serial('2')
1335
1336  @mock.patch(
1337      'mobly.controllers.android_device_lib.adb.AdbProxy',
1338      return_value=mock_android_device.MockAdbProxy('1'),
1339  )
1340  @mock.patch(
1341      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1342      return_value=mock_android_device.MockFastbootProxy('1'),
1343  )
1344  @mock.patch(
1345      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1346  )
1347  @mock.patch('mobly.utils.get_available_host_port')
1348  def test_AndroidDevice_load_snippet(
1349      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1350  ):
1351    ad = android_device.AndroidDevice(serial='1')
1352    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1353    self.assertTrue(hasattr(ad, 'snippet'))
1354
1355  @mock.patch(
1356      'mobly.controllers.android_device_lib.adb.AdbProxy',
1357      return_value=mock_android_device.MockAdbProxy('1'),
1358  )
1359  @mock.patch(
1360      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1361      return_value=mock_android_device.MockFastbootProxy('1'),
1362  )
1363  @mock.patch(
1364      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1365  )
1366  @mock.patch('mobly.utils.get_available_host_port')
1367  def test_AndroidDevice_getattr(
1368      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1369  ):
1370    ad = android_device.AndroidDevice(serial='1')
1371    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1372    value = {'value': 42}
1373    actual_value = getattr(ad, 'some_attr', value)
1374    self.assertEqual(actual_value, value)
1375
1376  @mock.patch(
1377      'mobly.controllers.android_device_lib.adb.AdbProxy',
1378      return_value=mock_android_device.MockAdbProxy('1'),
1379  )
1380  @mock.patch(
1381      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1382      return_value=mock_android_device.MockFastbootProxy('1'),
1383  )
1384  @mock.patch(
1385      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2',
1386      return_value=MockSnippetClient,
1387  )
1388  @mock.patch('mobly.utils.get_available_host_port')
1389  def test_AndroidDevice_load_snippet_dup_package(
1390      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1391  ):
1392    ad = android_device.AndroidDevice(serial='1')
1393    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1394    expected_msg = (
1395        'Snippet package "%s" has already been loaded under name "snippet".'
1396    ) % MOCK_SNIPPET_PACKAGE_NAME
1397    with self.assertRaisesRegex(android_device.Error, expected_msg):
1398      ad.load_snippet('snippet2', MOCK_SNIPPET_PACKAGE_NAME)
1399
1400  @mock.patch(
1401      'mobly.controllers.android_device_lib.adb.AdbProxy',
1402      return_value=mock_android_device.MockAdbProxy('1'),
1403  )
1404  @mock.patch(
1405      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1406      return_value=mock_android_device.MockFastbootProxy('1'),
1407  )
1408  @mock.patch(
1409      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2',
1410      return_value=MockSnippetClient,
1411  )
1412  @mock.patch('mobly.utils.get_available_host_port')
1413  def test_AndroidDevice_load_snippet_dup_snippet_name(
1414      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1415  ):
1416    ad = android_device.AndroidDevice(serial='1')
1417    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1418    expected_msg = (
1419        '.* Attribute "snippet" already exists, please use a different name.'
1420    )
1421    with self.assertRaisesRegex(android_device.Error, expected_msg):
1422      ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME + 'haha')
1423
1424  @mock.patch(
1425      'mobly.controllers.android_device_lib.adb.AdbProxy',
1426      return_value=mock_android_device.MockAdbProxy('1'),
1427  )
1428  @mock.patch(
1429      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1430      return_value=mock_android_device.MockFastbootProxy('1'),
1431  )
1432  @mock.patch(
1433      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1434  )
1435  @mock.patch('mobly.utils.get_available_host_port')
1436  def test_AndroidDevice_load_snippet_dup_attribute_name(
1437      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1438  ):
1439    ad = android_device.AndroidDevice(serial='1')
1440    expected_msg = (
1441        'Attribute "%s" already exists, please use a different name'
1442    ) % 'adb'
1443    with self.assertRaisesRegex(android_device.Error, expected_msg):
1444      ad.load_snippet('adb', MOCK_SNIPPET_PACKAGE_NAME)
1445
1446  @mock.patch(
1447      'mobly.controllers.android_device_lib.adb.AdbProxy',
1448      return_value=mock_android_device.MockAdbProxy('1'),
1449  )
1450  @mock.patch(
1451      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1452      return_value=mock_android_device.MockFastbootProxy('1'),
1453  )
1454  @mock.patch(
1455      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1456  )
1457  @mock.patch('mobly.utils.get_available_host_port')
1458  def test_AndroidDevice_load_snippet_start_app_fails(
1459      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1460  ):
1461    """Verifies that the correct exception is raised if start app failed.
1462
1463    It's possible that the `stop` call as part of the start app failure
1464    teardown also fails. So we want the exception from the start app
1465    failure.
1466    """
1467    expected_e = Exception('start failed.')
1468    MockSnippetClient.initialize = mock.Mock(side_effect=expected_e)
1469    MockSnippetClient.stop = mock.Mock(side_effect=Exception('stop failed.'))
1470    ad = android_device.AndroidDevice(serial='1')
1471    try:
1472      ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1473    except Exception as e:
1474      assertIs(e, expected_e)
1475
1476  @mock.patch(
1477      'mobly.controllers.android_device_lib.adb.AdbProxy',
1478      return_value=mock_android_device.MockAdbProxy('1'),
1479  )
1480  @mock.patch(
1481      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1482      return_value=mock_android_device.MockFastbootProxy('1'),
1483  )
1484  @mock.patch(
1485      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1486  )
1487  @mock.patch('mobly.utils.get_available_host_port')
1488  def test_AndroidDevice_load_snippet_with_snippet_config(
1489      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1490  ):
1491    ad = android_device.AndroidDevice(serial='1')
1492    snippet_config = snippet_client_v2.Config()
1493    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME, snippet_config)
1494    self.assertTrue(hasattr(ad, 'snippet'))
1495    MockSnippetClient.assert_called_once_with(
1496        package=mock.ANY, ad=mock.ANY, config=snippet_config
1497    )
1498
1499  @mock.patch(
1500      'mobly.controllers.android_device_lib.adb.AdbProxy',
1501      return_value=mock_android_device.MockAdbProxy('1'),
1502  )
1503  @mock.patch(
1504      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1505      return_value=mock_android_device.MockFastbootProxy('1'),
1506  )
1507  @mock.patch(
1508      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1509  )
1510  @mock.patch('mobly.utils.get_available_host_port')
1511  def test_AndroidDevice_unload_snippet(
1512      self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy
1513  ):
1514    ad = android_device.AndroidDevice(serial='1')
1515    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1516    ad.unload_snippet('snippet')
1517    self.assertFalse(hasattr(ad, 'snippet'))
1518    with self.assertRaisesRegex(
1519        android_device.SnippetError,
1520        '<AndroidDevice|1> No snippet registered with name "snippet"',
1521    ):
1522      ad.unload_snippet('snippet')
1523    # Loading the same snippet again should succeed
1524    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1525    self.assertTrue(hasattr(ad, 'snippet'))
1526
1527  @mock.patch(
1528      'mobly.controllers.android_device_lib.adb.AdbProxy',
1529      return_value=mock_android_device.MockAdbProxy('1'),
1530  )
1531  @mock.patch(
1532      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1533      return_value=mock_android_device.MockFastbootProxy('1'),
1534  )
1535  @mock.patch(
1536      'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2'
1537  )
1538  @mock.patch('mobly.utils.get_available_host_port')
1539  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1540  def test_AndroidDevice_snippet_cleanup(
1541      self,
1542      open_logcat_mock,
1543      MockGetPort,
1544      MockSnippetClient,
1545      MockFastboot,
1546      MockAdbProxy,
1547  ):
1548    ad = android_device.AndroidDevice(serial='1')
1549    ad.services.start_all()
1550    ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
1551    ad.unload_snippet('snippet')
1552    self.assertFalse(hasattr(ad, 'snippet'))
1553
1554  @mock.patch(
1555      'mobly.controllers.android_device_lib.adb.AdbProxy',
1556      return_value=mock_android_device.MockAdbProxy('1'),
1557  )
1558  @mock.patch(
1559      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1560      return_value=mock_android_device.MockFastbootProxy('1'),
1561  )
1562  def test_AndroidDevice_debug_tag(self, MockFastboot, MockAdbProxy):
1563    mock_serial = '1'
1564    ad = android_device.AndroidDevice(serial=mock_serial)
1565    self.assertEqual(ad.debug_tag, '1')
1566    with self.assertRaisesRegex(
1567        android_device.DeviceError, r'<AndroidDevice\|1> Something'
1568    ):
1569      raise android_device.DeviceError(ad, 'Something')
1570
1571    # Verify that debug tag's setter updates the debug prefix correctly.
1572    ad.debug_tag = 'Mememe'
1573    with self.assertRaisesRegex(
1574        android_device.DeviceError, r'<AndroidDevice\|Mememe> Something'
1575    ):
1576      raise android_device.DeviceError(ad, 'Something')
1577
1578    # Verify that repr is changed correctly.
1579    with self.assertRaisesRegex(
1580        Exception, r'(<AndroidDevice\|Mememe>, \'Something\')'
1581    ):
1582      raise Exception(ad, 'Something')
1583
1584  @mock.patch(
1585      'mobly.controllers.android_device_lib.adb.AdbProxy',
1586      return_value=mock_android_device.MockAdbProxy('1'),
1587  )
1588  @mock.patch(
1589      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1590      return_value=mock_android_device.MockFastbootProxy('1'),
1591  )
1592  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1593  @mock.patch('mobly.utils.stop_standing_subprocess')
1594  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1595  def test_AndroidDevice_handle_usb_disconnect(
1596      self,
1597      open_logcat_mock,
1598      stop_proc_mock,
1599      start_proc_mock,
1600      FastbootProxy,
1601      MockAdbProxy,
1602  ):
1603    class MockService(base_service.BaseService):
1604
1605      def __init__(self, device, configs=None):
1606        self._alive = False
1607        self.pause_called = False
1608        self.resume_called = False
1609
1610      @property
1611      def is_alive(self):
1612        return self._alive
1613
1614      def start(self, configs=None):
1615        self._alive = True
1616
1617      def stop(self):
1618        self._alive = False
1619
1620      def pause(self):
1621        self._alive = False
1622        self.pause_called = True
1623
1624      def resume(self):
1625        self._alive = True
1626        self.resume_called = True
1627
1628    ad = android_device.AndroidDevice(serial='1')
1629    ad.services.start_all()
1630    ad.services.register('mock_service', MockService)
1631    with ad.handle_usb_disconnect():
1632      self.assertFalse(ad.services.is_any_alive)
1633      self.assertTrue(ad.services.mock_service.pause_called)
1634      self.assertFalse(ad.services.mock_service.resume_called)
1635    self.assertTrue(ad.services.is_any_alive)
1636    self.assertTrue(ad.services.mock_service.resume_called)
1637
1638  @mock.patch(
1639      'mobly.controllers.android_device_lib.adb.AdbProxy',
1640      return_value=mock_android_device.MockAdbProxy('1'),
1641  )
1642  @mock.patch(
1643      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1644      return_value=mock_android_device.MockFastbootProxy('1'),
1645  )
1646  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1647  @mock.patch('mobly.utils.stop_standing_subprocess')
1648  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1649  def test_AndroidDevice_handle_reboot(
1650      self,
1651      open_logcat_mock,
1652      stop_proc_mock,
1653      start_proc_mock,
1654      FastbootProxy,
1655      MockAdbProxy,
1656  ):
1657    class MockService(base_service.BaseService):
1658
1659      def __init__(self, device, configs=None):
1660        self._alive = False
1661        self.pause_called = False
1662        self.resume_called = False
1663
1664      @property
1665      def is_alive(self):
1666        return self._alive
1667
1668      def start(self, configs=None):
1669        self._alive = True
1670
1671      def stop(self):
1672        self._alive = False
1673
1674      def pause(self):
1675        self._alive = False
1676        self.pause_called = True
1677
1678      def resume(self):
1679        self._alive = True
1680        self.resume_called = True
1681
1682    ad = android_device.AndroidDevice(serial='1')
1683    ad.services.start_all()
1684    ad.services.register('mock_service', MockService)
1685    with ad.handle_reboot():
1686      self.assertFalse(ad.services.is_any_alive)
1687      self.assertFalse(ad.services.mock_service.pause_called)
1688      self.assertFalse(ad.services.mock_service.resume_called)
1689    self.assertTrue(ad.services.is_any_alive)
1690    self.assertFalse(ad.services.mock_service.resume_called)
1691
1692  @mock.patch(
1693      'mobly.controllers.android_device_lib.adb.AdbProxy',
1694      return_value=mock_android_device.MockAdbProxy('1'),
1695  )
1696  @mock.patch(
1697      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1698      return_value=mock_android_device.MockFastbootProxy('1'),
1699  )
1700  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1701  @mock.patch('mobly.utils.stop_standing_subprocess')
1702  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1703  def test_AndroidDevice_handle_reboot_changes_build_info(
1704      self,
1705      open_logcat_mock,
1706      stop_proc_mock,
1707      start_proc_mock,
1708      FastbootProxy,
1709      MockAdbProxy,
1710  ):
1711    ad = android_device.AndroidDevice(serial='1')
1712    with ad.handle_reboot():
1713      ad.adb.mock_properties['ro.build.type'] = 'user'
1714      ad.adb.mock_properties['ro.debuggable'] = '0'
1715    self.assertEqual(ad.build_info['build_type'], 'user')
1716    self.assertEqual(ad.build_info['debuggable'], '0')
1717    self.assertFalse(ad.is_rootable)
1718    self.assertEqual(ad.adb.getprops_call_count, 2)
1719
1720  @mock.patch(
1721      'mobly.controllers.android_device_lib.adb.AdbProxy',
1722      return_value=mock_android_device.MockAdbProxy('1'),
1723  )
1724  @mock.patch(
1725      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1726      return_value=mock_android_device.MockFastbootProxy('1'),
1727  )
1728  @mock.patch('mobly.utils.start_standing_subprocess', return_value='process')
1729  @mock.patch('mobly.utils.stop_standing_subprocess')
1730  @mock.patch.object(logcat.Logcat, '_open_logcat_file')
1731  def test_AndroidDevice_handle_reboot_changes_build_info_with_caching(
1732      self,
1733      open_logcat_mock,
1734      stop_proc_mock,
1735      start_proc_mock,
1736      FastbootProxy,
1737      MockAdbProxy,
1738  ):
1739    ad = android_device.AndroidDevice(serial='1')  # Call getprops 1.
1740    rootable_states = [ad.is_rootable]
1741    with ad.handle_reboot():
1742      rootable_states.append(ad.is_rootable)  # Call getprops 2.
1743      ad.adb.mock_properties['ro.debuggable'] = '0'
1744      rootable_states.append(ad.is_rootable)  # Call getprops 3.
1745    # Call getprops 4, on context manager end.
1746    rootable_states.append(ad.is_rootable)  # Cached call.
1747    rootable_states.append(ad.is_rootable)  # Cached call.
1748    self.assertEqual(ad.adb.getprops_call_count, 4)
1749    self.assertEqual(rootable_states, [True, True, False, False, False])
1750
1751  @mock.patch(
1752      'mobly.controllers.android_device_lib.adb.AdbProxy',
1753      return_value=mock_android_device.MockAdbProxy('1'),
1754  )
1755  @mock.patch(
1756      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1757      return_value=mock_android_device.MockFastbootProxy('1'),
1758  )
1759  @mock.patch(
1760      'mobly.controllers.android_device.AndroidDevice.is_boot_completed',
1761      side_effect=[
1762          False,
1763          False,
1764          adb.AdbTimeoutError(
1765              ['adb', 'shell', 'getprop sys.boot_completed'],
1766              timeout=5,
1767              serial=1,
1768          ),
1769          True,
1770      ],
1771  )
1772  @mock.patch('time.sleep', return_value=None)
1773  @mock.patch('time.time', side_effect=[0, 5, 10, 15, 20, 25, 30])
1774  def test_AndroidDevice_wait_for_completion_completed(
1775      self,
1776      MockTime,
1777      MockSleep,
1778      MockIsBootCompleted,
1779      FastbootProxy,
1780      MockAdbProxy,
1781  ):
1782    ad = android_device.AndroidDevice(serial='1')
1783    raised = False
1784    try:
1785      ad.wait_for_boot_completion()
1786    except (adb.AdbError, adb.AdbTimeoutError):
1787      raised = True
1788    self.assertFalse(
1789        raised,
1790        'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.',
1791    )
1792
1793  @mock.patch(
1794      'mobly.controllers.android_device_lib.adb.AdbProxy',
1795      return_value=mock_android_device.MockAdbProxy('1'),
1796  )
1797  @mock.patch(
1798      'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
1799      return_value=mock_android_device.MockFastbootProxy('1'),
1800  )
1801  @mock.patch(
1802      'mobly.controllers.android_device.AndroidDevice.is_boot_completed',
1803      side_effect=[
1804          False,
1805          False,
1806          adb.AdbTimeoutError(
1807              ['adb', 'shell', 'getprop sys.boot_completed'],
1808              timeout=5,
1809              serial=1,
1810          ),
1811          False,
1812          False,
1813          False,
1814          False,
1815      ],
1816  )
1817  @mock.patch('time.sleep', return_value=None)
1818  @mock.patch('time.perf_counter', side_effect=[0, 5, 10, 15, 20, 25, 30])
1819  def test_AndroidDevice_wait_for_completion_never_boot(
1820      self,
1821      MockTime,
1822      MockSleep,
1823      MockIsBootCompleted,
1824      FastbootProxy,
1825      MockAdbProxy,
1826  ):
1827    ad = android_device.AndroidDevice(serial='1')
1828    raised = False
1829    try:
1830      with self.assertRaises(android_device.DeviceError):
1831        ad.wait_for_boot_completion(timeout=20)
1832    except (adb.AdbError, adb.AdbTimeoutError):
1833      raised = True
1834    self.assertFalse(
1835        raised,
1836        'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.',
1837    )
1838
1839  def test_AndroidDevice_parse_device_list_when_decode_error(self):
1840    gbk_str = b'\xc4\xe3\xba\xc3'
1841    raised = False
1842    try:
1843      android_device.parse_device_list(gbk_str, 'some_key')
1844    except UnicodeDecodeError:
1845      raised = True
1846    self.assertTrue(raised, 'did not raise an exception when parsing gbk bytes')
1847
1848
1849if __name__ == '__main__':
1850  unittest.main()
1851