Skip to contentSkip to conversation

Sumo-next patches for review

PATCH In review Armin Kuster 2 participants 47 messages Dec 13, 2018

lore
Share & tools
lore
#0 lore raw

cover Sumo-next patches for review

The Bulk of the changres are for QA automation related support and some misc backports.

Passed "A-Full" build

The following changes since commit a4c7d286883db186f17d4044a6531eac88473403:

bitbake: bitbake-user-manual: Added "usehead" parameter. (2018-12-10 20:41:28 +0000)

are available in the git repository at:

git://git.yoctoproject.org/poky-contrib stable/sumo-next
http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=stable/sumo-next

Michael Halstead (1):
scripts/runqemu: Replace subprocess.run() for compatibilty

Richard Purdie (34):
scripts/runqemu: Tidy up lock handling code scripts/runqemu: Improve lockfile handling for python with
close_fd=True
oeqa/selftest/signing: Skip tests if gpg isn't found oeqa/selftest/signing: Allow tests not to need gpg on the host oeqa/selftest/signing: Use do_populate_lic target instead of
do_package
oeqa/selftest/case: Use bb.utils.remove() instead of shutil.remove() oeqa/selftest/buildoptions: Improve ccache test failure output oeqa/utils/commands: Add extra qemu failure logging oeqa/utils/qemurunner: Fix python ResourceWarning for unclosed file oeqa/utils/commands: Avoid log message duplication oeqa/qemurunner: Remove resource python warnings oeqa/selftest/buildoptions: Improve ccache test oeqa/selftest/buildoptions: Ensure diskmon tests run consistently oeqa/selftest/runqemu: Improve testcase failure handling oeqa/utils/qemurunner: Avoid tracebacks on closed files oeqa/loader: Fix deprecation warning
oeqa/utils/commands: Avoid unclosed file warnings oeqa/selftest/context: Replace deprecated imp module usage oeqa/utils/qemurunner.py: Fix python regex warnings oeqa/selftest/context: Improve log file handling oeqa/core/runner: Improve test case comparision oeqa/runner: Ensure we don't print misleading results output oeqa/core/threaded: Remove in favour of using concurrenttests oeqa/runner: Simplify code
oeqa: Remove xmlrunner
oeqa/runtime/ptest: Inject results+logs into stored json results file oeqa/runner: Always show a summary of success/fail/error/skip counts oeqa/runner: Sort the test result output by result class oeqa/selftest: Improvements to the json logging oeqa/utils/metadata: Allow to function without the git module image-buildinfo,oeqa/selftest/containerimage: Ensure image-buildinfo
doesn't break tests
oeqa/selftest/esdk: Ensure parent directory exists oeqa/selftest/esdk: Fix typo causing test failure
busybox: Put klogd/syslogd alternative links in syslog package

Ross Burton (3):
oeqa/oelib/path: don't leak temporary directories
oeqa: don't litter /tmp with temporary directories oeqa/selftest/esdk: run selftest inside workdir not /tmp

Stefan Lendl (1):
default-versions.inc: Make PREFERRED_VERSION_openssl* overwritable

Yeoh Ee Peng (6):
oeqa/core/runner: refactor for OEQA to write json testresult oeqa/core/runner: write testresult to json files oeqa/selftest/context: write testresult to json files testimage.bbclass: write testresult to json files testsdk.bbclass: write testresult to json files oeqa/selftest: Standardize json logging output directory

 meta-selftest/recipes-test/delay/delay.bb          |  12 +
 meta/classes/image-buildinfo.bbclass               |   2 +
 meta/classes/testimage.bbclass                     |  31 ++-
 meta/classes/testsdk.bbclass                       |  40 ++-
 meta/conf/distro/include/default-versions.inc      |   6 +-
 meta/lib/oeqa/core/context.py                      |   1 -
 meta/lib/oeqa/core/decorator/depends.py            |   9 +-
 meta/lib/oeqa/core/decorator/oetimeout.py          |  40 +--
 meta/lib/oeqa/core/loader.py                       |   2 +-
 meta/lib/oeqa/core/runner.py                       | 186 +++++++-------
 .../core/tests/cases/loader/threaded/threaded.py   |  12 -
 .../tests/cases/loader/threaded/threaded_alone.py  |   8 -
 .../cases/loader/threaded/threaded_depends.py      |  10 -
 .../tests/cases/loader/threaded/threaded_module.py |  12 -
 meta/lib/oeqa/core/tests/common.py                 |  10 -
 meta/lib/oeqa/core/tests/test_data.py              |   4 +-
 meta/lib/oeqa/core/tests/test_decorators.py        |  12 -
 meta/lib/oeqa/core/tests/test_loader.py            |  30 +--
 meta/lib/oeqa/core/threaded.py                     | 275 ---------------------
 meta/lib/oeqa/runtime/cases/ptest.py               |  21 +-
 meta/lib/oeqa/sdk/context.py                       |   5 +-
 meta/lib/oeqa/selftest/case.py                     |   4 +-
 meta/lib/oeqa/selftest/cases/buildoptions.py       |  12 +-
 meta/lib/oeqa/selftest/cases/containerimage.py     |   1 +
 meta/lib/oeqa/selftest/cases/eSDK.py               |  14 +-
 meta/lib/oeqa/selftest/cases/oelib/path.py         |  10 +-
 meta/lib/oeqa/selftest/cases/runqemu.py            |  32 ++-
 meta/lib/oeqa/selftest/cases/signing.py            |  80 ++++--
 meta/lib/oeqa/selftest/context.py                  |  45 +++-
 meta/lib/oeqa/utils/buildproject.py                |   3 +-
 meta/lib/oeqa/utils/commands.py                    |  11 +-
 meta/lib/oeqa/utils/metadata.py                    |  17 +-
 meta/lib/oeqa/utils/qemurunner.py                  |  26 +-
 meta/lib/oeqa/utils/targetbuild.py                 |   5 +-
 meta/recipes-core/busybox/busybox.inc              |   5 +-
 scripts/runqemu                                    |  25 +-
 36 files changed, 409 insertions(+), 609 deletions(-)
 create mode 100644 meta-selftest/recipes-test/delay/delay.bb
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py
 delete mode 100644 meta/lib/oeqa/core/threaded.py
Signature · 1 line
2.7.4
#1 lore raw

PATCH 1/45 scripts/runqemu: Replace subprocess.run() for compatibilty

From: Michael Halstead <[email protected]>

subprocess.run() was introduced in Python 3.5. We currently support down to Python 3.4 so I've replaced it with subprocess.check_call() which is available in that version.

(From OE-Core rev: 1c61f3017a6a2d95747883c722c376763ec77c9d)

---
 scripts/runqemu | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
scripts/runqemu +2 -2
index bd3aee0..c9a351e 100755
@@ -1313,7 +1313,7 @@ def main():
             logger.info("SIGTERM received")
             os.kill(config.qemupid, signal.SIGTERM)
             config.cleanup()
-            subprocess.run(["tput", "smam"])
+            subprocess.check_call(["tput", "smam"])
         signal.signal(signal.SIGTERM, sigterm_handler)
 
         config.check_args()
@@ -1335,7 +1335,7 @@ def main():
         return 1
     finally:
         config.cleanup()
-        subprocess.run(["tput", "smam"])
+        subprocess.check_call(["tput", "smam"])
 
 if __name__ == "__main__":
     sys.exit(main())
Signature · 1 line
2.7.4
#2 lore raw

PATCH 2/45 scripts/runqemu: Tidy up lock handling code

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Various tweaks:
- Balance up the aquire/release functions
- Use debug messge for both acquiring and release message for consistency in logs
- Use None instead of an empty string
- Reset the value of the field if we don't have the lock any more

(From OE-Core rev: d3c052e6ccd81d544b23a3bee80ba00cafaedbbd)

---
 scripts/runqemu | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
scripts/runqemu +9 -7
index c9a351e..a83c8a6 100755
@@ -218,7 +218,7 @@ class BaseConfig(object):
         self.tcpserial_portnum = ''
         self.custombiosdir = ''
         self.lock = ''
-        self.lock_descriptor = ''
+        self.lock_descriptor = None
         self.bitbake_e = ''
         self.snapshot = False
         self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs',
@@ -252,13 +252,17 @@ class BaseConfig(object):
                 logger.info(msg)
             if self.lock_descriptor:
                 self.lock_descriptor.close()
+                self.lock_descriptor = None
             return False
         return True
 
     def release_lock(self):
-        fcntl.flock(self.lock_descriptor, fcntl.LOCK_UN)
-        self.lock_descriptor.close()
-        os.remove(self.lock)
+        if self.lock_descriptor:
+            logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
+            fcntl.flock(self.lock_descriptor, fcntl.LOCK_UN)
+            self.lock_descriptor.close()
+            os.remove(self.lock)
+            self.lock_descriptor = None
 
     def get(self, key):
         if key in self.d:
@@ -1232,9 +1236,7 @@ class BaseConfig(object):
             cmd = 'sudo %s %s %s' % (self.qemuifdown, self.tap, self.bindir_native)
             logger.debug('Running %s' % cmd)
             subprocess.check_call(cmd, shell=True)
-        if self.lock_descriptor:
-            logger.info("Releasing lockfile for tap device '%s'" % self.tap)
-            self.release_lock()
+        self.release_lock()
 
         if self.nfs_running:
             logger.info("Shutting down the userspace NFS server...")
Signature · 1 line
2.7.4
#3 lore raw

PATCH 3/45 scripts/runqemu: Improve lockfile handling for python with close_fd=True

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

On python versions with close_fds=True (python 3.2 onwards), the tap device lockfile isn't passed to the child process.

Since this guards against use of an active interface, we really want this here, so pass it in pass_fds. This means if the parent exits early, the child still holds the lock, avoiding messages like:

runqemu - ERROR - Failed to run qemu: qemu-system-x86_64: could not configure /dev/net/tun (tap0): Device or resource busy

(From OE-Core rev: 17a0a067d597c445c5892ff9914e91a2187f7e09)

(From OE-Core rev: d3b3c55ddc312039380ce8e23e68dd8bb2439388)

---
 scripts/runqemu | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
scripts/runqemu +4 -1
index a83c8a6..c6b7580 100755
@@ -1215,7 +1215,10 @@ class BaseConfig(object):
         cmd = "%s %s" % (self.qemu_opt, kernel_opts)
         cmds = shlex.split(cmd)
         logger.info('Running %s\n' % cmd)
-        process = subprocess.Popen(cmds, stderr=subprocess.PIPE)
+        pass_fds = []
+        if self.lock_descriptor:
+            pass_fds = [self.lock_descriptor.fileno()]
+        process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
         self.qemupid = process.pid
         retcode = process.wait()
         if retcode:
Signature · 1 line
2.7.4
#4 lore raw

PATCH 4/45 oeqa/selftest/signing: Skip tests if gpg isn't found

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Raising an assertionError in the class setup isn't a particuarly good way to indicate gpg isn't installed. Instead skip the tests if the required binary isn't present. For the signing tests we do require it to be present and can't use a prebuilt one.

(From OE-Core rev: 2d486af97e51b9daa9c40482c31d637c9ab4ae79)

(From OE-Core rev: 65403bb556f7e3132722288a62ef36631af0b557)

---
 meta/lib/oeqa/selftest/cases/signing.py | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)
meta/lib/oeqa/selftest/cases/signing.py +11 -12
index a750cfc..28afcdc 100644
@@ -15,23 +15,18 @@ class Signing(OESelftestTestCase):
     pub_key_path = ""
     secret_key_path = ""
 
-    @classmethod
-    def setUpClass(cls):
-        super(Signing, cls).setUpClass()
+    def setup_gpg(self):
         # Check that we can find the gpg binary and fail early if we can't
         if not shutil.which("gpg"):
-            raise AssertionError("This test needs GnuPG")
+            self.skipTest('gpg binary not found')
 
-        cls.gpg_dir = tempfile.mkdtemp(prefix="oeqa-signing-")
+        self.gpg_dir = tempfile.mkdtemp(prefix="oeqa-signing-")
+        self.track_for_cleanup(self.gpg_dir)
 
-        cls.pub_key_path = os.path.join(cls.testlayer_path, 'files', 'signing', "key.pub")
-        cls.secret_key_path = os.path.join(cls.testlayer_path, 'files', 'signing', "key.secret")
+        self.pub_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.pub")
+        self.secret_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.secret")
 
-        runCmd('gpg --batch --homedir %s --import %s %s' % (cls.gpg_dir, cls.pub_key_path, cls.secret_key_path))
-
-    @classmethod
-    def tearDownClass(cls):
-        shutil.rmtree(cls.gpg_dir, ignore_errors=True)
+        runCmd('gpg --batch --homedir %s --import %s %s' % (self.gpg_dir, self.pub_key_path, self.secret_key_path))
 
     @OETestID(1362)
     def test_signing_packages(self):
