#!/usr/bin/env python3
#
#   Copyright 2016 - The Android Open Source Project
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import logging
import mock
import os
import shutil
import tempfile
import unittest

from acts import logger
from acts.controllers import android_device
from acts.controllers.android_lib import errors

# Mock log path for a test run.
MOCK_LOG_PATH = "/tmp/logs/MockTest/xx-xx-xx_xx-xx-xx/"

# Mock start and end time of the adb cat.
MOCK_ADB_EPOCH_BEGIN_TIME = 191000123
MOCK_ADB_LOGCAT_BEGIN_TIME = logger.normalize_log_line_timestamp(
    logger.epoch_to_log_line_timestamp(MOCK_ADB_EPOCH_BEGIN_TIME))
MOCK_ADB_LOGCAT_END_TIME = "1970-01-02 21:22:02.000"

MOCK_SERIAL = 1
MOCK_RELEASE_BUILD_ID = "ABC1.123456.007"
MOCK_DEV_BUILD_ID = "ABC-MR1"
MOCK_NYC_BUILD_ID = "N4F27P"


def get_mock_ads(num):
    """Generates a list of mock AndroidDevice objects.

    The serial number of each device will be integer 0 through num - 1.

    Args:
        num: An integer that is the number of mock AndroidDevice objects to
            create.
    """
    ads = []
    for i in range(num):
        ad = mock.MagicMock(name="AndroidDevice", serial=i, h_port=None)
        ad.ensure_screen_on = mock.MagicMock(return_value=True)
        ads.append(ad)
    return ads


def mock_get_all_instances():
    return get_mock_ads(5)


def mock_list_adb_devices():
    return [ad.serial for ad in get_mock_ads(5)]


class MockAdbProxy(object):
    """Mock class that swaps out calls to adb with mock calls."""

    def __init__(self,
                 serial,
                 fail_br=False,
                 fail_br_before_N=False,
                 build_id=MOCK_RELEASE_BUILD_ID,
                 return_value=None):
        self.serial = serial
        self.fail_br = fail_br
        self.fail_br_before_N = fail_br_before_N
        self.return_value = return_value
        self.return_multiple = False
        self.build_id = build_id

    def shell(self, params, ignore_status=False, timeout=60):
        if params == "id -u":
            return "root"
        elif params == "bugreportz":
            if self.fail_br:
                return "OMG I died!\n"
            return "OK:/path/bugreport.zip\n"
        elif params == "bugreportz -v":
            if self.fail_br_before_N:
                return "/system/bin/sh: bugreportz: not found"
            return "1.1"
        else:
            if self.return_multiple:
                return self.return_value.pop(0)
            else:
                return self.return_value

    def getprop(self, params):
        if params == "ro.build.id":
            return self.build_id
        elif params == "ro.build.version.incremental":
            return "123456789"
        elif params == "ro.build.type":
            return "userdebug"
        elif params == "ro.build.product" or params == "ro.product.name":
            return "FakeModel"
        elif params == "sys.boot_completed":
            return "1"

    def devices(self):
        return "\t".join([str(self.serial), "device"])

    def bugreport(self, params, timeout=android_device.BUG_REPORT_TIMEOUT):
        expected = os.path.join(
            logging.log_path, "AndroidDevice%s" % self.serial,
            "AndroidDevice%s_%s.txt" %
            (self.serial,
             logger.normalize_log_line_timestamp(MOCK_ADB_LOGCAT_BEGIN_TIME)))
        assert expected in params, "Expected '%s', got '%s'." % (expected,
                                                                 params)

    def __getattr__(self, name):
        """All calls to the none-existent functions in adb proxy would
        simply return the adb command string.
        """

        def adb_call(*args, **kwargs):
            arg_str = ' '.join(str(elem) for elem in args)
            return arg_str

        return adb_call


class MockFastbootProxy():
    """Mock class that swaps out calls to adb with mock calls."""

    def __init__(self, serial):
        self.serial = serial

    def devices(self):
        return "xxxx\tdevice\nyyyy\tdevice"

    def __getattr__(self, name):
        def fastboot_call(*args):
            arg_str = ' '.join(str(elem) for elem in args)
            return arg_str

        return fastboot_call


