1#!/usr/bin/env python
2# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""
7Unit tests for the contents of device_utils.py (mostly DeviceUtils).
8"""
9
10# pylint: disable=protected-access
11# pylint: disable=unused-argument
12
13import contextlib
14import json
15import logging
16import os
17import stat
18import unittest
19
20from devil import devil_env
21from devil.android import device_errors
22from devil.android import device_signal
23from devil.android import device_utils
24from devil.android.sdk import adb_wrapper
25from devil.android.sdk import intent
26from devil.android.sdk import keyevent
27from devil.android.sdk import version_codes
28from devil.utils import cmd_helper
29from devil.utils import mock_calls
30
31with devil_env.SysPath(devil_env.PYMOCK_PATH):
32  import mock  # pylint: disable=import-error
33
34
35def Process(name, pid, ppid='1'):
36  return device_utils.ProcessInfo(name=name, pid=pid, ppid=ppid)
37
38
39def Processes(*args):
40  return [Process(*arg) for arg in args]
41
42
43class AnyStringWith(object):
44  def __init__(self, value):
45    self._value = value
46
47  def __eq__(self, other):
48    return self._value in other
49
50  def __repr__(self):
51    return '<AnyStringWith: %s>' % self._value
52
53
54class _MockApkHelper(object):
55
56  def __init__(self, path, package_name, perms=None):
57    self.path = path
58    self.package_name = package_name
59    self.perms = perms
60
61  def GetPackageName(self):
62    return self.package_name
63
64  def GetPermissions(self):
65    return self.perms
66
67
68class _MockMultipleDevicesError(Exception):
69  pass
70
71
72class DeviceUtilsInitTest(unittest.TestCase):
73
74  def testInitWithStr(self):
75    serial_as_str = str('0123456789abcdef')
76    d = device_utils.DeviceUtils('0123456789abcdef')
77    self.assertEqual(serial_as_str, d.adb.GetDeviceSerial())
78
79  def testInitWithUnicode(self):
80    serial_as_unicode = unicode('fedcba9876543210')
81    d = device_utils.DeviceUtils(serial_as_unicode)
82    self.assertEqual(serial_as_unicode, d.adb.GetDeviceSerial())
83
84  def testInitWithAdbWrapper(self):
85    serial = '123456789abcdef0'
86    a = adb_wrapper.AdbWrapper(serial)
87    d = device_utils.DeviceUtils(a)
88    self.assertEqual(serial, d.adb.GetDeviceSerial())
89
90  def testInitWithMissing_fails(self):
91    with self.assertRaises(ValueError):
92      device_utils.DeviceUtils(None)
93    with self.assertRaises(ValueError):
94      device_utils.DeviceUtils('')
95
96
97class DeviceUtilsGetAVDsTest(mock_calls.TestCase):
98
99  def testGetAVDs(self):
100    mocked_attrs = {
101      'android_sdk': '/my/sdk/path'
102    }
103    with mock.patch('devil.devil_env._Environment.LocalPath',
104                    mock.Mock(side_effect=lambda a: mocked_attrs[a])):
105      with self.assertCall(
106          mock.call.devil.utils.cmd_helper.GetCmdOutput(
107              [mock.ANY, 'list', 'avd']),
108          'Available Android Virtual Devices:\n'
109          '    Name: my_android5.0\n'
110          '    Path: /some/path/to/.android/avd/my_android5.0.avd\n'
111          '  Target: Android 5.0 (API level 21)\n'
112          ' Tag/ABI: default/x86\n'
113          '    Skin: WVGA800\n'):
114        self.assertEquals(['my_android5.0'], device_utils.GetAVDs())
115
116
117class DeviceUtilsRestartServerTest(mock_calls.TestCase):
118
119  @mock.patch('time.sleep', mock.Mock())
120  def testRestartServer_succeeds(self):
121    with self.assertCalls(
122        mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.KillServer(),
123        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
124            ['pgrep', 'adb']),
125         (1, '')),
126        mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.StartServer(),
127        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
128            ['pgrep', 'adb']),
129         (1, '')),
130        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
131            ['pgrep', 'adb']),
132         (0, '123\n'))):
133      device_utils.RestartServer()
134
135
136class MockTempFile(object):
137
138  def __init__(self, name='/tmp/some/file'):
139    self.file = mock.MagicMock(spec=file)
140    self.file.name = name
141    self.file.name_quoted = cmd_helper.SingleQuote(name)
142
143  def __enter__(self):
144    return self.file
145
146  def __exit__(self, exc_type, exc_val, exc_tb):
147    pass
148
149  @property
150  def name(self):
151    return self.file.name
152
153
154class MockLogger(mock.Mock):
155  def __init__(self, *args, **kwargs):
156    super(MockLogger, self).__init__(*args, **kwargs)
157    # TODO(perezju): Consider adding traps for error, info, etc.
158    self.warnings = []
159
160  def warning(self, message, *args):
161    self.warnings.append(message % args)
162
163
164def PatchLogger():
165  return mock.patch(
166      'devil.android.device_utils.logger', new_callable=MockLogger)
167
168
169class _PatchedFunction(object):
170
171  def __init__(self, patched=None, mocked=None):
172    self.patched = patched
173    self.mocked = mocked
174
175
176def _AdbWrapperMock(test_serial, is_ready=True):
177  adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
178  adb.__str__ = mock.Mock(return_value=test_serial)
179  adb.GetDeviceSerial.return_value = test_serial
180  adb.is_ready = is_ready
181  return adb
182
183
184class DeviceUtilsTest(mock_calls.TestCase):
185
186  def setUp(self):
187    self.adb = _AdbWrapperMock('0123456789abcdef')
188    self.device = device_utils.DeviceUtils(
189        self.adb, default_timeout=10, default_retries=0)
190    self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
191
192  def AdbCommandError(self, args=None, output=None, status=None, msg=None):
193    if args is None:
194      args = ['[unspecified]']
195    return mock.Mock(side_effect=device_errors.AdbCommandFailedError(
196        args, output, status, msg, str(self.device)))
197
198  def CommandError(self, msg=None):
199    if msg is None:
200      msg = 'Command failed'
201    return mock.Mock(side_effect=device_errors.CommandFailedError(
202        msg, str(self.device)))
203
204  def ShellError(self, output=None, status=1):
205    def action(cmd, *args, **kwargs):
206      raise device_errors.AdbShellCommandFailedError(
207          cmd, output, status, str(self.device))
208    if output is None:
209      output = 'Permission denied\n'
210    return action
211
212  def TimeoutError(self, msg=None):
213    if msg is None:
214      msg = 'Operation timed out'
215    return mock.Mock(side_effect=device_errors.CommandTimeoutError(
216        msg, str(self.device)))
217
218  def EnsureCacheInitialized(self, props=None, sdcard='/sdcard'):
219    props = props or []
220    ret = [sdcard, 'TOKEN'] + props
221    return (self.call.device.RunShellCommand(
222        AnyStringWith('getprop'),
223        shell=True, check_return=True, large_output=True), ret)
224
225
226class DeviceUtilsEqTest(DeviceUtilsTest):
227
228  def testEq_equal_deviceUtils(self):
229    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
230    self.assertTrue(self.device == other)
231    self.assertTrue(other == self.device)
232
233  def testEq_equal_adbWrapper(self):
234    other = adb_wrapper.AdbWrapper('0123456789abcdef')
235    self.assertTrue(self.device == other)
236    self.assertTrue(other == self.device)
237
238  def testEq_equal_string(self):
239    other = '0123456789abcdef'
240    self.assertTrue(self.device == other)
241    self.assertTrue(other == self.device)
242
243  def testEq_devicesNotEqual(self):
244    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee'))
245    self.assertFalse(self.device == other)
246    self.assertFalse(other == self.device)
247
248  def testEq_identity(self):
249    self.assertTrue(self.device == self.device)
250
251  def testEq_serialInList(self):
252    devices = [self.device]
253    self.assertTrue('0123456789abcdef' in devices)
254
255
256class DeviceUtilsLtTest(DeviceUtilsTest):
257
258  def testLt_lessThan(self):
259    other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff'))
260    self.assertTrue(self.device < other)
261    self.assertTrue(other > self.device)
262
263  def testLt_greaterThan_lhs(self):
264    other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000'))
265    self.assertFalse(self.device < other)
266    self.assertFalse(other > self.device)
267
268  def testLt_equal(self):
269    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
270    self.assertFalse(self.device < other)
271    self.assertFalse(other > self.device)
272
273  def testLt_sorted(self):
274    devices = [
275        device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')),
276        device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')),
277    ]
278    sorted_devices = sorted(devices)
279    self.assertEquals('0000000000000000',
280                      sorted_devices[0].adb.GetDeviceSerial())
281    self.assertEquals('ffffffffffffffff',
282                      sorted_devices[1].adb.GetDeviceSerial())
283
284
285class DeviceUtilsStrTest(DeviceUtilsTest):
286
287  def testStr_returnsSerial(self):
288    with self.assertCalls(
289        (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
290      self.assertEqual('0123456789abcdef', str(self.device))
291
292
293class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
294
295  def testIsOnline_true(self):
296    with self.assertCall(self.call.adb.GetState(), 'device'):
297      self.assertTrue(self.device.IsOnline())
298
299  def testIsOnline_false(self):
300    with self.assertCall(self.call.adb.GetState(), 'offline'):
301      self.assertFalse(self.device.IsOnline())
302
303  def testIsOnline_error(self):
304    with self.assertCall(self.call.adb.GetState(), self.CommandError()):
305      self.assertFalse(self.device.IsOnline())
306
307
308class DeviceUtilsHasRootTest(DeviceUtilsTest):
309
310  def testHasRoot_true(self):
311    with self.patch_call(self.call.device.product_name,
312                          return_value='notasailfish'), (
313        self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n')):
314      self.assertTrue(self.device.HasRoot())
315
316  def testhasRootSpecial_true(self):
317    with self.patch_call(self.call.device.product_name,
318                         return_value='sailfish'), (
319        self.assertCall(self.call.adb.Shell('getprop service.adb.root'),
320                        '1\n')):
321      self.assertTrue(self.device.HasRoot())
322
323  def testHasRoot_false(self):
324    with self.patch_call(self.call.device.product_name,
325                         return_value='notasailfish'), (
326        self.assertCall(self.call.adb.Shell('ls /root'),
327                        self.ShellError())):
328      self.assertFalse(self.device.HasRoot())
329
330  def testHasRootSpecial_false(self):
331    with self.patch_call(self.call.device.product_name,
332                         return_value='sailfish'), (
333        self.assertCall(self.call.adb.Shell('getprop service.adb.root'),
334                        '\n')):
335      self.assertFalse(self.device.HasRoot())
336
337
338class DeviceUtilsEnableRootTest(DeviceUtilsTest):
339
340  def testEnableRoot_succeeds(self):
341    with self.assertCalls(
342        self.call.adb.Root(),
343        self.call.adb.WaitForDevice(),
344        (self.call.device.GetProp('service.adb.root', cache=False), '1')):
345      self.device.EnableRoot()
346
347  def testEnableRoot_userBuild(self):
348    with self.assertCalls(
349        (self.call.adb.Root(), self.AdbCommandError()),
350        (self.call.device.IsUserBuild(), True)):
351      with self.assertRaises(device_errors.CommandFailedError):
352        self.device.EnableRoot()
353
354  def testEnableRoot_rootFails(self):
355    with self.assertCalls(
356        (self.call.adb.Root(), self.AdbCommandError()),
357        (self.call.device.IsUserBuild(), False)):
358      with self.assertRaises(device_errors.AdbCommandFailedError):
359        self.device.EnableRoot()
360
361
362class DeviceUtilsIsUserBuildTest(DeviceUtilsTest):
363
364  def testIsUserBuild_yes(self):
365    with self.assertCall(
366        self.call.device.GetProp('ro.build.type', cache=True), 'user'):
367      self.assertTrue(self.device.IsUserBuild())
368
369  def testIsUserBuild_no(self):
370    with self.assertCall(
371        self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'):
372      self.assertFalse(self.device.IsUserBuild())
373
374
375class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest):
376
377  def testGetExternalStoragePath_succeeds(self):
378    with self.assertCalls(
379        self.EnsureCacheInitialized(sdcard='/fake/storage/path')):
380      self.assertEquals('/fake/storage/path',
381                        self.device.GetExternalStoragePath())
382
383  def testGetExternalStoragePath_fails(self):
384    with self.assertCalls(
385        self.EnsureCacheInitialized(sdcard='')):
386      with self.assertRaises(device_errors.CommandFailedError):
387        self.device.GetExternalStoragePath()
388
389
390class DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest):
391
392  def testGetApplicationPathsInternal_exists(self):
393    with self.assertCalls(
394        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
395        (self.call.device.RunShellCommand(
396            ['pm', 'path', 'android'], check_return=True),
397         ['package:/path/to/android.apk'])):
398      self.assertEquals(['/path/to/android.apk'],
399                        self.device._GetApplicationPathsInternal('android'))
400
401  def testGetApplicationPathsInternal_notExists(self):
402    with self.assertCalls(
403        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
404        (self.call.device.RunShellCommand(
405            ['pm', 'path', 'not.installed.app'], check_return=True),
406         '')):
407      self.assertEquals([],
408          self.device._GetApplicationPathsInternal('not.installed.app'))
409
410  def testGetApplicationPathsInternal_garbageOutputRaises(self):
411    with self.assertCalls(
412        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
413        (self.call.device.RunShellCommand(
414            ['pm', 'path', 'android'], check_return=True),
415         ['garbage first line'])):
416      with self.assertRaises(device_errors.CommandFailedError):
417        self.device._GetApplicationPathsInternal('android')
418
419  def testGetApplicationPathsInternal_outputWarningsIgnored(self):
420    with self.assertCalls(
421        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
422        (self.call.device.RunShellCommand(
423            ['pm', 'path', 'not.installed.app'], check_return=True),
424         ['WARNING: some warning message from pm'])):
425      self.assertEquals([],
426          self.device._GetApplicationPathsInternal('not.installed.app'))
427
428  def testGetApplicationPathsInternal_fails(self):
429    with self.assertCalls(
430        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
431        (self.call.device.RunShellCommand(
432            ['pm', 'path', 'android'], check_return=True),
433         self.CommandError('ERROR. Is package manager running?\n'))):
434      with self.assertRaises(device_errors.CommandFailedError):
435        self.device._GetApplicationPathsInternal('android')
436
437
438class DeviceUtils_GetApplicationVersionTest(DeviceUtilsTest):
439
440  def test_GetApplicationVersion_exists(self):
441    with self.assertCalls(
442        (self.call.adb.Shell('dumpsys package com.android.chrome'),
443         'Packages:\n'
444         '  Package [com.android.chrome] (3901ecfb):\n'
445         '    userId=1234 gids=[123, 456, 789]\n'
446         '    pkg=Package{1fecf634 com.android.chrome}\n'
447         '    versionName=45.0.1234.7\n')):
448      self.assertEquals('45.0.1234.7',
449                        self.device.GetApplicationVersion('com.android.chrome'))
450
451  def test_GetApplicationVersion_notExists(self):
452    with self.assertCalls(
453        (self.call.adb.Shell('dumpsys package com.android.chrome'), '')):
454      self.assertEquals(None,
455                        self.device.GetApplicationVersion('com.android.chrome'))
456
457  def test_GetApplicationVersion_fails(self):
458    with self.assertCalls(
459        (self.call.adb.Shell('dumpsys package com.android.chrome'),
460         'Packages:\n'
461         '  Package [com.android.chrome] (3901ecfb):\n'
462         '    userId=1234 gids=[123, 456, 789]\n'
463         '    pkg=Package{1fecf634 com.android.chrome}\n')):
464      with self.assertRaises(device_errors.CommandFailedError):
465        self.device.GetApplicationVersion('com.android.chrome')
466
467
468class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest):
469
470  def testGetApplicationDataDirectory_exists(self):
471    with self.assertCall(
472        self.call.device._RunPipedShellCommand(
473            'pm dump foo.bar.baz | grep dataDir='),
474        ['dataDir=/data/data/foo.bar.baz']):
475      self.assertEquals(
476          '/data/data/foo.bar.baz',
477          self.device.GetApplicationDataDirectory('foo.bar.baz'))
478
479  def testGetApplicationDataDirectory_notExists(self):
480    with self.assertCall(
481        self.call.device._RunPipedShellCommand(
482            'pm dump foo.bar.baz | grep dataDir='),
483        self.ShellError()):
484      with self.assertRaises(device_errors.CommandFailedError):
485        self.device.GetApplicationDataDirectory('foo.bar.baz')
486
487
488@mock.patch('time.sleep', mock.Mock())
489class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest):
490
491  def testWaitUntilFullyBooted_succeedsNoWifi(self):
492    with self.assertCalls(
493        self.call.adb.WaitForDevice(),
494        # sd_card_ready
495        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
496        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
497        # pm_ready
498        (self.call.device._GetApplicationPathsInternal('android',
499                                                       skip_cache=True),
500         ['package:/some/fake/path']),
501        # boot_completed
502        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
503      self.device.WaitUntilFullyBooted(wifi=False)
504
505  def testWaitUntilFullyBooted_succeedsWithWifi(self):
506    with self.assertCalls(
507        self.call.adb.WaitForDevice(),
508        # sd_card_ready
509        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
510        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
511        # pm_ready
512        (self.call.device._GetApplicationPathsInternal('android',
513                                                       skip_cache=True),
514         ['package:/some/fake/path']),
515        # boot_completed
516        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
517        # wifi_enabled
518        (self.call.adb.Shell('dumpsys wifi'),
519         'stuff\nWi-Fi is enabled\nmore stuff\n')):
520      self.device.WaitUntilFullyBooted(wifi=True)
521
522  def testWaitUntilFullyBooted_deviceNotInitiallyAvailable(self):
523    with self.assertCalls(
524        self.call.adb.WaitForDevice(),
525        # sd_card_ready
526        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
527        # sd_card_ready
528        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
529        # sd_card_ready
530        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
531        # sd_card_ready
532        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
533        # sd_card_ready
534        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
535        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
536        # pm_ready
537        (self.call.device._GetApplicationPathsInternal('android',
538                                                       skip_cache=True),
539         ['package:/some/fake/path']),
540        # boot_completed
541        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
542      self.device.WaitUntilFullyBooted(wifi=False)
543
544  def testWaitUntilFullyBooted_deviceBrieflyOffline(self):
545    with self.assertCalls(
546        self.call.adb.WaitForDevice(),
547        # sd_card_ready
548        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
549        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
550        # pm_ready
551        (self.call.device._GetApplicationPathsInternal('android',
552                                                       skip_cache=True),
553         ['package:/some/fake/path']),
554        # boot_completed
555        (self.call.device.GetProp('sys.boot_completed', cache=False),
556         self.AdbCommandError()),
557        # boot_completed
558        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
559      self.device.WaitUntilFullyBooted(wifi=False)
560
561  def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
562    with self.assertCalls(
563        self.call.adb.WaitForDevice(),
564        # sd_card_ready
565        (self.call.device.GetExternalStoragePath(), self.CommandError())):
566      with self.assertRaises(device_errors.CommandFailedError):
567        self.device.WaitUntilFullyBooted(wifi=False)
568
569  def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self):
570    with self.assertCalls(
571        self.call.adb.WaitForDevice(),
572        # sd_card_ready
573        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
574        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
575        # sd_card_ready
576        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
577        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
578        # sd_card_ready
579        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
580        (self.call.adb.Shell('test -d /fake/storage/path'),
581         self.TimeoutError())):
582      with self.assertRaises(device_errors.CommandTimeoutError):
583        self.device.WaitUntilFullyBooted(wifi=False)
584
585  def testWaitUntilFullyBooted_devicePmFails(self):
586    with self.assertCalls(
587        self.call.adb.WaitForDevice(),
588        # sd_card_ready
589        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
590        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
591        # pm_ready
592        (self.call.device._GetApplicationPathsInternal('android',
593                                                       skip_cache=True),
594         self.CommandError()),
595        # pm_ready
596        (self.call.device._GetApplicationPathsInternal('android',
597                                                       skip_cache=True),
598         self.CommandError()),
599        # pm_ready
600        (self.call.device._GetApplicationPathsInternal('android',
601                                                       skip_cache=True),
602         self.TimeoutError())):
603      with self.assertRaises(device_errors.CommandTimeoutError):
604        self.device.WaitUntilFullyBooted(wifi=False)
605
606  def testWaitUntilFullyBooted_bootFails(self):
607    with self.assertCalls(
608        self.call.adb.WaitForDevice(),
609        # sd_card_ready
610        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
611        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
612        # pm_ready
613        (self.call.device._GetApplicationPathsInternal('android',
614                                                       skip_cache=True),
615         ['package:/some/fake/path']),
616        # boot_completed
617        (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
618        # boot_completed
619        (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
620        # boot_completed
621        (self.call.device.GetProp('sys.boot_completed', cache=False),
622         self.TimeoutError())):
623      with self.assertRaises(device_errors.CommandTimeoutError):
624        self.device.WaitUntilFullyBooted(wifi=False)
625
626  def testWaitUntilFullyBooted_wifiFails(self):
627    with self.assertCalls(
628        self.call.adb.WaitForDevice(),
629        # sd_card_ready
630        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
631        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
632        # pm_ready
633        (self.call.device._GetApplicationPathsInternal('android',
634                                                       skip_cache=True),
635         ['package:/some/fake/path']),
636        # boot_completed
637        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
638        # wifi_enabled
639        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
640        # wifi_enabled
641        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
642        # wifi_enabled
643        (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())):
644      with self.assertRaises(device_errors.CommandTimeoutError):
645        self.device.WaitUntilFullyBooted(wifi=True)
646
647
648@mock.patch('time.sleep', mock.Mock())
649class DeviceUtilsRebootTest(DeviceUtilsTest):
650
651  def testReboot_nonBlocking(self):
652    with self.assertCalls(
653        self.call.adb.Reboot(),
654        (self.call.device.IsOnline(), True),
655        (self.call.device.IsOnline(), False)):
656      self.device.Reboot(block=False)
657
658  def testReboot_blocking(self):
659    with self.assertCalls(
660        self.call.adb.Reboot(),
661        (self.call.device.IsOnline(), True),
662        (self.call.device.IsOnline(), False),
663        self.call.device.WaitUntilFullyBooted(wifi=False)):
664      self.device.Reboot(block=True)
665
666  def testReboot_blockUntilWifi(self):
667    with self.assertCalls(
668        self.call.adb.Reboot(),
669        (self.call.device.IsOnline(), True),
670        (self.call.device.IsOnline(), False),
671        self.call.device.WaitUntilFullyBooted(wifi=True)):
672      self.device.Reboot(block=True, wifi=True)
673
674
675class DeviceUtilsInstallTest(DeviceUtilsTest):
676
677  mock_apk = _MockApkHelper('/fake/test/app.apk', 'test.package', ['p1'])
678
679  def testInstall_noPriorInstall(self):
680    with self.patch_call(self.call.device.build_version_sdk, return_value=23):
681      with self.assertCalls(
682          (mock.call.os.path.exists('/fake/test/app.apk'), True),
683          (self.call.device._GetApplicationPathsInternal('test.package'), []),
684          self.call.adb.Install('/fake/test/app.apk', reinstall=False,
685                                allow_downgrade=False),
686          (self.call.device.GrantPermissions('test.package', ['p1']), [])):
687        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
688
689  def testInstall_permissionsPreM(self):
690    with self.patch_call(self.call.device.build_version_sdk, return_value=20):
691      with self.assertCalls(
692          (mock.call.os.path.exists('/fake/test/app.apk'), True),
693          (self.call.device._GetApplicationPathsInternal('test.package'), []),
694          (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
695                                 allow_downgrade=False))):
696        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
697
698  def testInstall_findPermissions(self):
699    with self.patch_call(self.call.device.build_version_sdk, return_value=23):
700      with self.assertCalls(
701          (mock.call.os.path.exists('/fake/test/app.apk'), True),
702          (self.call.device._GetApplicationPathsInternal('test.package'), []),
703          (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
704                                 allow_downgrade=False)),
705          (self.call.device.GrantPermissions('test.package', ['p1']), [])):
706        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
707
708  def testInstall_passPermissions(self):
709    with self.assertCalls(
710        (mock.call.os.path.exists('/fake/test/app.apk'), True),
711        (self.call.device._GetApplicationPathsInternal('test.package'), []),
712        (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
713                               allow_downgrade=False)),
714        (self.call.device.GrantPermissions('test.package', ['p1', 'p2']), [])):
715      self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
716                          permissions=['p1', 'p2'])
717
718  def testInstall_differentPriorInstall(self):
719    with self.assertCalls(
720        (mock.call.os.path.exists('/fake/test/app.apk'), True),
721        (self.call.device._GetApplicationPathsInternal('test.package'),
722         ['/fake/data/app/test.package.apk']),
723        (self.call.device._ComputeStaleApks('test.package',
724            ['/fake/test/app.apk']),
725         (['/fake/test/app.apk'], None)),
726        self.call.device.Uninstall('test.package'),
727        self.call.adb.Install('/fake/test/app.apk', reinstall=False,
728                              allow_downgrade=False)):
729      self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
730                          permissions=[])
731
732  def testInstall_differentPriorInstall_reinstall(self):
733    with self.assertCalls(
734        (mock.call.os.path.exists('/fake/test/app.apk'), True),
735        (self.call.device._GetApplicationPathsInternal('test.package'),
736         ['/fake/data/app/test.package.apk']),
737        (self.call.device._ComputeStaleApks('test.package',
738            ['/fake/test/app.apk']),
739         (['/fake/test/app.apk'], None)),
740        self.call.adb.Install('/fake/test/app.apk', reinstall=True,
741                              allow_downgrade=False)):
742      self.device.Install(DeviceUtilsInstallTest.mock_apk,
743          reinstall=True, retries=0, permissions=[])
744
745  def testInstall_identicalPriorInstall_reinstall(self):
746    with self.assertCalls(
747        (mock.call.os.path.exists('/fake/test/app.apk'), True),
748        (self.call.device._GetApplicationPathsInternal('test.package'),
749         ['/fake/data/app/test.package.apk']),
750        (self.call.device._ComputeStaleApks('test.package',
751            ['/fake/test/app.apk']),
752         ([], None)),
753        (self.call.device.ForceStop('test.package'))):
754      self.device.Install(DeviceUtilsInstallTest.mock_apk,
755          reinstall=True, retries=0, permissions=[])
756
757  def testInstall_missingApk(self):
758    with self.assertCalls(
759        (mock.call.os.path.exists('/fake/test/app.apk'), False)):
760      with self.assertRaises(device_errors.CommandFailedError):
761        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
762
763  def testInstall_fails(self):
764    with self.assertCalls(
765        (mock.call.os.path.exists('/fake/test/app.apk'), True),
766        (self.call.device._GetApplicationPathsInternal('test.package'), []),
767        (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
768                               allow_downgrade=False),
769         self.CommandError('Failure\r\n'))):
770      with self.assertRaises(device_errors.CommandFailedError):
771        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
772
773  def testInstall_downgrade(self):
774    with self.assertCalls(
775        (mock.call.os.path.exists('/fake/test/app.apk'), True),
776        (self.call.device._GetApplicationPathsInternal('test.package'),
777         ['/fake/data/app/test.package.apk']),
778        (self.call.device._ComputeStaleApks('test.package',
779            ['/fake/test/app.apk']),
780         (['/fake/test/app.apk'], None)),
781        self.call.adb.Install('/fake/test/app.apk', reinstall=True,
782                              allow_downgrade=True)):
783      self.device.Install(DeviceUtilsInstallTest.mock_apk,
784          reinstall=True, retries=0, permissions=[], allow_downgrade=True)
785
786
787class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest):
788
789  mock_apk = _MockApkHelper('base.apk', 'test.package', ['p1'])
790
791  def testInstallSplitApk_noPriorInstall(self):
792    with self.assertCalls(
793        (self.call.device._CheckSdkLevel(21)),
794        (mock.call.devil.android.sdk.split_select.SelectSplits(
795            self.device, 'base.apk',
796            ['split1.apk', 'split2.apk', 'split3.apk'],
797            allow_cached_props=False),
798         ['split2.apk']),
799        (mock.call.os.path.exists('base.apk'), True),
800        (mock.call.os.path.exists('split2.apk'), True),
801        (self.call.device._GetApplicationPathsInternal('test.package'), []),
802        (self.call.adb.InstallMultiple(
803            ['base.apk', 'split2.apk'], partial=None, reinstall=False,
804            allow_downgrade=False))):
805      self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
806          ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[], retries=0)
807
808  def testInstallSplitApk_partialInstall(self):
809    with self.assertCalls(
810        (self.call.device._CheckSdkLevel(21)),
811        (mock.call.devil.android.sdk.split_select.SelectSplits(
812            self.device, 'base.apk',
813            ['split1.apk', 'split2.apk', 'split3.apk'],
814            allow_cached_props=False),
815         ['split2.apk']),
816        (mock.call.os.path.exists('base.apk'), True),
817        (mock.call.os.path.exists('split2.apk'), True),
818        (self.call.device._GetApplicationPathsInternal('test.package'),
819         ['base-on-device.apk', 'split2-on-device.apk']),
820        (self.call.device._ComputeStaleApks('test.package',
821                                            ['base.apk', 'split2.apk']),
822         (['split2.apk'], None)),
823        (self.call.adb.InstallMultiple(
824            ['split2.apk'], partial='test.package', reinstall=True,
825            allow_downgrade=False))):
826      self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
827                                  ['split1.apk', 'split2.apk', 'split3.apk'],
828                                  reinstall=True, permissions=[], retries=0)
829
830  def testInstallSplitApk_downgrade(self):
831    with self.assertCalls(
832        (self.call.device._CheckSdkLevel(21)),
833        (mock.call.devil.android.sdk.split_select.SelectSplits(
834            self.device, 'base.apk',
835            ['split1.apk', 'split2.apk', 'split3.apk'],
836            allow_cached_props=False),
837         ['split2.apk']),
838        (mock.call.os.path.exists('base.apk'), True),
839        (mock.call.os.path.exists('split2.apk'), True),
840        (self.call.device._GetApplicationPathsInternal('test.package'),
841         ['base-on-device.apk', 'split2-on-device.apk']),
842        (self.call.device._ComputeStaleApks('test.package',
843                                            ['base.apk', 'split2.apk']),
844         (['split2.apk'], None)),
845        (self.call.adb.InstallMultiple(
846            ['split2.apk'], partial='test.package', reinstall=True,
847            allow_downgrade=True))):
848      self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
849                                  ['split1.apk', 'split2.apk', 'split3.apk'],
850                                  reinstall=True, permissions=[], retries=0,
851                                  allow_downgrade=True)
852
853  def testInstallSplitApk_missingSplit(self):
854    with self.assertCalls(
855        (self.call.device._CheckSdkLevel(21)),
856        (mock.call.devil.android.sdk.split_select.SelectSplits(
857            self.device, 'base.apk',
858            ['split1.apk', 'split2.apk', 'split3.apk'],
859            allow_cached_props=False),
860         ['split2.apk']),
861        (mock.call.os.path.exists('base.apk'), True),
862        (mock.call.os.path.exists('split2.apk'), False)):
863      with self.assertRaises(device_errors.CommandFailedError):
864        self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
865            ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[],
866            retries=0)
867
868
869class DeviceUtilsUninstallTest(DeviceUtilsTest):
870
871  def testUninstall_callsThrough(self):
872    with self.assertCalls(
873        (self.call.device._GetApplicationPathsInternal('test.package'),
874         ['/path.apk']),
875        self.call.adb.Uninstall('test.package', True)):
876      self.device.Uninstall('test.package', True)
877
878  def testUninstall_noop(self):
879    with self.assertCalls(
880        (self.call.device._GetApplicationPathsInternal('test.package'), [])):
881      self.device.Uninstall('test.package', True)
882
883
884class DeviceUtilsSuTest(DeviceUtilsTest):
885
886  def testSu_preM(self):
887    with self.patch_call(
888        self.call.device.build_version_sdk,
889        return_value=version_codes.LOLLIPOP_MR1):
890      self.assertEquals('su -c foo', self.device._Su('foo'))
891
892  def testSu_mAndAbove(self):
893    with self.patch_call(
894        self.call.device.build_version_sdk,
895        return_value=version_codes.MARSHMALLOW):
896      self.assertEquals('su 0 foo', self.device._Su('foo'))
897
898
899class DeviceUtilsRunShellCommandTest(DeviceUtilsTest):
900
901  def setUp(self):
902    super(DeviceUtilsRunShellCommandTest, self).setUp()
903    self.device.NeedsSU = mock.Mock(return_value=False)
904
905  def testRunShellCommand_commandAsList(self):
906    with self.assertCall(self.call.adb.Shell('pm list packages'), ''):
907      self.device.RunShellCommand(
908          ['pm', 'list', 'packages'], check_return=True)
909
910  def testRunShellCommand_commandAsListQuoted(self):
911    with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''):
912      self.device.RunShellCommand(
913          ['echo', 'hello world', '$10'], check_return=True)
914
915  def testRunShellCommand_commandAsString(self):
916    with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''):
917      self.device.RunShellCommand(
918          'echo "$VAR"', shell=True, check_return=True)
919
920  def testNewRunShellImpl_withEnv(self):
921    with self.assertCall(
922        self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''):
923      self.device.RunShellCommand(
924          'echo "$VAR"', shell=True, check_return=True,
925          env={'VAR': 'some_string'})
926
927  def testNewRunShellImpl_withEnvQuoted(self):
928    with self.assertCall(
929        self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''):
930      self.device.RunShellCommand(
931          ['run_this'], check_return=True, env={'PATH': '$PATH:/other/path'})
932
933  def testNewRunShellImpl_withEnv_failure(self):
934    with self.assertRaises(KeyError):
935      self.device.RunShellCommand(
936          ['some_cmd'], check_return=True, env={'INVALID NAME': 'value'})
937
938  def testNewRunShellImpl_withCwd(self):
939    with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''):
940      self.device.RunShellCommand(
941          ['ls'], check_return=True, cwd='/some/test/path')
942
943  def testNewRunShellImpl_withCwdQuoted(self):
944    with self.assertCall(
945        self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''):
946      self.device.RunShellCommand(
947          ['ls'], check_return=True, cwd='/some test/path with/spaces')
948
949  def testRunShellCommand_withHugeCmd(self):
950    payload = 'hi! ' * 1024
951    expected_cmd = "echo '%s'" % payload
952    with self.assertCalls(
953      (mock.call.devil.android.device_temp_file.DeviceTempFile(
954          self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
955      self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd),
956      (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
957      self.assertEquals(
958          [payload],
959          self.device.RunShellCommand(['echo', payload], check_return=True))
960
961  def testRunShellCommand_withHugeCmdAndSu(self):
962    payload = 'hi! ' * 1024
963    expected_cmd_without_su = """sh -c 'echo '"'"'%s'"'"''""" % payload
964    expected_cmd = 'su -c %s' % expected_cmd_without_su
965    with self.assertCalls(
966      (self.call.device.NeedsSU(), True),
967      (self.call.device._Su(expected_cmd_without_su), expected_cmd),
968      (mock.call.devil.android.device_temp_file.DeviceTempFile(
969          self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
970      self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd),
971      (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
972      self.assertEquals(
973          [payload],
974          self.device.RunShellCommand(
975              ['echo', payload], check_return=True, as_root=True))
976
977  def testRunShellCommand_withSu(self):
978    expected_cmd_without_su = "sh -c 'setprop service.adb.root 0'"
979    expected_cmd = 'su -c %s' % expected_cmd_without_su
980    with self.assertCalls(
981        (self.call.device.NeedsSU(), True),
982        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
983        (self.call.adb.Shell(expected_cmd), '')):
984      self.device.RunShellCommand(
985          ['setprop', 'service.adb.root', '0'],
986          check_return=True, as_root=True)
987
988  def testRunShellCommand_withRunAs(self):
989    expected_cmd_without_run_as = "sh -c 'mkdir -p files'"
990    expected_cmd = (
991        'run-as org.devil.test_package %s' % expected_cmd_without_run_as)
992    with self.assertCall(self.call.adb.Shell(expected_cmd), ''):
993      self.device.RunShellCommand(
994          ['mkdir', '-p', 'files'],
995          check_return=True, run_as='org.devil.test_package')
996
997  def testRunShellCommand_withRunAsAndSu(self):
998    expected_cmd_with_nothing = "sh -c 'mkdir -p files'"
999    expected_cmd_with_run_as = (
1000        'run-as org.devil.test_package %s' % expected_cmd_with_nothing)
1001    expected_cmd_without_su = (
1002        'sh -c %s' % cmd_helper.SingleQuote(expected_cmd_with_run_as))
1003    expected_cmd = 'su -c %s' % expected_cmd_without_su
1004    with self.assertCalls(
1005        (self.call.device.NeedsSU(), True),
1006        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
1007        (self.call.adb.Shell(expected_cmd), '')):
1008      self.device.RunShellCommand(
1009          ['mkdir', '-p', 'files'],
1010          check_return=True, run_as='org.devil.test_package',
1011          as_root=True)
1012
1013  def testRunShellCommand_manyLines(self):
1014    cmd = 'ls /some/path'
1015    with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'):
1016      self.assertEquals(
1017          ['file1', 'file2', 'file3'],
1018          self.device.RunShellCommand(cmd.split(), check_return=True))
1019
1020  def testRunShellCommand_manyLinesRawOutput(self):
1021    cmd = 'ls /some/path'
1022    with self.assertCall(self.call.adb.Shell(cmd), '\rfile1\nfile2\r\nfile3\n'):
1023      self.assertEquals(
1024          '\rfile1\nfile2\r\nfile3\n',
1025          self.device.RunShellCommand(
1026              cmd.split(), check_return=True, raw_output=True))
1027
1028  def testRunShellCommand_singleLine_success(self):
1029    cmd = 'echo $VALUE'
1030    with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'):
1031      self.assertEquals(
1032          'some value',
1033          self.device.RunShellCommand(
1034              cmd, shell=True, check_return=True, single_line=True))
1035
1036  def testRunShellCommand_singleLine_successEmptyLine(self):
1037    cmd = 'echo $VALUE'
1038    with self.assertCall(self.call.adb.Shell(cmd), '\n'):
1039      self.assertEquals(
1040          '',
1041          self.device.RunShellCommand(
1042              cmd, shell=True, check_return=True, single_line=True))
1043
1044  def testRunShellCommand_singleLine_successWithoutEndLine(self):
1045    cmd = 'echo -n $VALUE'
1046    with self.assertCall(self.call.adb.Shell(cmd), 'some value'):
1047      self.assertEquals(
1048          'some value',
1049          self.device.RunShellCommand(
1050              cmd, shell=True, check_return=True, single_line=True))
1051
1052  def testRunShellCommand_singleLine_successNoOutput(self):
1053    cmd = 'echo -n $VALUE'
1054    with self.assertCall(self.call.adb.Shell(cmd), ''):
1055      self.assertEquals(
1056          '',
1057          self.device.RunShellCommand(
1058              cmd, shell=True, check_return=True, single_line=True))
1059
1060  def testRunShellCommand_singleLine_failTooManyLines(self):
1061    cmd = 'echo $VALUE'
1062    with self.assertCall(self.call.adb.Shell(cmd),
1063                         'some value\nanother value\n'):
1064      with self.assertRaises(device_errors.CommandFailedError):
1065        self.device.RunShellCommand(
1066            cmd, shell=True, check_return=True, single_line=True)
1067
1068  def testRunShellCommand_checkReturn_success(self):
1069    cmd = 'echo $ANDROID_DATA'
1070    output = '/data\n'
1071    with self.assertCall(self.call.adb.Shell(cmd), output):
1072      self.assertEquals(
1073          [output.rstrip()],
1074          self.device.RunShellCommand(cmd, shell=True, check_return=True))
1075
1076  def testRunShellCommand_checkReturn_failure(self):
1077    cmd = 'ls /root'
1078    output = 'opendir failed, Permission denied\n'
1079    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
1080      with self.assertRaises(device_errors.AdbCommandFailedError):
1081        self.device.RunShellCommand(cmd.split(), check_return=True)
1082
1083  def testRunShellCommand_checkReturn_disabled(self):
1084    cmd = 'ls /root'
1085    output = 'opendir failed, Permission denied\n'
1086    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
1087      self.assertEquals(
1088          [output.rstrip()],
1089          self.device.RunShellCommand(cmd.split(), check_return=False))
1090
1091  def testRunShellCommand_largeOutput_enabled(self):
1092    cmd = 'echo $VALUE'
1093    temp_file = MockTempFile('/sdcard/temp-123')
1094    cmd_redirect = '( %s )>%s 2>&1' % (cmd, temp_file.name)
1095    with self.assertCalls(
1096        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
1097            temp_file),
1098        (self.call.adb.Shell(cmd_redirect)),
1099        (self.call.device.ReadFile(temp_file.name, force_pull=True),
1100         'something')):
1101      self.assertEquals(
1102          ['something'],
1103          self.device.RunShellCommand(
1104              cmd, shell=True, large_output=True, check_return=True))
1105
1106  def testRunShellCommand_largeOutput_disabledNoTrigger(self):
1107    cmd = 'something'
1108    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError('')):
1109      with self.assertRaises(device_errors.AdbCommandFailedError):
1110        self.device.RunShellCommand([cmd], check_return=True)
1111
1112  def testRunShellCommand_largeOutput_disabledTrigger(self):
1113    cmd = 'echo $VALUE'
1114    temp_file = MockTempFile('/sdcard/temp-123')
1115    cmd_redirect = '( %s )>%s 2>&1' % (cmd, temp_file.name)
1116    with self.assertCalls(
1117        (self.call.adb.Shell(cmd), self.ShellError('', None)),
1118        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
1119            temp_file),
1120        (self.call.adb.Shell(cmd_redirect)),
1121        (self.call.device.ReadFile(mock.ANY, force_pull=True),
1122         'something')):
1123      self.assertEquals(
1124          ['something'],
1125          self.device.RunShellCommand(cmd, shell=True, check_return=True))
1126
1127
1128class DeviceUtilsRunPipedShellCommandTest(DeviceUtilsTest):
1129
1130  def testRunPipedShellCommand_success(self):
1131    with self.assertCall(
1132        self.call.device.RunShellCommand(
1133            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1134            shell=True, check_return=True),
1135        ['This line contains foo', 'PIPESTATUS: 0 0']):
1136      self.assertEquals(['This line contains foo'],
1137                        self.device._RunPipedShellCommand('ps | grep foo'))
1138
1139  def testRunPipedShellCommand_firstCommandFails(self):
1140    with self.assertCall(
1141        self.call.device.RunShellCommand(
1142            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1143            shell=True, check_return=True),
1144        ['PIPESTATUS: 1 0']):
1145      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
1146        self.device._RunPipedShellCommand('ps | grep foo')
1147      self.assertEquals([1, 0], ec.exception.status)
1148
1149  def testRunPipedShellCommand_secondCommandFails(self):
1150    with self.assertCall(
1151        self.call.device.RunShellCommand(
1152            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1153            shell=True, check_return=True),
1154        ['PIPESTATUS: 0 1']):
1155      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
1156        self.device._RunPipedShellCommand('ps | grep foo')
1157      self.assertEquals([0, 1], ec.exception.status)
1158
1159  def testRunPipedShellCommand_outputCutOff(self):
1160    with self.assertCall(
1161        self.call.device.RunShellCommand(
1162            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1163            shell=True, check_return=True),
1164        ['foo.bar'] * 256 + ['foo.ba']):
1165      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
1166        self.device._RunPipedShellCommand('ps | grep foo')
1167      self.assertIs(None, ec.exception.status)
1168
1169
1170@mock.patch('time.sleep', mock.Mock())
1171class DeviceUtilsKillAllTest(DeviceUtilsTest):
1172
1173  def testKillAll_noMatchingProcessesFailure(self):
1174    with self.assertCall(self.call.device.ListProcesses('test_process'), []):
1175      with self.assertRaises(device_errors.CommandFailedError):
1176        self.device.KillAll('test_process')
1177
1178  def testKillAll_noMatchingProcessesQuiet(self):
1179    with self.assertCall(self.call.device.ListProcesses('test_process'), []):
1180      self.assertEqual(0, self.device.KillAll('test_process', quiet=True))
1181
1182  def testKillAll_nonblocking(self):
1183    with self.assertCalls(
1184        (self.call.device.ListProcesses('some.process'),
1185         Processes(('some.process', 1234), ('some.process.thing', 5678))),
1186        (self.call.adb.Shell('kill -9 1234 5678'), '')):
1187      self.assertEquals(
1188          2, self.device.KillAll('some.process', blocking=False))
1189
1190  def testKillAll_blocking(self):
1191    with self.assertCalls(
1192        (self.call.device.ListProcesses('some.process'),
1193         Processes(('some.process', 1234), ('some.process.thing', 5678))),
1194        (self.call.adb.Shell('kill -9 1234 5678'), ''),
1195        (self.call.device.ListProcesses('some.process'),
1196         Processes(('some.process.thing', 5678))),
1197        (self.call.device.ListProcesses('some.process'),
1198         # Other instance with different pid.
1199         Processes(('some.process', 111)))):
1200      self.assertEquals(
1201          2, self.device.KillAll('some.process', blocking=True))
1202
1203  def testKillAll_exactNonblocking(self):
1204    with self.assertCalls(
1205        (self.call.device.ListProcesses('some.process'),
1206         Processes(('some.process', 1234), ('some.process.thing', 5678))),
1207        (self.call.adb.Shell('kill -9 1234'), '')):
1208      self.assertEquals(
1209          1, self.device.KillAll('some.process', exact=True, blocking=False))
1210
1211  def testKillAll_exactBlocking(self):
1212    with self.assertCalls(
1213        (self.call.device.ListProcesses('some.process'),
1214         Processes(('some.process', 1234), ('some.process.thing', 5678))),
1215        (self.call.adb.Shell('kill -9 1234'), ''),
1216        (self.call.device.ListProcesses('some.process'),
1217         Processes(('some.process', 1234), ('some.process.thing', 5678))),
1218        (self.call.device.ListProcesses('some.process'),
1219         Processes(('some.process.thing', 5678)))):
1220      self.assertEquals(
1221          1, self.device.KillAll('some.process', exact=True, blocking=True))
1222
1223  def testKillAll_root(self):
1224    with self.assertCalls(
1225        (self.call.device.ListProcesses('some.process'),
1226         Processes(('some.process', 1234))),
1227        (self.call.device.NeedsSU(), True),
1228        (self.call.device._Su("sh -c 'kill -9 1234'"),
1229         "su -c sh -c 'kill -9 1234'"),
1230        (self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')):
1231      self.assertEquals(
1232          1, self.device.KillAll('some.process', as_root=True))
1233
1234  def testKillAll_sigterm(self):
1235    with self.assertCalls(
1236        (self.call.device.ListProcesses('some.process'),
1237         Processes(('some.process', 1234))),
1238        (self.call.adb.Shell('kill -15 1234'), '')):
1239      self.assertEquals(
1240          1, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
1241
1242  def testKillAll_multipleInstances(self):
1243    with self.assertCalls(
1244        (self.call.device.ListProcesses('some.process'),
1245         Processes(('some.process', 1234), ('some.process', 4567))),
1246        (self.call.adb.Shell('kill -15 1234 4567'), '')):
1247      self.assertEquals(
1248          2, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
1249
1250
1251class DeviceUtilsStartActivityTest(DeviceUtilsTest):
1252
1253  def testStartActivity_actionOnly(self):
1254    test_intent = intent.Intent(action='android.intent.action.VIEW')
1255    with self.assertCall(
1256        self.call.adb.Shell('am start '
1257                            '-a android.intent.action.VIEW'),
1258        'Starting: Intent { act=android.intent.action.VIEW }'):
1259      self.device.StartActivity(test_intent)
1260
1261  def testStartActivity_success(self):
1262    test_intent = intent.Intent(action='android.intent.action.VIEW',
1263                                package='test.package',
1264                                activity='.Main')
1265    with self.assertCall(
1266        self.call.adb.Shell('am start '
1267                            '-a android.intent.action.VIEW '
1268                            '-n test.package/.Main'),
1269        'Starting: Intent { act=android.intent.action.VIEW }'):
1270      self.device.StartActivity(test_intent)
1271
1272  def testStartActivity_failure(self):
1273    test_intent = intent.Intent(action='android.intent.action.VIEW',
1274                                package='test.package',
1275                                activity='.Main')
1276    with self.assertCall(
1277        self.call.adb.Shell('am start '
1278                            '-a android.intent.action.VIEW '
1279                            '-n test.package/.Main'),
1280        'Error: Failed to start test activity'):
1281      with self.assertRaises(device_errors.CommandFailedError):
1282        self.device.StartActivity(test_intent)
1283
1284  def testStartActivity_blocking(self):
1285    test_intent = intent.Intent(action='android.intent.action.VIEW',
1286                                package='test.package',
1287                                activity='.Main')
1288    with self.assertCall(
1289        self.call.adb.Shell('am start '
1290                            '-W '
1291                            '-a android.intent.action.VIEW '
1292                            '-n test.package/.Main'),
1293        'Starting: Intent { act=android.intent.action.VIEW }'):
1294      self.device.StartActivity(test_intent, blocking=True)
1295
1296  def testStartActivity_withCategory(self):
1297    test_intent = intent.Intent(action='android.intent.action.VIEW',
1298                                package='test.package',
1299                                activity='.Main',
1300                                category='android.intent.category.HOME')
1301    with self.assertCall(
1302        self.call.adb.Shell('am start '
1303                            '-a android.intent.action.VIEW '
1304                            '-c android.intent.category.HOME '
1305                            '-n test.package/.Main'),
1306        'Starting: Intent { act=android.intent.action.VIEW }'):
1307      self.device.StartActivity(test_intent)
1308
1309  def testStartActivity_withMultipleCategories(self):
1310    test_intent = intent.Intent(action='android.intent.action.VIEW',
1311                                package='test.package',
1312                                activity='.Main',
1313                                category=['android.intent.category.HOME',
1314                                          'android.intent.category.BROWSABLE'])
1315    with self.assertCall(
1316        self.call.adb.Shell('am start '
1317                            '-a android.intent.action.VIEW '
1318                            '-c android.intent.category.HOME '
1319                            '-c android.intent.category.BROWSABLE '
1320                            '-n test.package/.Main'),
1321        'Starting: Intent { act=android.intent.action.VIEW }'):
1322      self.device.StartActivity(test_intent)
1323
1324  def testStartActivity_withData(self):
1325    test_intent = intent.Intent(action='android.intent.action.VIEW',
1326                                package='test.package',
1327                                activity='.Main',
1328                                data='http://www.google.com/')
1329    with self.assertCall(
1330        self.call.adb.Shell('am start '
1331                            '-a android.intent.action.VIEW '
1332                            '-d http://www.google.com/ '
1333                            '-n test.package/.Main'),
1334        'Starting: Intent { act=android.intent.action.VIEW }'):
1335      self.device.StartActivity(test_intent)
1336
1337  def testStartActivity_withStringExtra(self):
1338    test_intent = intent.Intent(action='android.intent.action.VIEW',
1339                                package='test.package',
1340                                activity='.Main',
1341                                extras={'foo': 'test'})
1342    with self.assertCall(
1343        self.call.adb.Shell('am start '
1344                            '-a android.intent.action.VIEW '
1345                            '-n test.package/.Main '
1346                            '--es foo test'),
1347        'Starting: Intent { act=android.intent.action.VIEW }'):
1348      self.device.StartActivity(test_intent)
1349
1350  def testStartActivity_withBoolExtra(self):
1351    test_intent = intent.Intent(action='android.intent.action.VIEW',
1352                                package='test.package',
1353                                activity='.Main',
1354                                extras={'foo': True})
1355    with self.assertCall(
1356        self.call.adb.Shell('am start '
1357                            '-a android.intent.action.VIEW '
1358                            '-n test.package/.Main '
1359                            '--ez foo True'),
1360        'Starting: Intent { act=android.intent.action.VIEW }'):
1361      self.device.StartActivity(test_intent)
1362
1363  def testStartActivity_withIntExtra(self):
1364    test_intent = intent.Intent(action='android.intent.action.VIEW',
1365                                package='test.package',
1366                                activity='.Main',
1367                                extras={'foo': 123})
1368    with self.assertCall(
1369        self.call.adb.Shell('am start '
1370                            '-a android.intent.action.VIEW '
1371                            '-n test.package/.Main '
1372                            '--ei foo 123'),
1373        'Starting: Intent { act=android.intent.action.VIEW }'):
1374      self.device.StartActivity(test_intent)
1375
1376  def testStartActivity_withTraceFile(self):
1377    test_intent = intent.Intent(action='android.intent.action.VIEW',
1378                                package='test.package',
1379                                activity='.Main')
1380    with self.assertCall(
1381        self.call.adb.Shell('am start '
1382                            '--start-profiler test_trace_file.out '
1383                            '-a android.intent.action.VIEW '
1384                            '-n test.package/.Main'),
1385        'Starting: Intent { act=android.intent.action.VIEW }'):
1386      self.device.StartActivity(test_intent,
1387                                trace_file_name='test_trace_file.out')
1388
1389  def testStartActivity_withForceStop(self):
1390    test_intent = intent.Intent(action='android.intent.action.VIEW',
1391                                package='test.package',
1392                                activity='.Main')
1393    with self.assertCall(
1394        self.call.adb.Shell('am start '
1395                            '-S '
1396                            '-a android.intent.action.VIEW '
1397                            '-n test.package/.Main'),
1398        'Starting: Intent { act=android.intent.action.VIEW }'):
1399      self.device.StartActivity(test_intent, force_stop=True)
1400
1401  def testStartActivity_withFlags(self):
1402    test_intent = intent.Intent(action='android.intent.action.VIEW',
1403                                package='test.package',
1404                                activity='.Main',
1405                                flags=[
1406                                  intent.FLAG_ACTIVITY_NEW_TASK,
1407                                  intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1408                                ])
1409    with self.assertCall(
1410        self.call.adb.Shell('am start '
1411                            '-a android.intent.action.VIEW '
1412                            '-n test.package/.Main '
1413                            '-f 0x10200000'),
1414        'Starting: Intent { act=android.intent.action.VIEW }'):
1415      self.device.StartActivity(test_intent)
1416
1417
1418class DeviceUtilsStartInstrumentationTest(DeviceUtilsTest):
1419
1420  def testStartInstrumentation_nothing(self):
1421    with self.assertCalls(
1422        self.call.device.RunShellCommand(
1423            'p=test.package;am instrument "$p"/.TestInstrumentation',
1424            shell=True, check_return=True, large_output=True)):
1425      self.device.StartInstrumentation(
1426          'test.package/.TestInstrumentation',
1427          finish=False, raw=False, extras=None)
1428
1429  def testStartInstrumentation_finish(self):
1430    with self.assertCalls(
1431        (self.call.device.RunShellCommand(
1432            'p=test.package;am instrument -w "$p"/.TestInstrumentation',
1433            shell=True, check_return=True, large_output=True),
1434         ['OK (1 test)'])):
1435      output = self.device.StartInstrumentation(
1436          'test.package/.TestInstrumentation',
1437          finish=True, raw=False, extras=None)
1438      self.assertEquals(['OK (1 test)'], output)
1439
1440  def testStartInstrumentation_raw(self):
1441    with self.assertCalls(
1442        self.call.device.RunShellCommand(
1443            'p=test.package;am instrument -r "$p"/.TestInstrumentation',
1444            shell=True, check_return=True, large_output=True)):
1445      self.device.StartInstrumentation(
1446          'test.package/.TestInstrumentation',
1447          finish=False, raw=True, extras=None)
1448
1449  def testStartInstrumentation_extras(self):
1450    with self.assertCalls(
1451        self.call.device.RunShellCommand(
1452            'p=test.package;am instrument -e "$p".foo Foo -e bar \'Val \'"$p" '
1453            '"$p"/.TestInstrumentation',
1454            shell=True, check_return=True, large_output=True)):
1455      self.device.StartInstrumentation(
1456          'test.package/.TestInstrumentation',
1457          finish=False, raw=False, extras={'test.package.foo': 'Foo',
1458                                           'bar': 'Val test.package'})
1459
1460
1461class DeviceUtilsBroadcastIntentTest(DeviceUtilsTest):
1462
1463  def testBroadcastIntent_noExtras(self):
1464    test_intent = intent.Intent(action='test.package.with.an.INTENT')
1465    with self.assertCall(
1466        self.call.adb.Shell('am broadcast -a test.package.with.an.INTENT'),
1467        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
1468      self.device.BroadcastIntent(test_intent)
1469
1470  def testBroadcastIntent_withExtra(self):
1471    test_intent = intent.Intent(action='test.package.with.an.INTENT',
1472                                extras={'foo': 'bar value'})
1473    with self.assertCall(
1474        self.call.adb.Shell(
1475            "am broadcast -a test.package.with.an.INTENT --es foo 'bar value'"),
1476        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
1477      self.device.BroadcastIntent(test_intent)
1478
1479  def testBroadcastIntent_withExtra_noValue(self):
1480    test_intent = intent.Intent(action='test.package.with.an.INTENT',
1481                                extras={'foo': None})
1482    with self.assertCall(
1483        self.call.adb.Shell(
1484            'am broadcast -a test.package.with.an.INTENT --esn foo'),
1485        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
1486      self.device.BroadcastIntent(test_intent)
1487
1488
1489class DeviceUtilsGoHomeTest(DeviceUtilsTest):
1490
1491  def testGoHome_popupsExist(self):
1492    with self.assertCalls(
1493        (self.call.device.RunShellCommand(
1494            ['dumpsys', 'window', 'windows'], check_return=True,
1495            large_output=True), []),
1496        (self.call.device.RunShellCommand(
1497            ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
1498            '-c', 'android.intent.category.HOME'], check_return=True),
1499         'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
1500        (self.call.device.RunShellCommand(
1501            ['dumpsys', 'window', 'windows'], check_return=True,
1502            large_output=True), []),
1503        (self.call.device.RunShellCommand(
1504            ['input', 'keyevent', '66'], check_return=True)),
1505        (self.call.device.RunShellCommand(
1506            ['input', 'keyevent', '4'], check_return=True)),
1507        (self.call.device.RunShellCommand(
1508            ['dumpsys', 'window', 'windows'], check_return=True,
1509            large_output=True),
1510         ['mCurrentFocus Launcher'])):
1511      self.device.GoHome()
1512
1513  def testGoHome_willRetry(self):
1514    with self.assertCalls(
1515        (self.call.device.RunShellCommand(
1516            ['dumpsys', 'window', 'windows'], check_return=True,
1517            large_output=True), []),
1518        (self.call.device.RunShellCommand(
1519            ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
1520            '-c', 'android.intent.category.HOME'], check_return=True),
1521         'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
1522        (self.call.device.RunShellCommand(
1523            ['dumpsys', 'window', 'windows'], check_return=True,
1524            large_output=True), []),
1525        (self.call.device.RunShellCommand(
1526            ['input', 'keyevent', '66'], check_return=True,)),
1527        (self.call.device.RunShellCommand(
1528            ['input', 'keyevent', '4'], check_return=True)),
1529        (self.call.device.RunShellCommand(
1530            ['dumpsys', 'window', 'windows'], check_return=True,
1531            large_output=True), []),
1532        (self.call.device.RunShellCommand(
1533            ['input', 'keyevent', '66'], check_return=True)),
1534        (self.call.device.RunShellCommand(
1535            ['input', 'keyevent', '4'], check_return=True)),
1536        (self.call.device.RunShellCommand(
1537            ['dumpsys', 'window', 'windows'], check_return=True,
1538            large_output=True),
1539         self.TimeoutError())):
1540      with self.assertRaises(device_errors.CommandTimeoutError):
1541        self.device.GoHome()
1542
1543  def testGoHome_alreadyFocused(self):
1544    with self.assertCall(
1545        self.call.device.RunShellCommand(
1546            ['dumpsys', 'window', 'windows'], check_return=True,
1547            large_output=True),
1548        ['mCurrentFocus Launcher']):
1549      self.device.GoHome()
1550
1551  def testGoHome_alreadyFocusedAlternateCase(self):
1552    with self.assertCall(
1553        self.call.device.RunShellCommand(
1554            ['dumpsys', 'window', 'windows'], check_return=True,
1555            large_output=True),
1556        [' mCurrentFocus .launcher/.']):
1557      self.device.GoHome()
1558
1559  def testGoHome_obtainsFocusAfterGoingHome(self):
1560    with self.assertCalls(
1561        (self.call.device.RunShellCommand(
1562            ['dumpsys', 'window', 'windows'], check_return=True,
1563            large_output=True), []),
1564        (self.call.device.RunShellCommand(
1565            ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
1566            '-c', 'android.intent.category.HOME'], check_return=True),
1567         'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
1568        (self.call.device.RunShellCommand(
1569            ['dumpsys', 'window', 'windows'], check_return=True,
1570            large_output=True),
1571         ['mCurrentFocus Launcher'])):
1572      self.device.GoHome()
1573
1574
1575class DeviceUtilsForceStopTest(DeviceUtilsTest):
1576
1577  def testForceStop(self):
1578    with self.assertCalls(
1579        (self.call.device.GetApplicationPids('test.package'), [1111]),
1580        (self.call.device.RunShellCommand(
1581            ['am', 'force-stop', 'test.package'],
1582            check_return=True),
1583         ['Success'])):
1584      self.device.ForceStop('test.package')
1585
1586  def testForceStop_NoProcessFound(self):
1587    with self.assertCall(
1588        self.call.device.GetApplicationPids('test.package'), []):
1589      self.device.ForceStop('test.package')
1590
1591
1592class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest):
1593
1594  def testClearApplicationState_setPermissions(self):
1595    with self.assertCalls(
1596        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
1597        (self.call.device._GetApplicationPathsInternal('this.package.exists'),
1598         ['/data/app/this.package.exists.apk']),
1599        (self.call.device.RunShellCommand(
1600            ['pm', 'clear', 'this.package.exists'],
1601            check_return=True),
1602         ['Success']),
1603        (self.call.device.GrantPermissions(
1604            'this.package.exists', ['p1']), [])):
1605      self.device.ClearApplicationState(
1606          'this.package.exists', permissions=['p1'])
1607
1608  def testClearApplicationState_packageDoesntExist(self):
1609    with self.assertCalls(
1610        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '11'),
1611        (self.call.device._GetApplicationPathsInternal('does.not.exist'),
1612         [])):
1613      self.device.ClearApplicationState('does.not.exist')
1614
1615  def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self):
1616    with self.assertCalls(
1617        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
1618        (self.call.device.RunShellCommand(
1619            ['pm', 'clear', 'this.package.does.not.exist'],
1620            check_return=True),
1621         ['Failed'])):
1622      self.device.ClearApplicationState('this.package.does.not.exist')
1623
1624  def testClearApplicationState_packageExists(self):
1625    with self.assertCalls(
1626        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
1627        (self.call.device._GetApplicationPathsInternal('this.package.exists'),
1628         ['/data/app/this.package.exists.apk']),
1629        (self.call.device.RunShellCommand(
1630            ['pm', 'clear', 'this.package.exists'],
1631            check_return=True),
1632         ['Success'])):
1633      self.device.ClearApplicationState('this.package.exists')
1634
1635  def testClearApplicationState_packageExistsOnAndroidJBMR2OrAbove(self):
1636    with self.assertCalls(
1637        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
1638        (self.call.device.RunShellCommand(
1639            ['pm', 'clear', 'this.package.exists'],
1640            check_return=True),
1641         ['Success'])):
1642      self.device.ClearApplicationState('this.package.exists')
1643
1644
1645class DeviceUtilsSendKeyEventTest(DeviceUtilsTest):
1646
1647  def testSendKeyEvent(self):
1648    with self.assertCall(self.call.adb.Shell('input keyevent 66'), ''):
1649      self.device.SendKeyEvent(66)
1650
1651
1652class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsTest):
1653
1654  def testPushChangedFilesIndividually_empty(self):
1655    test_files = []
1656    with self.assertCalls():
1657      self.device._PushChangedFilesIndividually(test_files)
1658
1659  def testPushChangedFilesIndividually_single(self):
1660    test_files = [('/test/host/path', '/test/device/path')]
1661    with self.assertCalls(self.call.adb.Push(*test_files[0])):
1662      self.device._PushChangedFilesIndividually(test_files)
1663
1664  def testPushChangedFilesIndividually_multiple(self):
1665    test_files = [
1666        ('/test/host/path/file1', '/test/device/path/file1'),
1667        ('/test/host/path/file2', '/test/device/path/file2')]
1668    with self.assertCalls(
1669        self.call.adb.Push(*test_files[0]),
1670        self.call.adb.Push(*test_files[1])):
1671      self.device._PushChangedFilesIndividually(test_files)
1672
1673
1674class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest):
1675
1676  def testPushChangedFilesZipped_noUnzipCommand(self):
1677    test_files = [('/test/host/path/file1', '/test/device/path/file1')]
1678    with self.assertCalls(
1679        (self.call.device._MaybeInstallCommands(), False)):
1680      self.assertFalse(self.device._PushChangedFilesZipped(test_files,
1681                                                           ['/test/dir']))
1682
1683  def _testPushChangedFilesZipped_spec(self, test_files):
1684    @contextlib.contextmanager
1685    def mock_zip_temp_dir():
1686      yield '/test/temp/dir'
1687
1688    with self.assertCalls(
1689        (self.call.device._MaybeInstallCommands(), True),
1690        (mock.call.py_utils.tempfile_ext.NamedTemporaryDirectory(),
1691         mock_zip_temp_dir),
1692        (mock.call.devil.utils.zip_utils.WriteZipFile(
1693            '/test/temp/dir/tmp.zip', test_files)),
1694        (self.call.device.NeedsSU(), True),
1695        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb,
1696                                                                 suffix='.zip'),
1697             MockTempFile('/test/sdcard/foo123.zip')),
1698        self.call.adb.Push(
1699            '/test/temp/dir/tmp.zip', '/test/sdcard/foo123.zip'),
1700        self.call.device.RunShellCommand(
1701            'unzip /test/sdcard/foo123.zip&&chmod -R 777 /test/dir',
1702            shell=True, as_root=True,
1703            env={'PATH': '/data/local/tmp/bin:$PATH'},
1704            check_return=True)):
1705      self.assertTrue(self.device._PushChangedFilesZipped(test_files,
1706                                                          ['/test/dir']))
1707
1708  def testPushChangedFilesZipped_single(self):
1709    self._testPushChangedFilesZipped_spec(
1710        [('/test/host/path/file1', '/test/device/path/file1')])
1711
1712  def testPushChangedFilesZipped_multiple(self):
1713    self._testPushChangedFilesZipped_spec(
1714        [('/test/host/path/file1', '/test/device/path/file1'),
1715         ('/test/host/path/file2', '/test/device/path/file2')])
1716
1717
1718class DeviceUtilsPathExistsTest(DeviceUtilsTest):
1719
1720  def testPathExists_pathExists(self):
1721    with self.assertCall(
1722        self.call.device.RunShellCommand(
1723            ['test', '-e', '/path/file exists'],
1724            as_root=False, check_return=True, timeout=10, retries=0),
1725        []):
1726      self.assertTrue(self.device.PathExists('/path/file exists'))
1727
1728  def testPathExists_multiplePathExists(self):
1729    with self.assertCall(
1730        self.call.device.RunShellCommand(
1731            ['test', '-e', '/path 1', '-a', '-e', '/path2'],
1732            as_root=False, check_return=True, timeout=10, retries=0),
1733        []):
1734      self.assertTrue(self.device.PathExists(('/path 1', '/path2')))
1735
1736  def testPathExists_pathDoesntExist(self):
1737    with self.assertCall(
1738        self.call.device.RunShellCommand(
1739            ['test', '-e', '/path/file.not.exists'],
1740            as_root=False, check_return=True, timeout=10, retries=0),
1741        self.ShellError()):
1742      self.assertFalse(self.device.PathExists('/path/file.not.exists'))
1743
1744  def testPathExists_asRoot(self):
1745    with self.assertCall(
1746        self.call.device.RunShellCommand(
1747            ['test', '-e', '/root/path/exists'],
1748            as_root=True, check_return=True, timeout=10, retries=0),
1749        self.ShellError()):
1750      self.assertFalse(
1751          self.device.PathExists('/root/path/exists', as_root=True))
1752
1753  def testFileExists_pathDoesntExist(self):
1754    with self.assertCall(
1755        self.call.device.RunShellCommand(
1756            ['test', '-e', '/path/file.not.exists'],
1757            as_root=False, check_return=True, timeout=10, retries=0),
1758        self.ShellError()):
1759      self.assertFalse(self.device.FileExists('/path/file.not.exists'))
1760
1761
1762class DeviceUtilsRemovePathTest(DeviceUtilsTest):
1763
1764  def testRemovePath_regular(self):
1765    with self.assertCall(
1766        self.call.device.RunShellCommand(
1767            ['rm', 'some file'], as_root=False, check_return=True),
1768        []):
1769      self.device.RemovePath('some file')
1770
1771  def testRemovePath_withForce(self):
1772    with self.assertCall(
1773        self.call.device.RunShellCommand(
1774            ['rm', '-f', 'some file'], as_root=False, check_return=True),
1775        []):
1776      self.device.RemovePath('some file', force=True)
1777
1778  def testRemovePath_recursively(self):
1779    with self.assertCall(
1780        self.call.device.RunShellCommand(
1781            ['rm', '-r', '/remove/this/dir'], as_root=False, check_return=True),
1782        []):
1783      self.device.RemovePath('/remove/this/dir', recursive=True)
1784
1785  def testRemovePath_withRoot(self):
1786    with self.assertCall(
1787        self.call.device.RunShellCommand(
1788            ['rm', 'some file'], as_root=True, check_return=True),
1789        []):
1790      self.device.RemovePath('some file', as_root=True)
1791
1792  def testRemovePath_manyPaths(self):
1793    with self.assertCall(
1794        self.call.device.RunShellCommand(
1795            ['rm', 'eeny', 'meeny', 'miny', 'moe'],
1796            as_root=False, check_return=True),
1797        []):
1798      self.device.RemovePath(['eeny', 'meeny', 'miny', 'moe'])
1799
1800
1801class DeviceUtilsPullFileTest(DeviceUtilsTest):
1802
1803  def testPullFile_existsOnDevice(self):
1804    with mock.patch('os.path.exists', return_value=True):
1805      with self.assertCall(
1806          self.call.adb.Pull('/data/app/test.file.exists',
1807                             '/test/file/host/path')):
1808        self.device.PullFile('/data/app/test.file.exists',
1809                             '/test/file/host/path')
1810
1811  def testPullFile_doesntExistOnDevice(self):
1812    with mock.patch('os.path.exists', return_value=True):
1813      with self.assertCall(
1814          self.call.adb.Pull('/data/app/test.file.does.not.exist',
1815                             '/test/file/host/path'),
1816          self.CommandError('remote object does not exist')):
1817        with self.assertRaises(device_errors.CommandFailedError):
1818          self.device.PullFile('/data/app/test.file.does.not.exist',
1819                               '/test/file/host/path')
1820
1821
1822class DeviceUtilsReadFileTest(DeviceUtilsTest):
1823
1824  def testReadFileWithPull_success(self):
1825    tmp_host_dir = '/tmp/dir/on.host/'
1826    tmp_host = MockTempFile('/tmp/dir/on.host/tmp_ReadFileWithPull')
1827    tmp_host.file.read.return_value = 'some interesting contents'
1828    with self.assertCalls(
1829        (mock.call.tempfile.mkdtemp(), tmp_host_dir),
1830        (self.call.adb.Pull('/path/to/device/file', mock.ANY)),
1831        (mock.call.__builtin__.open(mock.ANY, 'r'), tmp_host),
1832        (mock.call.os.path.exists(tmp_host_dir), True),
1833        (mock.call.shutil.rmtree(tmp_host_dir), None)):
1834      self.assertEquals('some interesting contents',
1835                        self.device._ReadFileWithPull('/path/to/device/file'))
1836    tmp_host.file.read.assert_called_once_with()
1837
1838  def testReadFileWithPull_rejected(self):
1839    tmp_host_dir = '/tmp/dir/on.host/'
1840    with self.assertCalls(
1841        (mock.call.tempfile.mkdtemp(), tmp_host_dir),
1842        (self.call.adb.Pull('/path/to/device/file', mock.ANY),
1843         self.CommandError()),
1844        (mock.call.os.path.exists(tmp_host_dir), True),
1845        (mock.call.shutil.rmtree(tmp_host_dir), None)):
1846      with self.assertRaises(device_errors.CommandFailedError):
1847        self.device._ReadFileWithPull('/path/to/device/file')
1848
1849  def testReadFile_exists(self):
1850    with self.assertCalls(
1851        (self.call.device.FileSize('/read/this/test/file', as_root=False), 256),
1852        (self.call.device.RunShellCommand(
1853            ['cat', '/read/this/test/file'],
1854            as_root=False, check_return=True),
1855         ['this is a test file'])):
1856      self.assertEqual('this is a test file\n',
1857                       self.device.ReadFile('/read/this/test/file'))
1858
1859  def testReadFile_exists2(self):
1860    # Same as testReadFile_exists, but uses Android N ls output.
1861    with self.assertCalls(
1862        (self.call.device.FileSize('/read/this/test/file', as_root=False), 256),
1863        (self.call.device.RunShellCommand(
1864            ['cat', '/read/this/test/file'],
1865            as_root=False, check_return=True),
1866         ['this is a test file'])):
1867      self.assertEqual('this is a test file\n',
1868                       self.device.ReadFile('/read/this/test/file'))
1869
1870  def testReadFile_doesNotExist(self):
1871    with self.assertCall(
1872        self.call.device.FileSize('/this/file/does.not.exist', as_root=False),
1873        self.CommandError('File does not exist')):
1874      with self.assertRaises(device_errors.CommandFailedError):
1875        self.device.ReadFile('/this/file/does.not.exist')
1876
1877  def testReadFile_zeroSize(self):
1878    with self.assertCalls(
1879        (self.call.device.FileSize('/this/file/has/zero/size', as_root=False),
1880         0),
1881        (self.call.device._ReadFileWithPull('/this/file/has/zero/size'),
1882         'but it has contents\n')):
1883      self.assertEqual('but it has contents\n',
1884                       self.device.ReadFile('/this/file/has/zero/size'))
1885
1886  def testReadFile_withSU(self):
1887    with self.assertCalls(
1888        (self.call.device.FileSize(
1889            '/this/file/can.be.read.with.su', as_root=True), 256),
1890        (self.call.device.RunShellCommand(
1891            ['cat', '/this/file/can.be.read.with.su'],
1892            as_root=True, check_return=True),
1893         ['this is a test file', 'read with su'])):
1894      self.assertEqual(
1895          'this is a test file\nread with su\n',
1896          self.device.ReadFile('/this/file/can.be.read.with.su',
1897                               as_root=True))
1898
1899  def testReadFile_withPull(self):
1900    contents = 'a' * 123456
1901    with self.assertCalls(
1902        (self.call.device.FileSize('/read/this/big/test/file', as_root=False),
1903         123456),
1904        (self.call.device._ReadFileWithPull('/read/this/big/test/file'),
1905         contents)):
1906      self.assertEqual(
1907          contents, self.device.ReadFile('/read/this/big/test/file'))
1908
1909  def testReadFile_withPullAndSU(self):
1910    contents = 'b' * 123456
1911    with self.assertCalls(
1912        (self.call.device.FileSize(
1913            '/this/big/file/can.be.read.with.su', as_root=True), 123456),
1914        (self.call.device.NeedsSU(), True),
1915        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
1916         MockTempFile('/sdcard/tmp/on.device')),
1917        self.call.device.RunShellCommand(
1918            'SRC=/this/big/file/can.be.read.with.su DEST=/sdcard/tmp/on.device;'
1919            'cp "$SRC" "$DEST" && chmod 666 "$DEST"',
1920            shell=True, as_root=True, check_return=True),
1921        (self.call.device._ReadFileWithPull('/sdcard/tmp/on.device'),
1922         contents)):
1923      self.assertEqual(
1924          contents,
1925          self.device.ReadFile('/this/big/file/can.be.read.with.su',
1926                               as_root=True))
1927
1928  def testReadFile_forcePull(self):
1929    contents = 'a' * 123456
1930    with self.assertCall(
1931        self.call.device._ReadFileWithPull('/read/this/big/test/file'),
1932        contents):
1933      self.assertEqual(
1934          contents,
1935          self.device.ReadFile('/read/this/big/test/file', force_pull=True))
1936
1937
1938class DeviceUtilsWriteFileTest(DeviceUtilsTest):
1939
1940  def testWriteFileWithPush_success(self):
1941    tmp_host = MockTempFile('/tmp/file/on.host')
1942    contents = 'some interesting contents'
1943    with self.assertCalls(
1944        (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
1945        self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file')):
1946      self.device._WriteFileWithPush('/path/to/device/file', contents)
1947    tmp_host.file.write.assert_called_once_with(contents)
1948
1949  def testWriteFileWithPush_rejected(self):
1950    tmp_host = MockTempFile('/tmp/file/on.host')
1951    contents = 'some interesting contents'
1952    with self.assertCalls(
1953        (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
1954        (self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file'),
1955         self.CommandError())):
1956      with self.assertRaises(device_errors.CommandFailedError):
1957        self.device._WriteFileWithPush('/path/to/device/file', contents)
1958
1959  def testWriteFile_withPush(self):
1960    contents = 'some large contents ' * 26  # 20 * 26 = 520 chars
1961    with self.assertCalls(
1962        self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
1963      self.device.WriteFile('/path/to/device/file', contents)
1964
1965  def testWriteFile_withPushForced(self):
1966    contents = 'tiny contents'
1967    with self.assertCalls(
1968        self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
1969      self.device.WriteFile('/path/to/device/file', contents, force_push=True)
1970
1971  def testWriteFile_withPushAndSU(self):
1972    contents = 'some large contents ' * 26  # 20 * 26 = 520 chars
1973    with self.assertCalls(
1974        (self.call.device.NeedsSU(), True),
1975        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
1976         MockTempFile('/sdcard/tmp/on.device')),
1977        self.call.device._WriteFileWithPush('/sdcard/tmp/on.device', contents),
1978        self.call.device.RunShellCommand(
1979            ['cp', '/sdcard/tmp/on.device', '/path/to/device/file'],
1980            as_root=True, check_return=True)):
1981      self.device.WriteFile('/path/to/device/file', contents, as_root=True)
1982
1983  def testWriteFile_withEcho(self):
1984    with self.assertCall(self.call.adb.Shell(
1985        "echo -n the.contents > /test/file/to.write"), ''):
1986      self.device.WriteFile('/test/file/to.write', 'the.contents')
1987
1988  def testWriteFile_withEchoAndQuotes(self):
1989    with self.assertCall(self.call.adb.Shell(
1990        "echo -n 'the contents' > '/test/file/to write'"), ''):
1991      self.device.WriteFile('/test/file/to write', 'the contents')
1992
1993  def testWriteFile_withEchoAndSU(self):
1994    expected_cmd_without_su = "sh -c 'echo -n contents > /test/file'"
1995    expected_cmd = 'su -c %s' % expected_cmd_without_su
1996    with self.assertCalls(
1997        (self.call.device.NeedsSU(), True),
1998        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
1999        (self.call.adb.Shell(expected_cmd),
2000         '')):
2001      self.device.WriteFile('/test/file', 'contents', as_root=True)
2002
2003
2004class DeviceUtilsStatDirectoryTest(DeviceUtilsTest):
2005  # Note: Also tests ListDirectory in testStatDirectory_fileList.
2006
2007  EXAMPLE_LS_OUTPUT = [
2008    'total 12345',
2009    'drwxr-xr-x  19 root   root          0 1970-04-06 18:03 .',
2010    'drwxr-xr-x  19 root   root          0 1970-04-06 18:03 ..',
2011    'drwxr-xr-x   6 root   root            1970-01-01 00:00 some_dir',
2012    '-rw-r--r--   1 root   root        723 1971-01-01 07:04 some_file',
2013    '-rw-r-----   1 root   root        327 2009-02-13 23:30 My Music File',
2014    # Some Android versions escape spaces in file names
2015    '-rw-rw-rw-   1 root   root          0 2018-01-11 13:35 Local\\ State',
2016    # Older Android versions do not print st_nlink
2017    'lrwxrwxrwx root     root              1970-01-01 00:00 lnk -> /some/path',
2018    'srwxrwx--- system   system            2016-05-31 17:25 a_socket1',
2019    'drwxrwxrwt system   misc              1970-11-23 02:25 tmp',
2020    'drwxr-s--- system   shell             1970-11-23 02:24 my_cmd',
2021    'cr--r----- root     system    10, 183 1971-01-01 07:04 random',
2022    'brw------- root     root       7,   0 1971-01-01 07:04 block_dev',
2023    '-rwS------ root     shell      157404 2015-04-13 15:44 silly',
2024  ]
2025
2026  FILENAMES = [
2027    'some_dir', 'some_file', 'My Music File', 'Local State', 'lnk',
2028    'a_socket1', 'tmp', 'my_cmd', 'random', 'block_dev', 'silly']
2029
2030  def getStatEntries(self, path_given='/', path_listed='/'):
2031    with self.assertCall(
2032        self.call.device.RunShellCommand(
2033            ['ls', '-a', '-l', path_listed],
2034            check_return=True, as_root=False, env={'TZ': 'utc'}),
2035        self.EXAMPLE_LS_OUTPUT):
2036      entries = self.device.StatDirectory(path_given)
2037    return {f['filename']: f for f in entries}
2038
2039  def getListEntries(self):
2040    with self.assertCall(
2041        self.call.device.RunShellCommand(
2042            ['ls', '-a', '-l', '/'],
2043            check_return=True, as_root=False, env={'TZ': 'utc'}),
2044        self.EXAMPLE_LS_OUTPUT):
2045      return self.device.ListDirectory('/')
2046
2047  def testStatDirectory_forceTrailingSlash(self):
2048    self.getStatEntries(path_given='/foo/bar/', path_listed='/foo/bar/')
2049    self.getStatEntries(path_given='/foo/bar', path_listed='/foo/bar/')
2050
2051  def testStatDirectory_fileList(self):
2052    self.assertItemsEqual(self.getStatEntries().keys(), self.FILENAMES)
2053    self.assertItemsEqual(self.getListEntries(), self.FILENAMES)
2054
2055  def testStatDirectory_fileModes(self):
2056    expected_modes = (
2057      ('some_dir', stat.S_ISDIR),
2058      ('some_file', stat.S_ISREG),
2059      ('lnk', stat.S_ISLNK),
2060      ('a_socket1', stat.S_ISSOCK),
2061      ('block_dev', stat.S_ISBLK),
2062      ('random', stat.S_ISCHR),
2063    )
2064    entries = self.getStatEntries()
2065    for filename, check in expected_modes:
2066      self.assertTrue(check(entries[filename]['st_mode']))
2067
2068  def testStatDirectory_filePermissions(self):
2069    should_have = (
2070      ('some_file', stat.S_IWUSR),  # Owner can write.
2071      ('tmp', stat.S_IXOTH),  # Others can execute.
2072      ('tmp', stat.S_ISVTX),  # Has sticky bit.
2073      ('my_cmd', stat.S_ISGID),  # Has set-group-ID bit.
2074      ('silly', stat.S_ISUID),  # Has set UID bit.
2075    )
2076    should_not_have = (
2077      ('some_file', stat.S_IWOTH),  # Others can't write.
2078      ('block_dev', stat.S_IRGRP),  # Group can't read.
2079      ('silly', stat.S_IXUSR),  # Owner can't execute.
2080    )
2081    entries = self.getStatEntries()
2082    for filename, bit in should_have:
2083      self.assertTrue(entries[filename]['st_mode'] & bit)
2084    for filename, bit in should_not_have:
2085      self.assertFalse(entries[filename]['st_mode'] & bit)
2086
2087  def testStatDirectory_numHardLinks(self):
2088    entries = self.getStatEntries()
2089    self.assertEqual(entries['some_dir']['st_nlink'], 6)
2090    self.assertEqual(entries['some_file']['st_nlink'], 1)
2091    self.assertFalse('st_nlink' in entries['tmp'])
2092
2093  def testStatDirectory_fileOwners(self):
2094    entries = self.getStatEntries()
2095    self.assertEqual(entries['some_dir']['st_owner'], 'root')
2096    self.assertEqual(entries['my_cmd']['st_owner'], 'system')
2097    self.assertEqual(entries['my_cmd']['st_group'], 'shell')
2098    self.assertEqual(entries['tmp']['st_group'], 'misc')
2099
2100  def testStatDirectory_fileSize(self):
2101    entries = self.getStatEntries()
2102    self.assertEqual(entries['some_file']['st_size'], 723)
2103    self.assertEqual(entries['My Music File']['st_size'], 327)
2104    # Sizes are sometimes not reported for non-regular files, don't try to
2105    # guess the size in those cases.
2106    self.assertFalse('st_size' in entries['some_dir'])
2107
2108  def testStatDirectory_fileDateTime(self):
2109    entries = self.getStatEntries()
2110    self.assertEqual(entries['some_dir']['st_mtime'], 0)  # Epoch!
2111    self.assertEqual(entries['My Music File']['st_mtime'], 1234567800)
2112
2113  def testStatDirectory_deviceType(self):
2114    entries = self.getStatEntries()
2115    self.assertEqual(entries['random']['st_rdev_pair'], (10, 183))
2116    self.assertEqual(entries['block_dev']['st_rdev_pair'], (7, 0))
2117
2118  def testStatDirectory_symbolicLinks(self):
2119    entries = self.getStatEntries()
2120    self.assertEqual(entries['lnk']['symbolic_link_to'], '/some/path')
2121    for d in entries.itervalues():
2122      self.assertEqual('symbolic_link_to' in d, stat.S_ISLNK(d['st_mode']))
2123
2124
2125class DeviceUtilsStatPathTest(DeviceUtilsTest):
2126
2127  EXAMPLE_DIRECTORY = [
2128    {'filename': 'foo.txt', 'st_size': 123, 'st_time': 456},
2129    {'filename': 'some_dir', 'st_time': 0}
2130  ]
2131  INDEX = {e['filename']: e for e in EXAMPLE_DIRECTORY}
2132
2133  def testStatPath_file(self):
2134    with self.assertCall(
2135        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2136        self.EXAMPLE_DIRECTORY):
2137      self.assertEquals(self.INDEX['foo.txt'],
2138                        self.device.StatPath('/data/local/tmp/foo.txt'))
2139
2140  def testStatPath_directory(self):
2141    with self.assertCall(
2142        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2143        self.EXAMPLE_DIRECTORY):
2144      self.assertEquals(self.INDEX['some_dir'],
2145                        self.device.StatPath('/data/local/tmp/some_dir'))
2146
2147  def testStatPath_directoryWithTrailingSlash(self):
2148    with self.assertCall(
2149        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2150        self.EXAMPLE_DIRECTORY):
2151      self.assertEquals(self.INDEX['some_dir'],
2152                        self.device.StatPath('/data/local/tmp/some_dir/'))
2153
2154  def testStatPath_doesNotExist(self):
2155    with self.assertCall(
2156        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2157        self.EXAMPLE_DIRECTORY):
2158      with self.assertRaises(device_errors.CommandFailedError):
2159        self.device.StatPath('/data/local/tmp/does.not.exist.txt')
2160
2161
2162class DeviceUtilsFileSizeTest(DeviceUtilsTest):
2163
2164  EXAMPLE_DIRECTORY = [
2165    {'filename': 'foo.txt', 'st_size': 123, 'st_mtime': 456},
2166    {'filename': 'some_dir', 'st_mtime': 0}
2167  ]
2168
2169  def testFileSize_file(self):
2170    with self.assertCall(
2171        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2172        self.EXAMPLE_DIRECTORY):
2173      self.assertEquals(123,
2174                        self.device.FileSize('/data/local/tmp/foo.txt'))
2175
2176  def testFileSize_doesNotExist(self):
2177    with self.assertCall(
2178        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2179        self.EXAMPLE_DIRECTORY):
2180      with self.assertRaises(device_errors.CommandFailedError):
2181        self.device.FileSize('/data/local/tmp/does.not.exist.txt')
2182
2183  def testFileSize_directoryWithNoSize(self):
2184    with self.assertCall(
2185        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2186        self.EXAMPLE_DIRECTORY):
2187      with self.assertRaises(device_errors.CommandFailedError):
2188        self.device.FileSize('/data/local/tmp/some_dir')
2189
2190
2191class DeviceUtilsSetJavaAssertsTest(DeviceUtilsTest):
2192
2193  def testSetJavaAsserts_enable(self):
2194    with self.assertCalls(
2195        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2196         'some.example.prop=with an example value\n'
2197         'some.other.prop=value_ok\n'),
2198        self.call.device.WriteFile(
2199            self.device.LOCAL_PROPERTIES_PATH,
2200            'some.example.prop=with an example value\n'
2201            'some.other.prop=value_ok\n'
2202            'dalvik.vm.enableassertions=all\n'),
2203        (self.call.device.GetProp('dalvik.vm.enableassertions'), ''),
2204        self.call.device.SetProp('dalvik.vm.enableassertions', 'all')):
2205      self.assertTrue(self.device.SetJavaAsserts(True))
2206
2207  def testSetJavaAsserts_disable(self):
2208    with self.assertCalls(
2209        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2210         'some.example.prop=with an example value\n'
2211         'dalvik.vm.enableassertions=all\n'
2212         'some.other.prop=value_ok\n'),
2213        self.call.device.WriteFile(
2214            self.device.LOCAL_PROPERTIES_PATH,
2215            'some.example.prop=with an example value\n'
2216            'some.other.prop=value_ok\n'),
2217        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all'),
2218        self.call.device.SetProp('dalvik.vm.enableassertions', '')):
2219      self.assertTrue(self.device.SetJavaAsserts(False))
2220
2221  def testSetJavaAsserts_alreadyEnabled(self):
2222    with self.assertCalls(
2223        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2224         'some.example.prop=with an example value\n'
2225         'dalvik.vm.enableassertions=all\n'
2226         'some.other.prop=value_ok\n'),
2227        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
2228      self.assertFalse(self.device.SetJavaAsserts(True))
2229
2230  def testSetJavaAsserts_malformedLocalProp(self):
2231    with self.assertCalls(
2232        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2233         'some.example.prop=with an example value\n'
2234         'malformed_property\n'
2235         'dalvik.vm.enableassertions=all\n'
2236         'some.other.prop=value_ok\n'),
2237        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
2238      self.assertFalse(self.device.SetJavaAsserts(True))
2239
2240
2241class DeviceUtilsEnsureCacheInitializedTest(DeviceUtilsTest):
2242
2243  def testEnsureCacheInitialized_noCache_success(self):
2244    self.assertIsNone(self.device._cache['token'])
2245    with self.assertCall(
2246        self.call.device.RunShellCommand(
2247            AnyStringWith('getprop'),
2248            shell=True, check_return=True, large_output=True),
2249        ['/sdcard', 'TOKEN']):
2250      self.device._EnsureCacheInitialized()
2251    self.assertIsNotNone(self.device._cache['token'])
2252
2253  def testEnsureCacheInitialized_noCache_failure(self):
2254    self.assertIsNone(self.device._cache['token'])
2255    with self.assertCall(
2256        self.call.device.RunShellCommand(
2257            AnyStringWith('getprop'),
2258            shell=True, check_return=True, large_output=True),
2259        self.TimeoutError()):
2260      with self.assertRaises(device_errors.CommandTimeoutError):
2261        self.device._EnsureCacheInitialized()
2262    self.assertIsNone(self.device._cache['token'])
2263
2264  def testEnsureCacheInitialized_cache(self):
2265    self.device._cache['token'] = 'TOKEN'
2266    with self.assertCalls():
2267      self.device._EnsureCacheInitialized()
2268    self.assertIsNotNone(self.device._cache['token'])
2269
2270
2271class DeviceUtilsGetPropTest(DeviceUtilsTest):
2272
2273  def testGetProp_exists(self):
2274    with self.assertCall(
2275        self.call.device.RunShellCommand(
2276            ['getprop', 'test.property'], check_return=True, single_line=True,
2277            timeout=self.device._default_timeout,
2278            retries=self.device._default_retries),
2279        'property_value'):
2280      self.assertEqual('property_value',
2281                       self.device.GetProp('test.property'))
2282
2283  def testGetProp_doesNotExist(self):
2284    with self.assertCall(
2285        self.call.device.RunShellCommand(
2286            ['getprop', 'property.does.not.exist'],
2287            check_return=True, single_line=True,
2288            timeout=self.device._default_timeout,
2289            retries=self.device._default_retries),
2290        ''):
2291      self.assertEqual('', self.device.GetProp('property.does.not.exist'))
2292
2293  def testGetProp_cachedRoProp(self):
2294    with self.assertCalls(
2295        self.EnsureCacheInitialized(props=['[ro.build.type]: [userdebug]'])):
2296      self.assertEqual('userdebug',
2297                       self.device.GetProp('ro.build.type', cache=True))
2298      self.assertEqual('userdebug',
2299                       self.device.GetProp('ro.build.type', cache=True))
2300
2301
2302class DeviceUtilsSetPropTest(DeviceUtilsTest):
2303
2304  def testSetProp(self):
2305    with self.assertCall(
2306        self.call.device.RunShellCommand(
2307            ['setprop', 'test.property', 'test value'], check_return=True)):
2308      self.device.SetProp('test.property', 'test value')
2309
2310  def testSetProp_check_succeeds(self):
2311    with self.assertCalls(
2312        (self.call.device.RunShellCommand(
2313            ['setprop', 'test.property', 'new_value'], check_return=True)),
2314        (self.call.device.GetProp('test.property', cache=False), 'new_value')):
2315      self.device.SetProp('test.property', 'new_value', check=True)
2316
2317  def testSetProp_check_fails(self):
2318    with self.assertCalls(
2319        (self.call.device.RunShellCommand(
2320            ['setprop', 'test.property', 'new_value'], check_return=True)),
2321        (self.call.device.GetProp('test.property', cache=False), 'old_value')):
2322      with self.assertRaises(device_errors.CommandFailedError):
2323        self.device.SetProp('test.property', 'new_value', check=True)
2324
2325
2326class DeviceUtilsListProcessesTest(DeviceUtilsTest):
2327  def setUp(self):
2328    super(DeviceUtilsListProcessesTest, self).setUp()
2329    self.sample_output = [
2330        'USER  PID     PPID  VSIZE RSS   WCHAN          PC  NAME',
2331        'user  1001    100   1024  1024  ffffffff 00000000 one.match',
2332        'user  1002    100   1024  1024  ffffffff 00000000 two.match',
2333        'user  1003    101   1024  1024  ffffffff 00000000 three.match',
2334        'user  1234    101   1024  1024  ffffffff 00000000 my$process',
2335        'user  1236    100   1024  1024  ffffffff 00000000 foo',
2336        'user  1578    1236  1024  1024  ffffffff 00000000 foo',
2337    ]
2338
2339  def _grepOutput(self, substring):
2340    return [line for line in self.sample_output if substring in line]
2341
2342  def testListProcesses_sdkGreaterThanNougatMR1(self):
2343    with self.patch_call(self.call.device.build_version_sdk,
2344                         return_value=(version_codes.NOUGAT_MR1 + 1)):
2345      with self.patch_call(self.call.device.build_id,
2346                           return_value='ZZZ99Z'):
2347        with self.assertCall(
2348            self.call.device._RunPipedShellCommand(
2349                'ps -e | grep -F example.process'), []):
2350          self.device.ListProcesses('example.process')
2351
2352  def testListProcesses_noMatches(self):
2353    with self.patch_call(self.call.device.build_version_sdk,
2354                         return_value=version_codes.LOLLIPOP):
2355      with self.assertCall(
2356          self.call.device._RunPipedShellCommand('ps | grep -F does.not.match'),
2357          self._grepOutput('does.not.match')):
2358        self.assertEqual([], self.device.ListProcesses('does.not.match'))
2359
2360  def testListProcesses_oneMatch(self):
2361    with self.patch_call(self.call.device.build_version_sdk,
2362                         return_value=version_codes.LOLLIPOP):
2363      with self.assertCall(
2364          self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
2365          self._grepOutput('one.match')):
2366        self.assertEqual(
2367            Processes(('one.match', 1001, 100)),
2368            self.device.ListProcesses('one.match'))
2369
2370  def testListProcesses_multipleMatches(self):
2371    with self.patch_call(self.call.device.build_version_sdk,
2372                         return_value=version_codes.LOLLIPOP):
2373      with self.assertCall(
2374          self.call.device._RunPipedShellCommand('ps | grep -F match'),
2375          self._grepOutput('match')):
2376        self.assertEqual(
2377            Processes(('one.match', 1001, 100),
2378                      ('two.match', 1002, 100),
2379                      ('three.match', 1003, 101)),
2380            self.device.ListProcesses('match'))
2381
2382  def testListProcesses_quotable(self):
2383    with self.patch_call(self.call.device.build_version_sdk,
2384                         return_value=version_codes.LOLLIPOP):
2385      with self.assertCall(
2386          self.call.device._RunPipedShellCommand("ps | grep -F 'my$process'"),
2387          self._grepOutput('my$process')):
2388        self.assertEqual(
2389            Processes(('my$process', 1234, 101)),
2390            self.device.ListProcesses('my$process'))
2391
2392  # Tests for the GetPids wrapper interface.
2393  def testGetPids_multipleInstances(self):
2394    with self.patch_call(self.call.device.build_version_sdk,
2395                         return_value=version_codes.LOLLIPOP):
2396      with self.assertCall(
2397          self.call.device._RunPipedShellCommand('ps | grep -F foo'),
2398          self._grepOutput('foo')):
2399        self.assertEqual(
2400            {'foo': ['1236', '1578']},
2401            self.device.GetPids('foo'))
2402
2403  def testGetPids_allProcesses(self):
2404    with self.patch_call(self.call.device.build_version_sdk,
2405                         return_value=version_codes.LOLLIPOP):
2406      with self.assertCall(
2407          self.call.device.RunShellCommand(
2408              ['ps'], check_return=True, large_output=True),
2409          self.sample_output):
2410        self.assertEqual(
2411            {'one.match': ['1001'],
2412             'two.match': ['1002'],
2413             'three.match': ['1003'],
2414             'my$process': ['1234'],
2415             'foo': ['1236', '1578']},
2416            self.device.GetPids())
2417
2418  # Tests for the GetApplicationPids wrapper interface.
2419  def testGetApplicationPids_notFound(self):
2420    with self.patch_call(self.call.device.build_version_sdk,
2421                         return_value=version_codes.LOLLIPOP):
2422      with self.assertCall(
2423          self.call.device._RunPipedShellCommand('ps | grep -F match'),
2424          self._grepOutput('match')):
2425        # No PIDs found, process name should be exact match.
2426        self.assertEqual([], self.device.GetApplicationPids('match'))
2427
2428  def testGetApplicationPids_foundOne(self):
2429    with self.patch_call(self.call.device.build_version_sdk,
2430                         return_value=version_codes.LOLLIPOP):
2431      with self.assertCall(
2432          self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
2433          self._grepOutput('one.match')):
2434        self.assertEqual([1001], self.device.GetApplicationPids('one.match'))
2435
2436  def testGetApplicationPids_foundMany(self):
2437    with self.patch_call(self.call.device.build_version_sdk,
2438                         return_value=version_codes.LOLLIPOP):
2439      with self.assertCall(
2440          self.call.device._RunPipedShellCommand('ps | grep -F foo'),
2441          self._grepOutput('foo')):
2442        self.assertEqual(
2443            [1236, 1578],
2444            self.device.GetApplicationPids('foo'))
2445
2446  def testGetApplicationPids_atMostOneNotFound(self):
2447    with self.patch_call(self.call.device.build_version_sdk,
2448                         return_value=version_codes.LOLLIPOP):
2449      with self.assertCall(
2450          self.call.device._RunPipedShellCommand('ps | grep -F match'),
2451          self._grepOutput('match')):
2452        # No PIDs found, process name should be exact match.
2453        self.assertEqual(
2454            None,
2455            self.device.GetApplicationPids('match', at_most_one=True))
2456
2457  def testGetApplicationPids_atMostOneFound(self):
2458    with self.patch_call(self.call.device.build_version_sdk,
2459                         return_value=version_codes.LOLLIPOP):
2460      with self.assertCall(
2461          self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
2462          self._grepOutput('one.match')):
2463        self.assertEqual(
2464            1001,
2465            self.device.GetApplicationPids('one.match', at_most_one=True))
2466
2467  def testGetApplicationPids_atMostOneFoundTooMany(self):
2468    with self.patch_call(self.call.device.build_version_sdk,
2469                         return_value=version_codes.LOLLIPOP):
2470      with self.assertRaises(device_errors.CommandFailedError):
2471        with self.assertCall(
2472            self.call.device._RunPipedShellCommand('ps | grep -F foo'),
2473            self._grepOutput('foo')):
2474          self.device.GetApplicationPids('foo', at_most_one=True)
2475
2476
2477class DeviceUtilsGetSetEnforce(DeviceUtilsTest):
2478
2479  def testGetEnforce_Enforcing(self):
2480    with self.assertCall(self.call.adb.Shell('getenforce'), 'Enforcing'):
2481      self.assertEqual(True, self.device.GetEnforce())
2482
2483  def testGetEnforce_Permissive(self):
2484    with self.assertCall(self.call.adb.Shell('getenforce'), 'Permissive'):
2485      self.assertEqual(False, self.device.GetEnforce())
2486
2487  def testGetEnforce_Disabled(self):
2488    with self.assertCall(self.call.adb.Shell('getenforce'), 'Disabled'):
2489      self.assertEqual(None, self.device.GetEnforce())
2490
2491  def testSetEnforce_Enforcing(self):
2492    with self.assertCalls(
2493        (self.call.device.NeedsSU(), False),
2494        (self.call.adb.Shell('setenforce 1'), '')):
2495      self.device.SetEnforce(enabled=True)
2496
2497  def testSetEnforce_Permissive(self):
2498    with self.assertCalls(
2499        (self.call.device.NeedsSU(), False),
2500        (self.call.adb.Shell('setenforce 0'), '')):
2501      self.device.SetEnforce(enabled=False)
2502
2503  def testSetEnforce_EnforcingWithInt(self):
2504    with self.assertCalls(
2505        (self.call.device.NeedsSU(), False),
2506        (self.call.adb.Shell('setenforce 1'), '')):
2507      self.device.SetEnforce(enabled=1)
2508
2509  def testSetEnforce_PermissiveWithInt(self):
2510    with self.assertCalls(
2511        (self.call.device.NeedsSU(), False),
2512        (self.call.adb.Shell('setenforce 0'), '')):
2513      self.device.SetEnforce(enabled=0)
2514
2515  def testSetEnforce_EnforcingWithStr(self):
2516    with self.assertCalls(
2517        (self.call.device.NeedsSU(), False),
2518        (self.call.adb.Shell('setenforce 1'), '')):
2519      self.device.SetEnforce(enabled='1')
2520
2521  def testSetEnforce_PermissiveWithStr(self):
2522    with self.assertCalls(
2523        (self.call.device.NeedsSU(), False),
2524        (self.call.adb.Shell('setenforce 0'), '')):
2525      self.device.SetEnforce(enabled='0')  # Not recommended but it works!
2526
2527
2528class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest):
2529
2530  def testTakeScreenshot_fileNameProvided(self):
2531    with self.assertCalls(
2532        (mock.call.devil.android.device_temp_file.DeviceTempFile(
2533            self.adb, suffix='.png'),
2534         MockTempFile('/tmp/path/temp-123.png')),
2535        (self.call.adb.Shell('/system/bin/screencap -p /tmp/path/temp-123.png'),
2536         ''),
2537        self.call.device.PullFile('/tmp/path/temp-123.png',
2538                                  '/test/host/screenshot.png')):
2539      self.device.TakeScreenshot('/test/host/screenshot.png')
2540
2541
2542class DeviceUtilsDismissCrashDialogIfNeededTest(DeviceUtilsTest):
2543
2544  def testDismissCrashDialogIfNeeded_crashedPageckageNotFound(self):
2545    sample_dumpsys_output = '''
2546WINDOW MANAGER WINDOWS (dumpsys window windows)
2547  Window #11 Window{f8b647a u0 SearchPanel}:
2548    mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
2549    mOwnerUid=100 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
2550    mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
2551    Requested w=1080 h=1920 mLayoutSeq=426
2552    mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
2553'''
2554    with self.assertCalls(
2555        (self.call.device.RunShellCommand(
2556            ['dumpsys', 'window', 'windows'], check_return=True,
2557            large_output=True), sample_dumpsys_output.split('\n'))):
2558      package_name = self.device.DismissCrashDialogIfNeeded()
2559      self.assertIsNone(package_name)
2560
2561  def testDismissCrashDialogIfNeeded_crashedPageckageFound(self):
2562    sample_dumpsys_output = '''
2563WINDOW MANAGER WINDOWS (dumpsys window windows)
2564  Window #11 Window{f8b647a u0 SearchPanel}:
2565    mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
2566    mOwnerUid=102 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
2567    mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
2568    Requested w=1080 h=1920 mLayoutSeq=426
2569    mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
2570  mHasPermanentDpad=false
2571  mCurrentFocus=Window{3a27740f u0 Application Error: com.android.chrome}
2572  mFocusedApp=AppWindowToken{470af6f token=Token{272ec24e ActivityRecord{t894}}}
2573'''
2574    with self.assertCalls(
2575        (self.call.device.RunShellCommand(
2576            ['dumpsys', 'window', 'windows'], check_return=True,
2577            large_output=True), sample_dumpsys_output.split('\n')),
2578        (self.call.device.RunShellCommand(
2579            ['input', 'keyevent', '22'], check_return=True)),
2580        (self.call.device.RunShellCommand(
2581            ['input', 'keyevent', '22'], check_return=True)),
2582        (self.call.device.RunShellCommand(
2583            ['input', 'keyevent', '66'], check_return=True)),
2584        (self.call.device.RunShellCommand(
2585            ['dumpsys', 'window', 'windows'], check_return=True,
2586            large_output=True), [])):
2587      package_name = self.device.DismissCrashDialogIfNeeded()
2588      self.assertEqual(package_name, 'com.android.chrome')
2589
2590
2591class DeviceUtilsClientCache(DeviceUtilsTest):
2592
2593  def testClientCache_twoCaches(self):
2594    self.device._cache['test'] = 0
2595    client_cache_one = self.device.GetClientCache('ClientOne')
2596    client_cache_one['test'] = 1
2597    client_cache_two = self.device.GetClientCache('ClientTwo')
2598    client_cache_two['test'] = 2
2599    self.assertEqual(self.device._cache['test'], 0)
2600    self.assertEqual(client_cache_one, {'test': 1})
2601    self.assertEqual(client_cache_two, {'test': 2})
2602    self.device._ClearCache()
2603    self.assertTrue('test' not in self.device._cache)
2604    self.assertEqual(client_cache_one, {})
2605    self.assertEqual(client_cache_two, {})
2606
2607  def testClientCache_multipleInstances(self):
2608    client_cache_one = self.device.GetClientCache('ClientOne')
2609    client_cache_one['test'] = 1
2610    client_cache_two = self.device.GetClientCache('ClientOne')
2611    self.assertEqual(client_cache_one, {'test': 1})
2612    self.assertEqual(client_cache_two, {'test': 1})
2613    self.device._ClearCache()
2614    self.assertEqual(client_cache_one, {})
2615    self.assertEqual(client_cache_two, {})
2616
2617
2618class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase):
2619
2620  def testHealthyDevices_emptyBlacklist_defaultDeviceArg(self):
2621    test_serials = ['0123456789abcdef', 'fedcba9876543210']
2622    with self.assertCalls(
2623        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2624         [_AdbWrapperMock(s) for s in test_serials])):
2625      blacklist = mock.NonCallableMock(**{'Read.return_value': []})
2626      devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
2627    for serial, device in zip(test_serials, devices):
2628      self.assertTrue(isinstance(device, device_utils.DeviceUtils))
2629      self.assertEquals(serial, device.adb.GetDeviceSerial())
2630
2631  def testHealthyDevices_blacklist_defaultDeviceArg(self):
2632    test_serials = ['0123456789abcdef', 'fedcba9876543210']
2633    with self.assertCalls(
2634        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2635         [_AdbWrapperMock(s) for s in test_serials])):
2636      blacklist = mock.NonCallableMock(
2637          **{'Read.return_value': ['fedcba9876543210']})
2638      devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
2639    self.assertEquals(1, len(devices))
2640    self.assertTrue(isinstance(devices[0], device_utils.DeviceUtils))
2641    self.assertEquals('0123456789abcdef', devices[0].adb.GetDeviceSerial())
2642
2643  def testHealthyDevices_noneDeviceArg_multiple_attached(self):
2644    test_serials = ['0123456789abcdef', 'fedcba9876543210']
2645    with self.assertCalls(
2646        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2647         [_AdbWrapperMock(s) for s in test_serials]),
2648        (mock.call.devil.android.device_errors.MultipleDevicesError(mock.ANY),
2649         _MockMultipleDevicesError())):
2650      with self.assertRaises(_MockMultipleDevicesError):
2651        device_utils.DeviceUtils.HealthyDevices(device_arg=None)
2652
2653  def testHealthyDevices_noneDeviceArg_one_attached(self):
2654    test_serials = ['0123456789abcdef']
2655    with self.assertCalls(
2656        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2657         [_AdbWrapperMock(s) for s in test_serials])):
2658      devices = device_utils.DeviceUtils.HealthyDevices(device_arg=None)
2659    self.assertEquals(1, len(devices))
2660
2661  def testHealthyDevices_noneDeviceArg_no_attached(self):
2662    test_serials = []
2663    with self.assertCalls(
2664        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2665         [_AdbWrapperMock(s) for s in test_serials])):
2666      with self.assertRaises(device_errors.NoDevicesError):
2667        device_utils.DeviceUtils.HealthyDevices(device_arg=None, retry=False)
2668
2669  def testHealthyDevices_noneDeviceArg_multiple_attached_ANDROID_SERIAL(self):
2670    try:
2671      os.environ['ANDROID_SERIAL'] = '0123456789abcdef'
2672      with self.assertCalls():  # Should skip adb devices when device is known.
2673        device_utils.DeviceUtils.HealthyDevices(device_arg=None)
2674    finally:
2675      del os.environ['ANDROID_SERIAL']
2676
2677  def testHealthyDevices_stringDeviceArg(self):
2678    with self.assertCalls():  # Should skip adb devices when device is known.
2679      devices = device_utils.DeviceUtils.HealthyDevices(
2680          device_arg='0123456789abcdef')
2681    self.assertEquals(1, len(devices))
2682
2683  def testHealthyDevices_EmptyListDeviceArg_multiple_attached(self):
2684    test_serials = ['0123456789abcdef', 'fedcba9876543210']
2685    with self.assertCalls(
2686        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2687         [_AdbWrapperMock(s) for s in test_serials])):
2688      devices = device_utils.DeviceUtils.HealthyDevices(device_arg=())
2689    self.assertEquals(2, len(devices))
2690
2691  def testHealthyDevices_EmptyListDeviceArg_ANDROID_SERIAL(self):
2692    try:
2693      os.environ['ANDROID_SERIAL'] = '0123456789abcdef'
2694      with self.assertCalls():  # Should skip adb devices when device is known.
2695        devices = device_utils.DeviceUtils.HealthyDevices(device_arg=())
2696    finally:
2697      del os.environ['ANDROID_SERIAL']
2698    self.assertEquals(1, len(devices))
2699
2700  def testHealthyDevices_EmptyListDeviceArg_no_attached(self):
2701    test_serials = []
2702    with self.assertCalls(
2703        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2704         [_AdbWrapperMock(s) for s in test_serials])):
2705      with self.assertRaises(device_errors.NoDevicesError):
2706        device_utils.DeviceUtils.HealthyDevices(device_arg=[], retry=False)
2707
2708  def testHealthyDevices_EmptyListDeviceArg_no_attached_with_retry(self):
2709    test_serials = []
2710    with self.assertCalls(
2711        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2712         [_AdbWrapperMock(s) for s in test_serials]),
2713        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
2714         [_AdbWrapperMock(s) for s in test_serials])):
2715      with self.assertRaises(device_errors.NoDevicesError):
2716        device_utils.DeviceUtils.HealthyDevices(device_arg=[], retry=True)
2717
2718  def testHealthyDevices_ListDeviceArg(self):
2719    device_arg = ['0123456789abcdef', 'fedcba9876543210']
2720    try:
2721      os.environ['ANDROID_SERIAL'] = 'should-not-apply'
2722      with self.assertCalls():  # Should skip adb devices when device is known.
2723        devices = device_utils.DeviceUtils.HealthyDevices(device_arg=device_arg)
2724    finally:
2725      del os.environ['ANDROID_SERIAL']
2726    self.assertEquals(2, len(devices))
2727
2728
2729class DeviceUtilsRestartAdbdTest(DeviceUtilsTest):
2730
2731  def testAdbdRestart(self):
2732    mock_temp_file = '/sdcard/temp-123.sh'
2733    with self.assertCalls(
2734        (mock.call.devil.android.device_temp_file.DeviceTempFile(
2735            self.adb, suffix='.sh'), MockTempFile(mock_temp_file)),
2736        self.call.device.WriteFile(mock.ANY, mock.ANY),
2737        (self.call.device.RunShellCommand(
2738            ['source', mock_temp_file], check_return=True, as_root=True)),
2739        self.call.adb.WaitForDevice()):
2740      self.device.RestartAdbd()
2741
2742
2743class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest):
2744  def _PmGrantShellCall(self, package, permissions):
2745    fragment = 'p=%s;for q in %s;' % (package, ' '.join(sorted(permissions)))
2746    results = []
2747    for permission, result in sorted(permissions.iteritems()):
2748      if result:
2749        output, status = result + '\n', 1
2750      else:
2751        output, status = '', 0
2752      results.append(
2753          '{output}{sep}{permission}{sep}{status}{sep}\n'.format(
2754              output=output,
2755              permission=permission,
2756              status=status,
2757              sep=device_utils._SHELL_OUTPUT_SEPARATOR
2758          ))
2759    return (
2760        self.call.device.RunShellCommand(
2761            AnyStringWith(fragment),
2762            shell=True, raw_output=True, large_output=True, check_return=True),
2763        ''.join(results))
2764
2765  def testGrantPermissions_none(self):
2766    self.device.GrantPermissions('package', [])
2767
2768  def testGrantPermissions_underM(self):
2769    with self.patch_call(self.call.device.build_version_sdk,
2770                         return_value=version_codes.LOLLIPOP):
2771      self.device.GrantPermissions('package', ['p1'])
2772
2773  def testGrantPermissions_one(self):
2774    with self.patch_call(self.call.device.build_version_sdk,
2775                         return_value=version_codes.MARSHMALLOW):
2776      with self.assertCalls(
2777          self._PmGrantShellCall('package', {'p1': 0})):
2778        self.device.GrantPermissions('package', ['p1'])
2779
2780  def testGrantPermissions_multiple(self):
2781    with self.patch_call(self.call.device.build_version_sdk,
2782                         return_value=version_codes.MARSHMALLOW):
2783      with self.assertCalls(
2784          self._PmGrantShellCall('package', {'p1': 0, 'p2': 0})):
2785        self.device.GrantPermissions('package', ['p1', 'p2'])
2786
2787  def testGrantPermissions_WriteExtrnalStorage(self):
2788    WRITE = 'android.permission.WRITE_EXTERNAL_STORAGE'
2789    READ = 'android.permission.READ_EXTERNAL_STORAGE'
2790    with PatchLogger() as logger:
2791      with self.patch_call(self.call.device.build_version_sdk,
2792                           return_value=version_codes.MARSHMALLOW):
2793        with self.assertCalls(
2794            self._PmGrantShellCall('package', {READ: 0, WRITE: 0})):
2795          self.device.GrantPermissions('package', [WRITE])
2796      self.assertEqual(logger.warnings, [])
2797
2798  def testGrantPermissions_BlackList(self):
2799    with PatchLogger() as logger:
2800      with self.patch_call(self.call.device.build_version_sdk,
2801                           return_value=version_codes.MARSHMALLOW):
2802        with self.assertCalls(
2803            self._PmGrantShellCall('package', {'p1': 0})):
2804          self.device.GrantPermissions(
2805              'package', ['p1', 'foo.permission.C2D_MESSAGE'])
2806      self.assertEqual(logger.warnings, [])
2807
2808  def testGrantPermissions_unchangeablePermision(self):
2809    error_message = (
2810        'Operation not allowed: java.lang.SecurityException: '
2811        'Permission UNCHANGEABLE is not a changeable permission type')
2812    with PatchLogger() as logger:
2813      with self.patch_call(self.call.device.build_version_sdk,
2814                           return_value=version_codes.MARSHMALLOW):
2815        with self.assertCalls(
2816            self._PmGrantShellCall('package', {'UNCHANGEABLE': error_message})):
2817          self.device.GrantPermissions('package', ['UNCHANGEABLE'])
2818      self.assertEqual(
2819          logger.warnings, [mock.ANY, AnyStringWith('UNCHANGEABLE')])
2820
2821
2822class DeviecUtilsIsScreenOn(DeviceUtilsTest):
2823
2824  _L_SCREEN_ON = ['test=test mInteractive=true']
2825  _K_SCREEN_ON = ['test=test mScreenOn=true']
2826  _L_SCREEN_OFF = ['mInteractive=false']
2827  _K_SCREEN_OFF = ['mScreenOn=false']
2828
2829  def testIsScreenOn_onPreL(self):
2830    with self.patch_call(self.call.device.build_version_sdk,
2831                         return_value=version_codes.KITKAT):
2832      with self.assertCalls(
2833          (self.call.device._RunPipedShellCommand(
2834              'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_ON)):
2835        self.assertTrue(self.device.IsScreenOn())
2836
2837  def testIsScreenOn_onL(self):
2838    with self.patch_call(self.call.device.build_version_sdk,
2839                         return_value=version_codes.LOLLIPOP):
2840      with self.assertCalls(
2841          (self.call.device._RunPipedShellCommand(
2842              'dumpsys input_method | grep mInteractive'), self._L_SCREEN_ON)):
2843        self.assertTrue(self.device.IsScreenOn())
2844
2845  def testIsScreenOn_offPreL(self):
2846    with self.patch_call(self.call.device.build_version_sdk,
2847                         return_value=version_codes.KITKAT):
2848      with self.assertCalls(
2849          (self.call.device._RunPipedShellCommand(
2850              'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_OFF)):
2851        self.assertFalse(self.device.IsScreenOn())
2852
2853  def testIsScreenOn_offL(self):
2854    with self.patch_call(self.call.device.build_version_sdk,
2855                         return_value=version_codes.LOLLIPOP):
2856      with self.assertCalls(
2857          (self.call.device._RunPipedShellCommand(
2858              'dumpsys input_method | grep mInteractive'), self._L_SCREEN_OFF)):
2859        self.assertFalse(self.device.IsScreenOn())
2860
2861  def testIsScreenOn_noOutput(self):
2862    with self.patch_call(self.call.device.build_version_sdk,
2863                         return_value=version_codes.LOLLIPOP):
2864      with self.assertCalls(
2865          (self.call.device._RunPipedShellCommand(
2866              'dumpsys input_method | grep mInteractive'), [])):
2867        with self.assertRaises(device_errors.CommandFailedError):
2868          self.device.IsScreenOn()
2869
2870
2871class DeviecUtilsSetScreen(DeviceUtilsTest):
2872
2873  @mock.patch('time.sleep', mock.Mock())
2874  def testSetScren_alreadySet(self):
2875    with self.assertCalls(
2876        (self.call.device.IsScreenOn(), False)):
2877      self.device.SetScreen(False)
2878
2879  @mock.patch('time.sleep', mock.Mock())
2880  def testSetScreen_on(self):
2881    with self.assertCalls(
2882        (self.call.device.IsScreenOn(), False),
2883        (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
2884        (self.call.device.IsScreenOn(), True)):
2885      self.device.SetScreen(True)
2886
2887  @mock.patch('time.sleep', mock.Mock())
2888  def testSetScreen_off(self):
2889    with self.assertCalls(
2890        (self.call.device.IsScreenOn(), True),
2891        (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
2892        (self.call.device.IsScreenOn(), False)):
2893      self.device.SetScreen(False)
2894
2895  @mock.patch('time.sleep', mock.Mock())
2896  def testSetScreen_slow(self):
2897    with self.assertCalls(
2898        (self.call.device.IsScreenOn(), True),
2899        (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
2900        (self.call.device.IsScreenOn(), True),
2901        (self.call.device.IsScreenOn(), True),
2902        (self.call.device.IsScreenOn(), False)):
2903      self.device.SetScreen(False)
2904
2905class DeviecUtilsLoadCacheData(DeviceUtilsTest):
2906
2907  def testTokenMissing(self):
2908    with self.assertCalls(
2909        self.EnsureCacheInitialized()):
2910      self.assertFalse(self.device.LoadCacheData('{}'))
2911
2912  def testTokenStale(self):
2913    with self.assertCalls(
2914        self.EnsureCacheInitialized()):
2915      self.assertFalse(self.device.LoadCacheData('{"token":"foo"}'))
2916
2917  def testTokenMatches(self):
2918    with self.assertCalls(
2919        self.EnsureCacheInitialized()):
2920      self.assertTrue(self.device.LoadCacheData('{"token":"TOKEN"}'))
2921
2922  def testDumpThenLoad(self):
2923    with self.assertCalls(
2924        self.EnsureCacheInitialized()):
2925      data = json.loads(self.device.DumpCacheData())
2926      data['token'] = 'TOKEN'
2927      self.assertTrue(self.device.LoadCacheData(json.dumps(data)))
2928
2929
2930class DeviceUtilsGetIMEITest(DeviceUtilsTest):
2931
2932  def testSuccessfulDumpsys(self):
2933    dumpsys_output = (
2934        'Phone Subscriber Info:'
2935        '  Phone Type = GSM'
2936        '  Device ID = 123454321')
2937    with self.assertCalls(
2938        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
2939        (self.call.adb.Shell('dumpsys iphonesubinfo'), dumpsys_output)):
2940      self.assertEquals(self.device.GetIMEI(), '123454321')
2941
2942  def testSuccessfulServiceCall(self):
2943    service_output = """
2944        Result: Parcel(\n'
2945          0x00000000: 00000000 0000000f 00350033 00360033 '........7.6.5.4.'
2946          0x00000010: 00360032 00370030 00300032 00300039 '3.2.1.0.1.2.3.4.'
2947          0x00000020: 00380033 00000039                   '5.6.7...        ')
2948    """
2949    with self.assertCalls(
2950        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '24'),
2951        (self.call.adb.Shell('service call iphonesubinfo 1'), service_output)):
2952      self.assertEquals(self.device.GetIMEI(), '765432101234567')
2953
2954  def testNoIMEI(self):
2955    with self.assertCalls(
2956        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
2957        (self.call.adb.Shell('dumpsys iphonesubinfo'), 'no device id')):
2958      with self.assertRaises(device_errors.CommandFailedError):
2959        self.device.GetIMEI()
2960
2961  def testAdbError(self):
2962    with self.assertCalls(
2963        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '24'),
2964        (self.call.adb.Shell('service call iphonesubinfo 1'),
2965         self.ShellError())):
2966      with self.assertRaises(device_errors.CommandFailedError):
2967        self.device.GetIMEI()
2968
2969
2970if __name__ == '__main__':
2971  logging.getLogger().setLevel(logging.DEBUG)
2972  unittest.main(verbosity=2)
2973