@@ -46,6 +41,8 @@ class Signing(OESelftestTestCase):
         """
         import oe.packagedata
 
+        self.setup_gpg()
+
         package_classes = get_bb_var('PACKAGE_CLASSES')
         if 'package_rpm' not in package_classes:
             self.skipTest('This test requires RPM Packaging.')
@@ -111,6 +108,8 @@ class Signing(OESelftestTestCase):
         builddir = os.environ.get('BUILDDIR')
         sstatedir = os.path.join(builddir, 'test-sstate')
 
+        self.setup_gpg()
+
         self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe)
         self.add_command_to_tearDown('rm -rf %s' % sstatedir)
 
Signature · 1 line
2.7.4
#5 lore raw

PATCH 5/45 oeqa/selftest/signing: Allow tests not to need gpg on the host

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

We ideally don't want to use gpg from the host. This is straightforward for package management but not for sstate.

For sstate, create a second build directory to run the test in using gnupg-native from the original build directory.

(From OE-Core rev: 10afa94c3f0d7eb7524a26deda86949073d55fde)

(From OE-Core rev: c5d68a24b0c6df0a16f50075a690b3aab0e273ee)

---
 meta/lib/oeqa/selftest/cases/signing.py | 67 +++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 19 deletions(-)
meta/lib/oeqa/selftest/cases/signing.py +48 -19
index 28afcdc..21849a1 100644
@@ -1,10 +1,12 @@
 from oeqa.selftest.case import OESelftestTestCase
 from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
 import os
+import oe
 import glob
 import re
 import shutil
 import tempfile
+from contextlib import contextmanager
 from oeqa.core.decorator.oeid import OETestID
 from oeqa.utils.ftools import write_file
 
@@ -16,9 +18,7 @@ class Signing(OESelftestTestCase):
     secret_key_path = ""
 
     def setup_gpg(self):
-        # Check that we can find the gpg binary and fail early if we can't
-        if not shutil.which("gpg"):
-            self.skipTest('gpg binary not found')
+        bitbake('gnupg-native -c addto_recipe_sysroot')
 
         self.gpg_dir = tempfile.mkdtemp(prefix="oeqa-signing-")
         self.track_for_cleanup(self.gpg_dir)
@@ -26,7 +26,30 @@ class Signing(OESelftestTestCase):
         self.pub_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.pub")
         self.secret_key_path = os.path.join(self.testlayer_path, 'files', 'signing', "key.secret")
 
-        runCmd('gpg --batch --homedir %s --import %s %s' % (self.gpg_dir, self.pub_key_path, self.secret_key_path))
+        nsysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native")
+        runCmd('gpg --batch --homedir %s --import %s %s' % (self.gpg_dir, self.pub_key_path, self.secret_key_path), native_sysroot=nsysroot)
+        return nsysroot + get_bb_var("bindir_native")
+
+
+    @contextmanager
+    def create_new_builddir(self, builddir, newbuilddir):
+        bb.utils.mkdirhier(newbuilddir)
+        oe.path.copytree(builddir + "/conf", newbuilddir + "/conf")
+        oe.path.copytree(builddir + "/cache", newbuilddir + "/cache")
+
+        origenv = os.environ.copy()
+
+        for e in os.environ:
+            if builddir in os.environ[e]:
+                os.environ[e] = os.environ[e].replace(builddir, newbuilddir)
+
+        os.chdir(newbuilddir)
+        try:
+            yield
+        finally:
+            for e in origenv:
+                os.environ[e] = origenv[e]
+            os.chdir(builddir)
 
     @OETestID(1362)
     def test_signing_packages(self):
@@ -105,13 +128,12 @@ class Signing(OESelftestTestCase):
 
         test_recipe = 'ed'
 
-        builddir = os.environ.get('BUILDDIR')
+        # Since we need gpg but we can't use gpg-native for sstate signatures, we 
+        # build gpg-native in our original builddir then run the tests in a second one.
+        builddir = os.environ.get('BUILDDIR') + "-testsign"
         sstatedir = os.path.join(builddir, 'test-sstate')
 
-        self.setup_gpg()
-
-        self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe)
-        self.add_command_to_tearDown('rm -rf %s' % sstatedir)
+        nsysroot = self.setup_gpg()
 
         feature = 'SSTATE_SIG_KEY ?= "testuser"\n'
         feature += 'SSTATE_SIG_PASSPHRASE ?= "test123"\n'
@@ -123,19 +145,26 @@ class Signing(OESelftestTestCase):
 
         self.write_config(feature)
 
-        bitbake('-c clean %s' % test_recipe)
-        bitbake(test_recipe)
+        with self.create_new_builddir(os.environ['BUILDDIR'], builddir):
+
+            os.environ["PATH"] = nsysroot + ":" + os.environ["PATH"]
+            self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe)
+            self.add_command_to_tearDown('rm -rf %s' % sstatedir)
+            self.add_command_to_tearDown('rm -rf %s' % builddir)
+
+            bitbake('-c clean %s' % test_recipe)
+            bitbake(test_recipe)
 
-        recipe_sig = glob.glob(sstatedir + '/*/*:ed:*_package.tgz.sig')
-        recipe_tgz = glob.glob(sstatedir + '/*/*:ed:*_package.tgz')
+            recipe_sig = glob.glob(sstatedir + '/*/*:ed:*_package.tgz.sig')
+            recipe_tgz = glob.glob(sstatedir + '/*/*:ed:*_package.tgz')
 
-        self.assertEqual(len(recipe_sig), 1, 'Failed to find .sig file.')
-        self.assertEqual(len(recipe_tgz), 1, 'Failed to find .tgz file.')
+            self.assertEqual(len(recipe_sig), 1, 'Failed to find .sig file.')
+            self.assertEqual(len(recipe_tgz), 1, 'Failed to find .tgz file.')
 
-        ret = runCmd('gpg --homedir %s --verify %s %s' % (self.gpg_dir, recipe_sig[0], recipe_tgz[0]))
-        # gpg: Signature made Thu 22 Oct 2015 01:45:09 PM EEST using RSA key ID 61EEFB30
-        # gpg: Good signature from "testuser (nocomment) <[email protected]>"
-        self.assertIn('gpg: Good signature from', ret.output, 'Package signed incorrectly.')
+            ret = runCmd('gpg --homedir %s --verify %s %s' % (self.gpg_dir, recipe_sig[0], recipe_tgz[0]))
+            # gpg: Signature made Thu 22 Oct 2015 01:45:09 PM EEST using RSA key ID 61EEFB30
+            # gpg: Good signature from "testuser (nocomment) <[email protected]>"
+            self.assertIn('gpg: Good signature from', ret.output, 'Package signed incorrectly.')
 
 
 class LockedSignatures(OESelftestTestCase):
Signature · 1 line
2.7.4
#6 lore raw

PATCH 6/45 oeqa/selftest/signing: Use do_populate_lic target instead of do_package

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

This should speed the test up signficiantly without any loss of functionality for the purposes of the test.

(From OE-Core rev: 3dde0b749643575878bfbca2f8d2d9ec30bad166)

(From OE-Core rev: 51989db2d9eebd9f190994109c2932dac3f3034b)

---
 meta/lib/oeqa/selftest/cases/signing.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
meta/lib/oeqa/selftest/cases/signing.py +3 -3
index 21849a1..0edaf40 100644
@@ -153,10 +153,10 @@ class Signing(OESelftestTestCase):
             self.add_command_to_tearDown('rm -rf %s' % builddir)
 
             bitbake('-c clean %s' % test_recipe)
-            bitbake(test_recipe)
+            bitbake('-c populate_lic %s' % test_recipe)
 
-            recipe_sig = glob.glob(sstatedir + '/*/*:ed:*_package.tgz.sig')
-            recipe_tgz = glob.glob(sstatedir + '/*/*:ed:*_package.tgz')
+            recipe_sig = glob.glob(sstatedir + '/*/*:ed:*_populate_lic.tgz.sig')
+            recipe_tgz = glob.glob(sstatedir + '/*/*:ed:*_populate_lic.tgz')
 
             self.assertEqual(len(recipe_sig), 1, 'Failed to find .sig file.')
             self.assertEqual(len(recipe_tgz), 1, 'Failed to find .tgz file.')
Signature · 1 line
2.7.4
#7 lore raw

PATCH 7/45 oeqa/selftest/case: Use bb.utils.remove() instead of shutil.remove()

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

This avoids problems where shutil.remove will error with:

File "/usr/lib/python3.5/shutil.py", line 436, in _rmtree_safe_fd
os.unlink(name, dir_fd=topfd)
FileNotFoundError: [Errno 2] No such file or directory: 'S.gpg-agent.extra'

when there are races over file deletion (gpg agent may be slow to exit).

We already worked around speed and race issues in bb.utils.

(From OE-Core rev: 00a8fd5b93a5c19ce0b7498e2bc653ce8ad58aaf)

(From OE-Core rev: e7c0d29e063d1a47004acdc07a63996be98c74ef)

---
 meta/lib/oeqa/selftest/case.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
meta/lib/oeqa/selftest/case.py +3 -1
index e09915b..2e446b0 100644
@@ -12,6 +12,8 @@ import oeqa.utils.ftools as ftools
 from oeqa.utils.commands import runCmd, bitbake, get_bb_var
 from oeqa.core.case import OETestCase
 
+import bb.utils
+
 class OESelftestTestCase(OETestCase):
     def __init__(self, methodName="runTest"):
         self._extra_tear_down_commands = []
@@ -167,7 +169,7 @@ to ensure accurate results.")
         if self._track_for_cleanup:
             for path in self._track_for_cleanup:
                 if os.path.isdir(path):
-                    shutil.rmtree(path)
+                    bb.utils.remove(path, recurse=True)
                 if os.path.isfile(path):
                     os.remove(path)
             self._track_for_cleanup = []
Signature · 1 line
2.7.4
#8 lore raw

PATCH 8/45 oeqa/selftest/buildoptions: Improve ccache test failure output

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

The current failure mode doesn't show us what the logs actually looked like and later cleans can lose them. Show the whole log in case of failure to aid debugging intermittent problems on the autobuilder.

(From OE-Core rev: 7c3a0dc5978cea898b1ca51decf4d6e7cf9d519f)

(From OE-Core rev: 60b58e976dcc2a45a036e18cfcc87933a8859c9f)

---
 meta/lib/oeqa/selftest/cases/buildoptions.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
meta/lib/oeqa/selftest/cases/buildoptions.py +3 -2
index e60e32d..406b7e8 100644
@@ -40,8 +40,9 @@ class ImageOptionsTests(OESelftestTestCase):
         self.add_command_to_tearDown('bitbake -c clean m4')
         bitbake("m4 -f -c compile")
         log_compile = os.path.join(get_bb_var("WORKDIR","m4"), "temp/log.do_compile")
-        res = runCmd("grep ccache %s" % log_compile, ignore_status=True)
-        self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile. For further details: %s" % log_compile)
+        with open(log_compile, "r") as f:
+            loglines = "".join(f.readlines())
+        self.assertIn("ccache", loglines, msg="No match for ccache in m4 log.do_compile. For further details: %s" % log_compile)
 
     @OETestID(1435)
     def test_read_only_image(self):
Signature · 1 line
2.7.4
#9 lore raw

PATCH 9/45 oeqa/utils/commands: Add extra qemu failure logging

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Rather than just referring the user to the logs containing the failure, print them on the console. This aids debugging with oe-selftest with parallelisation as the logs may otherwise be lost.

(From OE-Core rev: 36a018e245a232f520ff946f152cc875927a6fb4)

(From OE-Core rev: 0ea441ab6a6fe752cc8820fb371e67eee92353e4)

---
 meta/lib/oeqa/utils/commands.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
meta/lib/oeqa/utils/commands.py +5 -1
index 0d9cf23..933af92 100644
@@ -333,7 +333,11 @@ def runqemu(pn, ssh=True, runqemuparams='', image_fstype=None, launch_cmd=None,
         try:
             qemu.start(params=qemuparams, ssh=ssh, runqemuparams=runqemuparams, launch_cmd=launch_cmd, discard_writes=discard_writes)
         except bb.build.FuncFailed:
-            raise Exception('Failed to start QEMU - see the logs in %s' % logdir)
+            msg = 'Failed to start QEMU - see the logs in %s' % logdir
+            if os.path.exists(qemu.qemurunnerlog):
+                with open(qemu.qemurunnerlog, 'r') as f:
+                    msg = msg + "Qemurunner log output from %s:\n%s" % (qemu.qemurunnerlog, f.read())
+            raise Exception(msg)
 
         yield qemu
 
Signature · 1 line
2.7.4
#10 lore raw

PATCH 10/45 oeqa/utils/qemurunner: Fix python ResourceWarning for unclosed file

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Fixes:

Stderr:
/media/build1/poky/meta/lib/oeqa/utils/qemurunner.py:381: ResourceWarning: unclosed file <_io.BufferedWriter name=16>
self.runqemu = None

(From OE-Core rev: b9e0bf919e6fc1a58e02145a363ebe7066e5bf4f)

(From OE-Core rev: b8a9eec2c9e56181350269acd6b42a14cc4abb3e)

---
 meta/lib/oeqa/utils/qemurunner.py | 2 ++
 1 file changed, 2 insertions(+)
meta/lib/oeqa/utils/qemurunner.py +2 -0
index c962602..983c8c7 100644
@@ -369,6 +369,8 @@ class QemuRunner:
             if self.runqemu.poll() is None:
                 self.logger.debug("Sending SIGKILL to runqemu")
                 os.killpg(os.getpgid(self.runqemu.pid), signal.SIGKILL)
+            self.runqemu.stdin.close()
+            self.runqemu.stdout.close()
             self.runqemu = None
         if hasattr(self, 'server_socket') and self.server_socket:
             self.server_socket.close()
Signature · 1 line
2.7.4
#11 lore raw

PATCH 11/45 oeqa/utils/commands: Avoid log message duplication

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Each time a runqemu() fails, the log handler would be left behind meaning messages from any subsequent run would be duplicated (or worse/more).

This ensures we remove the handler regardless and means we no longer have the duplication.

(From OE-Core rev: 532984708436bdfa3a8cac2c684a425eb249bad0)

(From OE-Core rev: 600e71ede1977c45fed1958dd5356911e4fcf272)

---
 meta/lib/oeqa/utils/commands.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
meta/lib/oeqa/utils/commands.py +1 -1
index 933af92..da70529 100644
@@ -342,11 +342,11 @@ def runqemu(pn, ssh=True, runqemuparams='', image_fstype=None, launch_cmd=None,
         yield qemu
 
     finally:
+        targetlogger.removeHandler(handler)
         try:
             qemu.stop()
         except:
             pass
-    targetlogger.removeHandler(handler)
 
 def updateEnv(env_file):
     """
Signature · 1 line
2.7.4
#12 lore raw

PATCH 12/45 oeqa/qemurunner: Remove resource python warnings

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

If runqemu fails it would leak an unclosed socket and file. Ensure we close these in all cases to remove the resource warning.

(From OE-Core rev: ed80e46ccbc8fe8e9148d80723152066fa00ba28)

(From OE-Core rev: baa8313e492cff8c31633a558792500b10493e9e)

---
 meta/lib/oeqa/utils/qemurunner.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
meta/lib/oeqa/utils/qemurunner.py +8 -2
index 983c8c7..0f1c5a5 100644
@@ -135,7 +135,7 @@ class QemuRunner:
 
     def launch(self, launch_cmd, get_ip = True, qemuparams = None, extra_bootparams = None, env = None):
         try:
-            threadsock, threadport = self.create_socket()
+            self.threadsock, threadport = self.create_socket()
             self.server_socket, self.serverport = self.create_socket()
         except socket.error as msg:
             self.logger.error("Failed to create listening socket: %s" % msg[1])
@@ -263,7 +263,7 @@ class QemuRunner:
         self.logger.debug("Target IP: %s" % self.ip)
         self.logger.debug("Server IP: %s" % self.server_ip)
 
