diff options
Diffstat (limited to 'yocto-poky/meta/lib/oeqa')
25 files changed, 810 insertions, 355 deletions
diff --git a/yocto-poky/meta/lib/oeqa/oetest.py b/yocto-poky/meta/lib/oeqa/oetest.py index a6f89b6a8..6f9edec58 100644 --- a/yocto-poky/meta/lib/oeqa/oetest.py +++ b/yocto-poky/meta/lib/oeqa/oetest.py @@ -11,9 +11,14 @@ import os, re, mmap import unittest import inspect import subprocess -import bb -from oeqa.utils.decorators import LogResults, gettag -from sys import exc_info, exc_clear +try: + import bb +except ImportError: + pass +import logging +from oeqa.utils.decorators import LogResults, gettag, getResults + +logger = logging.getLogger("BitBake") def getVar(obj): #extend form dict, if a variable didn't exists, need find it in testcase @@ -89,7 +94,7 @@ def loadTests(tc, type="runtime"): suite.dependencies.append(dep_suite) break else: - bb.warn("Test %s was declared as @skipUnlessPassed('%s') but that test is either not defined or not active. Will run the test anyway." % + logger.warning("Test %s was declared as @skipUnlessPassed('%s') but that test is either not defined or not active. Will run the test anyway." % (test, depends_on)) # Use brute-force topological sort to determine ordering. Sort by # depth (higher depth = must run later), with original ordering to @@ -106,14 +111,34 @@ def loadTests(tc, type="runtime"): suites.sort(cmp=lambda a,b: cmp((a.depth, a.index), (b.depth, b.index))) return testloader.suiteClass(suites) +_buffer = "" + +def custom_verbose(msg, *args, **kwargs): + global _buffer + if msg[-1] != "\n": + _buffer += msg + else: + _buffer += msg + try: + bb.plain(_buffer.rstrip("\n"), *args, **kwargs) + except NameError: + logger.info(_buffer.rstrip("\n"), *args, **kwargs) + _buffer = "" + def runTests(tc, type="runtime"): suite = loadTests(tc, type) - bb.note("Test modules %s" % tc.testslist) + logger.info("Test modules %s" % tc.testslist) if hasattr(tc, "tagexp") and tc.tagexp: - bb.note("Filter test cases by tags: %s" % tc.tagexp) - bb.note("Found %s tests" % suite.countTestCases()) + logger.info("Filter test cases by tags: %s" % tc.tagexp) + logger.info("Found %s tests" % suite.countTestCases()) runner = unittest.TextTestRunner(verbosity=2) + try: + if bb.msg.loggerDefaultVerbose: + runner.stream.write = custom_verbose + except NameError: + # Not in bb environment? + pass result = runner.run(suite) return result @@ -158,17 +183,24 @@ class oeRuntimeTest(oeTest): pass def tearDown(self): - # If a test fails or there is an exception - if not exc_info() == (None, None, None): - exc_clear() - #Only dump for QemuTarget - if (type(self.target).__name__ == "QemuTarget"): - self.tc.host_dumper.create_dir(self._testMethodName) - self.tc.host_dumper.dump_host() - self.target.target_dumper.dump_target( - self.tc.host_dumper.dump_dir) - print ("%s dump data stored in %s" % (self._testMethodName, - self.tc.host_dumper.dump_dir)) + res = getResults() + # If a test fails or there is an exception dump + # for QemuTarget only + if (type(self.target).__name__ == "QemuTarget" and + (self.id() in res.getErrorList() or + self.id() in res.getFailList())): + self.tc.host_dumper.create_dir(self._testMethodName) + self.tc.host_dumper.dump_host() + self.target.target_dumper.dump_target( + self.tc.host_dumper.dump_dir) + print ("%s dump data stored in %s" % (self._testMethodName, + self.tc.host_dumper.dump_dir)) + + self.tearDownLocal() + + # Method to be run after tearDown and implemented by child classes + def tearDownLocal(self): + pass #TODO: use package_manager.py to install packages on any type of image def install_packages(self, packagelist): @@ -190,7 +222,7 @@ class oeSDKTest(oeTest): return False def _run(self, cmd): - return subprocess.check_output(cmd, shell=True) + return subprocess.check_output(". %s; " % self.tc.sdkenv + cmd, shell=True) def getmodule(pos=2): # stack returns a list of tuples containg frame information diff --git a/yocto-poky/meta/lib/oeqa/runexported.py b/yocto-poky/meta/lib/oeqa/runexported.py index 96442b1b2..dba0d7aec 100755 --- a/yocto-poky/meta/lib/oeqa/runexported.py +++ b/yocto-poky/meta/lib/oeqa/runexported.py @@ -21,7 +21,7 @@ import sys import os import time -from optparse import OptionParser +import argparse try: import simplejson as json @@ -49,8 +49,8 @@ class FakeTarget(object): def exportStart(self): self.sshlog = os.path.join(self.testdir, "ssh_target_log.%s" % self.datetime) sshloglink = os.path.join(self.testdir, "ssh_target_log") - if os.path.islink(sshloglink): - os.unlink(sshloglink) + if os.path.exists(sshloglink): + os.remove(sshloglink) os.symlink(self.sshlog, sshloglink) print("SSH log file: %s" % self.sshlog) self.connection = SSHControl(self.ip, logfile=self.sshlog) @@ -76,43 +76,41 @@ class TestContext(object): def main(): - usage = "usage: %prog [options] <json file>" - parser = OptionParser(usage=usage) - parser.add_option("-t", "--target-ip", dest="ip", help="The IP address of the target machine. Use this to \ + parser = argparse.ArgumentParser() + parser.add_argument("-t", "--target-ip", dest="ip", help="The IP address of the target machine. Use this to \ overwrite the value determined from TEST_TARGET_IP at build time") - parser.add_option("-s", "--server-ip", dest="server_ip", help="The IP address of this machine. Use this to \ + parser.add_argument("-s", "--server-ip", dest="server_ip", help="The IP address of this machine. Use this to \ overwrite the value determined from TEST_SERVER_IP at build time.") - parser.add_option("-d", "--deploy-dir", dest="deploy_dir", help="Full path to the package feeds, that this \ + parser.add_argument("-d", "--deploy-dir", dest="deploy_dir", help="Full path to the package feeds, that this \ the contents of what used to be DEPLOY_DIR on the build machine. If not specified it will use the value \ specified in the json if that directory actually exists or it will error out.") - parser.add_option("-l", "--log-dir", dest="log_dir", help="This sets the path for TEST_LOG_DIR. If not specified \ + parser.add_argument("-l", "--log-dir", dest="log_dir", help="This sets the path for TEST_LOG_DIR. If not specified \ the current dir is used. This is used for usually creating a ssh log file and a scp test file.") + parser.add_argument("json", help="The json file exported by the build system", default="testdata.json", nargs='?') - (options, args) = parser.parse_args() - if len(args) != 1: - parser.error("Incorrect number of arguments. The one and only argument should be a json file exported by the build system") + args = parser.parse_args() - with open(args[0], "r") as f: + with open(args.json, "r") as f: loaded = json.load(f) - if options.ip: - loaded["target"]["ip"] = options.ip - if options.server_ip: - loaded["target"]["server_ip"] = options.server_ip + if args.ip: + loaded["target"]["ip"] = args.ip + if args.server_ip: + loaded["target"]["server_ip"] = args.server_ip d = MyDataDict() for key in loaded["d"].keys(): d[key] = loaded["d"][key] - if options.log_dir: - d["TEST_LOG_DIR"] = options.log_dir + if args.log_dir: + d["TEST_LOG_DIR"] = args.log_dir else: d["TEST_LOG_DIR"] = os.path.abspath(os.path.dirname(__file__)) - if options.deploy_dir: - d["DEPLOY_DIR"] = options.deploy_dir + if args.deploy_dir: + d["DEPLOY_DIR"] = args.deploy_dir else: if not os.path.isdir(d["DEPLOY_DIR"]): - raise Exception("The path to DEPLOY_DIR does not exists: %s" % d["DEPLOY_DIR"]) + print("WARNING: The path to DEPLOY_DIR does not exist: %s" % d["DEPLOY_DIR"]) target = FakeTarget(d) diff --git a/yocto-poky/meta/lib/oeqa/runtime/_ptest.py b/yocto-poky/meta/lib/oeqa/runtime/_ptest.py index 81c9c4386..0621028b8 100644 --- a/yocto-poky/meta/lib/oeqa/runtime/_ptest.py +++ b/yocto-poky/meta/lib/oeqa/runtime/_ptest.py @@ -98,7 +98,7 @@ class PtestRunnerTest(oeRuntimeTest): return complementary_pkgs.split() - def setUp(self): + def setUpLocal(self): self.ptest_log = os.path.join(oeRuntimeTest.tc.d.getVar("TEST_LOG_DIR",True), "ptest-%s.log" % oeRuntimeTest.tc.d.getVar('DATETIME', True)) @skipUnlessPassed('test_ssh') diff --git a/yocto-poky/meta/lib/oeqa/runtime/connman.py b/yocto-poky/meta/lib/oeqa/runtime/connman.py index ee69e5df9..bd9dba3bd 100644 --- a/yocto-poky/meta/lib/oeqa/runtime/connman.py +++ b/yocto-poky/meta/lib/oeqa/runtime/connman.py @@ -29,26 +29,3 @@ class ConnmanTest(oeRuntimeTest): if status != 0: print self.service_status("connman") self.fail("No connmand process running") - - @testcase(223) - def test_only_one_connmand_in_background(self): - """ - Summary: Only one connmand in background - Expected: There will be only one connmand instance in background. - Product: BSPs - Author: Alexandru Georgescu <alexandru.c.georgescu@intel.com> - AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com> - """ - - # Make sure that 'connmand' is running in background - (status, output) = self.target.run(oeRuntimeTest.pscmd + ' | grep [c]onnmand') - self.assertEqual(0, status, 'Failed to find "connmand" process running in background.') - - # Start a new instance of 'connmand' - (status, output) = self.target.run('connmand') - self.assertEqual(0, status, 'Failed to start a new "connmand" process.') - - # Make sure that only one 'connmand' is running in background - (status, output) = self.target.run(oeRuntimeTest.pscmd + ' | grep [c]onnmand | wc -l') - self.assertEqual(0, status, 'Failed to find "connmand" process running in background.') - self.assertEqual(1, int(output), 'Found {} connmand processes running, expected 1.'.format(output)) diff --git a/yocto-poky/meta/lib/oeqa/runtime/date.py b/yocto-poky/meta/lib/oeqa/runtime/date.py index 3a8fe8481..447987e07 100644 --- a/yocto-poky/meta/lib/oeqa/runtime/date.py +++ b/yocto-poky/meta/lib/oeqa/runtime/date.py @@ -4,11 +4,11 @@ import re class DateTest(oeRuntimeTest): - def setUp(self): + def setUpLocal(self): if oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager", True) == "systemd": self.target.run('systemctl stop systemd-timesyncd') - def tearDown(self): + def tearDownLocal(self): if oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager", True) == "systemd": self.target.run('systemctl start systemd-timesyncd') diff --git a/yocto-poky/meta/lib/oeqa/runtime/files/testsdkmakefile b/yocto-poky/meta/lib/oeqa/runtime/files/testsdkmakefile new file mode 100644 index 000000000..fb05f822f --- /dev/null +++ b/yocto-poky/meta/lib/oeqa/runtime/files/testsdkmakefile @@ -0,0 +1,5 @@ +test: test.o + $(CC) -o test test.o -lm +test.o: test.c + $(CC) -c test.c + diff --git a/yocto-poky/meta/lib/oeqa/runtime/kernelmodule.py b/yocto-poky/meta/lib/oeqa/runtime/kernelmodule.py index 2e8172032..38ca18454 100644 --- a/yocto-poky/meta/lib/oeqa/runtime/kernelmodule.py +++ b/yocto-poky/meta/lib/oeqa/runtime/kernelmodule.py @@ -10,7 +10,7 @@ def setUpModule(): class KernelModuleTest(oeRuntimeTest): - def setUp(self): + def setUpLocal(self): self.target.copy_to(os.path.join(oeRuntimeTest.tc.filesdir, "hellomod.c"), "/tmp/hellomod.c") self.target.copy_to(os.path.join(oeRuntimeTest.tc.filesdir, "hellomod_makefile"), "/tmp/Makefile") @@ -30,5 +30,5 @@ class KernelModuleTest(oeRuntimeTest): (status, output) = self.target.run(cmd, 900) self.assertEqual(status, 0, msg="\n".join([cmd, output])) - def tearDown(self): + def tearDownLocal(self): self.target.run('rm -f /tmp/Makefile /tmp/hellomod.c') diff --git a/yocto-poky/meta/lib/oeqa/runtime/parselogs.py b/yocto-poky/meta/lib/oeqa/runtime/parselogs.py index e20947b8b..fc2bc3893 100644 --- a/yocto-poky/meta/lib/oeqa/runtime/parselogs.py +++ b/yocto-poky/meta/lib/oeqa/runtime/parselogs.py @@ -36,6 +36,8 @@ common_errors = [ 'VGA arbiter: cannot open kernel arbiter, no multi-card support', 'Failed to find URL:http://ipv4.connman.net/online/status.html', 'Online check failed for', + 'netlink init failed', + 'Fast TSC calibration', ] x86_common = [ @@ -46,7 +48,6 @@ x86_common = [ ] + common_errors qemux86_common = [ - 'Fast TSC calibration', 'wrong ELF class', "fail to add MMCONFIG information, can't access extended PCI configuration space under this bridge.", "can't claim BAR ", @@ -89,7 +90,7 @@ ignore_errors = { '(EE) open /dev/fb0: No such file or directory', '(EE) AIGLX: reverting to software rendering', ] + x86_common, - 'core2_32' : [ + 'intel-core2-32' : [ 'ACPI: No _BQC method, cannot determine initial brightness', '[Firmware Bug]: ACPI: No _BQC method, cannot determine initial brightness', '(EE) Failed to load module "psb"', @@ -98,6 +99,7 @@ ignore_errors = { '(EE) Failed to load module psbdrv', '(EE) open /dev/fb0: No such file or directory', '(EE) AIGLX: reverting to software rendering', + "controller can't do DEVSLP, turning off", ] + x86_common, 'intel-corei7-64' : [ "controller can't do DEVSLP, turning off", @@ -108,13 +110,9 @@ ignore_errors = { 'edgerouter' : [ 'Fatal server error:', ] + common_errors, - 'minnow' : [ - 'netlink init failed', - ] + common_errors, 'jasperforest' : [ 'Activated service \'org.bluez\' failed:', 'Unable to find NFC netlink family', - 'netlink init failed', ] + common_errors, } @@ -233,8 +231,7 @@ class ParseLogsTest(oeRuntimeTest): #get the output of dmesg and write it in a file. This file is added to log_locations. def write_dmesg(self): - (status, dmesg) = self.target.run("dmesg") - (status, dmesg2) = self.target.run("echo \""+str(dmesg)+"\" > /tmp/dmesg_output.log") + (status, dmesg) = self.target.run("dmesg > /tmp/dmesg_output.log") @testcase(1059) @skipUnlessPassed('test_ssh') diff --git a/yocto-poky/meta/lib/oeqa/runtime/scanelf.py b/yocto-poky/meta/lib/oeqa/runtime/scanelf.py index 43a024ab9..67e02ff45 100644 --- a/yocto-poky/meta/lib/oeqa/runtime/scanelf.py +++ b/yocto-poky/meta/lib/oeqa/runtime/scanelf.py @@ -8,7 +8,7 @@ def setUpModule(): class ScanelfTest(oeRuntimeTest): - def setUp(self): + def setUpLocal(self): self.scancmd = 'scanelf --quiet --recursive --mount --ldpath --path' @testcase(966) diff --git a/yocto-poky/meta/lib/oeqa/sdk/gcc.py b/yocto-poky/meta/lib/oeqa/sdk/gcc.py index 67994b9b5..8395b9b90 100644 --- a/yocto-poky/meta/lib/oeqa/sdk/gcc.py +++ b/yocto-poky/meta/lib/oeqa/sdk/gcc.py @@ -14,7 +14,7 @@ class GccCompileTest(oeSDKTest): @classmethod def setUpClass(self): - for f in ['test.c', 'test.cpp', 'testmakefile']: + for f in ['test.c', 'test.cpp', 'testsdkmakefile']: shutil.copyfile(os.path.join(self.tc.filesdir, f), self.tc.sdktestdir + f) def test_gcc_compile(self): @@ -27,10 +27,10 @@ class GccCompileTest(oeSDKTest): self._run('$CXX %s/test.cpp -o %s/test -lm' % (self.tc.sdktestdir, self.tc.sdktestdir)) def test_make(self): - self._run('cd %s; make -f testmakefile' % self.tc.sdktestdir) + self._run('cd %s; make -f testsdkmakefile' % self.tc.sdktestdir) @classmethod def tearDownClass(self): - files = [self.tc.sdktestdir + f for f in ['test.c', 'test.cpp', 'test.o', 'test', 'testmakefile']] + files = [self.tc.sdktestdir + f for f in ['test.c', 'test.cpp', 'test.o', 'test', 'testsdkmakefile']] for f in files: bb.utils.remove(f) diff --git a/yocto-poky/meta/lib/oeqa/selftest/archiver.py b/yocto-poky/meta/lib/oeqa/selftest/archiver.py new file mode 100644 index 000000000..f2030c446 --- /dev/null +++ b/yocto-poky/meta/lib/oeqa/selftest/archiver.py @@ -0,0 +1,50 @@ +from oeqa.selftest.base import oeSelfTest +from oeqa.utils.commands import bitbake, get_bb_var +from oeqa.utils.decorators import testcase +import glob +import os +import shutil + + +class Archiver(oeSelfTest): + + @testcase(1345) + def test_archiver_allows_to_filter_on_recipe_name(self): + """ + Summary: The archiver should offer the possibility to filter on the recipe. (#6929) + Expected: 1. Included recipe (busybox) should be included + 2. Excluded recipe (zlib) should be excluded + Product: oe-core + Author: Daniel Istrate <daniel.alexandrux.istrate@intel.com> + AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com> + """ + + include_recipe = 'busybox' + exclude_recipe = 'zlib' + + features = 'INHERIT += "archiver"\n' + features += 'ARCHIVER_MODE[src] = "original"\n' + features += 'COPYLEFT_PN_INCLUDE = "%s"\n' % include_recipe + features += 'COPYLEFT_PN_EXCLUDE = "%s"\n' % exclude_recipe + + # Update local.conf + self.write_config(features) + + tmp_dir = get_bb_var('TMPDIR') + deploy_dir_src = get_bb_var('DEPLOY_DIR_SRC') + target_sys = get_bb_var('TARGET_SYS') + src_path = os.path.join(deploy_dir_src, target_sys) + + # Delete tmp directory + shutil.rmtree(tmp_dir) + + # Build core-image-minimal + bitbake('core-image-minimal') + + # Check that include_recipe was included + is_included = len(glob.glob(src_path + '/%s*' % include_recipe)) + self.assertEqual(1, is_included, 'Recipe %s was not included.' % include_recipe) + + # Check that exclude_recipe was excluded + is_excluded = len(glob.glob(src_path + '/%s*' % exclude_recipe)) + self.assertEqual(0, is_excluded, 'Recipe %s was not excluded.' % exclude_recipe) diff --git a/yocto-poky/meta/lib/oeqa/selftest/base.py b/yocto-poky/meta/lib/oeqa/selftest/base.py index b2faa661e..9bddc23f8 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/base.py +++ b/yocto-poky/meta/lib/oeqa/selftest/base.py @@ -31,7 +31,7 @@ class oeSelfTest(unittest.TestCase): self.testinc_bblayers_path = os.path.join(self.builddir, "conf/bblayers.inc") self.testlayer_path = oeSelfTest.testlayer_path self._extra_tear_down_commands = [] - self._track_for_cleanup = [] + self._track_for_cleanup = [self.testinc_path] super(oeSelfTest, self).__init__(methodName) def setUp(self): diff --git a/yocto-poky/meta/lib/oeqa/selftest/bbtests.py b/yocto-poky/meta/lib/oeqa/selftest/bbtests.py index 3d6860f65..94ca79c03 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/bbtests.py +++ b/yocto-poky/meta/lib/oeqa/selftest/bbtests.py @@ -1,8 +1,5 @@ -import unittest import os -import logging import re -import shutil import oeqa.utils.ftools as ftools from oeqa.selftest.base import oeSelfTest @@ -68,15 +65,43 @@ class BitbakeTests(oeSelfTest): bitbake('-cclean man') self.assertTrue("ERROR: Function failed: patch_do_patch" in result.output, msg = "Though no man-1.5h1-make.patch file exists, bitbake didn't output any err. message. bitbake output: %s" % result.output) + @testcase(1354) + def test_force_task_1(self): + # test 1 from bug 5875 + test_recipe = 'zlib' + test_data = "Microsoft Made No Profit From Anyone's Zunes Yo" + image_dir = get_bb_var('D', test_recipe) + pkgsplit_dir = get_bb_var('PKGDEST', test_recipe) + man_dir = get_bb_var('mandir', test_recipe) + + bitbake('-c cleansstate %s' % test_recipe) + bitbake(test_recipe) + self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe) + + man_file = os.path.join(image_dir + man_dir, 'man3/zlib.3') + ftools.append_file(man_file, test_data) + bitbake('-c package -f %s' % test_recipe) + + man_split_file = os.path.join(pkgsplit_dir, 'zlib-doc' + man_dir, 'man3/zlib.3') + man_split_content = ftools.read_file(man_split_file) + self.assertIn(test_data, man_split_content, 'The man file has not changed in packages-split.') + + ret = bitbake(test_recipe) + self.assertIn('task do_package_write_rpm:', ret.output, 'Task do_package_write_rpm did not re-executed.') + @testcase(163) - def test_force_task(self): - bitbake('m4-native') - self.add_command_to_tearDown('bitbake -c clean m4-native') - result = bitbake('-C compile m4-native') - look_for_tasks = ['do_compile', 'do_install', 'do_populate_sysroot'] + def test_force_task_2(self): + # test 2 from bug 5875 + test_recipe = 'zlib' + + bitbake('-c cleansstate %s' % test_recipe) + bitbake(test_recipe) + self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe) + + result = bitbake('-C compile %s' % test_recipe) + look_for_tasks = ['do_compile:', 'do_install:', 'do_populate_sysroot:', 'do_package:'] for task in look_for_tasks: - find_task = re.search("m4-native.*%s" % task, result.output) - self.assertTrue(find_task, msg = "Couldn't find %s task. bitbake output %s" % (task, result.output)) + self.assertIn(task, result.output, msg="Couldn't find %s task.") @testcase(167) def test_bitbake_g(self): @@ -101,6 +126,8 @@ class BitbakeTests(oeSelfTest): self.write_config("""DL_DIR = \"${TOPDIR}/download-selftest\" SSTATE_DIR = \"${TOPDIR}/download-selftest\" """) + self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) + bitbake('-ccleanall man') result = bitbake('-c fetch man', ignore_status=True) bitbake('-ccleanall man') @@ -116,20 +143,20 @@ doesn't exist, yet fetcher didn't report any error. bitbake output: %s" % result self.write_config("""DL_DIR = \"${TOPDIR}/download-selftest\" SSTATE_DIR = \"${TOPDIR}/download-selftest\" """) + self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) + data = 'SRC_URI_append = ";downloadfilename=test-aspell.tar.gz"' self.write_recipeinc('aspell', data) bitbake('-ccleanall aspell') result = bitbake('-c fetch aspell', ignore_status=True) self.delete_recipeinc('aspell') - self.addCleanup(bitbake, '-ccleanall aspell') self.assertEqual(result.status, 0, msg = "Couldn't fetch aspell. %s" % result.output) self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz')), msg = "File rename failed. No corresponding test-aspell.tar.gz file found under %s" % str(get_bb_var("DL_DIR"))) self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz.done')), "File rename failed. No corresponding test-aspell.tar.gz.done file found under %s" % str(get_bb_var("DL_DIR"))) @testcase(1028) def test_environment(self): - self.append_config("TEST_ENV=\"localconf\"") - self.addCleanup(self.remove_config, "TEST_ENV=\"localconf\"") + self.write_config("TEST_ENV=\"localconf\"") result = runCmd('bitbake -e | grep TEST_ENV=') self.assertTrue('localconf' in result.output, msg = "bitbake didn't report any value for TEST_ENV variable. To test, run 'bitbake -e | grep TEST_ENV='") @@ -156,8 +183,7 @@ SSTATE_DIR = \"${TOPDIR}/download-selftest\" ftools.write_file(preconf ,"TEST_PREFILE=\"prefile\"") result = runCmd('bitbake -r conf/prefile.conf -e | grep TEST_PREFILE=') self.assertTrue('prefile' in result.output, "Preconfigure file \"prefile.conf\"was not taken into consideration. ") - self.append_config("TEST_PREFILE=\"localconf\"") - self.addCleanup(self.remove_config, "TEST_PREFILE=\"localconf\"") + self.write_config("TEST_PREFILE=\"localconf\"") result = runCmd('bitbake -r conf/prefile.conf -e | grep TEST_PREFILE=') self.assertTrue('localconf' in result.output, "Preconfigure file \"prefile.conf\"was not taken into consideration.") @@ -166,8 +192,7 @@ SSTATE_DIR = \"${TOPDIR}/download-selftest\" postconf = os.path.join(self.builddir, 'conf/postfile.conf') self.track_for_cleanup(postconf) ftools.write_file(postconf , "TEST_POSTFILE=\"postfile\"") - self.append_config("TEST_POSTFILE=\"localconf\"") - self.addCleanup(self.remove_config, "TEST_POSTFILE=\"localconf\"") + self.write_config("TEST_POSTFILE=\"localconf\"") result = runCmd('bitbake -R conf/postfile.conf -e | grep TEST_POSTFILE=') self.assertTrue('postfile' in result.output, "Postconfigure file \"postfile.conf\"was not taken into consideration.") @@ -181,6 +206,7 @@ SSTATE_DIR = \"${TOPDIR}/download-selftest\" self.write_config("""DL_DIR = \"${TOPDIR}/download-selftest\" SSTATE_DIR = \"${TOPDIR}/download-selftest\" """) + self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) self.write_recipeinc('man',"\ndo_fail_task () {\nexit 1 \n}\n\naddtask do_fail_task before do_fetch\n" ) runCmd('bitbake -c cleanall man xcursor-transparent-theme') result = runCmd('bitbake man xcursor-transparent-theme -k', ignore_status=True) diff --git a/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py b/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py index 483803bf8..acf481f7b 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py +++ b/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py @@ -1,9 +1,6 @@ -import unittest import os -import logging import re import glob as g -import pexpect as p from oeqa.selftest.base import oeSelfTest from oeqa.selftest.buildhistory import BuildhistoryBase @@ -42,7 +39,7 @@ class ImageOptionsTests(oeSelfTest): for image_file in deploydir_files: if imagename in image_file and os.path.islink(os.path.join(deploydir, image_file)): track_original_files.append(os.path.realpath(os.path.join(deploydir, image_file))) - self.append_config("RM_OLD_IMAGE = \"1\"") + self.write_config("RM_OLD_IMAGE = \"1\"") bitbake("-C rootfs core-image-minimal") deploydir_files = os.listdir(deploydir) remaining_not_expected = [path for path in track_original_files if os.path.basename(path) in deploydir_files] @@ -100,7 +97,7 @@ class SanityOptionsTest(oeSelfTest): @testcase(278) def test_sanity_userspace_dependency(self): - self.append_config('WARN_QA_append = " unsafe-references-in-binaries unsafe-references-in-scripts"') + self.write_config('WARN_QA_append = " unsafe-references-in-binaries unsafe-references-in-scripts"') bitbake("-ccleansstate gzip nfs-utils") res = bitbake("gzip nfs-utils") self.assertTrue("WARNING: QA Issue: gzip" in res.output, "WARNING: QA Issue: gzip message is not present in bitbake's output: %s" % res.output) @@ -128,7 +125,7 @@ class BuildImagesTest(oeSelfTest): This method is used to test the build of directfb image for arm arch. In essence we build a coreimagedirectfb and test the exitcode of bitbake that in case of success is 0. """ - self.add_command_to_tearDown('cleanupworkdir') + self.add_command_to_tearDown('cleanup-workdir') self.write_config("DISTRO_FEATURES_remove = \"x11\"\nDISTRO_FEATURES_append = \" directfb\"\nMACHINE ??= \"qemuarm\"") res = bitbake("core-image-directfb", ignore_status=True) self.assertEqual(res.status, 0, "\ncoreimagedirectfb failed to build. Please check logs for further details.\nbitbake output %s" % res.output) @@ -139,7 +136,7 @@ class ArchiverTest(oeSelfTest): """ Test for archiving the work directory and exporting the source files. """ - self.add_command_to_tearDown('cleanupworkdir') + self.add_command_to_tearDown('cleanup-workdir') self.write_config("INHERIT = \"archiver\"\nARCHIVER_MODE[src] = \"original\"\nARCHIVER_MODE[srpm] = \"1\"") res = bitbake("xcursor-transparent-theme", ignore_status=True) self.assertEqual(res.status, 0, "\nCouldn't build xcursortransparenttheme.\nbitbake output %s" % res.output) diff --git a/yocto-poky/meta/lib/oeqa/selftest/devtool.py b/yocto-poky/meta/lib/oeqa/selftest/devtool.py index 6e731d677..dcdef5a14 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/devtool.py +++ b/yocto-poky/meta/lib/oeqa/selftest/devtool.py @@ -84,11 +84,44 @@ class DevtoolBase(oeSelfTest): class DevtoolTests(DevtoolBase): + def setUp(self): + """Test case setup function""" + super(DevtoolTests, self).setUp() + self.workspacedir = os.path.join(self.builddir, 'workspace') + self.assertTrue(not os.path.exists(self.workspacedir), + 'This test cannot be run with a workspace directory ' + 'under the build directory') + + def _check_src_repo(self, repo_dir): + """Check srctree git repository""" + self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')), + 'git repository for external source tree not found') + result = runCmd('git status --porcelain', cwd=repo_dir) + self.assertEqual(result.output.strip(), "", + 'Created git repo is not clean') + result = runCmd('git symbolic-ref HEAD', cwd=repo_dir) + self.assertEqual(result.output.strip(), "refs/heads/devtool", + 'Wrong branch in git repo') + + def _check_repo_status(self, repo_dir, expected_status): + """Check the worktree status of a repository""" + result = runCmd('git status . --porcelain', + cwd=repo_dir) + for line in result.output.splitlines(): + for ind, (f_status, fn_re) in enumerate(expected_status): + if re.match(fn_re, line[3:]): + if f_status != line[:2]: + self.fail('Unexpected status in line: %s' % line) + expected_status.pop(ind) + break + else: + self.fail('Unexpected modified file in line: %s' % line) + if expected_status: + self.fail('Missing file changes: %s' % expected_status) + @testcase(1158) def test_create_workspace(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') result = runCmd('bitbake-layers show-layers') self.assertTrue('/workspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf') # Try creating a workspace layer with a specific path @@ -99,19 +132,16 @@ class DevtoolTests(DevtoolBase): result = runCmd('bitbake-layers show-layers') self.assertIn(tempdir, result.output) # Try creating a workspace layer with the default path - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool create-workspace') - self.assertTrue(os.path.isfile(os.path.join(workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output) + self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output) result = runCmd('bitbake-layers show-layers') self.assertNotIn(tempdir, result.output) - self.assertIn(workspacedir, result.output) + self.assertIn(self.workspacedir, result.output) @testcase(1159) def test_devtool_add(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Fetch source tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) @@ -121,11 +151,11 @@ class DevtoolTests(DevtoolBase): srcdir = os.path.join(tempdir, 'pv-1.5.3') self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory') # Test devtool add - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake -c cleansstate pv') self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool add pv %s' % srcdir) - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') # Test devtool status result = runCmd('devtool status') self.assertIn('pv', result.output) @@ -144,9 +174,6 @@ class DevtoolTests(DevtoolBase): @testcase(1162) def test_devtool_add_library(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # We don't have the ability to pick up this dependency automatically yet... bitbake('libusb1') # Fetch source @@ -158,10 +185,10 @@ class DevtoolTests(DevtoolBase): srcdir = os.path.join(tempdir, 'libftdi1-1.1') self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory') # Test devtool add (and use -V so we test that too) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool add libftdi %s -V 1.1' % srcdir) - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') # Test devtool status result = runCmd('devtool status') self.assertIn('libftdi', result.output) @@ -185,9 +212,6 @@ class DevtoolTests(DevtoolBase): @testcase(1160) def test_devtool_add_fetch(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Fetch source tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) @@ -196,11 +220,11 @@ class DevtoolTests(DevtoolBase): testrecipe = 'python-markupsafe' srcdir = os.path.join(tempdir, testrecipe) # Test devtool add - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url)) - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. %s' % result.output) + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. %s' % result.output) self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') # Test devtool status result = runCmd('devtool status') @@ -232,9 +256,6 @@ class DevtoolTests(DevtoolBase): @testcase(1161) def test_devtool_add_fetch_git(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Fetch source tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) @@ -243,11 +264,11 @@ class DevtoolTests(DevtoolBase): testrecipe = 'libmatchbox2' srcdir = os.path.join(tempdir, testrecipe) # Test devtool add - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url)) - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created: %s' % result.output) + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created: %s' % result.output) self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure.ac in source directory') # Test devtool status result = runCmd('devtool status') @@ -284,32 +305,25 @@ class DevtoolTests(DevtoolBase): @testcase(1164) def test_devtool_modify(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Clean up anything in the workdir/sysroot/sstate cache bitbake('mdadm -c cleansstate') # Try modifying a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') self.add_command_to_tearDown('bitbake -c clean mdadm') result = runCmd('devtool modify mdadm -x %s' % tempdir) self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found') - self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found') - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') - matches = glob.glob(os.path.join(workspacedir, 'appends', 'mdadm_*.bbappend')) + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') + matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend')) self.assertTrue(matches, 'bbappend not created %s' % result.output) # Test devtool status result = runCmd('devtool status') self.assertIn('mdadm', result.output) self.assertIn(tempdir, result.output) # Check git repo - result = runCmd('git status --porcelain', cwd=tempdir) - self.assertEqual(result.output.strip(), "", 'Created git repo is not clean') - result = runCmd('git symbolic-ref HEAD', cwd=tempdir) - self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo') + self._check_src_repo(tempdir) # Try building bitbake('mdadm') # Try making (minor) modifications to the source @@ -336,13 +350,10 @@ class DevtoolTests(DevtoolBase): @testcase(1166) def test_devtool_modify_invalid(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Try modifying some recipes tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split() @@ -367,14 +378,14 @@ class DevtoolTests(DevtoolBase): self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output)) self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe) + @testcase(1365) def test_devtool_modify_native(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') + self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Try modifying some recipes tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') bbclassextended = False @@ -400,8 +411,6 @@ class DevtoolTests(DevtoolBase): @testcase(1165) def test_devtool_modify_git(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') testrecipe = 'mkelfimage' src_uri = get_bb_var('SRC_URI', testrecipe) self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) @@ -410,32 +419,26 @@ class DevtoolTests(DevtoolBase): # Try modifying a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found') - self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found') - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. devtool output: %s' % result.output) - matches = glob.glob(os.path.join(workspacedir, 'appends', 'mkelfimage_*.bbappend')) + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. devtool output: %s' % result.output) + matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mkelfimage_*.bbappend')) self.assertTrue(matches, 'bbappend not created') # Test devtool status result = runCmd('devtool status') self.assertIn(testrecipe, result.output) self.assertIn(tempdir, result.output) # Check git repo - result = runCmd('git status --porcelain', cwd=tempdir) - self.assertEqual(result.output.strip(), "", 'Created git repo is not clean') - result = runCmd('git symbolic-ref HEAD', cwd=tempdir) - self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo') + self._check_src_repo(tempdir) # Try building bitbake(testrecipe) @testcase(1167) def test_devtool_modify_localfiles(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') testrecipe = 'lighttpd' src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split() foundlocal = False @@ -449,13 +452,13 @@ class DevtoolTests(DevtoolBase): # Try modifying a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) self.assertTrue(os.path.exists(os.path.join(tempdir, 'configure.ac')), 'Extracted source could not be found') - self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') - matches = glob.glob(os.path.join(workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') + matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) self.assertTrue(matches, 'bbappend not created') # Test devtool status result = runCmd('devtool status') @@ -464,30 +467,46 @@ class DevtoolTests(DevtoolBase): # Try building bitbake(testrecipe) + @testcase(1378) + def test_devtool_modify_virtual(self): + # Try modifying a virtual recipe + virtrecipe = 'virtual/libx11' + realrecipe = 'libx11' + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir)) + self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') + matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe)) + self.assertTrue(matches, 'bbappend not created %s' % result.output) + # Test devtool status + result = runCmd('devtool status') + self.assertNotIn(virtrecipe, result.output) + self.assertIn(realrecipe, result.output) + # Check git repo + self._check_src_repo(tempdir) + # This is probably sufficient + + @testcase(1169) def test_devtool_update_recipe(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') testrecipe = 'minicom' recipefile = get_bb_var('FILE', testrecipe) src_uri = get_bb_var('SRC_URI', testrecipe) self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe) - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe) + self._check_repo_status(os.path.dirname(recipefile), []) # First, modify a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') # (don't bother with cleaning the recipe on teardown, we won't be building it) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) # Check git repo - self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found') - result = runCmd('git status --porcelain', cwd=tempdir) - self.assertEqual(result.output.strip(), "", 'Created git repo is not clean') - result = runCmd('git symbolic-ref HEAD', cwd=tempdir) - self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo') + self._check_src_repo(tempdir) # Add a couple of commits # FIXME: this only tests adding, need to also test update and remove result = runCmd('echo "Additional line" >> README', cwd=tempdir) @@ -497,25 +516,14 @@ class DevtoolTests(DevtoolBase): result = runCmd('git commit -m "Add a new file"', cwd=tempdir) self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) result = runCmd('devtool update-recipe %s' % testrecipe) - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertNotEqual(result.output.strip(), "", '%s recipe should be modified' % testrecipe) - status = result.output.splitlines() - self.assertEqual(len(status), 3, 'Less/more files modified than expected. Entire status:\n%s' % result.output) - for line in status: - if line.endswith('0001-Change-the-README.patch'): - self.assertEqual(line[:3], '?? ', 'Unexpected status in line: %s' % line) - elif line.endswith('0002-Add-a-new-file.patch'): - self.assertEqual(line[:3], '?? ', 'Unexpected status in line: %s' % line) - elif re.search('%s_[^_]*.bb$' % testrecipe, line): - self.assertEqual(line[:3], ' M ', 'Unexpected status in line: %s' % line) - else: - raise AssertionError('Unexpected modified file in status: %s' % line) + expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), + ('??', '.*/0001-Change-the-README.patch$'), + ('??', '.*/0002-Add-a-new-file.patch$')] + self._check_repo_status(os.path.dirname(recipefile), expected_status) @testcase(1172) def test_devtool_update_recipe_git(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') testrecipe = 'mtd-utils' recipefile = get_bb_var('FILE', testrecipe) src_uri = get_bb_var('SRC_URI', testrecipe) @@ -525,21 +533,16 @@ class DevtoolTests(DevtoolBase): if entry.startswith('file://') and entry.endswith('.patch'): patches.append(entry[7:].split(';')[0]) self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe) - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe) + self._check_repo_status(os.path.dirname(recipefile), []) # First, modify a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') # (don't bother with cleaning the recipe on teardown, we won't be building it) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) # Check git repo - self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found') - result = runCmd('git status --porcelain', cwd=tempdir) - self.assertEqual(result.output.strip(), "", 'Created git repo is not clean') - result = runCmd('git symbolic-ref HEAD', cwd=tempdir) - self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo') + self._check_src_repo(tempdir) # Add a couple of commits # FIXME: this only tests adding, need to also test update and remove result = runCmd('echo "# Additional line" >> Makefile', cwd=tempdir) @@ -549,19 +552,10 @@ class DevtoolTests(DevtoolBase): result = runCmd('git commit -m "Add a new file"', cwd=tempdir) self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe) - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertNotEqual(result.output.strip(), "", '%s recipe should be modified' % testrecipe) - status = result.output.splitlines() - for line in status: - for patch in patches: - if line.endswith(patch): - self.assertEqual(line[:3], ' D ', 'Unexpected status in line: %s' % line) - break - else: - if re.search('%s_[^_]*.bb$' % testrecipe, line): - self.assertEqual(line[:3], ' M ', 'Unexpected status in line: %s' % line) - else: - raise AssertionError('Unexpected modified file in status: %s' % line) + expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \ + [(' D', '.*/%s$' % patch) for patch in patches] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"'] srcurilines = src_uri.split() @@ -588,50 +582,33 @@ class DevtoolTests(DevtoolBase): # Now try with auto mode runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile))) result = runCmd('devtool update-recipe %s' % testrecipe) - result = runCmd('git rev-parse --show-toplevel') + result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile)) topleveldir = result.output.strip() - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - status = result.output.splitlines() relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe) - expectedstatus = [('M', os.path.relpath(recipefile, topleveldir)), - ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath), - ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)] - for line in status: - statusline = line.split(None, 1) - for fstatus, fn in expectedstatus: - if fn == statusline[1]: - if fstatus != statusline[0]: - self.fail('Unexpected status in line: %s' % line) - break - else: - self.fail('Unexpected modified file in line: %s' % line) + expected_status = [(' M', os.path.relpath(recipefile, topleveldir)), + ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath), + ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)] + self._check_repo_status(os.path.dirname(recipefile), expected_status) @testcase(1170) def test_devtool_update_recipe_append(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') testrecipe = 'mdadm' recipefile = get_bb_var('FILE', testrecipe) src_uri = get_bb_var('SRC_URI', testrecipe) self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe) - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe) + self._check_repo_status(os.path.dirname(recipefile), []) # First, modify a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') tempsrcdir = os.path.join(tempdir, 'source') templayerdir = os.path.join(tempdir, 'layer') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') # (don't bother with cleaning the recipe on teardown, we won't be building it) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir)) # Check git repo - self.assertTrue(os.path.isdir(os.path.join(tempsrcdir, '.git')), 'git repository for external source tree not found') - result = runCmd('git status --porcelain', cwd=tempsrcdir) - self.assertEqual(result.output.strip(), "", 'Created git repo is not clean') - result = runCmd('git symbolic-ref HEAD', cwd=tempsrcdir) - self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo') + self._check_src_repo(tempsrcdir) # Add a commit result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir) result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) @@ -642,8 +619,7 @@ class DevtoolTests(DevtoolBase): result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) self.assertNotIn('WARNING:', result.output) # Check recipe is still clean - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe) + self._check_repo_status(os.path.dirname(recipefile), []) # Check bbappend was created splitpath = os.path.dirname(recipefile).split(os.sep) appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1]) @@ -685,8 +661,6 @@ class DevtoolTests(DevtoolBase): @testcase(1171) def test_devtool_update_recipe_append_git(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') testrecipe = 'mtd-utils' recipefile = get_bb_var('FILE', testrecipe) src_uri = get_bb_var('SRC_URI', testrecipe) @@ -695,23 +669,18 @@ class DevtoolTests(DevtoolBase): if entry.startswith('git://'): git_uri = entry break - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe) + self._check_repo_status(os.path.dirname(recipefile), []) # First, modify a recipe tempdir = tempfile.mkdtemp(prefix='devtoolqa') tempsrcdir = os.path.join(tempdir, 'source') templayerdir = os.path.join(tempdir, 'layer') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') # (don't bother with cleaning the recipe on teardown, we won't be building it) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir)) # Check git repo - self.assertTrue(os.path.isdir(os.path.join(tempsrcdir, '.git')), 'git repository for external source tree not found') - result = runCmd('git status --porcelain', cwd=tempsrcdir) - self.assertEqual(result.output.strip(), "", 'Created git repo is not clean') - result = runCmd('git symbolic-ref HEAD', cwd=tempsrcdir) - self.assertEqual(result.output.strip(), "refs/heads/devtool", 'Wrong branch in git repo') + self._check_src_repo(tempsrcdir) # Add a commit result = runCmd('echo "# Additional line" >> Makefile', cwd=tempsrcdir) result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) @@ -731,8 +700,7 @@ class DevtoolTests(DevtoolBase): result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) self.assertNotIn('WARNING:', result.output) # Check recipe is still clean - result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile)) - self.assertEqual(result.output.strip(), "", '%s recipe is not clean' % testrecipe) + self._check_repo_status(os.path.dirname(recipefile), []) # Check bbappend was created splitpath = os.path.dirname(recipefile).split(os.sep) appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1]) @@ -779,28 +747,104 @@ class DevtoolTests(DevtoolBase): self.assertEqual(expectedlines, f.readlines()) # Deleting isn't expected to work under these circumstances + @testcase(1370) + def test_devtool_update_recipe_local_files(self): + """Check that local source files are copied over instead of patched""" + testrecipe = 'makedevs' + recipefile = get_bb_var('FILE', testrecipe) + # Setup srctree for modifying the recipe + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + # (don't bother with cleaning the recipe on teardown, we won't be + # building it) + result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) + # Check git repo + self._check_src_repo(tempdir) + # Edit / commit local source + runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir) + runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) + runCmd('echo "Bar" > new-file', cwd=tempdir) + runCmd('git add new-file', cwd=tempdir) + runCmd('git commit -m "Add new file"', cwd=tempdir) + self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' % + os.path.dirname(recipefile)) + runCmd('devtool update-recipe %s' % testrecipe) + expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), + (' M', '.*/makedevs/makedevs.c$'), + ('??', '.*/makedevs/new-local$'), + ('??', '.*/makedevs/0001-Add-new-file.patch$')] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + + @testcase(1371) + def test_devtool_update_recipe_local_files_2(self): + """Check local source files support when oe-local-files is in Git""" + testrecipe = 'lzo' + recipefile = get_bb_var('FILE', testrecipe) + # Setup srctree for modifying the recipe + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) + # Check git repo + self._check_src_repo(tempdir) + # Add oe-local-files to Git + runCmd('rm oe-local-files/.gitignore', cwd=tempdir) + runCmd('git add oe-local-files', cwd=tempdir) + runCmd('git commit -m "Add local sources"', cwd=tempdir) + # Edit / commit local sources + runCmd('echo "# Foobar" >> oe-local-files/acinclude.m4', cwd=tempdir) + runCmd('git commit -am "Edit existing file"', cwd=tempdir) + runCmd('git rm oe-local-files/run-ptest', cwd=tempdir) + runCmd('git commit -m"Remove file"', cwd=tempdir) + runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) + runCmd('git add oe-local-files/new-local', cwd=tempdir) + runCmd('git commit -m "Add new local file"', cwd=tempdir) + runCmd('echo "Gar" > new-file', cwd=tempdir) + runCmd('git add new-file', cwd=tempdir) + runCmd('git commit -m "Add new file"', cwd=tempdir) + self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' % + os.path.dirname(recipefile)) + # Checkout unmodified file to working copy -> devtool should still pick + # the modified version from HEAD + runCmd('git checkout HEAD^ -- oe-local-files/acinclude.m4', cwd=tempdir) + runCmd('devtool update-recipe %s' % testrecipe) + expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), + (' M', '.*/acinclude.m4$'), + (' D', '.*/run-ptest$'), + ('??', '.*/new-local$'), + ('??', '.*/0001-Add-new-file.patch$')] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + @testcase(1163) def test_devtool_extract(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') tempdir = tempfile.mkdtemp(prefix='devtoolqa') # Try devtool extract self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool extract remake %s' % tempdir) self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') - self.assertTrue(os.path.isdir(os.path.join(tempdir, '.git')), 'git repository for external source tree not found') + self._check_src_repo(tempdir) + + @testcase(1379) + def test_devtool_extract_virtual(self): + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + # Try devtool extract + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + result = runCmd('devtool extract virtual/libx11 %s' % tempdir) + self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') + self._check_src_repo(tempdir) @testcase(1168) def test_devtool_reset_all(self): - # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') testrecipe1 = 'mdadm' testrecipe2 = 'cronie' @@ -823,6 +867,7 @@ class DevtoolTests(DevtoolBase): matches2 = glob.glob(stampprefix2 + '*') self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2) + @testcase(1272) def test_devtool_deploy_target(self): # NOTE: Whilst this test would seemingly be better placed as a runtime test, # unfortunately the runtime tests run under bitbake and you can't run @@ -846,8 +891,7 @@ class DevtoolTests(DevtoolBase): break else: self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') + self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Definitions testrecipe = 'mdadm' testfile = '/sbin/mdadm' @@ -863,7 +907,7 @@ class DevtoolTests(DevtoolBase): # Try devtool modify tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) @@ -908,18 +952,19 @@ class DevtoolTests(DevtoolBase): result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True) self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have') + @testcase(1366) def test_devtool_build_image(self): """Test devtool build-image plugin""" # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') + self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') image = 'core-image-minimal' - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') self.add_command_to_tearDown('bitbake -c clean %s' % image) bitbake('%s -c clean' % image) # Add target and native recipes to workspace - for recipe in ('mdadm', 'parted-native'): + recipes = ['mdadm', 'parted-native'] + for recipe in recipes: tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) self.add_command_to_tearDown('bitbake -c clean %s' % recipe) @@ -927,17 +972,24 @@ class DevtoolTests(DevtoolBase): # Try to build image result = runCmd('devtool build-image %s' % image) self.assertNotEqual(result, 0, 'devtool build-image failed') - # Check if image.bbappend has required content - bbappend = os.path.join(workspacedir, 'appends', image+'.bbappend') - self.assertTrue(os.path.isfile(bbappend), 'bbappend not created %s' % result.output) - # NOTE: native recipe parted-native should not be in IMAGE_INSTALL_append - self.assertTrue('IMAGE_INSTALL_append = " mdadm"\n' in open(bbappend).readlines(), - 'IMAGE_INSTALL_append = " mdadm" not found in %s' % bbappend) + # Check if image contains expected packages + deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') + image_link_name = get_bb_var('IMAGE_LINK_NAME', image) + reqpkgs = [item for item in recipes if not item.endswith('-native')] + with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f: + for line in f: + splitval = line.split() + if splitval: + pkg = splitval[0] + if pkg in reqpkgs: + reqpkgs.remove(pkg) + if reqpkgs: + self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs)) + @testcase(1367) def test_devtool_upgrade(self): # Check preconditions - workspacedir = os.path.join(self.builddir, 'workspace') - self.assertTrue(not os.path.exists(workspacedir), 'This test cannot be run with a workspace directory under the build directory') + self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') # Check parameters result = runCmd('devtool upgrade -h') for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split(): @@ -955,9 +1007,9 @@ class DevtoolTests(DevtoolBase): # Check if srctree at least is populated self.assertTrue(len(os.listdir(tempdir)) > 0, 'scrtree (%s) should be populated with new (%s) source code' % (tempdir, version)) # Check new recipe folder is present - self.assertTrue(os.path.exists(os.path.join(workspacedir,'recipes',recipe)), 'Recipe folder should exist') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir,'recipes',recipe)), 'Recipe folder should exist') # Check new recipe file is present - self.assertTrue(os.path.exists(os.path.join(workspacedir,'recipes',recipe,"%s_%s.bb" % (recipe,version))), 'Recipe folder should exist') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir,'recipes',recipe,"%s_%s.bb" % (recipe,version))), 'Recipe folder should exist') # Check devtool status and make sure recipe is present result = runCmd('devtool status') self.assertIn(recipe, result.output) @@ -967,5 +1019,18 @@ class DevtoolTests(DevtoolBase): result = runCmd('devtool status') self.assertNotIn(recipe, result.output) self.track_for_cleanup(tempdir) - self.track_for_cleanup(workspacedir) + self.track_for_cleanup(self.workspacedir) self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + + @testcase(1352) + def test_devtool_layer_plugins(self): + """Test that devtool can use plugins from other layers. + + This test executes the selftest-reverse command from meta-selftest.""" + + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + + s = "Microsoft Made No Profit From Anyone's Zunes Yo" + result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s) + self.assertEqual(result.output, s[::-1]) diff --git a/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py b/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py index fcffc423e..4efb0d92a 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py +++ b/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py @@ -25,9 +25,7 @@ class ImageFeatures(oeSelfTest): features = 'EXTRA_IMAGE_FEATURES = "ssh-server-openssh empty-root-password allow-empty-password"\n' features += 'INHERIT += "extrausers"\n' features += 'EXTRA_USERS_PARAMS = "useradd -p \'\' {}; usermod -s /bin/sh {};"'.format(self.test_user, self.test_user) - - # Append 'features' to local.conf - self.append_config(features) + self.write_config(features) # Build a core-image-minimal bitbake('core-image-minimal') @@ -53,9 +51,7 @@ class ImageFeatures(oeSelfTest): features = 'EXTRA_IMAGE_FEATURES = "ssh-server-openssh allow-empty-password"\n' features += 'INHERIT += "extrausers"\n' features += 'EXTRA_USERS_PARAMS = "useradd -p \'\' {}; usermod -s /bin/sh {};"'.format(self.test_user, self.test_user) - - # Append 'features' to local.conf - self.append_config(features) + self.write_config(features) # Build a core-image-minimal bitbake('core-image-minimal') @@ -87,9 +83,7 @@ class ImageFeatures(oeSelfTest): features += 'IMAGE_INSTALL_append = " openssh"\n' features += 'EXTRA_IMAGE_FEATURES = "empty-root-password allow-empty-password package-management"\n' features += 'RPMROOTFSDEPENDS_remove = "rpmresolve-native:do_populate_sysroot"' - - # Append 'features' to local.conf - self.append_config(features) + self.write_config(features) # Build a core-image-minimal bitbake('core-image-minimal') @@ -159,9 +153,7 @@ class ImageFeatures(oeSelfTest): features = 'DISTRO_FEATURES_append = " wayland"\n' features += 'CORE_IMAGE_EXTRA_INSTALL += "wayland weston"' - - # Append 'features' to local.conf - self.append_config(features) + self.write_config(features) # Build a core-image-weston bitbake('core-image-weston') diff --git a/yocto-poky/meta/lib/oeqa/selftest/layerappend.py b/yocto-poky/meta/lib/oeqa/selftest/layerappend.py index a82a6c8b9..4de5034a9 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/layerappend.py +++ b/yocto-poky/meta/lib/oeqa/selftest/layerappend.py @@ -46,10 +46,11 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" SRC_URI_append += "file://appendtest.txt" """ - layerappend = "BBLAYERS += \"COREBASE/meta-layertest0 COREBASE/meta-layertest1 COREBASE/meta-layertest2\"" + layerappend = '' def tearDownLocal(self): - ftools.remove_from_file(self.builddir + "/conf/bblayers.conf", self.layerappend.replace("COREBASE", self.builddir + "/..")) + if self.layerappend: + ftools.remove_from_file(self.builddir + "/conf/bblayers.conf", self.layerappend) @testcase(1196) def test_layer_appends(self): @@ -79,7 +80,9 @@ SRC_URI_append += "file://appendtest.txt" with open(layer + "/recipes-test/layerappendtest/appendtest.txt", "w") as f: f.write("Layer 2 test") self.track_for_cleanup(layer) - ftools.append_file(self.builddir + "/conf/bblayers.conf", self.layerappend.replace("COREBASE", self.builddir + "/..")) + + self.layerappend = "BBLAYERS += \"{0}/meta-layertest0 {0}/meta-layertest1 {0}/meta-layertest2\"".format(corebase) + ftools.append_file(self.builddir + "/conf/bblayers.conf", self.layerappend) bitbake("layerappendtest") data = ftools.read_file(stagingdir + "/appendtest.txt") self.assertEqual(data, "Layer 2 test") diff --git a/yocto-poky/meta/lib/oeqa/selftest/manifest.py b/yocto-poky/meta/lib/oeqa/selftest/manifest.py new file mode 100644 index 000000000..44d0404c5 --- /dev/null +++ b/yocto-poky/meta/lib/oeqa/selftest/manifest.py @@ -0,0 +1,165 @@ +import unittest +import os + +from oeqa.selftest.base import oeSelfTest +from oeqa.utils.commands import get_bb_var, bitbake +from oeqa.utils.decorators import testcase + +class ManifestEntry: + '''A manifest item of a collection able to list missing packages''' + def __init__(self, entry): + self.file = entry + self.missing = [] + +class VerifyManifest(oeSelfTest): + '''Tests for the manifest files and contents of an image''' + + @classmethod + def check_manifest_entries(self, manifest, path): + manifest_errors = [] + try: + with open(manifest, "r") as mfile: + for line in mfile: + manifest_entry = os.path.join(path, line.split()[0]) + self.log.debug("{}: looking for {}"\ + .format(self.classname, manifest_entry)) + if not os.path.isfile(manifest_entry): + manifest_errors.append(manifest_entry) + self.log.debug("{}: {} not found"\ + .format(self.classname, manifest_entry)) + except OSError as e: + self.log.debug("{}: checking of {} failed"\ + .format(self.classname, manifest)) + raise e + + return manifest_errors + + #this will possibly move from here + @classmethod + def get_dir_from_bb_var(self, bb_var, target = None): + target == self.buildtarget if target == None else target + directory = get_bb_var(bb_var, target); + if not directory or not os.path.isdir(directory): + self.log.debug("{}: {} points to {} when target = {}"\ + .format(self.classname, bb_var, directory, target)) + raise OSError + return directory + + @classmethod + def setUpClass(self): + + self.buildtarget = 'core-image-minimal' + self.classname = 'VerifyManifest' + + self.log.info("{}: doing bitbake {} as a prerequisite of the test"\ + .format(self.classname, self.buildtarget)) + if bitbake(self.buildtarget).status: + self.log.debug("{} Failed to setup {}"\ + .format(self.classname, self.buildtarget)) + unittest.SkipTest("{}: Cannot setup testing scenario"\ + .format(self.classname)) + + @testcase(1380) + def test_SDK_manifest_entries(self): + '''Verifying the SDK manifest entries exist, this may take a build''' + + # the setup should bitbake core-image-minimal and here it is required + # to do an additional setup for the sdk + sdktask = '-c populate_sdk' + bbargs = sdktask + ' ' + self.buildtarget + self.log.debug("{}: doing bitbake {} as a prerequisite of the test"\ + .format(self.classname, bbargs)) + if bitbake(bbargs).status: + self.log.debug("{} Failed to bitbake {}"\ + .format(self.classname, bbargs)) + unittest.SkipTest("{}: Cannot setup testing scenario"\ + .format(self.classname)) + + + pkgdata_dir = reverse_dir = {} + mfilename = mpath = m_entry = {} + # get manifest location based on target to query about + d_target= dict(target = self.buildtarget, + host = 'nativesdk-packagegroup-sdk-host') + try: + mdir = self.get_dir_from_bb_var('SDK_DEPLOY', self.buildtarget) + for k in d_target.keys(): + mfilename[k] = "{}-toolchain-{}.{}.manifest".format( + get_bb_var("SDK_NAME", self.buildtarget), + get_bb_var("SDK_VERSION", self.buildtarget), + k) + mpath[k] = os.path.join(mdir, mfilename[k]) + if not os.path.isfile(mpath[k]): + self.log.debug("{}: {} does not exist".format( + self.classname, mpath[k])) + raise IOError + m_entry[k] = ManifestEntry(mpath[k]) + + pkgdata_dir[k] = self.get_dir_from_bb_var('PKGDATA_DIR', + d_target[k]) + reverse_dir[k] = os.path.join(pkgdata_dir[k], + 'runtime-reverse') + if not os.path.exists(reverse_dir[k]): + self.log.debug("{}: {} does not exist".format( + self.classname, reverse_dir[k])) + raise IOError + except OSError: + raise unittest.SkipTest("{}: Error in obtaining manifest dirs"\ + .format(self.classname)) + except IOError: + msg = "{}: Error cannot find manifests in the specified dir:\n{}"\ + .format(self.classname, mdir) + self.fail(msg) + + for k in d_target.keys(): + self.log.debug("{}: Check manifest {}".format( + self.classname, m_entry[k].file)) + + m_entry[k].missing = self.check_manifest_entries(\ + m_entry[k].file,reverse_dir[k]) + if m_entry[k].missing: + msg = '{}: {} Error has the following missing entries'\ + .format(self.classname, m_entry[k].file) + logmsg = msg+':\n'+'\n'.join(m_entry[k].missing) + self.log.debug(logmsg) + self.log.info(msg) + self.fail(logmsg) + + @testcase(1381) + def test_image_manifest_entries(self): + '''Verifying the image manifest entries exist''' + + # get manifest location based on target to query about + try: + mdir = self.get_dir_from_bb_var('DEPLOY_DIR_IMAGE', + self.buildtarget) + mfilename = get_bb_var("IMAGE_LINK_NAME", self.buildtarget)\ + + ".manifest" + mpath = os.path.join(mdir, mfilename) + if not os.path.isfile(mpath): raise IOError + m_entry = ManifestEntry(mpath) + + pkgdata_dir = {} + pkgdata_dir = self.get_dir_from_bb_var('PKGDATA_DIR', + self.buildtarget) + revdir = os.path.join(pkgdata_dir, 'runtime-reverse') + if not os.path.exists(revdir): raise IOError + except OSError: + raise unittest.SkipTest("{}: Error in obtaining manifest dirs"\ + .format(self.classname)) + except IOError: + msg = "{}: Error cannot find manifests in dir:\n{}"\ + .format(self.classname, mdir) + self.fail(msg) + + self.log.debug("{}: Check manifest {}"\ + .format(self.classname, m_entry.file)) + m_entry.missing = self.check_manifest_entries(\ + m_entry.file, revdir) + if m_entry.missing: + msg = '{}: {} Error has the following missing entries'\ + .format(self.classname, m_entry.file) + logmsg = msg+':\n'+'\n'.join(m_entry.missing) + self.log.debug(logmsg) + self.log.info(msg) + self.fail(logmsg) diff --git a/yocto-poky/meta/lib/oeqa/selftest/recipetool.py b/yocto-poky/meta/lib/oeqa/selftest/recipetool.py index c34ad6887..b1f1d2ab9 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/recipetool.py +++ b/yocto-poky/meta/lib/oeqa/selftest/recipetool.py @@ -492,9 +492,12 @@ class RecipetoolAppendsrcBase(RecipetoolBase): class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): + + @testcase(1273) def test_recipetool_appendsrcfile_basic(self): self._test_appendsrcfile('base-files', 'a-file') + @testcase(1274) def test_recipetool_appendsrcfile_basic_wildcard(self): testrecipe = 'base-files' self._test_appendsrcfile(testrecipe, 'a-file', options='-w') @@ -502,12 +505,15 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir) self.assertEqual(os.path.basename(bbappendfile), '%s_%%.bbappend' % testrecipe) + @testcase(1281) def test_recipetool_appendsrcfile_subdir_basic(self): self._test_appendsrcfile('base-files', 'a-file', 'tmp') + @testcase(1282) def test_recipetool_appendsrcfile_subdir_basic_dirdest(self): self._test_appendsrcfile('base-files', destdir='tmp') + @testcase(1280) def test_recipetool_appendsrcfile_srcdir_basic(self): testrecipe = 'bash' srcdir = get_bb_var('S', testrecipe) @@ -515,12 +521,14 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): subdir = os.path.relpath(srcdir, workdir) self._test_appendsrcfile(testrecipe, 'a-file', srcdir=subdir) + @testcase(1275) def test_recipetool_appendsrcfile_existing_in_src_uri(self): testrecipe = 'base-files' filepath = self._get_first_file_uri(testrecipe) self.assertTrue(filepath, 'Unable to test, no file:// uri found in SRC_URI for %s' % testrecipe) self._test_appendsrcfile(testrecipe, filepath, has_src_uri=False) + @testcase(1276) def test_recipetool_appendsrcfile_existing_in_src_uri_diff_params(self): testrecipe = 'base-files' subdir = 'tmp' @@ -530,6 +538,7 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): output = self._test_appendsrcfile(testrecipe, filepath, subdir, has_src_uri=False) self.assertTrue(any('with different parameters' in l for l in output)) + @testcase(1277) def test_recipetool_appendsrcfile_replace_file_srcdir(self): testrecipe = 'bash' filepath = 'Makefile.in' @@ -541,6 +550,7 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): bitbake('%s:do_unpack' % testrecipe) self.assertEqual(open(self.testfile, 'r').read(), open(os.path.join(srcdir, filepath), 'r').read()) + @testcase(1278) def test_recipetool_appendsrcfiles_basic(self, destdir=None): newfiles = [self.testfile] for i in range(1, 5): @@ -550,5 +560,6 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): newfiles.append(testfile) self._test_appendsrcfiles('gcc', newfiles, destdir=destdir, options='-W') + @testcase(1279) def test_recipetool_appendsrcfiles_basic_subdir(self): self.test_recipetool_appendsrcfiles_basic(destdir='testdir') diff --git a/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py b/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py index c4efc47fe..3c230620e 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py +++ b/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py @@ -34,7 +34,7 @@ class SStateTests(SStateBase): targetarch = get_bb_var('TUNE_ARCH') self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) - @testcase(975) + @testcase(1374) def test_sstate_creation_distro_specific_fail(self): targetarch = get_bb_var('TUNE_ARCH') self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False) @@ -43,7 +43,7 @@ class SStateTests(SStateBase): def test_sstate_creation_distro_nonspecific_pass(self): self.run_test_sstate_creation(['glibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) - @testcase(976) + @testcase(1375) def test_sstate_creation_distro_nonspecific_fail(self): self.run_test_sstate_creation(['glibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False) @@ -70,11 +70,11 @@ class SStateTests(SStateBase): targetarch = get_bb_var('TUNE_ARCH') self.run_test_cleansstate_task(['binutils-cross-' + targetarch, 'binutils-native', 'glibc-initial'], distro_specific=True, distro_nonspecific=True, temp_sstate_location=True) - @testcase(977) + @testcase(1376) def test_cleansstate_task_distro_nonspecific(self): self.run_test_cleansstate_task(['glibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) - @testcase(977) + @testcase(1377) def test_cleansstate_task_distro_specific(self): targetarch = get_bb_var('TUNE_ARCH') self.run_test_cleansstate_task(['binutils-cross-'+ targetarch, 'binutils-native', 'glibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) @@ -111,12 +111,12 @@ class SStateTests(SStateBase): targetarch = get_bb_var('TUNE_ARCH') self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch, 'binutils-native'], temp_sstate_location=True) - @testcase(175) + @testcase(1372) def test_rebuild_distro_specific_sstate_cross_target(self): targetarch = get_bb_var('TUNE_ARCH') self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch], temp_sstate_location=True) - @testcase(175) + @testcase(1373) def test_rebuild_distro_specific_sstate_native_target(self): self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True) @@ -211,6 +211,8 @@ class SStateTests(SStateBase): they're built on a 32 or 64 bit system. Rather than requiring two different build machines and running a builds, override the variables calling uname() manually and check using bitbake -S. + + Also check that SDKMACHINE changing doesn't change any of these stamps. """ topdir = get_bb_var('TOPDIR') @@ -219,6 +221,7 @@ class SStateTests(SStateBase): TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" BUILD_ARCH = \"x86_64\" BUILD_OS = \"linux\" +SDKMACHINE = \"x86_64\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash") bitbake("core-image-sato -S none") @@ -226,6 +229,7 @@ BUILD_OS = \"linux\" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" BUILD_ARCH = \"i686\" BUILD_OS = \"linux\" +SDKMACHINE = \"i686\" """) self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") bitbake("core-image-sato -S none") @@ -233,11 +237,16 @@ BUILD_OS = \"linux\" def get_files(d): f = [] for root, dirs, files in os.walk(d): + if "core-image-sato" in root: + # SDKMACHINE changing will change do_rootfs/do_testimage/do_build stamps of core-image-sato itself + # which is safe to ignore + continue f.extend(os.path.join(root, name) for name in files) return f files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash").replace("i686-linux", "x86_64-linux").replace("i686" + targetvendor + "-linux", "x86_64" + targetvendor + "-linux", ) for x in files2] + self.maxDiff = None self.assertItemsEqual(files1, files2) @@ -271,11 +280,13 @@ NATIVELSBSTRING = \"DistroB\" files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] + self.maxDiff = None self.assertItemsEqual(files1, files2) + @testcase(1368) def test_sstate_allarch_samesigs(self): """ - The sstate checksums off allarch packages should be independent of whichever + The sstate checksums of allarch packages should be independent of whichever MACHINE is set. Check this using bitbake -S. Also, rather than duplicate the test, check nativesdk stamps are the same between the two MACHINE values. @@ -319,4 +330,50 @@ MACHINE = \"qemuarm\" files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] self.maxDiff = None self.assertItemsEqual(files1, files2) - + + @testcase(1369) + def test_sstate_sametune_samesigs(self): + """ + The sstate checksums of two identical machines (using the same tune) should be the + same, apart from changes within the machine specific stamps directory. We use the + qemux86copy machine to test this. Also include multilibs in the test. + """ + + topdir = get_bb_var('TOPDIR') + targetos = get_bb_var('TARGET_OS') + targetvendor = get_bb_var('TARGET_VENDOR') + self.write_config(""" +TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" +MACHINE = \"qemux86\" +require conf/multilib.conf +MULTILIBS = "multilib:lib32" +DEFAULTTUNE_virtclass-multilib-lib32 = "x86" +""") + self.track_for_cleanup(topdir + "/tmp-sstatesamehash") + bitbake("world meta-toolchain -S none") + self.write_config(""" +TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" +MACHINE = \"qemux86copy\" +require conf/multilib.conf +MULTILIBS = "multilib:lib32" +DEFAULTTUNE_virtclass-multilib-lib32 = "x86" +""") + self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") + bitbake("world meta-toolchain -S none") + + def get_files(d): + f = [] + for root, dirs, files in os.walk(d): + for name in files: + if "meta-environment" in root or "cross-canadian" in root: + continue + if "qemux86copy-" in root or "qemux86-" in root: + continue + if "do_build" not in name and "do_populate_sdk" not in name: + f.append(os.path.join(root, name)) + return f + files1 = get_files(topdir + "/tmp-sstatesamehash/stamps") + files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps") + files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] + self.maxDiff = None + self.assertItemsEqual(files1, files2) diff --git a/yocto-poky/meta/lib/oeqa/selftest/wic.py b/yocto-poky/meta/lib/oeqa/selftest/wic.py index 3dc54a4c6..ea78e2259 100644 --- a/yocto-poky/meta/lib/oeqa/selftest/wic.py +++ b/yocto-poky/meta/lib/oeqa/selftest/wic.py @@ -31,50 +31,54 @@ from shutil import rmtree from oeqa.selftest.base import oeSelfTest from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.decorators import testcase + class Wic(oeSelfTest): """Wic test class.""" resultdir = "/var/tmp/wic/build/" + image_is_ready = False - @classmethod - def setUpClass(cls): - """Build wic runtime dependencies.""" - bitbake('syslinux syslinux-native parted-native gptfdisk-native ' - 'dosfstools-native mtools-native') - Wic.image_is_ready = False - - def setUp(self): + def setUpLocal(self): """This code is executed before each test method.""" + self.write_config('IMAGE_FSTYPES += " hddimg"\nMACHINE_FEATURES_append = " efi"\n') + + # Do this here instead of in setUpClass as the base setUp does some + # clean up which can result in the native tools built earlier in + # setUpClass being unavailable. if not Wic.image_is_ready: - # build core-image-minimal with required features - features = 'IMAGE_FSTYPES += " hddimg"\nMACHINE_FEATURES_append = " efi"\n' - self.append_config(features) + bitbake('syslinux syslinux-native parted-native gptfdisk-native ' + 'dosfstools-native mtools-native') bitbake('core-image-minimal') - # set this class variable to avoid buiding image many times Wic.image_is_ready = True rmtree(self.resultdir, ignore_errors=True) - def test01_help(self): + @testcase(1208) + def test_help(self): """Test wic --help""" self.assertEqual(0, runCmd('wic --help').status) - def test02_createhelp(self): + @testcase(1209) + def test_createhelp(self): """Test wic create --help""" self.assertEqual(0, runCmd('wic create --help').status) - def test03_listhelp(self): + @testcase(1210) + def test_listhelp(self): """Test wic list --help""" self.assertEqual(0, runCmd('wic list --help').status) - def test04_build_image_name(self): + @testcase(1211) + def test_build_image_name(self): """Test wic create directdisk --image-name core-image-minimal""" self.assertEqual(0, runCmd("wic create directdisk " "--image-name core-image-minimal").status) self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) - def test05_build_artifacts(self): + @testcase(1212) + def test_build_artifacts(self): """Test wic create directdisk providing all artifacts.""" vars = dict((var.lower(), get_bb_var(var, 'core-image-minimal')) \ for var in ('STAGING_DATADIR', 'DEPLOY_DIR_IMAGE', @@ -87,34 +91,41 @@ class Wic(oeSelfTest): self.assertEqual(0, status) self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) - def test06_gpt_image(self): + @testcase(1157) + def test_gpt_image(self): """Test creation of core-image-minimal with gpt table and UUID boot""" self.assertEqual(0, runCmd("wic create directdisk-gpt " "--image-name core-image-minimal").status) self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) - def test07_unsupported_subcommand(self): + @testcase(1213) + def test_unsupported_subcommand(self): """Test unsupported subcommand""" self.assertEqual(1, runCmd('wic unsupported', ignore_status=True).status) - def test08_no_command(self): + @testcase(1214) + def test_no_command(self): """Test wic without command""" self.assertEqual(1, runCmd('wic', ignore_status=True).status) - def test09_help_kickstart(self): + @testcase(1215) + def test_help_overview(self): """Test wic help overview""" self.assertEqual(0, runCmd('wic help overview').status) - def test10_help_plugins(self): + @testcase(1216) + def test_help_plugins(self): """Test wic help plugins""" self.assertEqual(0, runCmd('wic help plugins').status) - def test11_help_kickstart(self): + @testcase(1217) + def test_help_kickstart(self): """Test wic help kickstart""" self.assertEqual(0, runCmd('wic help kickstart').status) - def test12_compress_gzip(self): + @testcase(1264) + def test_compress_gzip(self): """Test compressing an image with gzip""" self.assertEqual(0, runCmd("wic create directdisk " "--image-name core-image-minimal " @@ -122,7 +133,8 @@ class Wic(oeSelfTest): self.assertEqual(1, len(glob(self.resultdir + \ "directdisk-*.direct.gz"))) - def test13_compress_gzip(self): + @testcase(1265) + def test_compress_bzip2(self): """Test compressing an image with bzip2""" self.assertEqual(0, runCmd("wic create directdisk " "--image-name core-image-minimal " @@ -130,7 +142,8 @@ class Wic(oeSelfTest): self.assertEqual(1, len(glob(self.resultdir + \ "directdisk-*.direct.bz2"))) - def test14_compress_gzip(self): + @testcase(1266) + def test_compress_xz(self): """Test compressing an image with xz""" self.assertEqual(0, runCmd("wic create directdisk " "--image-name core-image-minimal " @@ -138,13 +151,15 @@ class Wic(oeSelfTest): self.assertEqual(1, len(glob(self.resultdir + \ "directdisk-*.direct.xz"))) - def test15_wrong_compressor(self): + @testcase(1267) + def test_wrong_compressor(self): """Test how wic breaks if wrong compressor is provided""" self.assertEqual(2, runCmd("wic create directdisk " "--image-name core-image-minimal " "-c wrong", ignore_status=True).status) - def test16_rootfs_indirect_recipes(self): + @testcase(1268) + def test_rootfs_indirect_recipes(self): """Test usage of rootfs plugin with rootfs recipes""" wks = "directdisk-multi-rootfs" self.assertEqual(0, runCmd("wic create %s " @@ -154,7 +169,8 @@ class Wic(oeSelfTest): % wks).status) self.assertEqual(1, len(glob(self.resultdir + "%s*.direct" % wks))) - def test17_rootfs_artifacts(self): + @testcase(1269) + def test_rootfs_artifacts(self): """Test usage of rootfs plugin with rootfs paths""" vars = dict((var.lower(), get_bb_var(var, 'core-image-minimal')) \ for var in ('STAGING_DATADIR', 'DEPLOY_DIR_IMAGE', @@ -171,14 +187,16 @@ class Wic(oeSelfTest): self.assertEqual(1, len(glob(self.resultdir + \ "%(wks)s-*.direct" % vars))) - def test18_iso_image(self): - """Test creation of hybrid iso imagewith legacy and EFI boot""" + @testcase(1346) + def test_iso_image(self): + """Test creation of hybrid iso image with legacy and EFI boot""" self.assertEqual(0, runCmd("wic create mkhybridiso " "--image-name core-image-minimal").status) self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.direct"))) self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.iso"))) - def test19_image_env(self): + @testcase(1347) + def test_image_env(self): """Test generation of <image>.env files.""" image = 'core-image-minimal' stdir = get_bb_var('STAGING_DIR_TARGET', image) @@ -200,7 +218,8 @@ class Wic(oeSelfTest): self.assertTrue(var in content, "%s is not in .env file" % var) self.assertTrue(content[var]) - def test20_wic_image_type(self): + @testcase(1351) + def test_wic_image_type(self): """Test building wic images by bitbake""" self.assertEqual(0, bitbake('wic-image-minimal').status) @@ -214,21 +233,24 @@ class Wic(oeSelfTest): self.assertTrue(os.path.islink(path)) self.assertTrue(os.path.isfile(os.path.realpath(path))) - def test21_qemux86_directdisk(self): + @testcase(1348) + def test_qemux86_directdisk(self): """Test creation of qemux-86-directdisk image""" image = "qemux86-directdisk" self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ % image).status) self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - def test22_mkgummidisk(self): + @testcase(1349) + def test_mkgummidisk(self): """Test creation of mkgummidisk image""" image = "mkgummidisk" self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ % image).status) self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - def test23_mkefidisk(self): + @testcase(1350) + def test_mkefidisk(self): """Test creation of mkefidisk image""" image = "mkefidisk" self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ diff --git a/yocto-poky/meta/lib/oeqa/utils/decorators.py b/yocto-poky/meta/lib/oeqa/utils/decorators.py index b6adcb184..0d79223a2 100644 --- a/yocto-poky/meta/lib/oeqa/utils/decorators.py +++ b/yocto-poky/meta/lib/oeqa/utils/decorators.py @@ -33,6 +33,10 @@ class getResults(object): ret.append(s.replace("setUpModule (", "").replace(")","")) else: ret.append(s) + # Append also the test without the full path + testname = s.split('.')[-1] + if testname: + ret.append(testname) return ret self.faillist = handleList(upperf.f_locals['result'].failures) self.errorlist = handleList(upperf.f_locals['result'].errors) @@ -53,11 +57,11 @@ class skipIfFailure(object): self.testcase = testcase def __call__(self,f): - def wrapped_f(*args): + def wrapped_f(*args, **kwargs): res = getResults() if self.testcase in (res.getFailList() or res.getErrorList()): raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) - return f(*args) + return f(*args, **kwargs) wrapped_f.__name__ = f.__name__ return wrapped_f @@ -67,11 +71,11 @@ class skipIfSkipped(object): self.testcase = testcase def __call__(self,f): - def wrapped_f(*args): + def wrapped_f(*args, **kwargs): res = getResults() if self.testcase in res.getSkipList(): raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) - return f(*args) + return f(*args, **kwargs) wrapped_f.__name__ = f.__name__ return wrapped_f @@ -81,13 +85,13 @@ class skipUnlessPassed(object): self.testcase = testcase def __call__(self,f): - def wrapped_f(*args): + def wrapped_f(*args, **kwargs): res = getResults() if self.testcase in res.getSkipList() or \ self.testcase in res.getFailList() or \ self.testcase in res.getErrorList(): raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) - return f(*args) + return f(*args, **kwargs) wrapped_f.__name__ = f.__name__ wrapped_f._depends_on = self.testcase return wrapped_f @@ -98,8 +102,8 @@ class testcase(object): self.test_case = test_case def __call__(self, func): - def wrapped_f(*args): - return func(*args) + def wrapped_f(*args, **kwargs): + return func(*args, **kwargs) wrapped_f.test_case = self.test_case wrapped_f.__name__ = func.__name__ return wrapped_f @@ -111,6 +115,12 @@ class NoParsingFilter(logging.Filter): def LogResults(original_class): orig_method = original_class.run + from time import strftime, gmtime + caller = os.path.basename(sys.argv[0]) + timestamp = strftime('%Y%m%d%H%M%S',gmtime()) + logfile = os.path.join(os.getcwd(),'results-'+caller+'.'+timestamp+'.log') + linkfile = os.path.join(os.getcwd(),'results-'+caller+'.log') + #rewrite the run method of unittest.TestCase to add testcase logging def run(self, result, *args, **kws): orig_method(self, result, *args, **kws) @@ -127,14 +137,13 @@ def LogResults(original_class): #create custom logging level for filtering. custom_log_level = 100 logging.addLevelName(custom_log_level, 'RESULTS') - caller = os.path.basename(sys.argv[0]) def results(self, message, *args, **kws): if self.isEnabledFor(custom_log_level): self.log(custom_log_level, message, *args, **kws) logging.Logger.results = results - logging.basicConfig(filename=os.path.join(os.getcwd(),'results-'+caller+'.log'), + logging.basicConfig(filename=logfile, filemode='w', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%H:%M:%S', @@ -162,7 +171,13 @@ def LogResults(original_class): if passed: local_log.results("Testcase "+str(test_case)+": PASSED") + # Create symlink to the current log + if os.path.exists(linkfile): + os.remove(linkfile) + os.symlink(logfile, linkfile) + original_class.run = run + return original_class class TimeOut(BaseException): diff --git a/yocto-poky/meta/lib/oeqa/utils/dump.py b/yocto-poky/meta/lib/oeqa/utils/dump.py index 4ae871c65..63a591d36 100644 --- a/yocto-poky/meta/lib/oeqa/utils/dump.py +++ b/yocto-poky/meta/lib/oeqa/utils/dump.py @@ -16,9 +16,20 @@ class BaseDumper(object): def __init__(self, cmds, parent_dir): self.cmds = [] - self.parent_dir = parent_dir + # Some testing doesn't inherit testimage, so it is needed + # to set some defaults. + self.parent_dir = parent_dir or "/tmp/oe-saved-tests" + dft_cmds = """ top -bn1 + iostat -x -z -N -d -p ALL 20 2 + ps -ef + free + df + memstat + dmesg + ip -s link + netstat -an""" if not cmds: - return + cmds = dft_cmds for cmd in cmds.split('\n'): cmd = cmd.lstrip() if not cmd or cmd[0] == '#': diff --git a/yocto-poky/meta/lib/oeqa/utils/ftools.py b/yocto-poky/meta/lib/oeqa/utils/ftools.py index 64ebe3d21..1bd9a30a4 100644 --- a/yocto-poky/meta/lib/oeqa/utils/ftools.py +++ b/yocto-poky/meta/lib/oeqa/utils/ftools.py @@ -1,12 +1,19 @@ import os import re +import errno def write_file(path, data): + # In case data is None, return immediately + if data is None: + return wdata = data.rstrip() + "\n" with open(path, "w") as f: f.write(wdata) def append_file(path, data): + # In case data is None, return immediately + if data is None: + return wdata = data.rstrip() + "\n" with open(path, "a") as f: f.write(wdata) @@ -18,7 +25,18 @@ def read_file(path): return data def remove_from_file(path, data): - lines = read_file(path).splitlines() + # In case data is None, return immediately + if data is None: + return + try: + rdata = read_file(path) + except IOError as e: + # if file does not exit, just quit, otherwise raise an exception + if e.errno == errno.ENOENT: + return + else: + raise + lines = rdata.splitlines() rmdata = data.strip().splitlines() for l in rmdata: for c in range(0, lines.count(l)): diff --git a/yocto-poky/meta/lib/oeqa/utils/qemurunner.py b/yocto-poky/meta/lib/oeqa/utils/qemurunner.py index d32c9db46..bdc6e0a8f 100644 --- a/yocto-poky/meta/lib/oeqa/utils/qemurunner.py +++ b/yocto-poky/meta/lib/oeqa/utils/qemurunner.py @@ -13,12 +13,20 @@ import re import socket import select import errno +import string import threading +import codecs from oeqa.utils.dump import HostDumper import logging logger = logging.getLogger("BitBake.QemuRunner") +# Get Unicode non printable control chars +control_range = range(0,32)+range(127,160) +control_chars = [unichr(x) for x in control_range + if unichr(x) not in string.printable] +re_control_char = re.compile('[%s]' % re.escape("".join(control_chars))) + class QemuRunner: def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime, dump_dir, dump_host_cmds): @@ -61,7 +69,10 @@ class QemuRunner: def log(self, msg): if self.logfile: - with open(self.logfile, "a") as f: + # It is needed to sanitize the data received from qemu + # because is possible to have control characters + msg = re_control_char.sub('', unicode(msg, 'utf-8')) + with codecs.open(self.logfile, "a", encoding="utf-8") as f: f.write("%s" % msg) def getOutput(self, o): @@ -170,6 +181,9 @@ class QemuRunner: cmdline = '' with open('/proc/%s/cmdline' % self.qemupid) as p: cmdline = p.read() + # It is needed to sanitize the data received + # because is possible to have control characters + cmdline = re_control_char.sub('', cmdline) try: ips = re.findall("((?:[0-9]{1,3}\.){3}[0-9]{1,3})", cmdline.split("ip=")[1]) if not ips or len(ips) != 3: @@ -186,7 +200,6 @@ class QemuRunner: logger.info("Target IP: %s" % self.ip) logger.info("Server IP: %s" % self.server_ip) - logger.info("Starting logging thread") self.thread = LoggingThread(self.log, threadsock, logger) self.thread.start() if not self.thread.connection_established.wait(self.boottime): @@ -197,6 +210,7 @@ class QemuRunner: self.stop_thread() return False + logger.info("Output from runqemu:\n%s", self.getOutput(output)) logger.info("Waiting at most %d seconds for login banner" % self.boottime) endtime = time.time() + self.boottime socklist = [self.server_socket] @@ -259,8 +273,9 @@ class QemuRunner: def stop(self): self.stop_thread() - if self.runqemu: + if hasattr(self, "origchldhandler"): signal.signal(signal.SIGCHLD, self.origchldhandler) + if self.runqemu: os.kill(self.monitorpid, signal.SIGKILL) logger.info("Sending SIGTERM to runqemu") try: @@ -280,7 +295,6 @@ class QemuRunner: self.server_socket = None self.qemupid = None self.ip = None - signal.signal(signal.SIGCHLD, self.origchldhandler) def stop_thread(self): if self.thread and self.thread.is_alive(): @@ -440,9 +454,9 @@ class LoggingThread(threading.Thread): def eventloop(self): poll = select.poll() - eventmask = self.errorevents | self.readevents + event_read_mask = self.errorevents | self.readevents poll.register(self.serversock.fileno()) - poll.register(self.readpipe, eventmask) + poll.register(self.readpipe, event_read_mask) breakout = False self.running = True @@ -466,7 +480,7 @@ class LoggingThread(threading.Thread): self.readsock, _ = self.serversock.accept() self.readsock.setblocking(0) poll.unregister(self.serversock.fileno()) - poll.register(self.readsock.fileno()) + poll.register(self.readsock.fileno(), event_read_mask) self.logger.info("Setting connection established event") self.connection_established.set() |