diff options
| -rw-r--r-- | meta/classes/testimage.bbclass | 107 | ||||
| -rw-r--r-- | meta/lib/oeqa/oetest.py | 17 |
2 files changed, 98 insertions, 26 deletions
diff --git a/meta/classes/testimage.bbclass b/meta/classes/testimage.bbclass index 4777e140dc..75ab716270 100644 --- a/meta/classes/testimage.bbclass +++ b/meta/classes/testimage.bbclass | |||
| @@ -25,15 +25,16 @@ | |||
| 25 | 25 | ||
| 26 | TEST_LOG_DIR ?= "${WORKDIR}/testimage" | 26 | TEST_LOG_DIR ?= "${WORKDIR}/testimage" |
| 27 | 27 | ||
| 28 | TEST_EXPORT_DIR ?= "${TMPDIR}/testimage/${PN}" | ||
| 29 | TEST_EXPORT_ONLY ?= "0" | ||
| 30 | |||
| 28 | DEFAULT_TEST_SUITES = "ping auto" | 31 | DEFAULT_TEST_SUITES = "ping auto" |
| 29 | DEFAULT_TEST_SUITES_pn-core-image-minimal = "ping" | 32 | DEFAULT_TEST_SUITES_pn-core-image-minimal = "ping" |
| 30 | DEFAULT_TEST_SUITES_pn-core-image-sato = "ping ssh df connman syslog xorg scp vnc date rpm smart dmesg python" | 33 | DEFAULT_TEST_SUITES_pn-core-image-sato = "ping ssh df connman syslog xorg scp vnc date rpm smart dmesg python" |
| 31 | DEFAULT_TEST_SUITES_pn-core-image-sato-sdk = "ping ssh df connman syslog xorg scp vnc date perl ldd gcc rpm smart kernelmodule dmesg python" | 34 | DEFAULT_TEST_SUITES_pn-core-image-sato-sdk = "ping ssh df connman syslog xorg scp vnc date perl ldd gcc rpm smart kernelmodule dmesg python" |
| 32 | |||
| 33 | TEST_SUITES ?= "${DEFAULT_TEST_SUITES}" | 35 | TEST_SUITES ?= "${DEFAULT_TEST_SUITES}" |
| 34 | 36 | ||
| 35 | TEST_QEMUBOOT_TIMEOUT ?= "1000" | 37 | TEST_QEMUBOOT_TIMEOUT ?= "1000" |
| 36 | |||
| 37 | TEST_TARGET ?= "qemu" | 38 | TEST_TARGET ?= "qemu" |
| 38 | TEST_TARGET_IP ?= "" | 39 | TEST_TARGET_IP ?= "" |
| 39 | TEST_SERVER_IP ?= "" | 40 | TEST_SERVER_IP ?= "" |
| @@ -85,6 +86,71 @@ def get_tests_list(d): | |||
| 85 | 86 | ||
| 86 | return testslist | 87 | return testslist |
| 87 | 88 | ||
| 89 | |||
| 90 | def exportTests(d,tc): | ||
| 91 | import json | ||
| 92 | import shutil | ||
| 93 | import pkgutil | ||
| 94 | |||
| 95 | exportpath = d.getVar("TEST_EXPORT_DIR", True) | ||
| 96 | |||
| 97 | savedata = {} | ||
| 98 | savedata["d"] = {} | ||
| 99 | savedata["target"] = {} | ||
| 100 | for key in tc.__dict__: | ||
| 101 | # special cases | ||
| 102 | if key != "d" and key != "target": | ||
| 103 | savedata[key] = getattr(tc, key) | ||
| 104 | savedata["target"]["ip"] = tc.target.ip or d.getVar("TEST_TARGET_IP", True) | ||
| 105 | savedata["target"]["server_ip"] = tc.target.server_ip or d.getVar("TEST_SERVER_IP", True) | ||
| 106 | |||
| 107 | keys = [ key for key in d.keys() if not key.startswith("_") and not key.startswith("BB") \ | ||
| 108 | and not key.startswith("B_pn") and not key.startswith("do_") and not d.getVarFlag(key, "func")] | ||
| 109 | for key in keys: | ||
| 110 | try: | ||
| 111 | savedata["d"][key] = d.getVar(key, True) | ||
| 112 | except bb.data_smart.ExpansionError: | ||
| 113 | # we don't care about those anyway | ||
| 114 | pass | ||
| 115 | |||
| 116 | with open(os.path.join(exportpath, "testdata.json"), "w") as f: | ||
| 117 | json.dump(savedata, f, skipkeys=True, indent=4, sort_keys=True) | ||
| 118 | |||
| 119 | # now start copying files | ||
| 120 | # we'll basically copy everything under meta/lib/oeqa, with these exceptions | ||
| 121 | # - oeqa/targetcontrol.py - not needed | ||
| 122 | # - oeqa/selftest - something else | ||
| 123 | # That means: | ||
| 124 | # - all tests from oeqa/runtime defined in TEST_SUITES (including from other layers) | ||
| 125 | # - the contents of oeqa/utils and oeqa/runtime/files | ||
| 126 | # - oeqa/oetest.py and oeqa/runexport.py (this will get copied to exportpath not exportpath/oeqa) | ||
| 127 | # - __init__.py files | ||
| 128 | bb.utils.mkdirhier(os.path.join(exportpath, "oeqa/runtime/files")) | ||
| 129 | bb.utils.mkdirhier(os.path.join(exportpath, "oeqa/utils")) | ||
| 130 | # copy test modules, this should cover tests in other layers too | ||
| 131 | for t in tc.testslist: | ||
| 132 | mod = pkgutil.get_loader(t) | ||
| 133 | shutil.copy2(mod.filename, os.path.join(exportpath, "oeqa/runtime")) | ||
| 134 | # copy __init__.py files | ||
| 135 | oeqadir = pkgutil.get_loader("oeqa").filename | ||
| 136 | shutil.copy2(os.path.join(oeqadir, "__init__.py"), os.path.join(exportpath, "oeqa")) | ||
| 137 | shutil.copy2(os.path.join(oeqadir, "runtime/__init__.py"), os.path.join(exportpath, "oeqa/runtime")) | ||
| 138 | # copy oeqa/oetest.py and oeqa/runexported.py | ||
| 139 | shutil.copy2(os.path.join(oeqadir, "oetest.py"), os.path.join(exportpath, "oeqa")) | ||
| 140 | shutil.copy2(os.path.join(oeqadir, "runexported.py"), exportpath) | ||
| 141 | # copy oeqa/utils/*.py | ||
| 142 | for root, dirs, files in os.walk(os.path.join(oeqadir, "utils")): | ||
| 143 | for f in files: | ||
| 144 | if f.endswith(".py"): | ||
| 145 | shutil.copy2(os.path.join(root, f), os.path.join(exportpath, "oeqa/utils")) | ||
| 146 | # copy oeqa/runtime/files/* | ||
| 147 | for root, dirs, files in os.walk(os.path.join(oeqadir, "runtime/files")): | ||
| 148 | for f in files: | ||
| 149 | shutil.copy2(os.path.join(root, f), os.path.join(exportpath, "oeqa/runtime/files")) | ||
| 150 | |||
| 151 | bb.plain("Exported tests to: %s" % exportpath) | ||
| 152 | |||
| 153 | |||
| 88 | def testimage_main(d): | 154 | def testimage_main(d): |
| 89 | import unittest | 155 | import unittest |
| 90 | import os | 156 | import os |
| @@ -94,7 +160,11 @@ def testimage_main(d): | |||
| 94 | from oeqa.targetcontrol import get_target_controller | 160 | from oeqa.targetcontrol import get_target_controller |
| 95 | 161 | ||
| 96 | pn = d.getVar("PN", True) | 162 | pn = d.getVar("PN", True) |
| 163 | export = oe.utils.conditional("TEST_EXPORT_ONLY", "1", True, False, d) | ||
| 97 | bb.utils.mkdirhier(d.getVar("TEST_LOG_DIR", True)) | 164 | bb.utils.mkdirhier(d.getVar("TEST_LOG_DIR", True)) |
| 165 | if export: | ||
| 166 | bb.utils.remove(d.getVar("TEST_EXPORT_DIR", True), recurse=True) | ||
| 167 | bb.utils.mkdirhier(d.getVar("TEST_EXPORT_DIR", True)) | ||
| 98 | 168 | ||
| 99 | # tests in TEST_SUITES become required tests | 169 | # tests in TEST_SUITES become required tests |
| 100 | # they won't be skipped even if they aren't suitable for a image (like xorg for minimal) | 170 | # they won't be skipped even if they aren't suitable for a image (like xorg for minimal) |
| @@ -105,13 +175,18 @@ def testimage_main(d): | |||
| 105 | # the robot dance | 175 | # the robot dance |
| 106 | target = get_target_controller(d) | 176 | target = get_target_controller(d) |
| 107 | 177 | ||
| 108 | class TestContext: | 178 | class TestContext(object): |
| 109 | def __init__(self): | 179 | def __init__(self): |
| 110 | self.d = d | 180 | self.d = d |
| 111 | self.testslist = testslist | 181 | self.testslist = testslist |
| 112 | self.testsrequired = testsrequired | 182 | self.testsrequired = testsrequired |
| 113 | self.filesdir = os.path.join(os.path.dirname(os.path.abspath(oeqa.runtime.__file__)),"files") | 183 | self.filesdir = os.path.join(os.path.dirname(os.path.abspath(oeqa.runtime.__file__)),"files") |
| 114 | self.target = target | 184 | self.target = target |
| 185 | self.imagefeatures = d.getVar("IMAGE_FEATURES", True).split() | ||
| 186 | self.distrofeatures = d.getVar("DISTRO_FEATURES", True).split() | ||
| 187 | manifest = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("IMAGE_LINK_NAME", True) + ".manifest") | ||
| 188 | with open(manifest) as f: | ||
| 189 | self.pkgmanifest = f.read() | ||
| 115 | 190 | ||
| 116 | # test context | 191 | # test context |
| 117 | tc = TestContext() | 192 | tc = TestContext() |
| @@ -129,19 +204,21 @@ def testimage_main(d): | |||
| 129 | 204 | ||
| 130 | try: | 205 | try: |
| 131 | target.start() | 206 | target.start() |
| 132 | # run tests and get the results | 207 | if export: |
| 133 | starttime = time.time() | 208 | exportTests(d,tc) |
| 134 | result = runTests(tc) | ||
| 135 | stoptime = time.time() | ||
| 136 | if result.wasSuccessful(): | ||
| 137 | bb.plain("%s - Ran %d test%s in %.3fs" % (pn, result.testsRun, result.testsRun != 1 and "s" or "", stoptime - starttime)) | ||
| 138 | msg = "%s - OK - All required tests passed" % pn | ||
| 139 | skipped = len(result.skipped) | ||
| 140 | if skipped: | ||
| 141 | msg += " (skipped=%d)" % skipped | ||
| 142 | bb.plain(msg) | ||
| 143 | else: | 209 | else: |
| 144 | raise bb.build.FuncFailed("%s - FAILED - check the task log and the ssh log" % pn ) | 210 | starttime = time.time() |
| 211 | result = runTests(tc) | ||
| 212 | stoptime = time.time() | ||
| 213 | if result.wasSuccessful(): | ||
| 214 | bb.plain("%s - Ran %d test%s in %.3fs" % (pn, result.testsRun, result.testsRun != 1 and "s" or "", stoptime - starttime)) | ||
| 215 | msg = "%s - OK - All required tests passed" % pn | ||
| 216 | skipped = len(result.skipped) | ||
| 217 | if skipped: | ||
| 218 | msg += " (skipped=%d)" % skipped | ||
| 219 | bb.plain(msg) | ||
| 220 | else: | ||
| 221 | raise bb.build.FuncFailed("%s - FAILED - check the task log and the ssh log" % pn ) | ||
| 145 | finally: | 222 | finally: |
| 146 | target.stop() | 223 | target.stop() |
| 147 | 224 | ||
diff --git a/meta/lib/oeqa/oetest.py b/meta/lib/oeqa/oetest.py index 23a3e5d69f..0db6cb80a9 100644 --- a/meta/lib/oeqa/oetest.py +++ b/meta/lib/oeqa/oetest.py | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | import os, re, mmap | 10 | import os, re, mmap |
| 11 | import unittest | 11 | import unittest |
| 12 | import inspect | 12 | import inspect |
| 13 | import bb | ||
| 14 | from oeqa.utils.sshcontrol import SSHControl | ||
| 15 | 13 | ||
| 16 | 14 | ||
| 17 | def loadTests(tc): | 15 | def loadTests(tc): |
| @@ -31,15 +29,14 @@ def loadTests(tc): | |||
| 31 | def runTests(tc): | 29 | def runTests(tc): |
| 32 | 30 | ||
| 33 | suite = loadTests(tc) | 31 | suite = loadTests(tc) |
| 34 | bb.note("Test modules %s" % tc.testslist) | 32 | print("Test modules %s" % tc.testslist) |
| 35 | bb.note("Found %s tests" % suite.countTestCases()) | 33 | print("Found %s tests" % suite.countTestCases()) |
| 36 | runner = unittest.TextTestRunner(verbosity=2) | 34 | runner = unittest.TextTestRunner(verbosity=2) |
| 37 | result = runner.run(suite) | 35 | result = runner.run(suite) |
| 38 | 36 | ||
| 39 | return result | 37 | return result |
| 40 | 38 | ||
| 41 | 39 | ||
| 42 | |||
| 43 | class oeTest(unittest.TestCase): | 40 | class oeTest(unittest.TestCase): |
| 44 | 41 | ||
| 45 | longMessage = True | 42 | longMessage = True |
| @@ -60,18 +57,16 @@ class oeTest(unittest.TestCase): | |||
| 60 | 57 | ||
| 61 | @classmethod | 58 | @classmethod |
| 62 | def hasPackage(self, pkg): | 59 | def hasPackage(self, pkg): |
| 63 | manifest = os.path.join(oeTest.tc.d.getVar("DEPLOY_DIR_IMAGE", True), oeTest.tc.d.getVar("IMAGE_LINK_NAME", True) + ".manifest") | 60 | |
| 64 | with open(manifest) as f: | 61 | if re.search(pkg, oeTest.tc.pkgmanifest): |
| 65 | data = f.read() | ||
| 66 | if re.search(pkg, data): | ||
| 67 | return True | 62 | return True |
| 68 | return False | 63 | return False |
| 69 | 64 | ||
| 70 | @classmethod | 65 | @classmethod |
| 71 | def hasFeature(self,feature): | 66 | def hasFeature(self,feature): |
| 72 | 67 | ||
| 73 | if feature in oeTest.tc.d.getVar("IMAGE_FEATURES", True).split() or \ | 68 | if feature in oeTest.tc.imagefeatures or \ |
| 74 | feature in oeTest.tc.d.getVar("DISTRO_FEATURES", True).split(): | 69 | feature in oeTest.tc.distrofeatures: |
| 75 | return True | 70 | return True |
| 76 | else: | 71 | else: |
| 77 | return False | 72 | return False |