-        self.thread = LoggingThread(self.log, threadsock, self.logger)
+        self.thread = LoggingThread(self.log, self.threadsock, self.logger)
         self.thread.start()
         if not self.thread.connection_established.wait(self.boottime):
             self.logger.error("Didn't receive a console connection from qemu. "
@@ -372,13 +372,19 @@ class QemuRunner:
             self.runqemu.stdin.close()
             self.runqemu.stdout.close()
             self.runqemu = None
+
         if hasattr(self, 'server_socket') and self.server_socket:
             self.server_socket.close()
             self.server_socket = None
+        if hasattr(self, 'threadsock') and self.threadsock:
+            self.threadsock.close()
+            self.threadsock = None
         self.qemupid = None
         self.ip = None
         if os.path.exists(self.qemu_pidfile):
             os.remove(self.qemu_pidfile)
+        if self.monitorpipe:
+            self.monitorpipe.close()
 
     def stop_qemu_system(self):
         if self.qemupid:
Signature · 1 line
2.7.4
#13 lore raw

PATCH 13/45 oeqa/selftest/buildoptions: Improve ccache test

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

This test occisionally fails as m4 doesn't recompile, meaning the logfile test then doesn't find mention of ccache.

To ensure m4 does recompile, clean m4 before force compiling it.

(Reading the test is confusing due to the test cleanup also involving a clean)

(From OE-Core rev: 6e0b9214a0d57ed45a5df0ba5c9887a9045b89b1)

(From OE-Core rev: b729a46820cce38b3d500271df19bdaf31973140)

---
 meta/lib/oeqa/selftest/cases/buildoptions.py | 1 +
 1 file changed, 1 insertion(+)
meta/lib/oeqa/selftest/cases/buildoptions.py +1 -0
index 406b7e8..c406e95 100644
@@ -38,6 +38,7 @@ class ImageOptionsTests(OESelftestTestCase):
         self.assertTrue(os.path.isfile(p), msg = "No ccache found (%s)" % p)
         self.write_config('INHERIT += "ccache"')
         self.add_command_to_tearDown('bitbake -c clean m4')
+        bitbake("m4 -c clean")
         bitbake("m4 -f -c compile")
         log_compile = os.path.join(get_bb_var("WORKDIR","m4"), "temp/log.do_compile")
         with open(log_compile, "r") as f:
Signature · 1 line
2.7.4
#14 lore raw

PATCH 14/45 oeqa/selftest/buildoptions: Ensure diskmon tests run consistently

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Heartbeat events default to once a second and we need to ensure we have enough time in the task to see them.

Add a nostamp delay task 5s long so we can have a consistently timed task which doesn't need cleanup or have unneeded dependencies. This ensures we should deterministically see the disk moinitor events regardless of the state of the build. This is done in a way which doesn't corrupt build state or need cleanup and is efficient.

(From OE-Core rev: ecc49ee8986929e2429d948000a0ca588fe63959)

(From OE-Core rev: d5ce38168238181423c9dcd1d258253e3515d0a5)

---
 meta-selftest/recipes-test/delay/delay.bb    | 12 ++++++++++++
 meta/lib/oeqa/selftest/cases/buildoptions.py |  6 +++---
 2 files changed, 15 insertions(+), 3 deletions(-)
 create mode 100644 meta-selftest/recipes-test/delay/delay.bb
meta-selftest/recipes-test/delay/delay.bb new file +12 -0
new file mode 100644
index 0000000..f92d3d9
@@ -0,0 +1,12 @@
+SUMMARY = "Recipe with a fixed delay task"
+DESCRIPTION = "Contains a delay task to be used to for testing."
+LICENSE = "MIT"
+
+INHIBIT_DEFAULT_DEPS = "1"
+EXCLUDE_FROM_WORLD = "1"
+
+do_delay() {
+	sleep 5
+}
+do_delay[nostamp] = "1"
+addtask delay
\ No newline at end of file
meta/lib/oeqa/selftest/cases/buildoptions.py +3 -3
index c406e95..24597ac 100644
@@ -59,15 +59,15 @@ class DiskMonTest(OESelftestTestCase):
     @OETestID(277)
     def test_stoptask_behavior(self):
         self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"')
-        res = bitbake("m4", ignore_status = True)
+        res = bitbake("delay -c delay", ignore_status = True)
         self.assertTrue('ERROR: No new tasks can be executed since the disk space monitor action is "STOPTASKS"!' in res.output, msg = "Tasks should have stopped. Disk monitor is set to STOPTASK: %s" % res.output)
         self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output))
         self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"')
-        res = bitbake("m4", ignore_status = True)
+        res = bitbake("delay -c delay", ignore_status = True)
         self.assertTrue('ERROR: Immediately abort since the disk space monitor action is "ABORT"!' in res.output, "Tasks should have been aborted immediatelly. Disk monitor is set to ABORT: %s" % res.output)
         self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output))
         self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"')
-        res = bitbake("m4")
+        res = bitbake("delay -c delay")
         self.assertTrue('WARNING: The free space' in res.output, msg = "A warning should have been displayed for disk monitor is set to WARN: %s" %res.output)
 
 class SanityOptionsTest(OESelftestTestCase):
Signature · 1 line
2.7.4
#15 lore raw

PATCH 15/45 oeqa/oelib/path: don't leak temporary directories

In reply to Armin Kuster

From: Ross Burton <[email protected]>

setUp() is used to populate a directory of temporary files, and deleted in __del__. However setUp() is called once *per test* so __del__ would only be able to remove the last directory created.

Fix the code by using the natural counterpart to setUp, tearDown(), to clean up.

(From OE-Core rev: 68b4723e6fb11d171869185bccf28f32f6284c18)

(From OE-Core rev: edd2ecbc86d8b02a0467491451306f67e81d9ead)

---
 meta/lib/oeqa/selftest/cases/oelib/path.py | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
meta/lib/oeqa/selftest/cases/oelib/path.py +3 -7
index 75a27c0..e0eb813 100644
@@ -38,13 +38,6 @@ class TestRealPath(TestCase):
         ( "b/test", errno.ENOENT ),
     ]
 
-    def __del__(self):
-        try:
-            #os.system("tree -F %s" % self.tmpdir)
-            shutil.rmtree(self.tmpdir)
-        except:
-            pass
-
     def setUp(self):
         self.tmpdir = tempfile.mkdtemp(prefix = "oe-test_path")
         self.root = os.path.join(self.tmpdir, "R")
@@ -59,6 +52,9 @@ class TestRealPath(TestCase):
         for l in self.LINKS:
             os.symlink(l[1], os.path.join(self.root, l[0]))
 
+    def tearDown(self):
+        shutil.rmtree(self.tmpdir)
+
     def __realpath(self, file, use_physdir, assume_dir = True):
         return oe.path.realpath(os.path.join(self.root, file), self.root,
                                 use_physdir, assume_dir = assume_dir)
Signature · 1 line
2.7.4
#16 lore raw

PATCH 16/45 oeqa/selftest/runqemu: Improve testcase failure handling

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

assertTrue doesn't give good debug information when things fail. Update several to use assertIn which gives information upon failure, for the others print the log information upon failure.

(From OE-Core rev: c29cb75d5ce6b0873a934f4709b0c8824f7164d3)

(From OE-Core rev: 6f2bb2c12289422396deb793ae4b4e99cfa88c7b)

---
 meta/lib/oeqa/selftest/cases/runqemu.py | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)
meta/lib/oeqa/selftest/cases/runqemu.py +20 -12
index 5ebdd57..a758aaf 100644
@@ -44,7 +44,8 @@ SYSLINUX_TIMEOUT = "10"
         """Test runqemu machine"""
         cmd = "%s %s" % (self.cmd_common, self.machine)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
-            self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd)
+            with open(qemu.qemurunnerlog) as f:
+                self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
 
     @OETestID(2002)
     def test_boot_machine_ext4(self):
@@ -52,7 +53,7 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s %s ext4" % (self.cmd_common, self.machine)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue('rootfs.ext4' in f.read(), "Failed: %s" % cmd)
+                self.assertIn('rootfs.ext4', f.read(), "Failed: %s" % cmd)
 
     @OETestID(2003)
     def test_boot_machine_iso(self):
@@ -60,14 +61,16 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s %s iso" % (self.cmd_common, self.machine)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue('media=cdrom' in f.read(), "Failed: %s" % cmd)
+                self.assertIn('media=cdrom', f.read(), "Failed: %s" % cmd)
 
     @OETestID(2004)
     def test_boot_recipe_image(self):
         """Test runqemu recipe-image"""
         cmd = "%s %s" % (self.cmd_common, self.recipe)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
-            self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd)
+            with open(qemu.qemurunnerlog) as f:
+                self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
+
 
     @OETestID(2005)
     def test_boot_recipe_image_vmdk(self):
@@ -75,7 +78,7 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s %s wic.vmdk" % (self.cmd_common, self.recipe)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue('format=vmdk' in f.read(), "Failed: %s" % cmd)
+                self.assertIn('format=vmdk', f.read(), "Failed: %s" % cmd)
 
     @OETestID(2006)
     def test_boot_recipe_image_vdi(self):
@@ -83,14 +86,16 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s %s wic.vdi" % (self.cmd_common, self.recipe)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue('format=vdi' in f.read(), "Failed: %s" % cmd)
+                self.assertIn('format=vdi', f.read(), "Failed: %s" % cmd)
 
     @OETestID(2007)
     def test_boot_deploy(self):
         """Test runqemu deploy_dir_image"""
         cmd = "%s %s" % (self.cmd_common, self.deploy_dir_image)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
-            self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd)
+            with open(qemu.qemurunnerlog) as f:
+                self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
+
 
     @OETestID(2008)
     def test_boot_deploy_hddimg(self):
@@ -98,7 +103,7 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s %s hddimg" % (self.cmd_common, self.deploy_dir_image)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue(re.search('file=.*.hddimg', f.read()), "Failed: %s" % cmd)
+                self.assertTrue(re.search('file=.*.hddimg', f.read()), "Failed: %s, %s" % (cmd, f.read()))
 
     @OETestID(2009)
     def test_boot_machine_slirp(self):
@@ -106,7 +111,7 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s slirp %s" % (self.cmd_common, self.machine)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue(' -netdev user' in f.read(), "Failed: %s" % cmd)
+                self.assertIn(' -netdev user', f.read(), "Failed: %s" % cmd)
 
     @OETestID(2009)
     def test_boot_machine_slirp_qcow2(self):
@@ -114,7 +119,7 @@ SYSLINUX_TIMEOUT = "10"
         cmd = "%s slirp wic.qcow2 %s" % (self.cmd_common, self.machine)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
             with open(qemu.qemurunnerlog) as f:
-                self.assertTrue('format=qcow2' in f.read(), "Failed: %s" % cmd)
+                self.assertIn('format=qcow2', f.read(), "Failed: %s" % cmd)
 
     @OETestID(2010)
     def test_boot_qemu_boot(self):
@@ -125,7 +130,8 @@ SYSLINUX_TIMEOUT = "10"
             self.skipTest("%s not found" % qemuboot_conf)
         cmd = "%s %s" % (self.cmd_common, qemuboot_conf)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
-            self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd)
+            with open(qemu.qemurunnerlog) as f:
+                self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
 
     @OETestID(2011)
     def test_boot_rootfs(self):
@@ -136,7 +142,9 @@ SYSLINUX_TIMEOUT = "10"
             self.skipTest("%s not found" % rootfs)
         cmd = "%s %s" % (self.cmd_common, rootfs)
         with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu:
-            self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd)
+            with open(qemu.qemurunnerlog) as f:
+                self.assertTrue(qemu.runner.logged, "Failed: %s, %s" % (cmd, f.read()))
+
 
 # This test was designed as a separate class to test that shutdown
 # command will shutdown qemu as expected on each qemu architecture
Signature · 1 line
2.7.4
#17 lore raw

PATCH 17/45 oeqa/utils/qemurunner: Avoid tracebacks on closed files

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Reorder the shutdown/teardown to avoid:

File "/home/pokybuild/yocto-worker/oe-selftest-ubuntu/build/meta/lib/oeqa/utils/qemurunner.py", line 224, in launch
op = self.getOutput(output)
File "/home/pokybuild/yocto-worker/oe-selftest-ubuntu/build/meta/lib/oeqa/utils/qemurunner.py", line 90, in getOutput
fl = fcntl.fcntl(o, fcntl.F_GETFL)
ValueError: I/O operation on closed file

(From OE-Core rev: 8e7d756862d2a8d62f3c87497d6d65ddb3c1b962)

(From OE-Core rev: 48979ffbe25351f92179021a973207a71bbe7a4e)

---
 meta/lib/oeqa/utils/qemurunner.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
meta/lib/oeqa/utils/qemurunner.py +2 -2
index 0f1c5a5..4f6f1d0 100644
@@ -203,8 +203,8 @@ class QemuRunner:
                     # No point waiting any longer
                     self.logger.debug('runqemu exited with code %d' % self.runqemu.returncode)
                     self._dump_host()
-                    self.stop()
                     self.logger.debug("Output from runqemu:\n%s" % self.getOutput(output))
+                    self.stop()
                     return False
             time.sleep(0.5)
 
@@ -216,8 +216,8 @@ class QemuRunner:
             processes = ps.decode("utf-8")
             self.logger.debug("Running processes:\n%s" % processes)
             self._dump_host()
-            self.stop()
             op = self.getOutput(output)
+            self.stop()
             if op:
                 self.logger.error("Output from runqemu:\n%s" % op)
             else:
Signature · 1 line
2.7.4
#18 lore raw

PATCH 18/45 oeqa: don't litter /tmp with temporary directories

In reply to Armin Kuster

From: Ross Burton <[email protected]>

If we need to create a temporary directory in targetbuild or buildproject use tempfile.TemporaryDirectory so that when the test case is finished, the directory is deleted.

Also synchronise the logic and don't possibly store the temporary directory in self.tmpdir as nothing uses that.

(From OE-Core rev: db0e658097130d146752785d0d45f46a3e0bad71)

(From OE-Core rev: d39252324a13580cc96f0694b88bc10515e030a0)

---
 meta/lib/oeqa/utils/buildproject.py | 3 ++-
 meta/lib/oeqa/utils/targetbuild.py  | 5 +++--
 2 files changed, 5 insertions(+), 3 deletions(-)
meta/lib/oeqa/utils/buildproject.py +2 -1
index 721f35d..88e7b7f 100644
@@ -17,7 +17,8 @@ class BuildProject(metaclass=ABCMeta):
         self.uri = uri
         self.archive = os.path.basename(uri)
         if not tmpdir:
-            tmpdir = tempfile.mkdtemp(prefix='buildproject')
+            self.tempdirobj = tempfile.TemporaryDirectory(prefix='buildproject-')
+            tmpdir = self.tempdirobj.name
         self.localarchive = os.path.join(tmpdir, self.archive)
         self.dl_dir = dl_dir
         if foldername:
meta/lib/oeqa/utils/targetbuild.py +3 -2
index 1202d57..b8db7b2 100644
@@ -20,8 +20,9 @@ class BuildProject(metaclass=ABCMeta):
         if not tmpdir:
             tmpdir = self.d.getVar('WORKDIR')
             if not tmpdir:
-                tmpdir = tempfile.mkdtemp(prefix='buildproject')
-        self.localarchive = os.path.join(tmpdir,self.archive)
+                self.tempdirobj = tempfile.TemporaryDirectory(prefix='buildproject-')
+                tmpdir = self.tempdirobj.name
+        self.localarchive = os.path.join(tmpdir, self.archive)
         if foldername:
             self.fname = foldername
         else:
Signature · 1 line
2.7.4
#19 lore raw

PATCH 19/45 oeqa/selftest/esdk: run selftest inside workdir not /tmp

In reply to Armin Kuster

From: Ross Burton <[email protected]>

We've seen issues with rootfs size calculations and we've seen systems like opensuse which have btrfs mounted on /tmp causing selftest failures.

(From OE-Core rev: 61be3cd748d1b7321a1fc4cfe84efa9b26a6aee0)

(From OE-Core rev: d936faabfb29ea377d74e77332a2a91603747ac7)

---
 meta/lib/oeqa/selftest/cases/eSDK.py | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
meta/lib/oeqa/selftest/cases/eSDK.py +7 -6
index d03188f..14f75d8 100644
@@ -70,11 +70,12 @@ CORE_IMAGE_EXTRA_INSTALL = "perl"
     @classmethod
     def setUpClass(cls):
         super(oeSDKExtSelfTest, cls).setUpClass()
-        cls.tmpdir_eSDKQA = tempfile.mkdtemp(prefix='eSDKQA')
+        cls.image = 'core-image-minimal'
 
