# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import os
import xmlrpclib

from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import utils
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest


class firmware_FWupdate(FirmwareTest):
    """RO+RW firmware update using chromeos-firmware with various modes.
    If restore=false is given, the DUT is left running that firmware, so the
    test can be used to apply updates.

    Accepted --args names:
    old_bios=
    old_bios_ro=
    old_bios_rw=
    old_ec=
    old_pd=
    new_bios=
    new_bios_ro=
    new_bios_rw=
    new_ec=
    new_pd=
        apply the given image(s)
    restore=false|true (default true)
        if value is anything but 'false', once the test ends, the firmware will
        be restored to the backup that was made at the start of the test.
    """
    # Region to use for flashrom wp-region commands
    WP_REGION = 'WP_RO'

    MODE = 'recovery'

    def initialize(self, host, cmdline_args):

        self.flashed = False
        self._want_restore = None
        self._orig_sw_wp = {}
        self._orig_hw_wp = None

        dict_args = utils.args_to_dict(cmdline_args)

        if dict_args.get('restore', '').lower() == 'false':
            self._want_restore = False
        else:
            self._want_restore = True

        self.images = {}

        for old_or_new in ('old', 'new'):
            for target in ('bios', 'bios_ro', 'bios_rw', 'ec', 'pd'):
                arg_name = '%s_%s' % (old_or_new, target)
                arg_value = dict_args.get(arg_name)
                if arg_value:
                    logging.info('%s=%s', arg_name, arg_value)
                    image_path = os.path.expanduser(arg_value)
                    if not os.path.isabs(image_path):
                        raise error.TestError(
                            'Specified path must be absolute: %s=%s'
                            % (arg_name, arg_value))
                    if not os.path.isfile(image_path):
                        raise error.TestError(
                            'Specified file does not exist: %s=%s'
                            % (arg_name, arg_value))
                    self.images[arg_name] = image_path

        self.old_bios = self.images.get('old_bios')
        self.old_bios_ro = self.images.get('old_bios_ro')
        self.old_bios_rw = self.images.get('old_bios_rw')

        self.new_bios = self.images.get('new_bios')
        self.new_bios_ro = self.images.get('new_bios_ro')
        self.new_bios_rw = self.images.get('new_bios_rw')

        if not (self.new_bios or self.new_bios_rw):
            raise error.TestError('Must specify at least new_bios=<path>'
                                  ' or new_bios_rw=<path>')

        super(firmware_FWupdate, self).initialize(host, cmdline_args)

        self._orig_sw_wp = self.faft_client.bios.get_write_protect_status()

        self.backup_firmware()

        if self.faft_config.ap_access_ec_flash:
            self._setup_ec_write_protect(False)

        self._original_hw_wp = 'on' in self.servo.get('fw_wp_state')

        self.set_ap_write_protect_and_reboot(False)
        self.faft_client.bios.set_write_protect_region(self.WP_REGION, True)
        self.set_ap_write_protect_and_reboot(True)

    def cleanup(self):
        """Restore write protection, unless "restore" was false."""
        if not hasattr(self, 'run_id'):
            # Exited very early during initialize, so no cleanup needed
            return

        self.set_ap_write_protect_and_reboot(False)
        try:
            if self.flashed and self._want_restore and self.is_firmware_saved():
                self.restore_firmware()
        except (EnvironmentError, xmlrpclib.Fault,
                error.AutoservError, error.TestBaseException):
            logging.error("Problem restoring firmware:", exc_info=True)

        try:
            # Restore the old write-protection value at the end of the test.
            if self._orig_sw_wp:
                self.faft_client.bios.set_write_protect_range(
                        self._orig_sw_wp['start'],
                        self._orig_sw_wp['length'],
                        self._orig_sw_wp['enabled'])
        except (EnvironmentError, xmlrpclib.Fault,
                error.AutoservError, error.TestBaseException):
            logging.error("Problem restoring software write-protect:",
                          exc_info=True)

        if self._orig_hw_wp is not None:
            self.set_ap_write_protect_and_reboot(self._orig_hw_wp)
        elif hasattr(self, 'ec'):
            self.sync_and_ec_reboot()

        super(firmware_FWupdate, self).cleanup()

    def get_installed_versions(self):
        """Get the installed versions of BIOS and EC firmware.

        @return: A nested dict keyed by target ('bios' or 'ec') and then section
        @rtype: dict
        """
        versions = dict()
        versions['bios'] = self.faft_client.updater.get_device_fwids('bios')
        if self.faft_config.chrome_ec:
            versions['ec'] = self.faft_client.updater.get_device_fwids('ec')
        return versions

    def check_bios_specified(self,
            old_ro=False, old_rw=False, new_ro=False, new_rw=False):
        """Check if the required --args were specified.

        @raise error.TestError: if args required for the test were not given
        """
        missing = set()
        if old_ro and not (self.old_bios_ro or self.old_bios):
            missing.add('old_bios[_ro]=')
        if old_rw and not (self.old_bios_rw or self.old_bios):
            missing.add('old_bios[_rw]=')
        if new_ro and not (self.new_bios_ro or self.new_bios):
            missing.add('new_bios[_ro]=')
        if new_rw and not (self.new_bios_rw or self.new_bios):
            missing.add('new_bios[_rw]=')
        if missing:
            raise error.TestError('Must specify args: %s' % '; '.join(missing))

    def copy_cmdline_images(self, old_or_new, section=None):
        """Copy the specified command line images into the extracted shellball.

        @param old_or_new: 'old' or 'new', to select a set from self.images
        @param section: 'ro' or 'rw', to use bios_ro or bios_rw.
        """
        local_bios = (
            self.images.get('%s_bios_%s' % (old_or_new, section)) or
            self.images.get('%s_bios' % old_or_new)
        )
        local_ec = self.images.get('%s_ec' % old_or_new)
        local_pd = self.images.get('%s_pd' % old_or_new)

        extract_dir = self.faft_client.updater.get_work_path()

        if local_bios:
            bios_rel = self.faft_client.updater.get_bios_relative_path()
            remote_bios = os.path.join(extract_dir, bios_rel)
            self._client.send_file(local_bios, remote_bios)

        if local_ec:
            ec_rel = self.faft_client.updater.get_ec_relative_path()
            remote_ec = os.path.join(extract_dir, ec_rel)
            self._client.send_file(local_ec, remote_ec)

        if local_pd:
            # note: pd.bin might likewise need special path logic
            remote_pd = os.path.join(extract_dir, 'pd.bin')
            self._client.send_file(local_pd, remote_pd)

    def prepare_shellball(self, old_or_new, ro_or_rw=None):
        """Prepare a shellball with the given set of images (old or new).

        @param old_or_new: 'old' or 'new', to select a set from self.images
        @param section: 'ro' or 'rw', to use bios_ro or bios_rw.
        """
        self.faft_client.updater.reset_shellball()
        self.copy_cmdline_images(old_or_new, ro_or_rw)
        self.faft_client.updater.reload_images()
        self.faft_client.updater.repack_shellball(old_or_new)

    def run_shellball(self, append, wp, host_only=False):
        """Run chromeos-firmwareupdate with given sub-case

        @param append: additional piece to add to shellball name
        @param wp: is the flash write protected (--wp)?
        @return: a list of failure messages for the case
        """
        have_ec = bool(self.faft_config.chrome_ec)
        options = []

        if host_only:
            options += ['--host_only']
        options += ['--quirks=ec_partial_recovery=0']

        before_fwids = self.get_installed_versions()
        image_fwids = self.identify_shellball(include_ec=have_ec)

        # Unlock the protection of the wp-enable and wp-range registers
        self.set_ap_write_protect_and_reboot(False)

        if wp:
            self.faft_client.bios.set_write_protect_region(
                    self.WP_REGION, True)
            self.set_ap_write_protect_and_reboot(True)
        else:
            self.faft_client.bios.set_write_protect_region(
                    self.WP_REGION, False)

        cmd_desc = ['chromeos-firmwareupdate-%s' % append,
                    '--mode=%s' % self.MODE]
        cmd_desc += options
        cmd_desc += ['[wp=%s]' % wp]
        cmd_desc = ' '.join(cmd_desc)

        expected_written = {}

        if wp:
            bios_written = ['a', 'b']
            ec_written = []  # EC write is all-or-nothing

        elif host_only:
            bios_written = ['ro', 'a', 'b']
            ec_written = []

        else:
            bios_written = ['ro', 'a', 'b']
            ec_written = ['ro', 'rw']

        expected_written['bios'] = bios_written

        if self.faft_config.chrome_ec and ec_written:
            expected_written['ec'] = ec_written

        # remove quotes and braces: bios: [a, b], ec: [ro, rw]
        written_desc = repr(expected_written).replace("'", "")[1:-1]
        logging.debug('Before(%s): %s', append, before_fwids)
        logging.debug('Image(%s):  %s', append, image_fwids)
        logging.info("Run %s (should write %s)", cmd_desc, written_desc)

        # make sure we restore firmware after the test, if it tried to flash.
        self.flashed = True

        errors = []
        result = self.run_chromeos_firmwareupdate(
                self.MODE, append, options, ignore_status=True)

        if result.exit_status == 255:
            logging.warn("DUT network dropped during update.")
        elif result.exit_status != 0:
            if (image_fwids == before_fwids and
                    'Good. It seems nothing was changed.' in result.stdout):
                logging.info("DUT already matched the image; updater aborted.")
            else:
                errors.append('...updater: unexpectedly failed (rc=%s)' %
                              result.exit_status)

        after_fwids = self.get_installed_versions()
        logging.debug('After(%s):  %s', append, after_fwids)

        errors += self.check_fwids_written(
                before_fwids, image_fwids, after_fwids, expected_written)

        if errors:
            logging.debug('%s', '\n'.join(errors))
            return ["%s (should write %s)\n%s"
                    % (cmd_desc, written_desc, '\n'.join(errors))]
        return []

    def test_upgrade_rw(self, raise_error=True):
        """Test case: RO=old, RW=new"""
        logging.info('%s', self.test_upgrade_rw.__doc__)
        self.check_bios_specified(old_ro=True, new_rw=True)

        errors = []

        # wp=0: update RO+RW
        self.prepare_shellball('old', 'ro')
        errors += self.run_shellball('old', wp=0)

        # wp=1: update RW
        self.prepare_shellball('new', 'rw')
        errors += self.run_shellball('new', wp=1)

        self.reboot_and_reset_tpm()
        self.sync_and_ec_reboot()
        self.switcher.wait_for_client()

        if errors:
            fail_msg = "After flashing new RW over old RO, FWIDs were wrong."
            errors.insert(0, fail_msg)
            if raise_error:
                raise error.TestFail('\n'.join(errors))
            return ['\n'.join(errors)]
        return []

    def test_downgrade_rw(self, raise_error=True):
        """Test case: RO=old, RW=old->new->old (with reboots)"""
        logging.info('%s', self.test_downgrade_rw.__doc__)
        self.check_bios_specified(old_ro=True, old_rw=True, new_rw=True)
        errors = []

        # wp=0: update RO+RW
        self.prepare_shellball('old', 'ro')
        errors += self.run_shellball('old', wp=0)

        self.reboot_and_reset_tpm()
        self.sync_and_ec_reboot()
        self.switcher.wait_for_client()

        self.prepare_shellball('new', 'rw')
        errors += self.run_shellball('new', wp=1)

        self.sync_and_ec_reboot()
        self.switcher.wait_for_client()

        # Downgrade BIOS RW, but leave EC/PD at newer firmware
        self.prepare_shellball('old', 'rw')
        errors += self.run_shellball('old', wp=1, host_only=True)

        self.reboot_and_reset_tpm()
        self.sync_and_ec_reboot()
        self.switcher.wait_for_client()

        if errors:
            fail_msg = "After upgrading then downgrading RW, FWIDs were wrong."
            errors.insert(0, fail_msg)
            if raise_error:
                raise error.TestFail('\n'.join(errors))
            return ['\n'.join(errors)]
        return []

    def test_new(self, raise_error=True):
        """Test case: RO=new, RW=new"""
        logging.info('%s', self.test_new.__doc__)
        self.check_bios_specified(new_ro=True, old_rw=True)

        errors = []

        # wp=0: update RO+RW
        self.prepare_shellball('new', 'ro')
        errors += self.run_shellball('new', wp=0)

        self.reboot_and_reset_tpm()
        self.sync_and_ec_reboot()
        self.switcher.wait_for_client()

        if errors:
            fail_msg = "After flashing new RO+RW, FWIDs were wrong."
            errors.insert(0, fail_msg)
            if raise_error:
                raise error.TestFail('\n'.join(errors))
            return ['\n'.join(errors)]
        return []

    def test_old(self, raise_error=True):
        """Test case: RO=old, RW=old"""
        logging.info('%s', self.test_old.__doc__)
        self.check_bios_specified(old_ro=True, old_rw=True)

        errors = []

        # wp=0: update RO+RW
        self.prepare_shellball('old', 'ro')
        errors += self.run_shellball('old', wp=0)

        self.reboot_and_reset_tpm()
        self.sync_and_ec_reboot()
        self.switcher.wait_for_client()

        if errors:
            fail_msg = "After flashing old RO+RW, FWIDs were wrong."
            errors.insert(0, fail_msg)
            if raise_error:
                raise error.TestFail('\n'.join(errors))
            return ['\n'.join(errors)]
        return []

    def test(self):
        """Run all the test_* cases"""
        self.check_bios_specified(old_ro=True, old_rw=True, new_rw=True)

        errors = []
        errors += self.test_old(raise_error=False)
        errors += self.test_downgrade_rw(raise_error=False)
        errors += self.test_upgrade_rw(raise_error=False)
        if self.new_bios or (self.new_bios_ro and self.new_bios_rw):
            errors += self.test_new(raise_error=False)
        else:
            logging.warn("No 'new_bios_ro' given, skipping: %s",
                         self.test_new.__doc__)
        if errors:
            if len(errors) > 1:
                errors.insert(0, "%s RO+RW combinations failed." % len(errors))
            raise error.TestFail('\n'.join(errors))
