blob: c0a268cb5247ea3e4f62f1df07c395ee0a4a5e49 [file] [log] [blame]
# Copyright 2017 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 time
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import cr50_utils
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
from autotest_lib.server.cros import gsutil_wrapper
class Cr50Test(FirmwareTest):
"""
Base class that sets up helper objects/functions for cr50 tests.
"""
version = 1
CR50_GS_URL = 'gs://chromeos-localmirror-private/distfiles/chromeos-cr50-%s/'
CR50_DEBUG_FILE = 'cr50_dbg_%s.bin'
CR50_PROD_FILE = 'cr50.%s.bin.prod'
def initialize(self, host, cmdline_args):
super(Cr50Test, self).initialize(host, cmdline_args)
if not hasattr(self, 'cr50'):
raise error.TestNAError('Test can only be run on devices with '
'access to the Cr50 console')
self._original_cr50_ver = self.cr50.get_version()
self.host = host
def cleanup(self):
"""Make sure cr50 is running the same image"""
running_ver = self.cr50.get_version()
if (hasattr(self, '_original_cr50_ver') and
running_ver != self._original_cr50_ver):
raise error.TestError('Running %s not the original cr50 version '
'%s' % (running_ver,
self._original_cr50_ver))
super(Cr50Test, self).cleanup()
def find_cr50_gs_image(self, filename, image_type=None):
"""Find the cr50 gs image name
Args:
filename: the cr50 filename to match to
image_type: release or debug. If it is not specified we will search
both the release and debug directories
Returns:
a tuple of the gsutil bucket, filename
"""
gs_url = self.CR50_GS_URL % (image_type if image_type else '*')
gs_filename = os.path.join(gs_url, filename)
bucket, gs_filename = utils.gs_ls(gs_filename)[0].rsplit('/', 1)
return bucket, gs_filename
def download_cr50_gs_image(self, filename, bucket=None, image_type=None):
"""Get the image from gs and save it in the autotest dir
Returns:
the local path
"""
if not bucket:
bucket, filename = self.find_cr50_gs_image(filename, image_type)
remote_temp_dir = '/tmp/'
src = os.path.join(remote_temp_dir, filename)
dest = os.path.join(self.resultsdir, filename)
# Copy the image to the dut
gsutil_wrapper.copy_private_bucket(host=self.host,
bucket=bucket,
filename=filename,
destination=remote_temp_dir)
self.host.get_file(src, dest)
return dest
def download_cr50_debug_image(self, devid, board_id_info=None):
"""download the cr50 debug file
Get the file with the matching devid and board id info
Args:
devid: the cr50_devid string '${DEVID0} ${DEVID1}'
board_id_info: a list of [board id, board id mask, board id
flags]
Returns:
the local path to the debug image
"""
filename = self.CR50_DEBUG_FILE % (devid.replace(' ', '_'))
if board_id_info:
filename += '.' + '.'.join(board_id_info)
return self.download_cr50_gs_image(filename, image_type='debug')
def download_cr50_release_image(self, rw_ver, board_id_info=None):
"""download the cr50 release file
Get the file with the matching version and board id info
Args:
rw_ver: the rw version string
board_id_info: a list of strings [board id, board id mask, board id
flags]
Returns:
the local path to the release image
"""
filename = self.CR50_PROD_FILE % rw_ver
if board_id_info:
filename += '.' + '.'.join(board_id_info)
return self.download_cr50_gs_image(filename, image_type='release')
def _cr50_verify_update(self, expected_ver, expect_rollback):
"""Verify the expected version is running on cr50
Args:
expect_ver: The RW version string we expect to be running
expect_rollback: True if cr50 should have rolled back during the
update
Raises:
TestFail if there is any unexpected update state
"""
running_ver = self.cr50.get_version()
if expected_ver != running_ver:
raise error.TestFail('Unexpected update ver running %s not %s' %
(running_ver, expected_ver))
if expect_rollback != self.cr50.rolledback():
raise error.TestFail('Unexpected rollback behavior: %srollback '
'detected' % 'no ' if expect_rollback else '')
logging.info('RUNNING %s after %s', expected_ver,
'rollback' if expect_rollback else 'update')
def _cr50_run_update(self, path):
"""Install the image at path onto cr50
Args:
path: the location of the image to update to
Returns:
the rw version of the image
"""
tmp_dest = '/tmp/' + os.path.basename(path)
dest, image_ver = cr50_utils.InstallImage(self.host, path, tmp_dest)
cr50_utils.UsbUpdater(self.host, ['-s', dest])
return image_ver[1]
def cr50_update(self, path, rollback=False, erase_nvmem=False,
expect_rollback=False):
"""Attempt to update to the given image.
If rollback is True, we assume that cr50 is already running an image
that can rollback.
Args:
path: the location of the update image
rollback: True if we need to force cr50 to rollback to update to
the given image
erase_nvmem: True if we need to erase nvmem during rollback
expect_rollback: True if cr50 should rollback on its own
Raises:
TestFail if the update failed
"""
original_ver = self.cr50.get_version()
rw_ver = self._cr50_run_update(path)
if erase_nvmem and rollback:
self.cr50.erase_nvmem()
# Don't erase flashinfo during rollback. That would mess with the board
# id
if rollback:
self.cr50.rollback()
expected_ver = original_ver if expect_rollback else rw_ver
# If we expect a rollback, the version should remain unchanged
self._cr50_verify_update(expected_ver, rollback or expect_rollback)