Add rollback integration test autoupdate_Rollback.
This CL adds a rollback test that updates the DUT to a new image
and verifies that we can rollback to whatever we had installed
by inspecting the kernel state at each phase.
BUG=chromium:260568
TEST=Ran it several times.
Change-Id: Ie7f3c8ee7f0cfb4889989735f17870da19368da3
Reviewed-on: https://chromium-review.googlesource.com/173320
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Chris Sosa <sosa@chromium.org>
Tested-by: Chris Sosa <sosa@chromium.org>
diff --git a/server/cros/autoupdate_utils.py b/server/cros/autoupdate_utils.py
new file mode 100644
index 0000000..9e8e39b
--- /dev/null
+++ b/server/cros/autoupdate_utils.py
@@ -0,0 +1,53 @@
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 1
+# Use of this source code is governed by a BSD-style license that can be 2
+# found in the LICENSE file.
+
+"Module containing common utilities for server-side autoupdate tests."
+
+import logging
+
+import common
+from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib.cros import autoupdater, dev_server
+from autotest_lib.server.cros.dynamic_suite import tools
+
+
+def get_updater_from_repo_url(host, job_repo_url=None):
+ """Returns the autoupdater instance to use for a given autoupdate test.
+
+ All server-side tests that run in the lab have an associated job_repo_url
+ assigned to their host that is associated with the version of the build that
+ is currently installed on them. Given most autoupdate tests need to
+ update to some build as part of the test, we conveniently re-update to the
+ same version installed. This method serves as a helper to get the
+ instantiated autoupdater instance for that build.
+
+ This method guarantees that the devserver associated with the autoupdater
+ has already staged the necessary files for autoupdate.
+
+ @param host: The host for the DUT of the server-side test.
+ @param job_repo_url: If set, the job_repo_url to use.
+
+ @raise error.TestError: If we fail to get a job_repo_url.
+ """
+ # Get the job_repo_url -- if not present, attempt to use the one
+ # specified in the host attributes for the host.
+ if not job_repo_url:
+ try:
+ job_repo_url = host.lookup_job_repo_url()
+ except KeyError:
+ logging.fatal('Could not lookup job_repo_url from afe.')
+
+ if not job_repo_url:
+ raise error.TestError(
+ 'Could not find a job_repo_url for the given host.')
+
+ # Get the devserver url and build (image) from the repo url e.g.
+ # 'http://mydevserver:8080', 'x86-alex-release/R27-123.0.0'
+ ds_url, build = tools.get_devserver_build_from_package_url(job_repo_url)
+ devserver = dev_server.ImageServer(ds_url)
+ devserver.stage_artifacts(build, ['full_payload', 'stateful'])
+
+ # We only need to update stateful to do this test.
+ return autoupdater.ChromiumOSUpdater(devserver.get_update_url(build),
+ host=host)
diff --git a/server/site_tests/autoupdate_Rollback/autoupdate_Rollback.py b/server/site_tests/autoupdate_Rollback/autoupdate_Rollback.py
new file mode 100755
index 0000000..e6ccd56
--- /dev/null
+++ b/server/site_tests/autoupdate_Rollback/autoupdate_Rollback.py
@@ -0,0 +1,51 @@
+# Copyright (c) 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.
+
+import logging
+
+from autotest_lib.server import test
+from autotest_lib.server.cros import autoupdate_utils
+
+
+class autoupdate_Rollback(test.test):
+ """Test that updates the machine and performs rollback."""
+ version = 1
+
+
+ def run_once(self, host, job_repo_url=None):
+ """Runs the test.
+
+ @param host: A host object representing the DUT.
+ @param job_repo_url: URL to get the image.
+
+ @raise error.TestError if anything went wrong with setting up the test;
+ error.TestFail if any part of the test has failed.
+
+ """
+ updater = autoupdate_utils.get_updater_from_repo_url(host, job_repo_url)
+
+ initial_kernel, updated_kernel = updater.get_kernel_state()
+ logging.info('Initial device state: active kernel %s, '
+ 'inactive kernel %s.', initial_kernel, updated_kernel)
+
+ logging.info('Performing an update.')
+ updater.update_rootfs()
+ host.reboot()
+
+ # We should be booting from the new partition.
+ error_message = 'Failed to set up test by updating DUT.'
+ updater.verify_boot_expectations(expected_kernel_state=updated_kernel,
+ rollback_message=error_message)
+ logging.info('Update verified, initiating rollback.')
+
+ # Powerwash is tested separately from rollback.
+ updater.rollback_rootfs(powerwash=False)
+ host.reboot()
+
+ # We should be back on our initial partition.
+ error_message = ('Autoupdate reported that rollback succeeded but we '
+ 'did not boot into the correct partition.')
+ updater.verify_boot_expectations(expected_kernel_state=initial_kernel,
+ rollback_message=error_message)
+ logging.info('We successfully rolled back to initial kernel.')
diff --git a/server/site_tests/autoupdate_Rollback/control b/server/site_tests/autoupdate_Rollback/control
new file mode 100644
index 0000000..bf14dda
--- /dev/null
+++ b/server/site_tests/autoupdate_Rollback/control
@@ -0,0 +1,55 @@
+# Copyright (c) 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.
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chromium OS"
+NAME = "autoupdate_Rollback"
+TIME = "MEDIUM"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "platform"
+TEST_TYPE = "server"
+
+DOC = """
+This is a rollback test for Chrome OS releases. It first updates a machine and
+then invokes rollback to boot from its previously booted partition. It tests
+rollback using the update_engine_client rather than manipulating the UI.
+
+Setup for this test is exactly like platform_RebootAfterUpdate. Namely:
+
+Arg:
+ job_repo_url: repo url to use to find image to update from -- assumes caller
+ has staged image. By default if host[repo_job_url] is set, it'll
+ use that. This overrides that value. This value must follow
+ the package_url_pattern in the global config.
+
+To run locally:
+ 1) Setup your devserver in your shadow config that your DUT can reach.
+ 2) Start your devserver and stage the image you want for example:
+ http://localhost:8080/download?archive_url=\
+ gs://chromeos-image-archive/parrot-release/R32-4793.0.0 (and leave it on).
+ 3) Run with test_that etc passing
+ args="job_repo_url=http://<your_hostname>:8080/static/\
+ parrot-release/R32-4793.0.0/autotest/packages"
+
+For example:
+
+test_that -b parrot --args="job_repo_url=http://<your_machine>:8080/static/\
+parrot-release/R32-4793.0.0/autotest/packages" --fast \
+<dut_ip> autoupdate_Rollback
+"""
+
+args_dict = utils.args_to_dict(args)
+job_repo_url = args_dict.get('job_repo_url')
+
+
+def run_test(machine):
+ """Execute a test configuration on a given machine."""
+ host = hosts.create_host(machine)
+ job.run_test("autoupdate_Rollback", host=host,
+ job_repo_url=job_repo_url)
+
+
+# Invoke parallel tests.
+parallel_simple(run_test, machines)
diff --git a/server/site_tests/platform_RebootAfterUpdate/control b/server/site_tests/platform_RebootAfterUpdate/control
index e4a62aa..eea060f 100644
--- a/server/site_tests/platform_RebootAfterUpdate/control
+++ b/server/site_tests/platform_RebootAfterUpdate/control
@@ -30,7 +30,7 @@
http://localhost:8080/download?archive_url=\
gs://chromeos-image-archive/x86-alex/R29-4165.0.0
3) Run with run_remote_test etc passing
- args="job_repo_url=http://localhost:8080/static/\
+ args="job_repo_url=http://<your_hostname>:8080/static/\
x86-alex/R29-4165.0.0/autotest/packages"
"""
diff --git a/server/site_tests/platform_RebootAfterUpdate/platform_RebootAfterUpdate.py b/server/site_tests/platform_RebootAfterUpdate/platform_RebootAfterUpdate.py
index 5710b6b..27199ba 100755
--- a/server/site_tests/platform_RebootAfterUpdate/platform_RebootAfterUpdate.py
+++ b/server/site_tests/platform_RebootAfterUpdate/platform_RebootAfterUpdate.py
@@ -6,9 +6,8 @@
import time
from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib.cros import autoupdater, dev_server
from autotest_lib.server import autotest, test
-from autotest_lib.server.cros.dynamic_suite import tools
+from autotest_lib.server.cros import autoupdate_utils
class platform_RebootAfterUpdate(test.test):
@@ -68,28 +67,7 @@
error.TestFail if any part of the test has failed.
"""
- # Get the job_repo_url -- if not present, attempt to use the one
- # specified in the host attributes for the host.
- if not job_repo_url:
- try:
- job_repo_url = host.lookup_job_repo_url()
- except KeyError:
- logging.fatal('Could not lookup job_repo_url from afe.')
-
- if not job_repo_url:
- raise error.TestError(
- 'Test could not be run. Missing the url with which to '
- 're-image the device!')
-
- # Get the devserver url and build (image) from the repo url e.g.
- # 'http://mydevserver:8080', 'x86-alex-release/R27-123.0.0'
- ds, build = tools.get_devserver_build_from_package_url(job_repo_url)
- devserver = dev_server.ImageServer(ds)
- devserver.stage_artifacts(build, ['stateful'])
-
- # We only need to update stateful to do this test.
- updater = autoupdater.ChromiumOSUpdater(
- devserver.get_update_url(build), host=host)
+ updater = autoupdate_utils.get_updater_from_repo_url(host, job_repo_url)
updater.update_stateful(clobber=True)
logging.info('Rebooting after performing update.')