class ActsAndroidDeviceTest(unittest.TestCase):
    """This test class has unit tests for the implementation of everything
    under acts.controllers.android_device.
    """

    def setUp(self):
        # Set log_path to logging since acts logger setup is not called.
        if not hasattr(logging, "log_path"):
            setattr(logging, "log_path", "/tmp/logs")
        # Creates a temp dir to be used by tests in this test class.
        self.tmp_dir = tempfile.mkdtemp()

    def tearDown(self):
        """Removes the temp dir.
        """
        shutil.rmtree(self.tmp_dir)

    # Tests for android_device module functions.
    # These tests use mock AndroidDevice instances.

    @mock.patch.object(
        android_device, "get_all_instances", new=mock_get_all_instances)
    @mock.patch.object(
        android_device, "list_adb_devices", new=mock_list_adb_devices)
    def test_create_with_pickup_all(self):
        pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN
        actual_ads = android_device.create(pick_all_token)
        for actual, expected in zip(actual_ads, get_mock_ads(5)):
            self.assertEqual(actual.serial, expected.serial)

    def test_create_with_empty_config(self):
        expected_msg = android_device.ANDROID_DEVICE_EMPTY_CONFIG_MSG
        with self.assertRaisesRegex(errors.AndroidDeviceConfigError,
                                    expected_msg):
            android_device.create([])

    def test_create_with_not_list_config(self):
        expected_msg = android_device.ANDROID_DEVICE_NOT_LIST_CONFIG_MSG
        with self.assertRaisesRegex(errors.AndroidDeviceConfigError,
                                    expected_msg):
            android_device.create("HAHA")

    def test_get_device_success_with_serial(self):
        ads = get_mock_ads(5)
        expected_serial = 0
        ad = android_device.get_device(ads, serial=expected_serial)
        self.assertEqual(ad.serial, expected_serial)

    def test_get_device_success_with_serial_and_extra_field(self):
        ads = get_mock_ads(5)
        expected_serial = 1
        expected_h_port = 5555
        ads[1].h_port = expected_h_port
        ad = android_device.get_device(
            ads, serial=expected_serial, h_port=expected_h_port)
        self.assertEqual(ad.serial, expected_serial)
        self.assertEqual(ad.h_port, expected_h_port)

    def test_get_device_no_match(self):
        ads = get_mock_ads(5)
        expected_msg = ("Could not find a target device that matches condition"
                        ": {'serial': 5}.")
        with self.assertRaisesRegex(ValueError, expected_msg):
            ad = android_device.get_device(ads, serial=len(ads))

    def test_get_device_too_many_matches(self):
        ads = get_mock_ads(5)
        target_serial = ads[1].serial = ads[0].serial
        expected_msg = "More than one device matched: \[0, 0\]"
        with self.assertRaisesRegex(ValueError, expected_msg):
            ad = android_device.get_device(ads, serial=target_serial)

    def test_start_services_on_ads(self):
        """Makes sure when an AndroidDevice fails to start some services, all
        AndroidDevice objects get cleaned up.
        """
        msg = "Some error happened."
        ads = get_mock_ads(3)
        ads[0].start_services = mock.MagicMock()
        ads[0].clean_up = mock.MagicMock()
        ads[1].start_services = mock.MagicMock()
        ads[1].clean_up = mock.MagicMock()
        ads[2].start_services = mock.MagicMock(
            side_effect=errors.AndroidDeviceError(msg))
        ads[2].clean_up = mock.MagicMock()
        with self.assertRaisesRegex(errors.AndroidDeviceError, msg):
            android_device._start_services_on_ads(ads)
        ads[0].clean_up.assert_called_once_with()
        ads[1].clean_up.assert_called_once_with()
        ads[2].clean_up.assert_called_once_with()

    # Tests for android_device.AndroidDevice class.
    # These tests mock out any interaction with the OS and real android device
    # in AndroidDeivce.

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy):
        """Verifies the AndroidDevice object's basic attributes are correctly
        set after instantiation.
        """
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        self.assertEqual(ad.serial, 1)
        self.assertEqual(ad.model, "fakemodel")
        self.assertIsNone(ad.adb_logcat_process)
        expected_lp = os.path.join(logging.log_path,
                                   "AndroidDevice%s" % MOCK_SERIAL)
        self.assertEqual(ad.log_path, expected_lp)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_AndroidDevice_build_info_release(self, MockFastboot,
                                              MockAdbProxy):
        """Verifies the AndroidDevice object's basic attributes are correctly
        set after instantiation.
        """
        ad = android_device.AndroidDevice(serial=1)
        build_info = ad.build_info
        self.assertEqual(build_info["build_id"], "ABC1.123456.007")
        self.assertEqual(build_info["build_type"], "userdebug")

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL, build_id=MOCK_DEV_BUILD_ID))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_AndroidDevice_build_info_dev(self, MockFastboot, MockAdbProxy):
        """Verifies the AndroidDevice object's basic attributes are correctly
        set after instantiation.
        """
        ad = android_device.AndroidDevice(serial=1)
        build_info = ad.build_info
        self.assertEqual(build_info["build_id"], "123456789")
        self.assertEqual(build_info["build_type"], "userdebug")

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL, build_id=MOCK_NYC_BUILD_ID))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_AndroidDevice_build_info_nyc(self, MockFastboot, MockAdbProxy):
        """Verifies the AndroidDevice object's build id is set correctly for
        NYC releases.
        """
        ad = android_device.AndroidDevice(serial=1)
        build_info = ad.build_info
        self.assertEqual(build_info["build_id"], MOCK_NYC_BUILD_ID)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    @mock.patch('os.makedirs')
    @mock.patch('acts.utils.exe_cmd')
    @mock.patch(
        'acts.controllers.android_device.AndroidDevice.device_log_path',
        new_callable=mock.PropertyMock)
    def test_AndroidDevice_take_bug_report(self, mock_log_path, exe_mock,
                                           mock_makedirs, FastbootProxy,
                                           MockAdbProxy):
        """Verifies AndroidDevice.take_bug_report calls the correct adb command
        and writes the bugreport file to the correct path.
        """
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        mock_log_path.return_value = os.path.join(
            logging.log_path, "AndroidDevice%s" % ad.serial)
        ad.take_bug_report("test_something", 234325.32)
        mock_makedirs.assert_called_with(mock_log_path(), exist_ok=True)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL, fail_br=True))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    @mock.patch('os.makedirs')
    @mock.patch('acts.utils.exe_cmd')
    @mock.patch(
        'acts.controllers.android_device.AndroidDevice.device_log_path',
        new_callable=mock.PropertyMock)
    def test_AndroidDevice_take_bug_report_fail(self, mock_log_path, *_):
        """Verifies AndroidDevice.take_bug_report writes out the correct message
        when taking bugreport fails.
        """
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        mock_log_path.return_value = os.path.join(
            logging.log_path, "AndroidDevice%s" % ad.serial)
        expected_msg = "Failed to take bugreport on 1: OMG I died!"
        with self.assertRaisesRegex(errors.AndroidDeviceError, expected_msg):
            ad.take_bug_report("test_something", 4346343.23)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL, fail_br_before_N=True))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    @mock.patch('os.makedirs')
    @mock.patch('acts.utils.exe_cmd')
    @mock.patch(
        'acts.controllers.android_device.AndroidDevice.device_log_path',
        new_callable=mock.PropertyMock)
    def test_AndroidDevice_take_bug_report_fallback(
            self, mock_log_path, exe_mock, mock_makedirs, FastbootProxy,
            MockAdbProxy):
        """Verifies AndroidDevice.take_bug_report falls back to traditional
        bugreport on builds that do not have bugreportz.
        """
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        mock_log_path.return_value = os.path.join(
            logging.log_path, "AndroidDevice%s" % ad.serial)
        ad.take_bug_report("test_something", MOCK_ADB_EPOCH_BEGIN_TIME)
        mock_makedirs.assert_called_with(mock_log_path(), exist_ok=True)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    @mock.patch('acts.libs.proc.process.Process')
    def test_AndroidDevice_start_adb_logcat(self, proc_mock, FastbootProxy,
                                            MockAdbProxy):
        """Verifies the AndroidDevice method start_adb_logcat. Checks that the
        underlying logcat process is started properly and correct warning msgs
        are generated.
        """
        with mock.patch(('acts.controllers.android_lib.logcat.'
                         'create_logcat_keepalive_process'),
                        return_value=proc_mock) as create_proc_mock:
            ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
            ad.start_adb_logcat()
            # Verify start did the correct operations.
            self.assertTrue(ad.adb_logcat_process)
            log_dir = "AndroidDevice%s" % ad.serial
            create_proc_mock.assert_called_with(ad.serial, log_dir, '-b all')
            proc_mock.start.assert_called_with()
            # Expect warning msg if start is called back to back.
            expected_msg = "Android device .* already has a running adb logcat"
            proc_mock.is_running.return_value = True
            with self.assertLogs(level='WARNING') as log:
                ad.start_adb_logcat()
                self.assertRegex(log.output[0], expected_msg)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    @mock.patch('acts.controllers.android_lib.logcat.'
                'create_logcat_keepalive_process')
    def test_AndroidDevice_start_adb_logcat_with_user_param(
            self, create_proc_mock, FastbootProxy, MockAdbProxy):
        """Verifies that start_adb_logcat generates the correct adb logcat
        command if adb_logcat_param is specified.
        """
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb_logcat_param = "-b radio"
        ad.start_adb_logcat()
        # Verify that create_logcat_keepalive_process is called with the
        # correct command.
        log_dir = "AndroidDevice%s" % ad.serial
        create_proc_mock.assert_called_with(ad.serial, log_dir, '-b radio')

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    @mock.patch('acts.libs.proc.process.Process')
    def test_AndroidDevice_stop_adb_logcat(self, proc_mock, FastbootProxy,
                                           MockAdbProxy):
        """Verifies the AndroidDevice method stop_adb_logcat. Checks that the
        underlying logcat process is stopped properly and correct warning msgs
        are generated.
        """
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb_logcat_process = proc_mock
        # Expect warning msg if stop is called before start.
        expected_msg = (
            "Android device .* does not have an ongoing adb logcat")
        proc_mock.is_running.return_value = False
        with self.assertLogs(level='WARNING') as log:
            ad.stop_adb_logcat()
            self.assertRegex(log.output[0], expected_msg)

        # Verify the underlying process is stopped.
        proc_mock.is_running.return_value = True
        ad.stop_adb_logcat()
        proc_mock.stop.assert_called_with()

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_get_apk_process_id_process_cannot_find(self, fastboot_proxy,
                                                    adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb.return_value = "does_not_contain_value"
        self.assertEqual(None, ad.get_package_pid("some_package"))

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_get_apk_process_id_process_exists_second_try(self, fastboot_proxy,
                                                          adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb.return_multiple = True
        ad.adb.return_value = ["", "system 1 2 3 4  S com.some_package"]
        self.assertEqual(1, ad.get_package_pid("some_package"))

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_get_apk_process_id_bad_return(self, fastboot_proxy, adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb.return_value = "bad_return_index_error"
        self.assertEqual(None, ad.get_package_pid("some_package"))

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_get_apk_process_id_bad_return(self, fastboot_proxy, adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb.return_value = "bad return value error"
        self.assertEqual(None, ad.get_package_pid("some_package"))

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_ensure_verity_enabled_only_system_enabled(self, fastboot_proxy,
                                                       adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        root_user_id = '0'

        ad.adb.get_user_id = mock.MagicMock()
        ad.adb.get_user_id.return_value = root_user_id

        ad.adb.getprop = mock.MagicMock(side_effect=[
            '',  # system.verified
            '2'
        ])  # vendor.verified
        ad.adb.ensure_user = mock.MagicMock()
        ad.reboot = mock.MagicMock()
        ad.ensure_verity_enabled()
        ad.reboot.assert_called_once()

        ad.adb.ensure_user.assert_called_with(root_user_id)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_ensure_verity_enabled_only_vendor_enabled(self, fastboot_proxy,
                                                       adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        root_user_id = '0'

        ad.adb.get_user_id = mock.MagicMock()
        ad.adb.get_user_id.return_value = root_user_id

        ad.adb.getprop = mock.MagicMock(side_effect=[
            '2',  # system.verified
            ''
        ])  # vendor.verified
        ad.adb.ensure_user = mock.MagicMock()
        ad.reboot = mock.MagicMock()

        ad.ensure_verity_enabled()

        ad.reboot.assert_called_once()
        ad.adb.ensure_user.assert_called_with(root_user_id)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_ensure_verity_enabled_both_enabled_at_start(self, fastboot_proxy,
                                                         adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        root_user_id = '0'

        ad.adb.get_user_id = mock.MagicMock()
        ad.adb.get_user_id.return_value = root_user_id

        ad.adb.getprop = mock.MagicMock(side_effect=[
            '2',  # system.verified
            '2'
        ])  # vendor.verified
        ad.adb.ensure_user = mock.MagicMock()
        ad.reboot = mock.MagicMock()
        ad.ensure_verity_enabled()

        assert not ad.reboot.called

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_ensure_verity_disabled_system_already_disabled(
            self, fastboot_proxy, adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        root_user_id = '0'

        ad.adb.get_user_id = mock.MagicMock()
        ad.adb.get_user_id.return_value = root_user_id

        ad.adb.getprop = mock.MagicMock(side_effect=[
            '2',  # system.verified
            ''
        ])  # vendor.verified
        ad.adb.ensure_user = mock.MagicMock()
        ad.reboot = mock.MagicMock()
        ad.ensure_verity_disabled()

        ad.reboot.assert_called_once()

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_ensure_verity_disabled_vendor_already_disabled(
            self, fastboot_proxy, adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        root_user_id = '0'

        ad.adb.get_user_id = mock.MagicMock()
        ad.adb.get_user_id.return_value = root_user_id

        ad.adb.getprop = mock.MagicMock(side_effect=[
            '',  # system.verified
            '2'
        ])  # vendor.verified
        ad.adb.ensure_user = mock.MagicMock()
        ad.reboot = mock.MagicMock()

        ad.ensure_verity_disabled()

        ad.reboot.assert_called_once()
        ad.adb.ensure_user.assert_called_with(root_user_id)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_ensure_verity_disabled_disabled_at_start(
            self, fastboot_proxy, adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        root_user_id = '0'

        ad.adb.get_user_id = mock.MagicMock()
        ad.adb.get_user_id.return_value = root_user_id

        ad.adb.getprop = mock.MagicMock(side_effect=[
            '',  # system.verified
            ''
        ])  # vendor.verified
        ad.adb.ensure_user = mock.MagicMock()
        ad.reboot = mock.MagicMock()

        ad.ensure_verity_disabled()

        assert not ad.reboot.called

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_push_system_file(self, fastboot_proxy, adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.ensure_verity_disabled = mock.MagicMock()
        ad.adb.remount = mock.MagicMock()
        ad.adb.push = mock.MagicMock()

        ret = ad.push_system_file('asdf', 'jkl')
        self.assertTrue(ret)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_push_system_file_returns_false_on_error(self, fastboot_proxy,
                                                     adb_proxy):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.ensure_verity_disabled = mock.MagicMock()
        ad.adb.remount = mock.MagicMock()
        ad.adb.push = mock.MagicMock(return_value='error')

        ret = ad.push_system_file('asdf', 'jkl')
        self.assertFalse(ret)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_get_my_current_focus_window_return_empty_string(self, *_):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb.return_value = ''

        ret = ad.get_my_current_focus_window()

        self.assertEqual('', ret)

    @mock.patch(
        'acts.controllers.adb.AdbProxy',
        return_value=MockAdbProxy(MOCK_SERIAL))
    @mock.patch(
        'acts.controllers.fastboot.FastbootProxy',
        return_value=MockFastbootProxy(MOCK_SERIAL))
    def test_get_my_current_focus_window_return_current_window(self, *_):
        ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
        ad.adb.return_value = 'mCurrentFocus=Window{a247ded u0 NotificationShade}'

        ret = ad.get_my_current_focus_window()

        self.assertEqual('NotificationShade', ret)


if __name__ == "__main__":
    unittest.main()