blob: ac70f5c793a98f32ad76ba53f488a81f695cdb0b [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 urlparse
from autotest_lib.server import autotest
class ChromiumOSTestPlatform(object):
"""Represents a CrOS device during autoupdate.
This class is used with autoupdate_EndToEndTest. It has functions for all
the device specific things that we need during an update: reboot,
check active slot, login, get logs, start an update etc.
"""
_UPDATE_ENGINE_PERF_PATH = '/mnt/stateful_partition/unencrypted/preserve'
_UPDATE_ENGINE_PERF_SCRIPT = 'update_engine_performance_monitor.py'
_UPDATE_ENGINE_PERF_RESULTS_FILE = 'perf_data_results.json'
def __init__(self, host, autotest_devserver, results_dir):
"""Initialize the class.
@param: host: The DUT host.
@param: autotest_devserver: The devserver to call cros_au on.
@param: results_dir: Where to save the autoupdate logs files.
"""
self._host = host
self._autotest_devserver = autotest_devserver
self._results_dir = results_dir
def _install_version(self, payload_uri, clobber_stateful=False):
"""Install the specified payload.
@param payload_uri: GS URI of the payload to install.
@param clobber_stateful: force a reinstall of the stateful image.
"""
build_name, payload_file = self._get_update_parameters_from_uri(
payload_uri)
logging.info('Installing %s on the DUT', payload_uri)
try:
ds = self._autotest_devserver
_, pid = ds.auto_update(host_name=self._host.hostname,
build_name=build_name,
force_update=True,
full_update=True,
log_dir=self._results_dir,
payload_filename=payload_file,
clobber_stateful=clobber_stateful)
except:
logging.fatal('ERROR: Failed to install image on the DUT.')
raise
return pid
def _run_login_test(self, tag):
"""Runs login_LoginSuccess test on the DUT."""
client_at = autotest.Autotest(self._host)
client_at.run_test('login_LoginSuccess', tag=tag)
@staticmethod
def _get_update_parameters_from_uri(payload_uri):
"""Extract the two vars needed for cros_au from the Google Storage URI.
dev_server.auto_update needs two values from this test:
(1) A build_name string e.g samus-release/R60-9583.0.0
(2) A filename of the exact payload file to use for the update. This
payload needs to have already been staged on the devserver.
This function extracts those two values from a Google Storage URI.
@param payload_uri: Google Storage URI to extract values from
"""
archive_url, _, payload_file = payload_uri.rpartition('/')
build_name = urlparse.urlsplit(archive_url).path.strip('/')
# This test supports payload uris from two Google Storage buckets.
# They store their payloads slightly differently. One stores them in
# a separate payloads directory. E.g
# gs://chromeos-image-archive/samus-release/R60-9583.0.0/blah.bin
# gs://chromeos-releases/dev-channel/samus/9334.0.0/payloads/blah.bin
if build_name.endswith('payloads'):
build_name = build_name.rpartition('/')[0]
payload_file = 'payloads/' + payload_file
logging.debug('Extracted build_name: %s, payload_file: %s from %s.',
build_name, payload_file, payload_uri)
return build_name, payload_file
def reboot_device(self):
"""Reboot the device."""
self._host.reboot()
def install_source_image(self, source_payload_uri):
"""Install source payload on device."""
if source_payload_uri:
self._install_version(source_payload_uri, clobber_stateful=True)
def check_login_after_source_update(self):
"""Make sure we can login before the target update."""
self._run_login_test('source_update')
def get_active_slot(self):
"""Returns the current active slot."""
return self._host.run('rootdev -s').stdout.strip()
def copy_perf_script_to_device(self, bindir):
"""Copy performance monitoring script to DUT.
The updater will kick off the script during the update.
"""
logging.info('Copying %s to device.', self._UPDATE_ENGINE_PERF_SCRIPT)
path = os.path.join(bindir, self._UPDATE_ENGINE_PERF_SCRIPT)
self._host.send_file(path, self._UPDATE_ENGINE_PERF_PATH)
def get_perf_stats_for_update(self, resultdir):
""" Get the performance metrics created during update."""
try:
path = os.path.join('/var/log',
self._UPDATE_ENGINE_PERF_RESULTS_FILE)
self._host.get_file(path, resultdir)
self._host.run('rm %s' % path)
script = os.path.join(self._UPDATE_ENGINE_PERF_PATH,
self._UPDATE_ENGINE_PERF_SCRIPT)
self._host.run('rm %s' % script)
return os.path.join(resultdir,
self._UPDATE_ENGINE_PERF_RESULTS_FILE)
except:
logging.warning('Failed to copy performance metrics from DUT.')
return None
def install_target_image(self, target_payload_uri):
"""Install target payload on the device."""
logging.info('Updating device to target image.')
return self._install_version(target_payload_uri)
def get_update_log(self, num_lines):
"""Get the latest lines from the update engine log."""
return self._host.run_output(
'tail -n %d /var/log/update_engine.log' % num_lines,
stdout_tee=None)
def check_login_after_target_update(self):
"""Check we can login after updating."""
self._run_login_test('target_update')
def oobe_triggers_update(self):
"""Check if this device has an OOBE that completes itself."""
return self._host.oobe_triggers_update()
def get_cros_version(self):
"""Returns the ChromeOS version installed on this device."""
return self._host.get_release_version()