-        sstate_dir = get_bb_var('SSTATE_DIR')
+        bb_vars = get_bb_vars(['SSTATE_DIR', 'WORKDIR'], cls.image)
+        cls.tmpdirobj = tempfile.TemporaryDirectory(prefix="selftest-esdk-", dir=bb_vars["WORKDIR"])
+        cls.tmpdir_eSDKQA = cls.tempdirobj.name
 
-        cls.image = 'core-image-minimal'
         oeSDKExtSelfTest.generate_eSDK(cls.image)
 
         # Install eSDK
@@ -87,14 +88,14 @@ CORE_IMAGE_EXTRA_INSTALL = "perl"
         sstate_config="""
 SDK_LOCAL_CONF_WHITELIST = "SSTATE_MIRRORS"
 SSTATE_MIRRORS =  "file://.* file://%s/PATH"
-            """ % sstate_dir
+            """ % bb_vars["SSTATE_DIR"]
         with open(os.path.join(cls.tmpdir_eSDKQA, 'conf', 'local.conf'), 'a+') as f:
             f.write(sstate_config)
 
     @classmethod
     def tearDownClass(cls):
-        shutil.rmtree(cls.tmpdir_eSDKQA, ignore_errors=True)
-        super(oeSDKExtSelfTest, cls).tearDownClass()
+        cls.tmpdirobj.cleanup()
+        super().tearDownClass()
 
     @OETestID(1602)
     def test_install_libraries_headers(self):
Signature · 1 line
2.7.4
#20 lore raw

PATCH 20/45 oeqa/loader: Fix deprecation warning

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Clean up the warning:
meta/lib/oeqa/core/loader.py:27: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() or inspect.getfullargspec()
_failed_test_args = inspect.getargspec(unittest.loader._make_failed_test).args

(From OE-Core rev: d2deb66830be2d44532fea3d5db763b57778252a)

(From OE-Core rev: f9ab10bb08446052fd6af2a21f38d8454e466d51)

---
 meta/lib/oeqa/core/loader.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
meta/lib/oeqa/core/loader.py +1 -1
index 98fc0f6..2255cf1 100644
@@ -24,7 +24,7 @@ from oeqa.core.decorator import decoratorClasses, OETestDecorator, \
 # Generate the function definition because this differ across python versions
 # Python >= 3.4.4 uses tree parameters instead four but for example Python 3.5.3
 # ueses four parameters so isn't incremental.
-_failed_test_args = inspect.getargspec(unittest.loader._make_failed_test).args
+_failed_test_args = inspect.getfullargspec(unittest.loader._make_failed_test).args
 exec("""def _make_failed_test(%s): raise exception""" % ', '.join(_failed_test_args))
 unittest.loader._make_failed_test = _make_failed_test
 
Signature · 1 line
2.7.4
#21 lore raw

PATCH 21/45 oeqa/utils/commands: Avoid unclosed file warnings

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Avoid warnings such as:

meta/lib/oeqa/utils/commands.py:213: ResourceWarning: unclosed file <_io.BufferedReader name=4>
return runCmd(cmd, ignore_status, timeout, output_log=output_log, **options)

(From OE-Core rev: 6a68c42de08cffbadb59ebda63fa5e19f6e5acef)

(From OE-Core rev: 682d7b2810b235e86a28a8afe034e3853dbe8c45)

---
 meta/lib/oeqa/utils/commands.py | 3 +++
 1 file changed, 3 insertions(+)
meta/lib/oeqa/utils/commands.py +3 -0
index da70529..2e6a228 100644
@@ -146,6 +146,9 @@ class Command(object):
         # At this point we know that the process has closed stdout/stderr, so
         # it is safe and necessary to wait for the actual process completion.
         self.status = self.process.wait()
+        self.process.stdout.close()
+        if self.process.stderr:
+            self.process.stderr.close()
 
         self.log.debug("Command '%s' returned %d as exit code." % (self.cmd, self.status))
         # logging the complete output is insane
Signature · 1 line
2.7.4
#22 lore raw

PATCH 22/45 oeqa/selftest/context: Replace deprecated imp module usage

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Avoid the warning:

meta/lib/oeqa/selftest/context.py:8: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
import imp

In this case importlib is a direct replacement.

(From OE-Core rev: db7a60c36a2d3eefc61ae6e1ede01680dc932035)

(From OE-Core rev: 351a7b75959593922909d7e1929a6429a2bf94a7)

---
 meta/lib/oeqa/selftest/context.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
meta/lib/oeqa/selftest/context.py +2 -2
index 9e90d3c..cac049f 100644
@@ -5,7 +5,7 @@ import os
 import time
 import glob
 import sys
-import imp
+import importlib
 import signal
 from shutil import copyfile
 from random import choice
@@ -174,7 +174,7 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
                     self.tc.logger.info("\t%s" % l)
 
                 sys.path.extend(layer_libdirs)
-                imp.reload(oeqa.selftest)
+                importlib.reload(oeqa.selftest)
 
         _check_required_env_variables(["BUILDDIR"])
         _check_presence_meta_selftest()
Signature · 1 line
2.7.4
#23 lore raw

PATCH 23/45 oeqa/utils/qemurunner.py: Fix python regex warnings

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Fix the warnings:

meta/lib/oeqa/utils/qemurunner.py:250: DeprecationWarning: invalid escape sequence \.
ips = re.findall("((?:[0-9]{1,3}\.){3}[0-9]{1,3})", cmdline.split("ip=")[1])
meta/lib/oeqa/utils/qemurunner.py:343: DeprecationWarning: invalid escape sequence \-
if re.search("root@[a-zA-Z0-9\-]+:~#", output):
poky/meta/lib/oeqa/utils/qemurunner.py:350: DeprecationWarning: invalid escape sequence \-
if re.search("root@[a-zA-Z0-9\-]+:~#", output):
meta/lib/oeqa/utils/qemurunner.py:448: DeprecationWarning: invalid escape sequence \-
if re.search("[a-zA-Z0-9]+@[a-zA-Z0-9\-]+:~#", data):

by correctly marking the regexs.

(From OE-Core rev: 8e6987735002560fca714f77ea8ece9d4b28f7fa)

(From OE-Core rev: 7eb1f0be82d7ee12f893cdd40384da306fa597a7)

---
 meta/lib/oeqa/utils/qemurunner.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
meta/lib/oeqa/utils/qemurunner.py +5 -5
index 4f6f1d0..b87d776 100644
@@ -238,13 +238,13 @@ class QemuRunner:
                 # 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])
+                ips = re.findall(r"((?:[0-9]{1,3}\.){3}[0-9]{1,3})", cmdline.split("ip=")[1])
                 self.ip = ips[0]
                 self.server_ip = ips[1]
                 self.logger.debug("qemu cmdline used:\n{}".format(cmdline))
             except (IndexError, ValueError):
                 # Try to get network configuration from runqemu output
-                match = re.match('.*Network configuration: ([0-9.]+)::([0-9.]+):([0-9.]+)$.*',
+                match = re.match(r'.*Network configuration: ([0-9.]+)::([0-9.]+):([0-9.]+)$.*',
                                  out, re.MULTILINE|re.DOTALL)
                 if match:
                     self.ip, self.server_ip, self.netmask = match.groups()
@@ -331,14 +331,14 @@ class QemuRunner:
         # If we are not able to login the tests can continue
         try:
             (status, output) = self.run_serial("root\n", raw=True)
-            if re.search("root@[a-zA-Z0-9\-]+:~#", output):
+            if re.search(r"root@[a-zA-Z0-9\-]+:~#", output):
                 self.logged = True
                 self.logger.debug("Logged as root in serial console")
                 if netconf:
                     # configure guest networking
                     cmd = "ifconfig eth0 %s netmask %s up\n" % (self.ip, self.netmask)
                     output = self.run_serial(cmd, raw=True)[1]
-                    if re.search("root@[a-zA-Z0-9\-]+:~#", output):
+                    if re.search(r"root@[a-zA-Z0-9\-]+:~#", output):
                         self.logger.debug("configured ip address %s", self.ip)
                     else:
                         self.logger.debug("Couldn't configure guest networking")
@@ -444,7 +444,7 @@ class QemuRunner:
                 if answer:
                     data += answer.decode('utf-8')
                     # Search the prompt to stop
-                    if re.search("[a-zA-Z0-9]+@[a-zA-Z0-9\-]+:~#", data):
+                    if re.search(r"[a-zA-Z0-9]+@[a-zA-Z0-9\-]+:~#", data):
                         break
                 else:
                     raise Exception("No data on serial console socket")
Signature · 1 line
2.7.4
#24 lore raw

PATCH 24/45 oeqa/selftest/context: Improve log file handling

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

The existing logfile is simply placed in the current directory. Since the test changes cwd to BUILDDIR, the symlink to the log can be placed in an invalid directory. We also see trackbacks if the symlink is invalid.

Improve things by:

* Placing logs in LOG_DIR (or BUILDDIR if unset).
* Using a full path to the log meaning the log and link are placed in the same directory.
* Using lexists instead of exists so invalid symlinks are handled correctly.

(From OE-Core rev: 750ece11bed0e62a11e0003d1d16a81f7c219761)

(From OE-Core rev: 9c4c3c876dd5d224133571fcad1095af1098ae1d)

---
 meta/lib/oeqa/selftest/context.py | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
meta/lib/oeqa/selftest/context.py +10 -4
index cac049f..33316d3 100644
@@ -96,11 +96,17 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         return cases_paths
 
     def _process_args(self, logger, args):
-        args.output_log = '%s-results-%s.log' % (self.name,
-                time.strftime("%Y%m%d%H%M%S"))
+
+        args.test_start_time = time.strftime("%Y%m%d%H%M%S")
         args.test_data_file = None
         args.CASES_PATHS = None
 
+        bbvars = get_bb_vars()
+        logdir = os.environ.get("BUILDDIR")
+        if 'LOG_DIR' in bbvars:
+            logdir = bbvars['LOG_DIR']
+        args.output_log = logdir + '/%s-results-%s.log' % (self.name, args.test_start_time)
+
         super(OESelftestTestContextExecutor, self)._process_args(logger, args)
 
         if args.list_modules:
@@ -110,7 +116,7 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         elif args.list_tests:
             args.list_tests = 'name'
 
-        self.tc_kwargs['init']['td'] = get_bb_vars()
+        self.tc_kwargs['init']['td'] = bbvars
         self.tc_kwargs['init']['machines'] = self._get_available_machines()
 
         builddir = os.environ.get("BUILDDIR")
@@ -270,7 +276,7 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
 
             output_link = os.path.join(os.path.dirname(args.output_log),
                     "%s-results.log" % self.name)
-            if os.path.exists(output_link):
+            if os.path.lexists(output_link):
                 os.remove(output_link)
             os.symlink(args.output_log, output_link)
 
Signature · 1 line
2.7.4
#25 lore raw

PATCH 25/45 oeqa/core/runner: Improve test case comparision

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

We can directly compare the test case IDs rather than representations, then if we're using subunit to split the tests, the comparisions still work as intended.

(From OE-Core rev: 72e5f46f75454ba4c445c65c1cbc616a9e72fc6e)

(From OE-Core rev: 4c53aac5315f9d0a0ed95cbeb48b7704e274e3a9)

---
 meta/lib/oeqa/core/runner.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
meta/lib/oeqa/core/runner.py +2 -2
index 13cdf5b..16345fa 100644
@@ -88,10 +88,10 @@ class OETestResult(_TestResult):
                     break
                 scase_str = scase.test_id
             else:
-                if case == scase:
+                if case.id() == scase.id():
                     found = True
                     break
-                scase_str = str(scase)
+                scase_str = str(scase.id())
 
             # When fails at module or class level the class name is passed as string
             # so figure out to see if match
Signature · 1 line
2.7.4
#26 lore raw

PATCH 26/45 oeqa/runner: Ensure we don't print misleading results output

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

The current code assumes if something isn't a failure of some kind, it was a pass. When test case IDs weren't matching, this lead to very confusing output where things would fail, then be listed as passing.

This adds code to track successes, ensuring we don't end up in this position again with unmatched entries being listed as UNKNOWN.

(From OE-Core rev: 4374c296d8963e4f6a1aa7bef7983ad0a1c2fcff)

(From OE-Core rev: bcb2948773d76befef2be787be6d25cf544e49a9)

---
 meta/lib/oeqa/core/runner.py | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
meta/lib/oeqa/core/runner.py +11 -3
index 16345fa..374d30c 100644
@@ -42,6 +42,8 @@ class OETestResult(_TestResult):
     def __init__(self, tc, *args, **kwargs):
         super(OETestResult, self).__init__(*args, **kwargs)
 
+        self.successes = []
+
         self.tc = tc
         self._tc_map_results()
 
@@ -58,6 +60,7 @@ class OETestResult(_TestResult):
         self.tc._results['errors'] = self.errors
         self.tc._results['skipped'] = self.skipped
         self.tc._results['expectedFailures'] = self.expectedFailures
+        self.tc._results['successes'] = self.successes
 
     def logSummary(self, component, context_msg=''):
         elapsed_time = self.tc._run_end_time - self.tc._run_start_time
@@ -115,13 +118,18 @@ class OETestResult(_TestResult):
 
         return (found, None)
 
+    def addSuccess(self, test):
+        #Added so we can keep track of successes too
+        self.successes.append((test, None))
+        super(OETestResult, self).addSuccess(test)
+
     def logDetails(self):
         self.tc.logger.info("RESULTS:")
         for case_name in self.tc._registry['cases']:
             case = self.tc._registry['cases'][case_name]
 
-            result_types = ['failures', 'errors', 'skipped', 'expectedFailures']
-            result_desc = ['FAILED', 'ERROR', 'SKIPPED', 'EXPECTEDFAIL']
+            result_types = ['failures', 'errors', 'skipped', 'expectedFailures', 'successes']
+            result_desc = ['FAILED', 'ERROR', 'SKIPPED', 'EXPECTEDFAIL', 'PASSED']
 
             fail = False
             desc = None
@@ -143,7 +151,7 @@ class OETestResult(_TestResult):
                     oeid, desc))
             else:
                 self.tc.logger.info("RESULTS - %s - Testcase %s: %s" % (case.id(),
-                    oeid, 'PASSED'))
+                    oeid, 'UNKNOWN'))
 
 class OEListTestsResult(object):
     def wasSuccessful(self):
Signature · 1 line
2.7.4
#27 lore raw

PATCH 27/45 oeqa/core/threaded: Remove in favour of using concurrenttests

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

We have several options for parallel processing in oeqa, parallel execution of modules, threading and mulitple processes for the runners.

After much experimentation is appears the most scalable and least invasive approach is multiple processes using concurrenttestsuite from testtools. This means we can drop the current threading code which is only used by the sdk test execution.

oeqa/decorator/depends: Remove threading code

Revert "oeqa/sdk: Enable usage of OEQA thread mode" This reverts commit adc434c0636b7dea2ef70c8d2c8e61cdb5c703b1.

Revert "oeqa/core/tests: Add tests of OEQA Threaded mode" This reverts commit a4eef558c9933eb32413b61ff80a11b999951b40.

Revert "oeqa/core/decorator/oetimeout: Add support for OEQA threaded mode" This reverts commit d3d4ba902dee8b19fa1054330cffdf73f9b81fe7.

(From OE-Core rev: a98ab5e560e73b6988512fbae5cefe9e42ceed53)

(From OE-Core rev: bb9a85e157e669d7a91c3bbefc8d5138e7b8b6ae)

---
 meta/classes/testsdk.bbclass                       |   4 -
 meta/lib/oeqa/core/decorator/depends.py            |   7 +-
 meta/lib/oeqa/core/decorator/oetimeout.py          |  40 +--
 .../core/tests/cases/loader/threaded/threaded.py   |  12 -
 .../tests/cases/loader/threaded/threaded_alone.py  |   8 -
 .../cases/loader/threaded/threaded_depends.py      |  10 -
 .../tests/cases/loader/threaded/threaded_module.py |  12 -
 meta/lib/oeqa/core/tests/common.py                 |  10 -
 meta/lib/oeqa/core/tests/test_decorators.py        |  12 -
 meta/lib/oeqa/core/tests/test_loader.py            |  30 +--
 meta/lib/oeqa/core/threaded.py                     | 275 ---------------------
 meta/lib/oeqa/sdk/context.py                       |   5 +-
 12 files changed, 14 insertions(+), 411 deletions(-)
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py
 delete mode 100644 meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py
 delete mode 100644 meta/lib/oeqa/core/threaded.py
meta/classes/testsdk.bbclass +0 -4
index 2e43343..103cc56 100644
@@ -24,8 +24,6 @@ def testsdk_main(d):
     from oeqa.sdk.context import OESDKTestContext, OESDKTestContextExecutor
     from oeqa.utils import make_logger_bitbake_compatible
 
-    bb.event.enable_threadlock()
-
     pn = d.getVar("PN")
     logger = make_logger_bitbake_compatible(logging.getLogger("BitBake"))
 
@@ -99,8 +97,6 @@ def testsdkext_main(d):
     from oeqa.utils import avoid_paths_in_environ, make_logger_bitbake_compatible, subprocesstweak
     from oeqa.sdkext.context import OESDKExtTestContext, OESDKExtTestContextExecutor
 
-    bb.event.enable_threadlock()
-
     pn = d.getVar("PN")
     logger = make_logger_bitbake_compatible(logging.getLogger("BitBake"))
 
meta/lib/oeqa/core/decorator/depends.py +1 -6
index baa0434..99eccc1 100644
@@ -3,7 +3,6 @@
 
 from unittest import SkipTest
 
-from oeqa.core.threaded import OETestRunnerThreaded
 from oeqa.core.exception import OEQADependency
 
 from . import OETestDiscover, registerDecorator
@@ -64,11 +63,7 @@ def _order_test_case_by_depends(cases, depends):
     return [cases[case_id] for case_id in cases_ordered]
 
 def _skipTestDependency(case, depends):
-    if isinstance(case.tc.runner, OETestRunnerThreaded):
-        import threading
-        results = case.tc._results[threading.get_ident()]
-    else:
-        results = case.tc._results
+    results = case.tc._results
 
     skipReasons = ['errors', 'failures', 'skipped']
 
meta/lib/oeqa/core/decorator/oetimeout.py +10 -30
index f85e7d9..a247583 100644
@@ -1,12 +1,8 @@
 # Copyright (C) 2016 Intel Corporation
 # Released under the MIT license (see COPYING.MIT)
 
-from . import OETestDecorator, registerDecorator
-
 import signal
-from threading import Timer
-
-from oeqa.core.threaded import OETestRunnerThreaded
+from . import OETestDecorator, registerDecorator
 from oeqa.core.exception import OEQATimeoutError
 
 @registerDecorator
@@ -14,32 +10,16 @@ class OETimeout(OETestDecorator):
     attrs = ('oetimeout',)
 
     def setUpDecorator(self):
-        self.logger.debug("Setting up a %d second(s) timeout" % self.oetimeout)
-
-        if isinstance(self.case.tc.runner, OETestRunnerThreaded):
-            self.timeouted = False
-            def _timeoutHandler():
-                self.timeouted = True
-
-            self.timer = Timer(self.oetimeout, _timeoutHandler)
-            self.timer.start()
-        else:
-            timeout = self.oetimeout
-            def _timeoutHandler(signum, frame):
-                raise OEQATimeoutError("Timed out after %s "
+        timeout = self.oetimeout
+        def _timeoutHandler(signum, frame):
+            raise OEQATimeoutError("Timed out after %s "
                     "seconds of execution" % timeout)
 
-            self.alarmSignal = signal.signal(signal.SIGALRM, _timeoutHandler)
-            signal.alarm(self.oetimeout)
+        self.logger.debug("Setting up a %d second(s) timeout" % self.oetimeout)
+        self.alarmSignal = signal.signal(signal.SIGALRM, _timeoutHandler)
+        signal.alarm(self.oetimeout)
 
     def tearDownDecorator(self):
-        if isinstance(self.case.tc.runner, OETestRunnerThreaded):
-            self.timer.cancel()
-            self.logger.debug("Removed Timer handler")
-            if self.timeouted:
-                raise OEQATimeoutError("Timed out after %s "
-                    "seconds of execution" % self.oetimeout)
-        else:
-            signal.alarm(0)
-            signal.signal(signal.SIGALRM, self.alarmSignal)
-            self.logger.debug("Removed SIGALRM handler")
+        signal.alarm(0)
+        signal.signal(signal.SIGALRM, self.alarmSignal)
+        self.logger.debug("Removed SIGALRM handler")
meta/lib/oeqa/core/tests/cases/loader/threaded/threaded.py deleted +0 -12
deleted file mode 100644
index 0fe4cb3..0000000
@@ -1,12 +0,0 @@
-# Copyright (C) 2017 Intel Corporation
-# Released under the MIT license (see COPYING.MIT)
-
-from oeqa.core.case import OETestCase
-
-class ThreadedTest(OETestCase):
-    def test_threaded_no_depends(self):
-        self.assertTrue(True, msg='How is this possible?')
-
-class ThreadedTest2(OETestCase):
-    def test_threaded_same_module(self):
-        self.assertTrue(True, msg='How is this possible?')
meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_alone.py deleted +0 -8
deleted file mode 100644
index 905f397..0000000
@@ -1,8 +0,0 @@
-# Copyright (C) 2017 Intel Corporation
-# Released under the MIT license (see COPYING.MIT)
-
-from oeqa.core.case import OETestCase
-
-class ThreadedTestAlone(OETestCase):
-    def test_threaded_alone(self):
-        self.assertTrue(True, msg='How is this possible?')
meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_depends.py deleted +0 -10
deleted file mode 100644
index 0c158d3..0000000
@@ -1,10 +0,0 @@
-# Copyright (C) 2017 Intel Corporation
-# Released under the MIT license (see COPYING.MIT)
-
-from oeqa.core.case import OETestCase
-from oeqa.core.decorator.depends import OETestDepends
-
-class ThreadedTest3(OETestCase):
-    @OETestDepends(['threaded.ThreadedTest.test_threaded_no_depends'])
-    def test_threaded_depends(self):
-        self.assertTrue(True, msg='How is this possible?')
meta/lib/oeqa/core/tests/cases/loader/threaded/threaded_module.py deleted +0 -12
deleted file mode 100644
index 63d17e0..0000000
@@ -1,12 +0,0 @@
-# Copyright (C) 2017 Intel Corporation
-# Released under the MIT license (see COPYING.MIT)
-
-from oeqa.core.case import OETestCase
-
-class ThreadedTestModule(OETestCase):
-    def test_threaded_module(self):
-        self.assertTrue(True, msg='How is this possible?')
-
-class ThreadedTestModule2(OETestCase):
-    def test_threaded_module2(self):
-        self.assertTrue(True, msg='How is this possible?')
meta/lib/oeqa/core/tests/common.py +0 -10
index 1932323..52b18a1 100644
@@ -33,13 +33,3 @@ class TestBase(unittest.TestCase):
         tc.loadTests(self.cases_path, modules=modules, tests=tests,
                      filters=filters)
         return tc
-
-    def _testLoaderThreaded(self, d={}, modules=[],
-            tests=[], filters={}):
-        from oeqa.core.threaded import OETestContextThreaded
-
-        tc = OETestContextThreaded(d, self.logger)
-        tc.loadTests(self.cases_path, modules=modules, tests=tests,
-                     filters=filters)
-
-        return tc
meta/lib/oeqa/core/tests/test_decorators.py +0 -12
index cf99e0d..f7d11e8 100755
@@ -131,17 +131,5 @@ class TestTimeoutDecorator(TestBase):
         msg = "OETestTimeout didn't restore SIGALRM"
         self.assertIs(alarm_signal, signal.getsignal(signal.SIGALRM), msg=msg)
 
-    def test_timeout_thread(self):
-        tests = ['timeout.TimeoutTest.testTimeoutPass']
-        msg = 'Failed to run test using OETestTimeout'
-        tc = self._testLoaderThreaded(modules=self.modules, tests=tests)
-        self.assertTrue(tc.runTests().wasSuccessful(), msg=msg)
-
-    def test_timeout_threaded_fail(self):
-        tests = ['timeout.TimeoutTest.testTimeoutFail']
-        msg = "OETestTimeout test didn't timeout as expected"
-        tc = self._testLoaderThreaded(modules=self.modules, tests=tests)
-        self.assertFalse(tc.runTests().wasSuccessful(), msg=msg)
-
 if __name__ == '__main__':
     unittest.main()
meta/lib/oeqa/core/tests/test_loader.py +1 -29
index e0d917d..b79b8ba 100755
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# Copyright (C) 2016-2017 Intel Corporation
+# Copyright (C) 2016 Intel Corporation
 # Released under the MIT license (see COPYING.MIT)
 
 import os
@@ -82,33 +82,5 @@ class TestLoader(TestBase):
         msg = 'Expected modules from two different paths'
         self.assertEqual(modules, expected_modules, msg=msg)
 
-    def test_loader_threaded(self):
-        cases_path = self.cases_path
-
-        self.cases_path = [os.path.join(self.cases_path, 'loader', 'threaded')]
-
-        tc = self._testLoaderThreaded()
-        self.assertEqual(len(tc.suites), 3, "Expected to be 3 suites")
-
-        case_ids = ['threaded.ThreadedTest.test_threaded_no_depends',
-                'threaded.ThreadedTest2.test_threaded_same_module',
-                'threaded_depends.ThreadedTest3.test_threaded_depends']
-        for case in tc.suites[0]._tests:
-            self.assertEqual(case.id(),
-                    case_ids[tc.suites[0]._tests.index(case)])
-
-        case_ids = ['threaded_alone.ThreadedTestAlone.test_threaded_alone']
-        for case in tc.suites[1]._tests:
-            self.assertEqual(case.id(),
-                    case_ids[tc.suites[1]._tests.index(case)])
-
-        case_ids = ['threaded_module.ThreadedTestModule.test_threaded_module',
-                'threaded_module.ThreadedTestModule2.test_threaded_module2']
-        for case in tc.suites[2]._tests:
-            self.assertEqual(case.id(),
-                    case_ids[tc.suites[2]._tests.index(case)])
-
-        self.cases_path = cases_path
-
 if __name__ == '__main__':
     unittest.main()
meta/lib/oeqa/core/threaded.py deleted +0 -275

275 lines not on this page · raw message

meta/lib/oeqa/sdk/context.py +2 -3
index b3d7c75..82e4c19 100644
@@ -6,10 +6,9 @@ import sys
 import glob
 import re
 
-from oeqa.core.context import OETestContextExecutor
-from oeqa.core.threaded import OETestContextThreaded
+from oeqa.core.context import OETestContext, OETestContextExecutor
 
-class OESDKTestContext(OETestContextThreaded):
+class OESDKTestContext(OETestContext):
     sdk_files_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files")
 
     def __init__(self, td=None, logger=None, sdk_dir=None, sdk_env=None,
Signature · 1 line
2.7.4
#28 lore raw

PATCH 28/45 oeqa/runner: Simplify code

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

There doesn't appear to be any reason we need this _results indirection any more so remove it.

(From OE-Core rev: b618261811c48ff3b98eab1b340a8cd09ef183c6)

(From OE-Core rev: ab271b49d9b55ea271d519c3a4da0b639a07f0bb)

---
 meta/lib/oeqa/core/context.py           |  1 -
 meta/lib/oeqa/core/decorator/depends.py |  4 +---
 meta/lib/oeqa/core/runner.py            | 15 +++++----------
 meta/lib/oeqa/core/tests/test_data.py   |  4 ++--
 4 files changed, 8 insertions(+), 16 deletions(-)
meta/lib/oeqa/core/context.py +0 -1
index acd5474..ef00845 100644
@@ -27,7 +27,6 @@ class OETestContext(object):
         self.logger = logger
         self._registry = {}
         self._registry['cases'] = collections.OrderedDict()
-        self._results = {}
 
     def _read_modules_from_manifest(self, manifest):
         if not os.path.exists(manifest):
meta/lib/oeqa/core/decorator/depends.py +1 -3
index 99eccc1..69c604d 100644
@@ -63,12 +63,10 @@ def _order_test_case_by_depends(cases, depends):
     return [cases[case_id] for case_id in cases_ordered]
 
 def _skipTestDependency(case, depends):
-    results = case.tc._results
-
     skipReasons = ['errors', 'failures', 'skipped']
 
     for reason in skipReasons:
-        for test, _ in results[reason]:
+        for test, _ in getattr(case.tc.results, reason):
             if test.id() in depends:
                 raise SkipTest("Test case %s depends on %s and was in %s." \
                         % (case.id(), test.id(), reason))
meta/lib/oeqa/core/runner.py +5 -10
index 374d30c..50122f2 100644
@@ -44,8 +44,10 @@ class OETestResult(_TestResult):
 
         self.successes = []
 
+        # Inject into tc so that TestDepends decorator can see results
+        tc.results = self
+
         self.tc = tc
-        self._tc_map_results()
 
     def startTest(self, test):
         # Allow us to trigger the testcase buffer mode on a per test basis
@@ -55,13 +57,6 @@ class OETestResult(_TestResult):
             self.buffer = test.buffer
         super(OETestResult, self).startTest(test)
 
-    def _tc_map_results(self):
-        self.tc._results['failures'] = self.failures
-        self.tc._results['errors'] = self.errors
-        self.tc._results['skipped'] = self.skipped
-        self.tc._results['expectedFailures'] = self.expectedFailures
-        self.tc._results['successes'] = self.successes
-
     def logSummary(self, component, context_msg=''):
         elapsed_time = self.tc._run_end_time - self.tc._run_start_time
         self.tc.logger.info("SUMMARY:")
@@ -73,7 +68,7 @@ class OETestResult(_TestResult):
             msg = "%s - OK - All required tests passed" % component
         else:
             msg = "%s - FAIL - Required tests failed" % component
-        skipped = len(self.tc._results['skipped'])
+        skipped = len(self.skipped)
         if skipped: 
             msg += " (skipped=%d)" % skipped
         self.tc.logger.info(msg)
@@ -81,7 +76,7 @@ class OETestResult(_TestResult):
     def _getDetailsNotPassed(self, case, type, desc):
         found = False
 
-        for (scase, msg) in self.tc._results[type]:
+        for (scase, msg) in getattr(self, type):
             # XXX: When XML reporting is enabled scase is
             # xmlrunner.result._TestInfo instance instead of
             # string.
meta/lib/oeqa/core/tests/test_data.py +2 -2
index 320468c..21b6c68 100755
@@ -21,7 +21,7 @@ class TestData(TestBase):
 
         tc = self._testLoader(modules=self.modules)
         self.assertEqual(False, tc.runTests().wasSuccessful())
-        for test, data in tc._results['errors']:
+        for test, data in tc.errors:
             expect = False
             if expectedException in data:
                 expect = True
@@ -34,7 +34,7 @@ class TestData(TestBase):
 
         tc = self._testLoader(d=d, modules=self.modules)
         self.assertEqual(False, tc.runTests().wasSuccessful())
-        for test, data in tc._results['failures']:
+        for test, data in tc.failures:
             expect = False
             if expectedError in data:
                 expect = True
Signature · 1 line
2.7.4
#29 lore raw

PATCH 29/45 oeqa: Remove xmlrunner

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

This isn't present on modern distros by default and doesn't work with testtools, needing multiple code paths in the code. Remove it in favour of finding a better replacement for results collection/analysis.

(From OE-Core rev: 8001d933a8dc86004db014777f094d718086687d)

(From OE-Core rev: 02449e89d62a7714d30ab6e2e58c476dc9441f7a)

---
 meta/lib/oeqa/core/runner.py | 54 ++++++++------------------------------------
 1 file changed, 9 insertions(+), 45 deletions(-)
meta/lib/oeqa/core/runner.py +9 -45
index 50122f2..429c216 100644
@@ -7,16 +7,8 @@ import unittest
 import logging
 import re
 
-xmlEnabled = False
-try:
-    import xmlrunner
-    from xmlrunner.result import _XMLTestResult as _TestResult
-    from xmlrunner.runner import XMLTestRunner as _TestRunner
-    xmlEnabled = True
-except ImportError:
-    # use the base runner instead
-    from unittest import TextTestResult as _TestResult
-    from unittest import TextTestRunner as _TestRunner
+from unittest import TextTestResult as _TestResult
+from unittest import TextTestRunner as _TestRunner
 
 class OEStreamLogger(object):
     def __init__(self, logger):
@@ -77,19 +69,10 @@ class OETestResult(_TestResult):
         found = False
 
         for (scase, msg) in getattr(self, type):
-            # XXX: When XML reporting is enabled scase is
-            # xmlrunner.result._TestInfo instance instead of
-            # string.
-            if xmlEnabled:
-                if case.id() == scase.test_id:
-                    found = True
-                    break
-                scase_str = scase.test_id
-            else:
-                if case.id() == scase.id():
-                    found = True
-                    break
-                scase_str = str(scase.id())
+            if case.id() == scase.id():
+                found = True
+                break
+            scase_str = str(scase.id())
 
             # When fails at module or class level the class name is passed as string
             # so figure out to see if match
@@ -156,33 +139,14 @@ class OETestRunner(_TestRunner):
     streamLoggerClass = OEStreamLogger
 
     def __init__(self, tc, *args, **kwargs):
-        if xmlEnabled:
-            if not kwargs.get('output'):
-                kwargs['output'] = os.path.join(os.getcwd(),
-                        'TestResults_%s_%s' % (time.strftime("%Y%m%d%H%M%S"), os.getpid()))
-
         kwargs['stream'] = self.streamLoggerClass(tc.logger)
         super(OETestRunner, self).__init__(*args, **kwargs)
         self.tc = tc
         self.resultclass = OETestResult
 
-    # XXX: The unittest-xml-reporting package defines _make_result method instead
-    # of _makeResult standard on unittest.
-    if xmlEnabled:
-        def _make_result(self):
-            """
-            Creates a TestResult object which will be used to store
-            information about the executed tests.
-            """
-            # override in subclasses if necessary.
-            return self.resultclass(self.tc,
-                self.stream, self.descriptions, self.verbosity, self.elapsed_times
-            )
-    else:
-        def _makeResult(self):
-            return self.resultclass(self.tc, self.stream, self.descriptions,
-                    self.verbosity)
-
+    def _makeResult(self):
+        return self.resultclass(self.tc, self.stream, self.descriptions,
+                self.verbosity)
 
     def _walk_suite(self, suite, func):
         for obj in suite:
Signature · 1 line
2.7.4
#30 lore raw

PATCH 30/45 oeqa/core/runner: refactor for OEQA to write json testresult

In reply to Armin Kuster

From: Yeoh Ee Peng <[email protected]>

Refactor the original _getDetailsNotPassed method to return testresult details (test status and log), which will be reused by future OEQA code to write json testresult.

Take the opportunity to consolidate and simplify the logic used to gather test status and log within the TestResult instance.

(From OE-Core rev: 79ee7d1c371a86edeb61c99679985118da657e5d)

(From OE-Core rev: bc444181f9658423856621b2f2c60364642ae5b1)

---
 meta/lib/oeqa/core/runner.py | 70 ++++++++++++++++++--------------------------
 1 file changed, 29 insertions(+), 41 deletions(-)
meta/lib/oeqa/core/runner.py +29 -41
index 429c216..a7b7463 100644
@@ -61,40 +61,43 @@ class OETestResult(_TestResult):
         else:
             msg = "%s - FAIL - Required tests failed" % component
         skipped = len(self.skipped)
-        if skipped: 
+        if skipped:
             msg += " (skipped=%d)" % skipped
         self.tc.logger.info(msg)
 
-    def _getDetailsNotPassed(self, case, type, desc):
-        found = False
+    def _getTestResultDetails(self, case):
+        result_types = {'failures': 'FAILED', 'errors': 'ERROR', 'skipped': 'SKIPPED',
+                        'expectedFailures': 'EXPECTEDFAIL', 'successes': 'PASSED'}
 
-        for (scase, msg) in getattr(self, type):
-            if case.id() == scase.id():
-                found = True
-                break
-            scase_str = str(scase.id())
-
-            # When fails at module or class level the class name is passed as string
-            # so figure out to see if match
-            m = re.search("^setUpModule \((?P<module_name>.*)\)$", scase_str)
-            if m:
-                if case.__class__.__module__ == m.group('module_name'):
+        for rtype in result_types:
+            found = False
+            for (scase, msg) in getattr(self, rtype):
+                if case.id() == scase.id():
                     found = True
                     break
+                scase_str = str(scase.id())
 
-            m = re.search("^setUpClass \((?P<class_name>.*)\)$", scase_str)
-            if m:
-                class_name = "%s.%s" % (case.__class__.__module__,
-                        case.__class__.__name__)
+                # When fails at module or class level the class name is passed as string
+                # so figure out to see if match
+                m = re.search("^setUpModule \((?P<module_name>.*)\)$", scase_str)
+                if m:
+                    if case.__class__.__module__ == m.group('module_name'):
+                        found = True
+                        break
 
-                if class_name == m.group('class_name'):
-                    found = True
-                    break
+                m = re.search("^setUpClass \((?P<class_name>.*)\)$", scase_str)
+                if m:
+                    class_name = "%s.%s" % (case.__class__.__module__,
+                                            case.__class__.__name__)
+
+                    if class_name == m.group('class_name'):
+                        found = True
+                        break
 
-        if found:
-            return (found, msg)
+            if found:
+                return result_types[rtype], msg
 
-        return (found, None)
+        return 'UNKNOWN', None
 
     def addSuccess(self, test):
         #Added so we can keep track of successes too
@@ -106,17 +109,7 @@ class OETestResult(_TestResult):
         for case_name in self.tc._registry['cases']:
             case = self.tc._registry['cases'][case_name]
 
-            result_types = ['failures', 'errors', 'skipped', 'expectedFailures', 'successes']
-            result_desc = ['FAILED', 'ERROR', 'SKIPPED', 'EXPECTEDFAIL', 'PASSED']
-
-            fail = False
-            desc = None
-            for idx, name in enumerate(result_types):
-                (fail, msg) = self._getDetailsNotPassed(case, result_types[idx],
-                        result_desc[idx])
-                if fail:
-                    desc = result_desc[idx]
-                    break
+            (status, log) = self._getTestResultDetails(case)
 
             oeid = -1
             if hasattr(case, 'decorators'):
@@ -124,12 +117,7 @@ class OETestResult(_TestResult):
                     if hasattr(d, 'oeid'):
                         oeid = d.oeid
 
-            if fail:
-                self.tc.logger.info("RESULTS - %s - Testcase %s: %s" % (case.id(),
-                    oeid, desc))
-            else:
-                self.tc.logger.info("RESULTS - %s - Testcase %s: %s" % (case.id(),
-                    oeid, 'UNKNOWN'))
+            self.tc.logger.info("RESULTS - %s - Testcase %s: %s" % (case.id(), oeid, status))
 
 class OEListTestsResult(object):
     def wasSuccessful(self):
Signature · 1 line
2.7.4
#31 lore raw

PATCH 31/45 oeqa/core/runner: write testresult to json files

In reply to Armin Kuster

From: Yeoh Ee Peng <[email protected]>

As part of the solution to replace Testopia to store testresult, OEQA need to output testresult into single json file, where json testresult file will be stored in git repository by the future test-case-management tools.

The json testresult file will store more than one set of results, where each set of results was uniquely identified by the result_id. The result_id would be like "runtime-qemux86-core-image-sato", where it was a runtime test with target machine equal to qemux86 and running on core-image-sato image. The json testresult file will only store the latest test content for a given result_id. The json testresult file contains the configuration (eg. COMMIT, BRANCH, MACHINE, IMAGE), result (eg. PASSED, FAILED, ERROR), test log, and result_id.

Based on the destination json testresult file directory provided, it could have multiple instances of bitbake trying to write json testresult to a single testresult file, using locking a lockfile alongside the results file directory to prevent races.

Also the library class inside this patch will be reused by the future test-case-management tools to write json testresult for manual test case executed.

(From OE-Core rev: 00e03b5004f1eb6d59295544b3a8620504278f51)

(From OE-Core rev: 045511425577ccbe89d8eb91e2a87e385390cabf)

---
 meta/lib/oeqa/core/runner.py | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)
meta/lib/oeqa/core/runner.py +34 -1
index a7b7463..7e0b61b 100644
@@ -6,6 +6,7 @@ import time
 import unittest
 import logging
 import re
+import json
 
 from unittest import TextTestResult as _TestResult
 from unittest import TextTestRunner as _TestRunner
@@ -104,8 +105,9 @@ class OETestResult(_TestResult):
         self.successes.append((test, None))
         super(OETestResult, self).addSuccess(test)
 
-    def logDetails(self):
+    def logDetails(self, json_file_dir=None, configuration=None, result_id=None):
         self.tc.logger.info("RESULTS:")
+        result = {}
         for case_name in self.tc._registry['cases']:
             case = self.tc._registry['cases'][case_name]
 
@@ -118,6 +120,11 @@ class OETestResult(_TestResult):
                         oeid = d.oeid
 
             self.tc.logger.info("RESULTS - %s - Testcase %s: %s" % (case.id(), oeid, status))
+            result[case.id()] = {'status': status, 'log': log}
+
+        if json_file_dir:
+            tresultjsonhelper = OETestResultJSONHelper()
+            tresultjsonhelper.dump_testresult_file(json_file_dir, configuration, result_id, result)
 
 class OEListTestsResult(object):
     def wasSuccessful(self):
@@ -230,3 +237,29 @@ class OETestRunner(_TestRunner):
             self._list_tests_module(suite)
 
         return OEListTestsResult()
+
+class OETestResultJSONHelper(object):
+
+    testresult_filename = 'testresults.json'
+
+    def _get_existing_testresults_if_available(self, write_dir):
+        testresults = {}
+        file = os.path.join(write_dir, self.testresult_filename)
+        if os.path.exists(file):
+            with open(file, "r") as f:
+                testresults = json.load(f)
+        return testresults
+
+    def _write_file(self, write_dir, file_name, file_content):
+        file_path = os.path.join(write_dir, file_name)
+        with open(file_path, 'w') as the_file:
+            the_file.write(file_content)
+
+    def dump_testresult_file(self, write_dir, configuration, result_id, test_result):
+        bb.utils.mkdirhier(write_dir)
+        lf = bb.utils.lockfile(os.path.join(write_dir, 'jsontestresult.lock'))
+        test_results = self._get_existing_testresults_if_available(write_dir)
+        test_results[result_id] = {'configuration': configuration, 'result': test_result}
+        json_testresults = json.dumps(test_results, sort_keys=True, indent=4)
+        self._write_file(write_dir, self.testresult_filename, json_testresults)
+        bb.utils.unlockfile(lf)
Signature · 1 line
2.7.4
#32 lore raw

PATCH 32/45 oeqa/runtime/ptest: Inject results+logs into stored json results file

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

This allows the ptest results from ptest-runner, run in an image to be transferred over to the resulting json results output.

Each test is given a pass/skip/fail so individual results can be monitored and the raw log output from the ptest-runner is also dumped into the results json file as this means after the fact debugging becomes much easier.

Currently the log output is not split up per test but that would make a good future enhancement.

I attempted to implement this as python subTests however it failed as the output was too confusing, subTests don't support any kind of log output handling, subTest successes aren't logged and it was making things far more complex than they needed to be.

We mark ptest-runner as "EXPECTEDFAILURE" since its unlikely every ptest will pass currently and we don't want that to fail the whole image test run. Its assumed there would be later analysis of the json output to determine regressions. We do have to change the test runner code so that 'unexpectedsuccess' is not a failure.

Also, the test names are manipuated to remove spaces and brackets with "_" used as a replacement and any duplicate occurrences truncated.

(From OE-Core rev: a13e088942e2a3c3521e98954a394e61a15234e8)

(From OE-Core rev: 526ceab9d0e43f73635bb92e8dd7763ef75ad33b)

---
 meta/lib/oeqa/core/runner.py         |  8 ++++++++
 meta/lib/oeqa/runtime/cases/ptest.py | 21 +++++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)
meta/lib/oeqa/core/runner.py +8 -0
index 7e0b61b..9a64e49 100644
@@ -107,7 +107,11 @@ class OETestResult(_TestResult):
 
     def logDetails(self, json_file_dir=None, configuration=None, result_id=None):
         self.tc.logger.info("RESULTS:")
+
         result = {}
+        if hasattr(self.tc, "extraresults"):
+            result = self.tc.extraresults
+
         for case_name in self.tc._registry['cases']:
             case = self.tc._registry['cases'][case_name]
 
@@ -126,6 +130,10 @@ class OETestResult(_TestResult):
             tresultjsonhelper = OETestResultJSONHelper()
             tresultjsonhelper.dump_testresult_file(json_file_dir, configuration, result_id, result)
 
+    def wasSuccessful(self):
+        # Override as we unexpected successes aren't failures for us
+        return (len(self.failures) == len(self.errors) == 0)
+
 class OEListTestsResult(object):
     def wasSuccessful(self):
         return True
meta/lib/oeqa/runtime/cases/ptest.py +19 -2
index f60a433..77ae7b6 100644
@@ -1,3 +1,6 @@
+import unittest
+import pprint
+
 from oeqa.runtime.case import OERuntimeTestCase
 from oeqa.core.decorator.depends import OETestDepends
 from oeqa.core.decorator.oeid import OETestID
@@ -49,6 +52,7 @@ class PtestRunnerTest(OERuntimeTestCase):
     @OETestID(1600)
     @skipIfNotFeature('ptest', 'Test requires ptest to be in DISTRO_FEATURES')
     @OETestDepends(['ssh.SSHTest.test_ssh'])
+    @unittest.expectedFailure
     def test_ptestrunner(self):
         status, output = self.target.run('which ptest-runner', 0)
         if status != 0:
@@ -76,6 +80,11 @@ class PtestRunnerTest(OERuntimeTestCase):
         # status != 0 is OK since some ptest tests may fail
         self.assertTrue(status != 127, msg="Cannot execute ptest-runner!")
 
+        if not hasattr(self.tc, "extraresults"):
+            self.tc.extraresults = {}
+        extras = self.tc.extraresults
+        extras['ptestresult.rawlogs'] = {'log': output}
+
         # Parse and save results
         parse_result = self.parse_ptest(ptest_runner_log)
         parse_result.log_as_files(ptest_log_dir, test_status = ['pass','fail', 'skip'])
@@ -84,10 +93,18 @@ class PtestRunnerTest(OERuntimeTestCase):
             os.remove(ptest_log_dir_link)
         os.symlink(os.path.basename(ptest_log_dir), ptest_log_dir_link)
 
+        trans = str.maketrans("()", "__")
+        resmap = {'pass': 'PASSED', 'skip': 'SKIPPED', 'fail': 'FAILED'}
+        for section in parse_result.result_dict:
+            for test, result in parse_result.result_dict[section]:
+                testname = "ptestresult." + section + "." + "_".join(test.translate(trans).split())
+                extras[testname] = {'status': resmap[result]}
+
         failed_tests = {}
         for section in parse_result.result_dict:
-            failed_testcases = [ test for test, result in parse_result.result_dict[section] if result == 'fail' ]
+            failed_testcases = [ "_".join(test.translate(trans).split()) for test, result in parse_result.result_dict[section] if result == 'fail' ]
             if failed_testcases:
                 failed_tests[section] = failed_testcases
 
-        self.assertFalse(failed_tests, msg = "Failed ptests: %s" %(str(failed_tests)))
+        if failed_tests:
+            self.fail("Failed ptests:\n%s" % pprint.pformat(failed_tests))
Signature · 1 line
2.7.4
#33 lore raw

PATCH 33/45 oeqa/runner: Always show a summary of success/fail/error/skip counts

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Its useful to have the counts of success/failure/error/skipped at the end of the results to allow for easier human reading of what happened.

(From OE-Core rev: 5942318a261ce7a885f351e214669068ff9d8931)

---
 meta/lib/oeqa/core/runner.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
meta/lib/oeqa/core/runner.py +1 -3
index 9a64e49..0cb1a95 100644
@@ -61,9 +61,7 @@ class OETestResult(_TestResult):
             msg = "%s - OK - All required tests passed" % component
         else:
             msg = "%s - FAIL - Required tests failed" % component
-        skipped = len(self.skipped)
-        if skipped:
-            msg += " (skipped=%d)" % skipped
+        msg += " (successes=%d, skipped=%d, failures=%d, errors=%d)" % (len(self.successes), len(self.skipped), len(self.failures), len(self.errors))
         self.tc.logger.info(msg)
 
     def _getTestResultDetails(self, case):
Signature · 1 line
2.7.4
#34 lore raw

PATCH 34/45 oeqa/runner: Sort the test result output by result class

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

We want to see failures/errors listed last since this is the most easily visible part of the log on consoles or autobuilder output and makes human processing easier rather than having to scroll up and scan for a single failure.

(From OE-Core rev: 2cc07ab253f1ba6a1f07a66051c9ba6d98cd2357)

---
 meta/lib/oeqa/core/runner.py | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
meta/lib/oeqa/core/runner.py +14 -2
index 0cb1a95..f8bb23f 100644
@@ -107,6 +107,7 @@ class OETestResult(_TestResult):
         self.tc.logger.info("RESULTS:")
 
         result = {}
+        logs = {}
         if hasattr(self.tc, "extraresults"):
             result = self.tc.extraresults
 
@@ -121,8 +122,19 @@ class OETestResult(_TestResult):
                     if hasattr(d, 'oeid'):
                         oeid = d.oeid
 
-            self.tc.logger.info("RESULTS - %s - Testcase %s: %s" % (case.id(), oeid, status))
-            result[case.id()] = {'status': status, 'log': log}
+            if status not in logs:
+                logs[status] = []
+            logs[status].append("RESULTS - %s - Testcase %s: %s" % (case.id(), oeid, status))
+            if log:
+                result[case.id()] = {'status': status, 'log': log}
+            else:
+                result[case.id()] = {'status': status}
+
+        for i in ['PASSED', 'SKIPPED', 'EXPECTEDFAIL', 'ERROR', 'FAILED', 'UNKNOWN']:
+            if i not in logs:
+                continue
+            for l in logs[i]:
+                self.tc.logger.info(l)
 
         if json_file_dir:
             tresultjsonhelper = OETestResultJSONHelper()
Signature · 1 line
2.7.4
#35 lore raw

PATCH 35/45 oeqa/selftest/context: write testresult to json files

In reply to Armin Kuster

From: Yeoh Ee Peng <[email protected]>

As part of the solution to replace Testopia to store testresult, OEQA selftest need to output testresult into json files, where these json testresult files will be stored into git repository by the future test-case-management tools.

By default, json testresult file will be written to "oeqa" directory under the oe-selftest log directory.

To configure multiple instances of bitbake to write json testresult to a single testresult file at custom directory, user will define the variable "OEQA_JSON_RESULT_DIR" with the custom directory for json testresult.

(From OE-Core rev: a95218525a4c8228fff9908ffbda85c6b85e101c)

---
 meta/lib/oeqa/selftest/context.py | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)
meta/lib/oeqa/selftest/context.py +29 -1
index 33316d3..964a46c 100644
@@ -202,6 +202,31 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         self.tc.logger.info("Running bitbake -p")
         runCmd("bitbake -p")
 
+    def _get_json_result_dir(self, args):
+        json_result_dir = os.path.join(os.path.dirname(os.path.abspath(args.output_log)), 'oeqa')
+        if "OEQA_JSON_RESULT_DIR" in self.tc.td:
+            json_result_dir = self.tc.td["OEQA_JSON_RESULT_DIR"]
+
+        return json_result_dir
+
+    def _get_configuration(self, args):
+        import platform
+        from oeqa.utils.metadata import metadata_from_bb
+        metadata = metadata_from_bb()
+        configuration = {'TEST_TYPE': 'oeselftest',
+                        'START_TIME': args.test_start_time,
+                        'MACHINE': self.tc.td["MACHINE"],
+                        'HOST_DISTRO': ('-'.join(platform.linux_distribution())).replace(' ', '-'),
+                        'HOST_NAME': metadata['hostname']}
+        layers = metadata['layers']
+        for l in layers:
+            configuration['%s_BRANCH_REV' % os.path.basename(l)] = '%s:%s' % (metadata['layers'][l]['branch'],
+                                                                              metadata['layers'][l]['commit'])
+        return configuration
+
+    def _get_result_id(self, configuration):
+        return '%s_%s_%s' % (configuration['TEST_TYPE'], configuration['HOST_DISTRO'], configuration['MACHINE'])
+
     def _internal_run(self, logger, args):
         self.module_paths = self._get_cases_paths(
                 self.tc_kwargs['init']['td']['BBPATH'].split(':'))
@@ -218,7 +243,10 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         else:
             self._pre_run()
             rc = self.tc.runTests(**self.tc_kwargs['run'])
-            rc.logDetails()
+            configuration = self._get_configuration(args)
+            rc.logDetails(self._get_json_result_dir(args),
+                          configuration,
+                          self._get_result_id(configuration))
             rc.logSummary(self.name)
 
         return rc
Signature · 1 line
2.7.4
#36 lore raw

PATCH 36/45 testimage.bbclass: write testresult to json files

In reply to Armin Kuster

From: Yeoh Ee Peng <[email protected]>

As part of the solution to replace Testopia to store testresult, OEQA testimage need to output testresult into json files, where these json testresult files will be stored into git repository by the future test-case-management tools.

By default, json testresult file will be written to "oeqa" directory under the "WORKDIR" directory.

To configure multiple instances of bitbake to write json testresult to a single testresult file at custom directory, user will define the variable "OEQA_JSON_RESULT_DIR" with the custom directory for json testresult.

(From OE-Core rev: 2b8b47ec8ee835d2e70cc4ff3ec484f9e4e4d02d)

---
 meta/classes/testimage.bbclass | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)
meta/classes/testimage.bbclass +29 -2
index 9feb267..e95ce0c 100644
@@ -2,7 +2,7 @@
 #
 # Released under the MIT license (see COPYING.MIT)
 
-
+inherit metadata_scm
 # testimage.bbclass enables testing of qemu images using python unittests.
 # Most of the tests are commands run on target image over ssh.
 # To use it add testimage to global inherit and call your target image with -c testimage
@@ -132,6 +132,30 @@ def testimage_sanity(d):
         bb.fatal('When TEST_TARGET is set to "simpleremote" '
                  'TEST_TARGET_IP and TEST_SERVER_IP are needed too.')
 
+def _get_testimage_configuration(d, test_type, pid, machine):
+    import platform
+    configuration = {'TEST_TYPE': test_type,
+                    'PROCESS_ID': pid,
+                    'MACHINE': machine,
+                    'IMAGE_BASENAME': d.getVar("IMAGE_BASENAME"),
+                    'IMAGE_PKGTYPE': d.getVar("IMAGE_PKGTYPE"),
+                    'HOST_DISTRO': ('-'.join(platform.linux_distribution())).replace(' ', '-')}
+    layers = (d.getVar("BBLAYERS") or "").split()
+    for l in layers:
+        configuration['%s_BRANCH_REV' % os.path.basename(l)] = '%s:%s' % (base_get_metadata_git_branch(l, None).strip(),
+                                                                          base_get_metadata_git_revision(l, None))
+    return configuration
+
+def _get_testimage_json_result_dir(d):
+    json_result_dir = os.path.join(d.getVar("WORKDIR"), 'oeqa')
+    custom_json_result_dir = d.getVar("OEQA_JSON_RESULT_DIR")
+    if custom_json_result_dir:
+        json_result_dir = custom_json_result_dir
+    return json_result_dir
+
+def _get_testimage_result_id(configuration):
+    return '%s_%s_%s' % (configuration['TEST_TYPE'], configuration['IMAGE_BASENAME'], configuration['MACHINE'])
+
 def testimage_main(d):
     import os
     import json
@@ -299,7 +323,10 @@ def testimage_main(d):
     # Show results (if we have them)
     if not results:
         bb.fatal('%s - FAILED - tests were interrupted during execution' % pn, forcelog=True)
-    results.logDetails()
+    configuration = _get_testimage_configuration(d, 'runtime', os.getpid(), machine)
+    results.logDetails(_get_testimage_json_result_dir(d),
+                       configuration,
+                       _get_testimage_result_id(configuration))
     results.logSummary(pn)
     if not results.wasSuccessful():
         bb.fatal('%s - FAILED - check the task log and the ssh log' % pn, forcelog=True)
Signature · 1 line
2.7.4
#37 lore raw

PATCH 37/45 testsdk.bbclass: write testresult to json files

In reply to Armin Kuster

From: Yeoh Ee Peng <[email protected]>

As part of the solution to replace Testopia to store testresult, OEQA sdk and sdkext need to output testresult into json files, where these json testresult files will be stored into git repository by the future test-case-management tools.

By default, json testresult file will be written to "oeqa" directory under the "WORKDIR" directory.

To configure multiple instances of bitbake to write json testresult to a single testresult file at custom directory, user will define the variable "OEQA_JSON_RESULT_DIR" with the custom directory for json testresult.

(From OE-Core rev: eefb07907873d20f2e66d3784106f6f72030b5b2)

---
 meta/classes/testsdk.bbclass | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)
meta/classes/testsdk.bbclass +32 -4
index 103cc56..66170e3 100644
@@ -14,6 +14,30 @@
 #
 # where "<image-name>" is an image like core-image-sato.
 
+def _get_sdk_configuration(d, test_type, pid):
+    import platform
+    configuration = {'TEST_TYPE': test_type,
+                    'PROCESS_ID': pid,
+                    'SDK_MACHINE': d.getVar("SDKMACHINE"),
+                    'IMAGE_BASENAME': d.getVar("IMAGE_BASENAME"),
+                    'IMAGE_PKGTYPE': d.getVar("IMAGE_PKGTYPE"),
+                    'HOST_DISTRO': ('-'.join(platform.linux_distribution())).replace(' ', '-')}
+    layers = (d.getVar("BBLAYERS") or "").split()
+    for l in layers:
+        configuration['%s_BRANCH_REV' % os.path.basename(l)] = '%s:%s' % (base_get_metadata_git_branch(l, None).strip(),
+                                                                          base_get_metadata_git_revision(l, None))
+    return configuration
+
+def _get_sdk_json_result_dir(d):
+    json_result_dir = os.path.join(d.getVar("WORKDIR"), 'oeqa')
+    custom_json_result_dir = d.getVar("OEQA_JSON_RESULT_DIR")
+    if custom_json_result_dir:
+        json_result_dir = custom_json_result_dir
+    return json_result_dir
+
+def _get_sdk_result_id(configuration):
+    return '%s_%s_%s' % (configuration['TEST_TYPE'], configuration['IMAGE_BASENAME'], configuration['SDK_MACHINE'])
+
 def testsdk_main(d):
     import os
     import subprocess
@@ -69,8 +93,10 @@ def testsdk_main(d):
 
         component = "%s %s" % (pn, OESDKTestContextExecutor.name)
         context_msg = "%s:%s" % (os.path.basename(tcname), os.path.basename(sdk_env))
-
-        result.logDetails()
+        configuration = _get_sdk_configuration(d, 'sdk', os.getpid())
+        result.logDetails(_get_sdk_json_result_dir(d),
+                          configuration,
+                          _get_sdk_result_id(configuration))
         result.logSummary(component, context_msg)
 
         if not result.wasSuccessful():
@@ -172,8 +198,10 @@ def testsdkext_main(d):
 
         component = "%s %s" % (pn, OESDKExtTestContextExecutor.name)
         context_msg = "%s:%s" % (os.path.basename(tcname), os.path.basename(sdk_env))
-
-        result.logDetails()
+        configuration = _get_sdk_configuration(d, 'sdkext', os.getpid())
+        result.logDetails(_get_sdk_json_result_dir(d),
+                          configuration,
+                          _get_sdk_result_id(configuration))
         result.logSummary(component, context_msg)
 
         if not result.wasSuccessful():
Signature · 1 line
2.7.4
#38 lore raw

PATCH 38/45 oeqa/selftest: Improvements to the json logging

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Tweak the preceeding commit to:

* Add STARTTIME to the identifier to make it unique
* Use LOG_DIR
* Store the layer config in a more natural json format
* Drop '_' function prefixes

(From OE-Core rev: 173f59acf9722e2ef27fdd49c20f7d3d664917eb)

(From OE-Core rev: 3b69099edc7db99c11bfb41eab2af50bd0e3d4f2)

---
 meta/lib/oeqa/selftest/context.py | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)
meta/lib/oeqa/selftest/context.py +11 -14
index 964a46c..a5116a7 100644
@@ -202,30 +202,27 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         self.tc.logger.info("Running bitbake -p")
         runCmd("bitbake -p")
 
-    def _get_json_result_dir(self, args):
-        json_result_dir = os.path.join(os.path.dirname(os.path.abspath(args.output_log)), 'oeqa')
+    def get_json_result_dir(self, args):
+        json_result_dir = os.path.join(os.path.dirname(os.path.abspath(args.output_log)), 'log', 'oeqa')
         if "OEQA_JSON_RESULT_DIR" in self.tc.td:
             json_result_dir = self.tc.td["OEQA_JSON_RESULT_DIR"]
 
         return json_result_dir
 
-    def _get_configuration(self, args):
+    def get_configuration(self, args):
         import platform
         from oeqa.utils.metadata import metadata_from_bb
         metadata = metadata_from_bb()
         configuration = {'TEST_TYPE': 'oeselftest',
-                        'START_TIME': args.test_start_time,
+                        'STARTTIME': args.test_start_time,
                         'MACHINE': self.tc.td["MACHINE"],
                         'HOST_DISTRO': ('-'.join(platform.linux_distribution())).replace(' ', '-'),
-                        'HOST_NAME': metadata['hostname']}
-        layers = metadata['layers']
-        for l in layers:
-            configuration['%s_BRANCH_REV' % os.path.basename(l)] = '%s:%s' % (metadata['layers'][l]['branch'],
-                                                                              metadata['layers'][l]['commit'])
+                        'HOST_NAME': metadata['hostname'],
+                        'LAYERS': metadata['layers']}
         return configuration
 
-    def _get_result_id(self, configuration):
-        return '%s_%s_%s' % (configuration['TEST_TYPE'], configuration['HOST_DISTRO'], configuration['MACHINE'])
+    def get_result_id(self, configuration):
+        return '%s_%s_%s_%s' % (configuration['TEST_TYPE'], configuration['HOST_DISTRO'], configuration['MACHINE'], configuration['STARTTIME'])
 
     def _internal_run(self, logger, args):
         self.module_paths = self._get_cases_paths(
@@ -243,10 +240,10 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         else:
             self._pre_run()
             rc = self.tc.runTests(**self.tc_kwargs['run'])
-            configuration = self._get_configuration(args)
-            rc.logDetails(self._get_json_result_dir(args),
+            configuration = self.get_configuration(args)
+            rc.logDetails(self.get_json_result_dir(args),
                           configuration,
-                          self._get_result_id(configuration))
+                          self.get_result_id(configuration))
             rc.logSummary(self.name)
 
         return rc
Signature · 1 line
2.7.4
#39 lore raw

PATCH 39/45 oeqa/selftest: Standardize json logging output directory

In reply to Armin Kuster

From: Yeoh Ee Peng <[email protected]>

Currently sdk & sdkext will output json file to LOG_DIR, while selftest will output json file to TOPDIR/log.

Standardize selftest json output file to LOG_DIR.

(From OE-Core rev: 9f2e39684cbbe9f87eeef6a81961e6db783439e3)

---
 meta/lib/oeqa/selftest/context.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
meta/lib/oeqa/selftest/context.py +1 -1
index a5116a7..9a56888 100644
@@ -203,7 +203,7 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
         runCmd("bitbake -p")
 
     def get_json_result_dir(self, args):
-        json_result_dir = os.path.join(os.path.dirname(os.path.abspath(args.output_log)), 'log', 'oeqa')
+        json_result_dir = os.path.join(self.tc.td["LOG_DIR"], 'oeqa')
         if "OEQA_JSON_RESULT_DIR" in self.tc.td:
             json_result_dir = self.tc.td["OEQA_JSON_RESULT_DIR"]
 
Signature · 1 line
2.7.4
#40 lore raw

PATCH 40/45 oeqa/utils/metadata: Allow to function without the git module

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

The python git module may or may not be enabled, allow this code to function without it, falling back to the same method as metadata_scm.bbclass uses. This will be cleaned up in the next round of feature development.

(From OE-Core rev: 6350586ba9f4a4107a2d457590824cd4d662d5b9)

(From OE-Core rev: 32c9169b76e13e53b6a9ab4a59932cea7863d992)

---
 meta/lib/oeqa/utils/metadata.py | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)
meta/lib/oeqa/utils/metadata.py +15 -2
index 65bbdc6..b7def77 100644
@@ -58,9 +58,22 @@ def metadata_from_data_store(d):
 
 def git_rev_info(path):
     """Get git revision information as a dict"""
-    from git import Repo, InvalidGitRepositoryError, NoSuchPathError
-
     info = OrderedDict()
+
+    try:
+        from git import Repo, InvalidGitRepositoryError, NoSuchPathError
+    except ImportError:
+        import subprocess
+        try:
+            info['branch'] = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=path).decode('utf-8').strip()
+        except subprocess.CalledProcessError:
+            pass
+        try:
+            info['commit'] = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=path).decode('utf-8').strip()
+        except subprocess.CalledProcessError:
+            pass
+        return info
+
     try:
         repo = Repo(path, search_parent_directories=True)
     except (InvalidGitRepositoryError, NoSuchPathError):
Signature · 1 line
2.7.4
#41 lore raw

PATCH 41/45 image-buildinfo, oeqa/selftest/containerimage: Ensure image-buildinfo doesn't break tests

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Having image-buildinfo enabled causes containerimage.ContainerImageTests.test_expected_files to fail due to the presence of an unexpected file:
['./',
'./etc/',
- './etc/build',
'./etc/default/',
'./etc/default/postinst',

Tweak the class to allow it to be disabled and disable it from the test just in case it was enabled.

(From OE-Core rev: af67bf422a4df5b7e07894512ff73a5f493682ab)

(From OE-Core rev: f49ab8b1610c045acaed7b964d12f07f969df856)

---
 meta/classes/image-buildinfo.bbclass           | 2 ++
 meta/lib/oeqa/selftest/cases/containerimage.py | 1 +
 2 files changed, 3 insertions(+)
meta/classes/image-buildinfo.bbclass +2 -0
index 213fb9c..87a6a1a 100644
@@ -64,6 +64,8 @@ def buildinfo_target(d):
 
 # Write build information to target filesystem
 python buildinfo () {
+    if not d.getVar('IMAGE_BUILDINFO_FILE'):
+        return
     with open(d.expand('${IMAGE_ROOTFS}${IMAGE_BUILDINFO_FILE}'), 'w') as build:
         build.writelines((
             '''-----------------------
meta/lib/oeqa/selftest/cases/containerimage.py +1 -0
index 99a5cc9..8deaae7 100644
@@ -39,6 +39,7 @@ class ContainerImageTests(OESelftestTestCase):
 IMAGE_FSTYPES = "container"
 PACKAGE_CLASSES = "package_ipk"
 IMAGE_FEATURES = ""
+IMAGE_BUILDINFO_FILE = ""
 """)
 
         bbvars = get_bb_vars(['bindir', 'sysconfdir', 'localstatedir',
Signature · 1 line
2.7.4
#42 lore raw

PATCH 42/45 oeqa/selftest/esdk: Ensure parent directory exists

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

INFO - ======================================================================
INFO - ERROR: setUpClass (eSDK.oeSDKExtSelfTest)
INFO - ----------------------------------------------------------------------
INFO - Traceback (most recent call last):
File "/home/pokybuild/yocto-worker/oe-selftest-debian/build/meta/lib/oeqa/core/case.py", line 32, in _oeSetUpClass
clss.setUpClassMethod()
File "/home/pokybuild/yocto-worker/oe-selftest-debian/build/meta/lib/oeqa/selftest/cases/eSDK.py", line 76, in setUpClass
cls.tmpdirobj = tempfile.TemporaryDirectory(prefix="selftest-esdk-", dir=bb_vars["WORKDIR"])
File "/usr/lib/python3.5/tempfile.py", line 929, in __init__
self.name = mkdtemp(suffix, prefix, dir)
File "/usr/lib/python3.5/tempfile.py", line 507, in mkdtemp

    _os.mkdir(file, 0o700)

FileNotFoundError: [Errno 2] No such file or directory: '/home/pokybuild/yocto-worker/oe-selftest-debian/build/build/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0-r0/selftest-esdk-q7ln84gc'

(From OE-Core rev: 170a601a99836d13b69e5287bee0d3e71983dd46)

---
 meta/lib/oeqa/selftest/cases/eSDK.py | 1 +
 1 file changed, 1 insertion(+)
meta/lib/oeqa/selftest/cases/eSDK.py +1 -0
index 14f75d8..1e79d1d 100644
@@ -73,6 +73,7 @@ CORE_IMAGE_EXTRA_INSTALL = "perl"
         cls.image = 'core-image-minimal'
 
         bb_vars = get_bb_vars(['SSTATE_DIR', 'WORKDIR'], cls.image)
+        bb.utils.mkdirhier(bb_vars["WORKDIR"])
         cls.tmpdirobj = tempfile.TemporaryDirectory(prefix="selftest-esdk-", dir=bb_vars["WORKDIR"])
         cls.tmpdir_eSDKQA = cls.tempdirobj.name
 
Signature · 1 line
2.7.4
#43 lore raw

PATCH 43/45 default-versions.inc: Make PREFERRED_VERSION_openssl* overwritable

In reply to Armin Kuster

From: Stefan Lendl <[email protected]>

defaultsetup.conf and therefore default-versions.inc is sourced pretty late in bitbake.conf. default-versions.inc overwrites previous assignments of PREFERRED_VERSION_openssl. Assigning it with ?= allows other .conf files to assign correctly.
in particular assignment in conf/local.conf and machine config is used instead of default.

(From OE-Core rev: c9786adf81434e2d58247f55cf80fdd3131121e7)

---
 meta/conf/distro/include/default-versions.inc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
meta/conf/distro/include/default-versions.inc +3 -3
index 8680738..3d88e8f 100644
@@ -2,6 +2,6 @@
 # Default preferred versions
 #
 
-PREFERRED_VERSION_openssl = "1.0.%"
-PREFERRED_VERSION_openssl-native = "1.0.%"
-PREFERRED_VERSION_nativesdk-openssl = "1.0.%"
+PREFERRED_VERSION_openssl ?= "1.0.%"
+PREFERRED_VERSION_openssl-native ?= "1.0.%"
+PREFERRED_VERSION_nativesdk-openssl ?= "1.0.%"
Signature · 1 line
2.7.4
#44 lore raw

PATCH 44/45 oeqa/selftest/esdk: Fix typo causing test failure

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

2018-12-06 23:19:24,564 - oe-selftest - INFO - Traceback (most recent call last):
  File "/media/build1/poky-sumo/meta/lib/oeqa/core/case.py", line 32, in _oeSetUpClass
    clss.setUpClassMethod()
  File "/media/build1/poky-sumo/meta/lib/oeqa/selftest/cases/eSDK.py", line 78, in setUpClass
    cls.tmpdir_eSDKQA = cls.tempdirobj.name

AttributeError: type object 'oeSDKExtSelfTest' has no attribute 'tempdirobj'

(From OE-Core rev: 2c60908a2039d333a9fe2651622750ff6ed4cce1)

---
 meta/lib/oeqa/selftest/cases/eSDK.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
meta/lib/oeqa/selftest/cases/eSDK.py +1 -1
index 1e79d1d..d7aef93 100644
@@ -75,7 +75,7 @@ CORE_IMAGE_EXTRA_INSTALL = "perl"
         bb_vars = get_bb_vars(['SSTATE_DIR', 'WORKDIR'], cls.image)
         bb.utils.mkdirhier(bb_vars["WORKDIR"])
         cls.tmpdirobj = tempfile.TemporaryDirectory(prefix="selftest-esdk-", dir=bb_vars["WORKDIR"])
-        cls.tmpdir_eSDKQA = cls.tempdirobj.name
+        cls.tmpdir_eSDKQA = cls.tmpdirobj.name
 
         oeSDKExtSelfTest.generate_eSDK(cls.image)
 
Signature · 1 line
2.7.4
#45 lore raw

PATCH 45/45 busybox: Put klogd/syslogd alternative links in syslog package

In reply to Armin Kuster

From: Richard Purdie <[email protected]>

Currently these are in ${PN} and ${PN}-syslog may get replaced by other packages but update-alternatives would error in the postinst if other files were installed first. Avoid the problems by putting the links in the correct package.

(From OE-Core rev: ef11c54ba99af261a70ec31091216cdd1556da24)

---
 meta/recipes-core/busybox/busybox.inc | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
meta/recipes-core/busybox/busybox.inc +4 -1
index f1b09d9..c8919ce 100644
@@ -368,7 +368,10 @@ python do_package_prepend () {
             # Match coreutils
             if alt_name == '[':
                 alt_name = 'lbracket'
-            d.appendVar('ALTERNATIVE_%s' % (pn), ' ' + alt_name)
+            if alt_name == 'klogd' or alt_name == 'syslogd':
+                d.appendVar('ALTERNATIVE_%s-syslog' % (pn), ' ' + alt_name)
+            else:
+                d.appendVar('ALTERNATIVE_%s' % (pn), ' ' + alt_name)
             d.setVarFlag('ALTERNATIVE_LINK_NAME', alt_name, alt_link_name)
             if os.path.exists('%s%s' % (dvar, target)):
                 d.setVarFlag('ALTERNATIVE_TARGET', alt_name, target)
Signature · 1 line
2.7.4
#46 lore raw

✗ patchtest: failure for Sumo-next patches for review

In reply to Armin Kuster

== Series Details ==

Series: Sumo-next patches for review
Revision: 1
URL : https://patchwork.openembedded.org/series/15331/
State : failure

== Summary ==

Thank you for submitting this patch series to OpenEmbedded Core. This is an automated response. Several tests have been executed on the proposed series by patchtest resulting in the following failures:

* Issue Series does not apply on top of target branch [test_series_merge_on_head]
Suggested fix Rebase your series on top of targeted branch
Targeted branch master (currently at 6d666b0413)

If you believe any of these test results are incorrect, please reply to the mailing list ([email protected]) raising your concerns. Otherwise we would appreciate you correcting the issues and submitting a new version of the patchset if applicable. Please ensure you add/increment the version number when sending the new version (i.e. [PATCH] -> [PATCH v2] -> [PATCH v3] -> ...).

---

Guidelines:     https://www.openembedded.org/wiki/Commit_Patch_Message_Guidelines
Test framework: http://git.yoctoproject.org/cgit/cgit.cgi/patchtest
Test suite:     http://git.yoctoproject.org/cgit/cgit.cgi/patchtest-oe