# Copyright 2013 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.

"""Check release or test OS image version on internal storage.

Description
-----------
This test checks if Chrome OS test image or release image version in
'/etc/lsb-release' are greater than or equal to the value of argument
``min_version``. If the version is too old and argument ``reimage`` is set to
True, reflash either local netboot firmware or remote netboot firmware from
factory server (e.g., Mini-Omaha or Umpire). After that, the DUT will reboot
into netboot firmware and start network image installation process to reimage.

Test Procedure
--------------
1. This test will first check if test image (when ``check_release_image`` is
   False) or release image (when ``check_release_image`` is True) version >=
   ``min_version``. If so, this test will pass.
2. If ``reimage`` is set to False, this test will fail.
3. If ``require_space`` is set to True, this test will wait for the user presses
   spacebar.
4. If ``download_from_server`` is set to True, this test will try to download
   netboot firmware from factory server to the path indicated by argument
   ``netboot_fw``. If there is no available netboot firmware on factory server,
   this test will fail.
5. Main firmware will be flashed with the firmware image in path ``netboot_fw``.
6. The DUT will then reboot into netboot firmware and start network image
   installation process to reimage.

Dependency
----------
- If argument ``reimage`` is set to True, factory server must be set up and be
  ready for network image installation.
- If argument ``download_from_server`` is set to True, netboot firmware must be
  available on factory server. If ``download_from_server`` is set to False,
  netboot firmware must be prepared in the path that argument ``netboot_fw``
  indicated.

Examples
--------
To check test image version is greater than or equal to 9876.5.4::

  OperatorTest(pytest_name='check_image_version',
               dargs=dict(min_version='9876.5.4', reimage=False))

Reimage if release image version is older than 9876.5.4 by flashing local
netboot firmware, which is located in '/usr/local/factory/board/image.net.bin',
and make pressing spacebar not needed::

  OperatorTest(pytest_name='check_image_version',
               dargs=dict(check_release_image=True, min_version='9876.5.4',
                          require_space=False))

Reimage if test image version is greater than or equal to 9876.5.2012_12_21_2359
(loose format version) by flashing netboot firmware image on factory server::

  OperatorTest(pytest_name='check_image_version',
               dargs=dict(min_version='9876.5.2012_12_21_2359',
                          loose_version=True, download_from_server=True))
"""

from distutils import version
import logging
import shutil
import time
import unittest

import factory_common  # pylint: disable=unused-import
from cros.factory.device import device_utils
from cros.factory.test.event_log import Log
from cros.factory.test import factory_task
from cros.factory.test.i18n import test_ui as i18n_test_ui
from cros.factory.test import shopfloor
from cros.factory.test import test_ui
from cros.factory.test import ui_templates
from cros.factory.test.utils import deploy_utils
from cros.factory.tools import flash_netboot
from cros.factory.utils.arg_utils import Arg


_CSS = """
.start-font-size {
  font-size: 2em;
}
"""

# Messages for tasks
_MSG_VERSION_MISMATCH = i18n_test_ui.MakeI18nLabelWithClass(
    'Image version is incorrect. Please re-image this device.',
    'start-font-size test-error')
_MSG_NETWORK = i18n_test_ui.MakeI18nLabel('Please connect to ethernet.')
_MSG_NO_FIRMWARE_ON_SERVER = i18n_test_ui.MakeI18nLabel(
    'Netboot firmware not available on factory server.')
_MSG_NETBOOT = i18n_test_ui.MakeI18nLabel(
    'Image version is incorrect. Press space to re-image.')
_MSG_REIMAGING = i18n_test_ui.MakeI18nLabel('Flashing netboot firmware...')
_MSG_FLASH_ERROR = i18n_test_ui.MakeI18nLabelWithClass(
    'Error flashing netboot firmware!', 'start-font-size test-error')


class ImageCheckTask(factory_task.FactoryTask):

  def __init__(self, test):
    super(ImageCheckTask, self).__init__()
    self._test = test
    self.dut = test.dut

  def CheckNetwork(self):
    while not self.dut.status.eth_on:
      time.sleep(0.5)
      self._test.template.SetState(_MSG_NETWORK)

  def PromptReimage(self):
    self._test.template.SetState(_MSG_NETBOOT)
    self._test.ui.BindKey(test_ui.SPACE_KEY, self.Reimage)

  def Reimage(self):
    # TODO(b/64881268): Run cros_payload to update release image directly.
    if self._test.args.download_from_server:
      payload, unused_components, downloader = (
          shopfloor.GetUpdateFromCROSPayload(
              'netboot_firmware',
              proxy=shopfloor.get_instance()))
      del unused_components
      if not payload:
        self._test.template.SetState(_MSG_NO_FIRMWARE_ON_SERVER)
        return
      with downloader() as res_path:
        shutil.move(res_path, self._test.args.netboot_fw)

    self._test.template.SetState(_MSG_REIMAGING)
    try:
      with self.dut.temp.TempFile() as temp_file:
        self.dut.link.Push(self._test.args.netboot_fw, temp_file)
        factory_par = deploy_utils.CreateFactoryTools(self.dut)
        factory_par.CheckCall(
            ['flash_netboot', '-y', '-i', temp_file, '--no-reboot'], log=True)
      self.dut.CheckCall(['reboot'], log=True)
      self.Fail('Incorrect image version, DUT is rebooting to reimage.')
    except Exception:
      self._test.template.SetState(_MSG_FLASH_ERROR)

  def CheckImageVersion(self):
    if self._test.args.check_release_image:
      ver = self.dut.info.release_image_version
    else:
      ver = self.dut.info.factory_image_version
    Log('image_version', version=ver)
    version_format = (version.LooseVersion if self._test.args.loose_version else
                      version.StrictVersion)
    logging.info('Using version format: %r', version_format.__name__)
    logging.info('current version: %r', ver)
    logging.info('expected version: %r', self._test.args.min_version)
    return version_format(ver) < version_format(self._test.args.min_version)

  def Run(self):
    if self.CheckImageVersion():
      if self._test.args.reimage:
        self.CheckNetwork()
        if self._test.args.require_space:
          self.PromptReimage()
        else:
          self.Reimage()
      else:
        self._test.template.SetState(_MSG_VERSION_MISMATCH)
      return
    self.Pass()


class CheckImageVersionTest(unittest.TestCase):
  ARGS = [
      Arg('min_version', str, 'Minimum allowed test or release image version.'),
      Arg('loose_version', bool, 'Allow any version number representation.',
          default=False),
      Arg('netboot_fw', str, 'The path to netboot firmware image.',
          default=flash_netboot.DEFAULT_NETBOOT_FIRMWARE_PATH),
      Arg('reimage', bool, 'True to re-image when image version mismatch.',
          default=True),
      Arg('require_space', bool,
          'True to require a space key press before reimaging.', default=True),
      Arg('check_release_image', bool,
          'True to check release image instead of test image.', default=False),
      Arg('download_from_server', bool,
          'True to download netboot firmware image from factory server.',
          default=False)]

  def setUp(self):
    self.dut = device_utils.CreateDUTInterface()
    self._task_list = [ImageCheckTask(self)]
    self.ui = test_ui.UI()
    self.template = ui_templates.OneSection(self.ui)
    self.ui.AppendCSS(_CSS)

  def runTest(self):
    factory_task.FactoryTaskManager(self.ui, self._task_list).Run()
