blob: 04ece9fbd8cac109eea47b3c0a56aa7a2bad8a58 [file] [log] [blame]
# Copyright 2014 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Script to mount a built image and run tests on it."""
import contextlib
import os
import unittest
from chromite.lib import commandline
from chromite.lib import constants
from chromite.lib import image_lib
from chromite.lib import image_test_lib
from chromite.lib import osutils
from chromite.lib import path_util
def ParseArgs(args):
"""Return parsed commandline arguments."""
parser = commandline.ArgumentParser(description=__doc__)
parser.add_argument(
"--test_results_root",
type="str_path",
help="Directory to store test results",
)
parser.add_argument("--board", type=str, help="Board (wolf, beaglebone...)")
parser.add_argument(
"image",
type="str_path",
help="Image directory or file to test",
)
parser.add_argument(
"-l",
"--list",
default=False,
action="store_true",
help="List all the available tests",
)
parser.add_bool_argument(
"--bind-mount",
default=False,
enabled_desc="bind mount the image path as ROOT-A",
disabled_desc="mount ROOT-A and STATE from the image file",
)
parser.add_argument(
"tests",
nargs="*",
metavar="test",
help="Specific tests to run (default runs all)",
)
opts = parser.parse_args(args)
opts.Freeze()
return opts
def FindImage(image_path):
"""Return the path to the image file.
Args:
image_path: A path to the image file, or a directory containing the base
image.
Returns:
ImageFileAndMountScripts containing absolute paths to the image,
the mount and umount invocation commands
"""
if os.path.isdir(image_path):
# Assume base image.
image_file = os.path.join(
image_path, constants.BASE_IMAGE_NAME + ".bin"
)
if not os.path.exists(image_file):
raise ValueError("Cannot find base image %s" % image_file)
elif os.path.isfile(image_path):
image_file = image_path
else:
raise ValueError("%s is neither a directory nor a file" % image_path)
return image_file
def main(args):
opts = ParseArgs(args)
# Build up test suites.
loader = unittest.TestLoader()
loader.suiteClass = image_test_lib.ImageTestSuite
# We use a different prefix here so that unittest DO NOT pick up the
# image tests automatically because they depend on a proper environment.
loader.testMethodPrefix = "Test"
tests_namespace = "chromite.cros.test.image_test"
if opts.tests:
tests = ["%s.%s" % (tests_namespace, x) for x in opts.tests]
else:
tests = (tests_namespace,)
all_tests = loader.loadTestsFromNames(tests)
# If they just want to see the lists of tests, show them now.
if opts.list:
def _WalkSuite(suite):
for test in suite:
if isinstance(test, unittest.BaseTestSuite):
for result in _WalkSuite(test):
yield result
else:
yield (
test.id()[len(tests_namespace) + 1 :],
test.shortDescription() or "",
)
test_list = list(_WalkSuite(all_tests))
maxlen = max(len(x[0]) for x in test_list)
for name, desc in test_list:
print("%-*s %s" % (maxlen, name, desc))
return
# Run them in the image directory.
runner = image_test_lib.ImageTestRunner()
runner.SetBoard(opts.board)
runner.SetResultDir(opts.test_results_root)
tmp_in_chroot = path_util.FromChrootPath("/tmp")
with contextlib.ExitStack() as stack:
temp_dir = stack.enter_context(osutils.TempDir(base_dir=tmp_in_chroot))
if opts.bind_mount:
runner.SetImageType(image_test_lib.ImageType.BIND_MOUNT)
mount_path = temp_dir + "/dir-" + constants.PART_ROOT_A
stack.enter_context(
osutils.MountDirContext(
opts.image, mount_path, mount_opts=("bind", "ro")
)
)
else:
runner.SetImageType(image_test_lib.ImageType.BIN_FILE)
image_file = FindImage(opts.image)
stack.enter_context(
image_lib.LoopbackPartitions(
image_file,
temp_dir,
(constants.PART_ROOT_A, constants.PART_STATE),
)
)
with osutils.ChdirContext(temp_dir):
result = runner.run(all_tests)
if result and not result.wasSuccessful():
return 1
return 0