summaryrefslogtreecommitdiff
path: root/import-layers/yocto-poky/scripts/oe-selftest
diff options
context:
space:
mode:
Diffstat (limited to 'import-layers/yocto-poky/scripts/oe-selftest')
-rwxr-xr-ximport-layers/yocto-poky/scripts/oe-selftest164
1 files changed, 151 insertions, 13 deletions
diff --git a/import-layers/yocto-poky/scripts/oe-selftest b/import-layers/yocto-poky/scripts/oe-selftest
index d9ffd40e8..52366b1c8 100755
--- a/import-layers/yocto-poky/scripts/oe-selftest
+++ b/import-layers/yocto-poky/scripts/oe-selftest
@@ -46,6 +46,7 @@ import argparse_oe
import oeqa.selftest
import oeqa.utils.ftools as ftools
from oeqa.utils.commands import runCmd, get_bb_var, get_test_layer
+from oeqa.utils.metadata import metadata_from_bb, write_metadata_file
from oeqa.selftest.base import oeSelfTest, get_available_machines
try:
@@ -61,7 +62,8 @@ log_prefix = "oe-selftest-" + t.strftime("%Y%m%d-%H%M%S")
def logger_create():
log_file = log_prefix + ".log"
- if os.path.exists("oe-selftest.log"): os.remove("oe-selftest.log")
+ if os.path.lexists("oe-selftest.log"):
+ os.remove("oe-selftest.log")
os.symlink(log_file, "oe-selftest.log")
log = logging.getLogger("selftest")
@@ -85,7 +87,7 @@ def logger_create():
log = logger_create()
def get_args_parser():
- description = "Script that runs unit tests agains bitbake and other Yocto related tools. The goal is to validate tools functionality and metadata integrity. Refer to https://wiki.yoctoproject.org/wiki/Oe-selftest for more information."
+ description = "Script that runs unit tests against bitbake and other Yocto related tools. The goal is to validate tools functionality and metadata integrity. Refer to https://wiki.yoctoproject.org/wiki/Oe-selftest for more information."
parser = argparse_oe.ArgumentParser(description=description)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-r', '--run-tests', required=False, action='store', nargs='*', dest="run_tests", default=None, help='Select what tests to run (modules, classes or test methods). Format should be: <module>.<class>.<test_method>')
@@ -106,11 +108,17 @@ def get_args_parser():
help='List all tags that have been set to test cases.')
parser.add_argument('--machine', required=False, dest='machine', choices=['random', 'all'], default=None,
help='Run tests on different machines (random/all).')
+ parser.add_argument('--repository', required=False, dest='repository', default='', action='store',
+ help='Submit test results to a repository')
return parser
+builddir = None
+
def preflight_check():
+ global builddir
+
log.info("Checking that everything is in order before running the tests")
if not os.environ.get("BUILDDIR"):
@@ -123,7 +131,27 @@ def preflight_check():
os.chdir(builddir)
if not "meta-selftest" in get_bb_var("BBLAYERS"):
- log.error("You don't seem to have the meta-selftest layer in BBLAYERS")
+ log.warn("meta-selftest layer not found in BBLAYERS, adding it")
+ meta_selftestdir = os.path.join(
+ get_bb_var("BBLAYERS_FETCH_DIR"),
+ 'meta-selftest')
+ if os.path.isdir(meta_selftestdir):
+ runCmd("bitbake-layers add-layer %s" %meta_selftestdir)
+ else:
+ log.error("could not locate meta-selftest in:\n%s"
+ %meta_selftestdir)
+ return False
+
+ if "buildhistory.bbclass" in get_bb_var("BBINCLUDED"):
+ log.error("You have buildhistory enabled already and this isn't recommended for selftest, please disable it first.")
+ return False
+
+ if get_bb_var("PRSERV_HOST"):
+ log.error("Please unset PRSERV_HOST in order to run oe-selftest")
+ return False
+
+ if get_bb_var("SANITY_TESTED_DISTROS"):
+ log.error("Please unset SANITY_TESTED_DISTROS in order to run oe-selftest")
return False
log.info("Running bitbake -p")
@@ -132,7 +160,7 @@ def preflight_check():
return True
def add_include():
- builddir = os.environ.get("BUILDDIR")
+ global builddir
if "#include added by oe-selftest.py" \
not in ftools.read_file(os.path.join(builddir, "conf/local.conf")):
log.info("Adding: \"include selftest.inc\" in local.conf")
@@ -146,7 +174,7 @@ def add_include():
"\n#include added by oe-selftest.py\ninclude bblayers.inc")
def remove_include():
- builddir = os.environ.get("BUILDDIR")
+ global builddir
if builddir is None:
return
if "#include added by oe-selftest.py" \
@@ -162,18 +190,21 @@ def remove_include():
"\n#include added by oe-selftest.py\ninclude bblayers.inc")
def remove_inc_files():
+ global builddir
+ if builddir is None:
+ return
try:
- os.remove(os.path.join(os.environ.get("BUILDDIR"), "conf/selftest.inc"))
+ os.remove(os.path.join(builddir, "conf/selftest.inc"))
for root, _, files in os.walk(get_test_layer()):
for f in files:
if f == 'test_recipe.inc':
os.remove(os.path.join(root, f))
- except (AttributeError, OSError,) as e: # AttributeError may happen if BUILDDIR is not set
+ except OSError as e:
pass
for incl_file in ['conf/bblayers.inc', 'conf/machine.inc']:
try:
- os.remove(os.path.join(os.environ.get("BUILDDIR"), incl_file))
+ os.remove(os.path.join(builddir, incl_file))
except:
pass
@@ -336,10 +367,15 @@ def list_testsuite_by(criteria, keyword):
# Get a testsuite based on 'keyword'
# criteria: name, class, module, id, tag
# keyword: a list of tests, classes, modules, ids, tags
-
- ts = sorted([ (tc.tcid, tc.tctag, tc.tcname, tc.tcclass, tc.tcmodule) for tc in get_testsuite_by(criteria, keyword) ])
-
- print('%-4s\t%-20s\t%-60s\t%-25s\t%-20s' % ('id', 'tag', 'name', 'class', 'module'))
+ def tc_key(t):
+ if t[0] is None:
+ return (0,) + t[1:]
+ return t
+ # tcid may be None if no ID was assigned, in which case sorted() will throw
+ # a TypeError as Python 3 does not allow comparison (<,<=,>=,>) of
+ # heterogeneous types, handle this by using a custom key generator
+ ts = sorted([ (tc.tcid, tc.tctag, tc.tcname, tc.tcclass, tc.tcmodule) \
+ for tc in get_testsuite_by(criteria, keyword) ], key=tc_key)
print('_' * 150)
for t in ts:
if isinstance(t[1], (tuple, list)):
@@ -386,7 +422,7 @@ def coverage_setup(coverage_source, coverage_include, coverage_omit):
""" Set up the coverage measurement for the testcases to be run """
import datetime
import subprocess
- builddir = os.environ.get("BUILDDIR")
+ global builddir
pokydir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
curcommit= subprocess.check_output(["git", "--git-dir", os.path.join(pokydir, ".git"), "rev-parse", "HEAD"]).decode('utf-8')
coveragerc = "%s/.coveragerc" % builddir
@@ -463,6 +499,9 @@ def main():
sys.path.extend(layer_libdirs)
imp.reload(oeqa.selftest)
+ # act like bitbake and enforce en_US.UTF-8 locale
+ os.environ["LC_ALL"] = "en_US.UTF-8"
+
if args.run_tests_by and len(args.run_tests_by) >= 2:
valid_options = ['name', 'class', 'module', 'id', 'tag']
if args.run_tests_by[0] not in valid_options:
@@ -564,6 +603,76 @@ def main():
log.info("Finished")
+ if args.repository:
+ import git
+ # Commit tests results to repository
+ metadata = metadata_from_bb()
+ git_dir = os.path.join(os.getcwd(), 'selftest')
+ if not os.path.isdir(git_dir):
+ os.mkdir(git_dir)
+
+ log.debug('Checking for git repository in %s' % git_dir)
+ try:
+ repo = git.Repo(git_dir)
+ except git.exc.InvalidGitRepositoryError:
+ log.debug("Couldn't find git repository %s; "
+ "cloning from %s" % (git_dir, args.repository))
+ repo = git.Repo.clone_from(args.repository, git_dir)
+
+ r_branches = repo.git.branch(r=True)
+ r_branches = set(r_branches.replace('origin/', '').split())
+ l_branches = {str(branch) for branch in repo.branches}
+ branch = '%s/%s/%s' % (metadata['hostname'],
+ metadata['layers']['meta'].get('branch', '(nogit)'),
+ metadata['config']['MACHINE'])
+
+ if branch in l_branches:
+ log.debug('Found branch in local repository, checking out')
+ repo.git.checkout(branch)
+ elif branch in r_branches:
+ log.debug('Found branch in remote repository, checking'
+ ' out and pulling')
+ repo.git.checkout(branch)
+ repo.git.pull()
+ else:
+ log.debug('New branch %s' % branch)
+ repo.git.checkout('master')
+ repo.git.checkout(b=branch)
+
+ cleanResultsDir(repo)
+ xml_dir = os.path.join(os.getcwd(), log_prefix)
+ copyResultFiles(xml_dir, git_dir, repo)
+ metadata_file = os.path.join(git_dir, 'metadata.xml')
+ write_metadata_file(metadata_file, metadata)
+ repo.index.add([metadata_file])
+ repo.index.write()
+
+ # Get information for commit message
+ layer_info = ''
+ for layer, values in metadata['layers'].items():
+ layer_info = '%s%-17s = %s:%s\n' % (layer_info, layer,
+ values.get('branch', '(nogit)'), values.get('commit', '0'*40))
+ msg = 'Selftest for build %s of %s for machine %s on %s\n\n%s' % (
+ log_prefix[12:], metadata['distro']['pretty_name'],
+ metadata['config']['MACHINE'], metadata['hostname'], layer_info)
+
+ log.debug('Commiting results to local repository')
+ repo.index.commit(msg)
+ if not repo.is_dirty():
+ try:
+ if branch in r_branches:
+ log.debug('Pushing changes to remote repository')
+ repo.git.push()
+ else:
+ log.debug('Pushing changes to remote repository '
+ 'creating new branch')
+ repo.git.push('-u', 'origin', branch)
+ except GitCommandError:
+ log.error('Falied to push to remote repository')
+ return 1
+ else:
+ log.error('Local repository is dirty, not pushing commits')
+
if result.wasSuccessful():
return 0
else:
@@ -647,6 +756,35 @@ def buildResultClass(args):
return StampedResult
+def cleanResultsDir(repo):
+ """ Remove result files from directory """
+
+ xml_files = []
+ directory = repo.working_tree_dir
+ for f in os.listdir(directory):
+ path = os.path.join(directory, f)
+ if os.path.isfile(path) and path.endswith('.xml'):
+ xml_files.append(f)
+ repo.index.remove(xml_files, working_tree=True)
+
+def copyResultFiles(src, dst, repo):
+ """ Copy result files from src to dst removing the time stamp. """
+
+ import shutil
+
+ re_time = re.compile("-[0-9]+")
+ file_list = []
+
+ for root, subdirs, files in os.walk(src):
+ tmp_dir = root.replace(src, '').lstrip('/')
+ for s in subdirs:
+ os.mkdir(os.path.join(dst, tmp_dir, s))
+ for f in files:
+ file_name = os.path.join(dst, tmp_dir, re_time.sub("", f))
+ shutil.copy2(os.path.join(root, f), file_name)
+ file_list.append(file_name)
+ repo.index.add(file_list)
+
class TestRunner(_TestRunner):
"""Test runner class aware of exporting tests."""
def __init__(self, *args, **kwargs):