summaryrefslogtreecommitdiffstats
path: root/meta/lib
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib')
-rw-r--r--meta/lib/oe/copy_buildsystem.py6
-rw-r--r--meta/lib/oe/cve_check.py65
-rw-r--r--meta/lib/oe/package_manager/__init__.py2
-rw-r--r--meta/lib/oe/package_manager/deb/__init__.py6
-rw-r--r--meta/lib/oe/package_manager/deb/sdk.py4
-rw-r--r--meta/lib/oe/patch.py14
-rw-r--r--meta/lib/oe/path.py21
-rw-r--r--meta/lib/oe/prservice.py4
-rw-r--r--meta/lib/oe/recipeutils.py2
-rw-r--r--meta/lib/oe/reproducible.py2
-rw-r--r--meta/lib/oe/sstatesig.py8
-rw-r--r--meta/lib/oe/terminal.py16
-rw-r--r--meta/lib/oe/utils.py2
-rw-r--r--meta/lib/oeqa/manual/oe-core.json2
-rw-r--r--meta/lib/oeqa/runtime/cases/df.py2
-rw-r--r--meta/lib/oeqa/runtime/cases/pam.py3
-rw-r--r--meta/lib/oeqa/selftest/cases/buildoptions.py6
-rw-r--r--meta/lib/oeqa/selftest/cases/cve_check.py44
-rw-r--r--meta/lib/oeqa/selftest/cases/devtool.py4
-rw-r--r--meta/lib/oeqa/selftest/cases/pseudo.py27
-rw-r--r--meta/lib/oeqa/selftest/cases/reproducible.py7
-rw-r--r--meta/lib/oeqa/selftest/cases/tinfoil.py6
-rw-r--r--meta/lib/oeqa/selftest/cases/wic.py36
-rw-r--r--meta/lib/oeqa/selftest/context.py17
-rw-r--r--meta/lib/oeqa/utils/commands.py7
25 files changed, 268 insertions, 45 deletions
diff --git a/meta/lib/oe/copy_buildsystem.py b/meta/lib/oe/copy_buildsystem.py
index 31a84f5b06..d97bf9d1b9 100644
--- a/meta/lib/oe/copy_buildsystem.py
+++ b/meta/lib/oe/copy_buildsystem.py
@@ -20,7 +20,7 @@ def _smart_copy(src, dest):
20 mode = os.stat(src).st_mode 20 mode = os.stat(src).st_mode
21 if stat.S_ISDIR(mode): 21 if stat.S_ISDIR(mode):
22 bb.utils.mkdirhier(dest) 22 bb.utils.mkdirhier(dest)
23 cmd = "tar --exclude='.git' --xattrs --xattrs-include='*' -chf - -C %s -p . \ 23 cmd = "tar --exclude='.git' --exclude='__pycache__' --xattrs --xattrs-include='*' -chf - -C %s -p . \
24 | tar --xattrs --xattrs-include='*' -xf - -C %s" % (src, dest) 24 | tar --xattrs --xattrs-include='*' -xf - -C %s" % (src, dest)
25 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) 25 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
26 else: 26 else:
@@ -259,7 +259,7 @@ def create_locked_sstate_cache(lockedsigs, input_sstate_cache, output_sstate_cac
259 bb.note('Generating sstate-cache...') 259 bb.note('Generating sstate-cache...')
260 260
261 nativelsbstring = d.getVar('NATIVELSBSTRING') 261 nativelsbstring = d.getVar('NATIVELSBSTRING')
262 bb.process.run("gen-lockedsig-cache %s %s %s %s %s" % (lockedsigs, input_sstate_cache, output_sstate_cache, nativelsbstring, filterfile or '')) 262 bb.process.run("PYTHONDONTWRITEBYTECODE=1 gen-lockedsig-cache %s %s %s %s %s" % (lockedsigs, input_sstate_cache, output_sstate_cache, nativelsbstring, filterfile or ''))
263 if fixedlsbstring and nativelsbstring != fixedlsbstring: 263 if fixedlsbstring and nativelsbstring != fixedlsbstring:
264 nativedir = output_sstate_cache + '/' + nativelsbstring 264 nativedir = output_sstate_cache + '/' + nativelsbstring
265 if os.path.isdir(nativedir): 265 if os.path.isdir(nativedir):
@@ -286,7 +286,7 @@ def check_sstate_task_list(d, targets, filteroutfile, cmdprefix='', cwd=None, lo
286 logparam = '-l %s' % logfile 286 logparam = '-l %s' % logfile
287 else: 287 else:
288 logparam = '' 288 logparam = ''
289 cmd = "%sBB_SETSCENE_ENFORCE=1 PSEUDO_DISABLED=1 oe-check-sstate %s -s -o %s %s" % (cmdprefix, targets, filteroutfile, logparam) 289 cmd = "%sPYTHONDONTWRITEBYTECODE=1 BB_SETSCENE_ENFORCE=1 PSEUDO_DISABLED=1 oe-check-sstate %s -s -o %s %s" % (cmdprefix, targets, filteroutfile, logparam)
290 env = dict(d.getVar('BB_ORIGENV', False)) 290 env = dict(d.getVar('BB_ORIGENV', False))
291 env.pop('BUILDDIR', '') 291 env.pop('BUILDDIR', '')
292 env.pop('BBPATH', '') 292 env.pop('BBPATH', '')
diff --git a/meta/lib/oe/cve_check.py b/meta/lib/oe/cve_check.py
new file mode 100644
index 0000000000..a1d7c292af
--- /dev/null
+++ b/meta/lib/oe/cve_check.py
@@ -0,0 +1,65 @@
1import collections
2import re
3import itertools
4import functools
5
6_Version = collections.namedtuple(
7 "_Version", ["release", "patch_l", "pre_l", "pre_v"]
8)
9
10@functools.total_ordering
11class Version():
12
13 def __init__(self, version, suffix=None):
14
15 suffixes = ["alphabetical", "patch"]
16
17 if str(suffix) == "alphabetical":
18 version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<patch>[-_\.]?(?P<patch_l>[a-z]))?(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?"""
19 elif str(suffix) == "patch":
20 version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<patch>[-_\.]?(p|patch)(?P<patch_l>[0-9]+))?(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?"""
21 else:
22 version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?"""
23 regex = re.compile(r"^\s*" + version_pattern + r"\s*$", re.VERBOSE | re.IGNORECASE)
24
25 match = regex.search(version)
26 if not match:
27 raise Exception("Invalid version: '{0}'".format(version))
28
29 self._version = _Version(
30 release=tuple(int(i) for i in match.group("release").replace("-",".").split(".")),
31 patch_l=match.group("patch_l") if str(suffix) in suffixes and match.group("patch_l") else "",
32 pre_l=match.group("pre_l"),
33 pre_v=match.group("pre_v")
34 )
35
36 self._key = _cmpkey(
37 self._version.release,
38 self._version.patch_l,
39 self._version.pre_l,
40 self._version.pre_v
41 )
42
43 def __eq__(self, other):
44 if not isinstance(other, Version):
45 return NotImplemented
46 return self._key == other._key
47
48 def __gt__(self, other):
49 if not isinstance(other, Version):
50 return NotImplemented
51 return self._key > other._key
52
53def _cmpkey(release, patch_l, pre_l, pre_v):
54 # remove leading 0
55 _release = tuple(
56 reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
57 )
58
59 _patch = patch_l.upper()
60
61 if pre_l is None and pre_v is None:
62 _pre = float('inf')
63 else:
64 _pre = float(pre_v) if pre_v else float('-inf')
65 return _release, _patch, _pre
diff --git a/meta/lib/oe/package_manager/__init__.py b/meta/lib/oe/package_manager/__init__.py
index 42225a3b2e..26f9f82aaa 100644
--- a/meta/lib/oe/package_manager/__init__.py
+++ b/meta/lib/oe/package_manager/__init__.py
@@ -189,7 +189,7 @@ class PackageManager(object, metaclass=ABCMeta):
189 bb.utils.remove(self.intercepts_dir, True) 189 bb.utils.remove(self.intercepts_dir, True)
190 bb.utils.mkdirhier(self.intercepts_dir) 190 bb.utils.mkdirhier(self.intercepts_dir)
191 for intercept in postinst_intercepts: 191 for intercept in postinst_intercepts:
192 bb.utils.copyfile(intercept, os.path.join(self.intercepts_dir, os.path.basename(intercept))) 192 shutil.copy(intercept, os.path.join(self.intercepts_dir, os.path.basename(intercept)))
193 193
194 @abstractmethod 194 @abstractmethod
195 def _handle_intercept_failure(self, failed_script): 195 def _handle_intercept_failure(self, failed_script):
diff --git a/meta/lib/oe/package_manager/deb/__init__.py b/meta/lib/oe/package_manager/deb/__init__.py
index 26157f591a..0f9b27f831 100644
--- a/meta/lib/oe/package_manager/deb/__init__.py
+++ b/meta/lib/oe/package_manager/deb/__init__.py
@@ -312,6 +312,12 @@ class DpkgPM(OpkgDpkgPM):
312 if not pkgs: 312 if not pkgs:
313 return 313 return
314 314
315 os.environ['D'] = self.target_rootfs
316 os.environ['OFFLINE_ROOT'] = self.target_rootfs
317 os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs
318 os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs
319 os.environ['INTERCEPT_DIR'] = self.intercepts_dir
320
315 if with_dependencies: 321 if with_dependencies:
316 os.environ['APT_CONFIG'] = self.apt_conf_file 322 os.environ['APT_CONFIG'] = self.apt_conf_file
317 cmd = "%s purge %s" % (self.apt_get_cmd, ' '.join(pkgs)) 323 cmd = "%s purge %s" % (self.apt_get_cmd, ' '.join(pkgs))
diff --git a/meta/lib/oe/package_manager/deb/sdk.py b/meta/lib/oe/package_manager/deb/sdk.py
index b25eb70b00..76548b06f0 100644
--- a/meta/lib/oe/package_manager/deb/sdk.py
+++ b/meta/lib/oe/package_manager/deb/sdk.py
@@ -65,6 +65,8 @@ class DpkgSdk(Sdk):
65 65
66 self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY')) 66 self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
67 67
68 self.target_pm.run_pre_post_installs()
69
68 self.target_pm.run_intercepts(populate_sdk='target') 70 self.target_pm.run_intercepts(populate_sdk='target')
69 71
70 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND")) 72 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
@@ -78,6 +80,8 @@ class DpkgSdk(Sdk):
78 self._populate_sysroot(self.host_pm, self.host_manifest) 80 self._populate_sysroot(self.host_pm, self.host_manifest)
79 self.install_locales(self.host_pm) 81 self.install_locales(self.host_pm)
80 82
83 self.host_pm.run_pre_post_installs()
84
81 self.host_pm.run_intercepts(populate_sdk='host') 85 self.host_pm.run_intercepts(populate_sdk='host')
82 86
83 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND")) 87 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
diff --git a/meta/lib/oe/patch.py b/meta/lib/oe/patch.py
index 40755fbb03..8ad70f53f1 100644
--- a/meta/lib/oe/patch.py
+++ b/meta/lib/oe/patch.py
@@ -38,15 +38,19 @@ def runcmd(args, dir = None):
38 args = [ pipes.quote(str(arg)) for arg in args ] 38 args = [ pipes.quote(str(arg)) for arg in args ]
39 cmd = " ".join(args) 39 cmd = " ".join(args)
40 # print("cmd: %s" % cmd) 40 # print("cmd: %s" % cmd)
41 (exitstatus, output) = subprocess.getstatusoutput(cmd) 41 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
42 stdout, stderr = proc.communicate()
43 stdout = stdout.decode('utf-8')
44 stderr = stderr.decode('utf-8')
45 exitstatus = proc.returncode
42 if exitstatus != 0: 46 if exitstatus != 0:
43 raise CmdError(cmd, exitstatus >> 8, output) 47 raise CmdError(cmd, exitstatus >> 8, "stdout: %s\nstderr: %s" % (stdout, stderr))
44 if " fuzz " in output and "Hunk " in output: 48 if " fuzz " in stdout and "Hunk " in stdout:
45 # Drop patch fuzz info with header and footer to log file so 49 # Drop patch fuzz info with header and footer to log file so
46 # insane.bbclass can handle to throw error/warning 50 # insane.bbclass can handle to throw error/warning
47 bb.note("--- Patch fuzz start ---\n%s\n--- Patch fuzz end ---" % format(output)) 51 bb.note("--- Patch fuzz start ---\n%s\n--- Patch fuzz end ---" % format(stdout))
48 52
49 return output 53 return stdout
50 54
51 finally: 55 finally:
52 if dir: 56 if dir:
diff --git a/meta/lib/oe/path.py b/meta/lib/oe/path.py
index 082972457b..c8d8ad05b9 100644
--- a/meta/lib/oe/path.py
+++ b/meta/lib/oe/path.py
@@ -320,3 +320,24 @@ def which_wild(pathname, path=None, mode=os.F_OK, *, reverse=False, candidates=F
320 320
321 return files 321 return files
322 322
323def canonicalize(paths, sep=','):
324 """Given a string with paths (separated by commas by default), expand
325 each path using os.path.realpath() and return the resulting paths as a
326 string (separated using the same separator a the original string).
327 """
328 # Ignore paths containing "$" as they are assumed to be unexpanded bitbake
329 # variables. Normally they would be ignored, e.g., when passing the paths
330 # through the shell they would expand to empty strings. However, when they
331 # are passed through os.path.realpath(), it will cause them to be prefixed
332 # with the absolute path to the current directory and thus not be empty
333 # anymore.
334 #
335 # Also maintain trailing slashes, as the paths may actually be used as
336 # prefixes in sting compares later on, where the slashes then are important.
337 canonical_paths = []
338 for path in (paths or '').split(sep):
339 if '$' not in path:
340 trailing_slash = path.endswith('/') and '/' or ''
341 canonical_paths.append(os.path.realpath(path) + trailing_slash)
342
343 return sep.join(canonical_paths)
diff --git a/meta/lib/oe/prservice.py b/meta/lib/oe/prservice.py
index 2d3c9c7e50..fcdbe66c19 100644
--- a/meta/lib/oe/prservice.py
+++ b/meta/lib/oe/prservice.py
@@ -3,10 +3,6 @@
3# 3#
4 4
5def prserv_make_conn(d, check = False): 5def prserv_make_conn(d, check = False):
6 # Otherwise this fails when called from recipes which e.g. inherit python3native (which sets _PYTHON_SYSCONFIGDATA_NAME) with:
7 # No module named '_sysconfigdata'
8 if '_PYTHON_SYSCONFIGDATA_NAME' in os.environ:
9 del os.environ['_PYTHON_SYSCONFIGDATA_NAME']
10 import prserv.serv 6 import prserv.serv
11 host_params = list([_f for _f in (d.getVar("PRSERV_HOST") or '').split(':') if _f]) 7 host_params = list([_f for _f in (d.getVar("PRSERV_HOST") or '').split(':') if _f])
12 try: 8 try:
diff --git a/meta/lib/oe/recipeutils.py b/meta/lib/oe/recipeutils.py
index ef69ef207f..407d168894 100644
--- a/meta/lib/oe/recipeutils.py
+++ b/meta/lib/oe/recipeutils.py
@@ -409,7 +409,7 @@ def copy_recipe_files(d, tgt_dir, whole_dir=False, download=True, all_variants=F
409 fetch.download() 409 fetch.download()
410 for pth in fetch.localpaths(): 410 for pth in fetch.localpaths():
411 if pth not in localpaths: 411 if pth not in localpaths:
412 localpaths.append(pth) 412 localpaths.append(os.path.abspath(pth))
413 uri_values.append(srcuri) 413 uri_values.append(srcuri)
414 414
415 fetch_urls(d) 415 fetch_urls(d)
diff --git a/meta/lib/oe/reproducible.py b/meta/lib/oe/reproducible.py
index 421bb12f54..0fb02ccdb0 100644
--- a/meta/lib/oe/reproducible.py
+++ b/meta/lib/oe/reproducible.py
@@ -47,7 +47,7 @@ def find_git_folder(d, sourcedir):
47 return None 47 return None
48 48
49def get_source_date_epoch_from_git(d, sourcedir): 49def get_source_date_epoch_from_git(d, sourcedir):
50 if not "git://" in d.getVar('SRC_URI'): 50 if not "git://" in d.getVar('SRC_URI') and not "gitsm://" in d.getVar('SRC_URI'):
51 return None 51 return None
52 52
53 gitpath = find_git_folder(d, sourcedir) 53 gitpath = find_git_folder(d, sourcedir)
diff --git a/meta/lib/oe/sstatesig.py b/meta/lib/oe/sstatesig.py
index 64fb84ec92..31a6140984 100644
--- a/meta/lib/oe/sstatesig.py
+++ b/meta/lib/oe/sstatesig.py
@@ -439,7 +439,7 @@ def find_sstate_manifest(taskdata, taskdata2, taskname, d, multilibcache):
439 d2 = multilibcache[variant] 439 d2 = multilibcache[variant]
440 440
441 if taskdata.endswith("-native"): 441 if taskdata.endswith("-native"):
442 pkgarchs = ["${BUILD_ARCH}"] 442 pkgarchs = ["${BUILD_ARCH}", "${BUILD_ARCH}_${ORIGNATIVELSBSTRING}"]
443 elif taskdata.startswith("nativesdk-"): 443 elif taskdata.startswith("nativesdk-"):
444 pkgarchs = ["${SDK_ARCH}_${SDK_OS}", "allarch"] 444 pkgarchs = ["${SDK_ARCH}_${SDK_OS}", "allarch"]
445 elif "-cross-canadian" in taskdata: 445 elif "-cross-canadian" in taskdata:
@@ -557,9 +557,11 @@ def OEOuthashBasic(path, sigfile, task, d):
557 try: 557 try:
558 update_hash(" %10s" % pwd.getpwuid(s.st_uid).pw_name) 558 update_hash(" %10s" % pwd.getpwuid(s.st_uid).pw_name)
559 update_hash(" %10s" % grp.getgrgid(s.st_gid).gr_name) 559 update_hash(" %10s" % grp.getgrgid(s.st_gid).gr_name)
560 except KeyError: 560 except KeyError as e:
561 bb.warn("KeyError in %s" % path) 561 bb.warn("KeyError in %s" % path)
562 raise 562 msg = ("KeyError: %s\nPath %s is owned by uid %d, gid %d, which doesn't match "
563 "any user/group on target. This may be due to host contamination." % (e, path, s.st_uid, s.st_gid))
564 raise Exception(msg).with_traceback(e.__traceback__)
563 565
564 if include_timestamps: 566 if include_timestamps:
565 update_hash(" %10d" % s.st_mtime) 567 update_hash(" %10d" % s.st_mtime)
diff --git a/meta/lib/oe/terminal.py b/meta/lib/oe/terminal.py
index eb10a6e33e..2ac39df9e1 100644
--- a/meta/lib/oe/terminal.py
+++ b/meta/lib/oe/terminal.py
@@ -163,7 +163,12 @@ class Tmux(Terminal):
163 # devshells, if it's already there, add a new window to it. 163 # devshells, if it's already there, add a new window to it.
164 window_name = 'devshell-%i' % os.getpid() 164 window_name = 'devshell-%i' % os.getpid()
165 165
166 self.command = 'tmux new -c "{{cwd}}" -d -s {0} -n {0} "{{command}}"'.format(window_name) 166 self.command = 'tmux new -c "{{cwd}}" -d -s {0} -n {0} "{{command}}"'
167 if not check_tmux_version('1.9'):
168 # `tmux new-session -c` was added in 1.9;
169 # older versions fail with that flag
170 self.command = 'tmux new -d -s {0} -n {0} "{{command}}"'
171 self.command = self.command.format(window_name)
167 Terminal.__init__(self, sh_cmd, title, env, d) 172 Terminal.__init__(self, sh_cmd, title, env, d)
168 173
169 attach_cmd = 'tmux att -t {0}'.format(window_name) 174 attach_cmd = 'tmux att -t {0}'.format(window_name)
@@ -253,13 +258,18 @@ def spawn(name, sh_cmd, title=None, env=None, d=None):
253 except OSError: 258 except OSError:
254 return 259 return
255 260
261def check_tmux_version(desired):
262 vernum = check_terminal_version("tmux")
263 if vernum and LooseVersion(vernum) < desired:
264 return False
265 return vernum
266
256def check_tmux_pane_size(tmux): 267def check_tmux_pane_size(tmux):
257 import subprocess as sub 268 import subprocess as sub
258 # On older tmux versions (<1.9), return false. The reason 269 # On older tmux versions (<1.9), return false. The reason
259 # is that there is no easy way to get the height of the active panel 270 # is that there is no easy way to get the height of the active panel
260 # on current window without nested formats (available from version 1.9) 271 # on current window without nested formats (available from version 1.9)
261 vernum = check_terminal_version("tmux") 272 if not check_tmux_version('1.9'):
262 if vernum and LooseVersion(vernum) < '1.9':
263 return False 273 return False
264 try: 274 try:
265 p = sub.Popen('%s list-panes -F "#{?pane_active,#{pane_height},}"' % tmux, 275 p = sub.Popen('%s list-panes -F "#{?pane_active,#{pane_height},}"' % tmux,
diff --git a/meta/lib/oe/utils.py b/meta/lib/oe/utils.py
index 468c76f30f..9a2187e36f 100644
--- a/meta/lib/oe/utils.py
+++ b/meta/lib/oe/utils.py
@@ -193,7 +193,7 @@ def parallel_make(d, makeinst=False):
193 193
194 return int(v) 194 return int(v)
195 195
196 return None 196 return ''
197 197
198def parallel_make_argument(d, fmt, limit=None, makeinst=False): 198def parallel_make_argument(d, fmt, limit=None, makeinst=False):
199 """ 199 """
diff --git a/meta/lib/oeqa/manual/oe-core.json b/meta/lib/oeqa/manual/oe-core.json
index fb47c5ec36..4ad524d89b 100644
--- a/meta/lib/oeqa/manual/oe-core.json
+++ b/meta/lib/oeqa/manual/oe-core.json
@@ -80,7 +80,7 @@
80 "expected_results": "" 80 "expected_results": ""
81 }, 81 },
82 "7": { 82 "7": {
83 "action": "Run command:./configure && make ", 83 "action": "Run command:./configure ${CONFIGUREOPTS} && make ",
84 "expected_results": "Verify that \"matchbox-desktop\" binary file was created successfully under \"src/\" directory " 84 "expected_results": "Verify that \"matchbox-desktop\" binary file was created successfully under \"src/\" directory "
85 }, 85 },
86 "8": { 86 "8": {
diff --git a/meta/lib/oeqa/runtime/cases/df.py b/meta/lib/oeqa/runtime/cases/df.py
index 89fd0fb901..bb155c9cf9 100644
--- a/meta/lib/oeqa/runtime/cases/df.py
+++ b/meta/lib/oeqa/runtime/cases/df.py
@@ -4,12 +4,14 @@
4 4
5from oeqa.runtime.case import OERuntimeTestCase 5from oeqa.runtime.case import OERuntimeTestCase
6from oeqa.core.decorator.depends import OETestDepends 6from oeqa.core.decorator.depends import OETestDepends
7from oeqa.core.decorator.data import skipIfDataVar, skipIfInDataVar
7from oeqa.runtime.decorator.package import OEHasPackage 8from oeqa.runtime.decorator.package import OEHasPackage
8 9
9class DfTest(OERuntimeTestCase): 10class DfTest(OERuntimeTestCase):
10 11
11 @OETestDepends(['ssh.SSHTest.test_ssh']) 12 @OETestDepends(['ssh.SSHTest.test_ssh'])
12 @OEHasPackage(['coreutils', 'busybox']) 13 @OEHasPackage(['coreutils', 'busybox'])
14 @skipIfInDataVar('IMAGE_FEATURES', 'read-only-rootfs', 'Test case df requires a writable rootfs')
13 def test_df(self): 15 def test_df(self):
14 cmd = "df -P / | sed -n '2p' | awk '{print $4}'" 16 cmd = "df -P / | sed -n '2p' | awk '{print $4}'"
15 (status,output) = self.target.run(cmd) 17 (status,output) = self.target.run(cmd)
diff --git a/meta/lib/oeqa/runtime/cases/pam.py b/meta/lib/oeqa/runtime/cases/pam.py
index 271a1943e3..a482ded945 100644
--- a/meta/lib/oeqa/runtime/cases/pam.py
+++ b/meta/lib/oeqa/runtime/cases/pam.py
@@ -8,11 +8,14 @@
8from oeqa.runtime.case import OERuntimeTestCase 8from oeqa.runtime.case import OERuntimeTestCase
9from oeqa.core.decorator.depends import OETestDepends 9from oeqa.core.decorator.depends import OETestDepends
10from oeqa.core.decorator.data import skipIfNotFeature 10from oeqa.core.decorator.data import skipIfNotFeature
11from oeqa.runtime.decorator.package import OEHasPackage
11 12
12class PamBasicTest(OERuntimeTestCase): 13class PamBasicTest(OERuntimeTestCase):
13 14
14 @skipIfNotFeature('pam', 'Test requires pam to be in DISTRO_FEATURES') 15 @skipIfNotFeature('pam', 'Test requires pam to be in DISTRO_FEATURES')
15 @OETestDepends(['ssh.SSHTest.test_ssh']) 16 @OETestDepends(['ssh.SSHTest.test_ssh'])
17 @OEHasPackage(['shadow'])
18 @OEHasPackage(['shadow-base'])
16 def test_pam(self): 19 def test_pam(self):
17 status, output = self.target.run('login --help') 20 status, output = self.target.run('login --help')
18 msg = ('login command does not work as expected. ' 21 msg = ('login command does not work as expected. '
diff --git a/meta/lib/oeqa/selftest/cases/buildoptions.py b/meta/lib/oeqa/selftest/cases/buildoptions.py
index e91f0bd18f..b1b9ea7e55 100644
--- a/meta/lib/oeqa/selftest/cases/buildoptions.py
+++ b/meta/lib/oeqa/selftest/cases/buildoptions.py
@@ -57,15 +57,15 @@ class ImageOptionsTests(OESelftestTestCase):
57class DiskMonTest(OESelftestTestCase): 57class DiskMonTest(OESelftestTestCase):
58 58
59 def test_stoptask_behavior(self): 59 def test_stoptask_behavior(self):
60 self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"') 60 self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
61 res = bitbake("delay -c delay", ignore_status = True) 61 res = bitbake("delay -c delay", ignore_status = True)
62 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) 62 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)
63 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output)) 63 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output))
64 self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"') 64 self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
65 res = bitbake("delay -c delay", ignore_status = True) 65 res = bitbake("delay -c delay", ignore_status = True)
66 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) 66 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)
67 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output)) 67 self.assertEqual(res.status, 1, msg = "bitbake reported exit code %s. It should have been 1. Bitbake output: %s" % (str(res.status), res.output))
68 self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"') 68 self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"\nBB_HEARTBEAT_EVENT = "1"')
69 res = bitbake("delay -c delay") 69 res = bitbake("delay -c delay")
70 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) 70 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)
71 71
diff --git a/meta/lib/oeqa/selftest/cases/cve_check.py b/meta/lib/oeqa/selftest/cases/cve_check.py
new file mode 100644
index 0000000000..d1947baffc
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/cve_check.py
@@ -0,0 +1,44 @@
1from oe.cve_check import Version
2from oeqa.selftest.case import OESelftestTestCase
3
4class CVECheck(OESelftestTestCase):
5
6 def test_version_compare(self):
7 result = Version("100") > Version("99")
8 self.assertTrue( result, msg="Failed to compare version '100' > '99'")
9 result = Version("2.3.1") > Version("2.2.3")
10 self.assertTrue( result, msg="Failed to compare version '2.3.1' > '2.2.3'")
11 result = Version("2021-01-21") > Version("2020-12-25")
12 self.assertTrue( result, msg="Failed to compare version '2021-01-21' > '2020-12-25'")
13 result = Version("1.2-20200910") < Version("1.2-20200920")
14 self.assertTrue( result, msg="Failed to compare version '1.2-20200910' < '1.2-20200920'")
15
16 result = Version("1.0") >= Version("1.0beta")
17 self.assertTrue( result, msg="Failed to compare version '1.0' >= '1.0beta'")
18 result = Version("1.0-rc2") > Version("1.0-rc1")
19 self.assertTrue( result, msg="Failed to compare version '1.0-rc2' > '1.0-rc1'")
20 result = Version("1.0.alpha1") < Version("1.0")
21 self.assertTrue( result, msg="Failed to compare version '1.0.alpha1' < '1.0'")
22 result = Version("1.0_dev") <= Version("1.0")
23 self.assertTrue( result, msg="Failed to compare version '1.0_dev' <= '1.0'")
24
25 # ignore "p1" and "p2", so these should be equal
26 result = Version("1.0p2") == Version("1.0p1")
27 self.assertTrue( result ,msg="Failed to compare version '1.0p2' to '1.0p1'")
28 # ignore the "b" and "r"
29 result = Version("1.0b") == Version("1.0r")
30 self.assertTrue( result ,msg="Failed to compare version '1.0b' to '1.0r'")
31
32 # consider the trailing alphabet as patched level when comparing
33 result = Version("1.0b","alphabetical") < Version("1.0r","alphabetical")
34 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'")
35 result = Version("1.0b","alphabetical") > Version("1.0","alphabetical")
36 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'")
37
38 # consider the trailing "p" and "patch" as patched released when comparing
39 result = Version("1.0","patch") < Version("1.0p1","patch")
40 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0' < '1.0p1'")
41 result = Version("1.0p2","patch") > Version("1.0p1","patch")
42 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0p2' > '1.0p1'")
43 result = Version("1.0_patch2","patch") < Version("1.0_patch3","patch")
44 self.assertTrue( result ,msg="Failed to compare version with suffix '1.0_patch2' < '1.0_patch3'")
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index d3d2e04c20..4eba23890f 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -57,7 +57,7 @@ def setUpModule():
57 if relpth.endswith('/'): 57 if relpth.endswith('/'):
58 destdir = os.path.join(corecopydir, relpth) 58 destdir = os.path.join(corecopydir, relpth)
59 # avoid race condition by not copying .pyc files YPBZ#13421,13803 59 # avoid race condition by not copying .pyc files YPBZ#13421,13803
60 shutil.copytree(pth, destdir, ignore=ignore_patterns('*.pyc', '__pycache__')) 60 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
61 else: 61 else:
62 destdir = os.path.join(corecopydir, os.path.dirname(relpth)) 62 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
63 bb.utils.mkdirhier(destdir) 63 bb.utils.mkdirhier(destdir)
@@ -269,7 +269,7 @@ class DevtoolAddTests(DevtoolBase):
269 self.track_for_cleanup(tempdir) 269 self.track_for_cleanup(tempdir)
270 pn = 'pv' 270 pn = 'pv'
271 pv = '1.5.3' 271 pv = '1.5.3'
272 url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2' 272 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
273 result = runCmd('wget %s' % url, cwd=tempdir) 273 result = runCmd('wget %s' % url, cwd=tempdir)
274 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir) 274 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
275 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv)) 275 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
diff --git a/meta/lib/oeqa/selftest/cases/pseudo.py b/meta/lib/oeqa/selftest/cases/pseudo.py
new file mode 100644
index 0000000000..33593d5ce9
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/pseudo.py
@@ -0,0 +1,27 @@
1#
2# SPDX-License-Identifier: MIT
3#
4
5import glob
6import os
7import shutil
8from oeqa.utils.commands import bitbake, get_test_layer
9from oeqa.selftest.case import OESelftestTestCase
10
11class Pseudo(OESelftestTestCase):
12
13 def test_pseudo_pyc_creation(self):
14 self.write_config("")
15
16 metaselftestpath = get_test_layer()
17 pycache_path = os.path.join(metaselftestpath, 'lib/__pycache__')
18 if os.path.exists(pycache_path):
19 shutil.rmtree(pycache_path)
20
21 bitbake('pseudo-pyc-test -c install')
22
23 test1_pyc_present = len(glob.glob(os.path.join(pycache_path, 'pseudo_pyc_test1.*.pyc')))
24 self.assertTrue(test1_pyc_present, 'test1 pyc file missing, should be created outside of pseudo context.')
25
26 test2_pyc_present = len(glob.glob(os.path.join(pycache_path, 'pseudo_pyc_test2.*.pyc')))
27 self.assertFalse(test2_pyc_present, 'test2 pyc file present, should not be created in pseudo context.')
diff --git a/meta/lib/oeqa/selftest/cases/reproducible.py b/meta/lib/oeqa/selftest/cases/reproducible.py
index a7ef336143..cd7be7d436 100644
--- a/meta/lib/oeqa/selftest/cases/reproducible.py
+++ b/meta/lib/oeqa/selftest/cases/reproducible.py
@@ -68,7 +68,7 @@ def compare_file(reference, test, diffutils_sysroot):
68 result.status = MISSING 68 result.status = MISSING
69 return result 69 return result
70 70
71 r = runCmd(['cmp', '--quiet', reference, test], native_sysroot=diffutils_sysroot, ignore_status=True) 71 r = runCmd(['cmp', '--quiet', reference, test], native_sysroot=diffutils_sysroot, ignore_status=True, sync=False)
72 72
73 if r.status: 73 if r.status:
74 result.status = DIFFERENT 74 result.status = DIFFERENT
@@ -184,9 +184,10 @@ class ReproducibleTests(OESelftestTestCase):
184 # mirror, forcing a complete build from scratch 184 # mirror, forcing a complete build from scratch
185 config += textwrap.dedent('''\ 185 config += textwrap.dedent('''\
186 SSTATE_DIR = "${TMPDIR}/sstate" 186 SSTATE_DIR = "${TMPDIR}/sstate"
187 SSTATE_MIRROR = "" 187 SSTATE_MIRRORS = ""
188 ''') 188 ''')
189 189
190 self.logger.info("Building %s (sstate%s allowed)..." % (name, '' if use_sstate else ' NOT'))
190 self.write_config(config) 191 self.write_config(config)
191 d = get_bb_vars(capture_vars) 192 d = get_bb_vars(capture_vars)
192 bitbake(' '.join(self.images)) 193 bitbake(' '.join(self.images))
@@ -213,6 +214,7 @@ class ReproducibleTests(OESelftestTestCase):
213 self.logger.info('Non-reproducible packages will be copied to %s', save_dir) 214 self.logger.info('Non-reproducible packages will be copied to %s', save_dir)
214 215
215 vars_A = self.do_test_build('reproducibleA', self.build_from_sstate) 216 vars_A = self.do_test_build('reproducibleA', self.build_from_sstate)
217
216 vars_B = self.do_test_build('reproducibleB', False) 218 vars_B = self.do_test_build('reproducibleB', False)
217 219
218 # NOTE: The temp directories from the reproducible build are purposely 220 # NOTE: The temp directories from the reproducible build are purposely
@@ -227,6 +229,7 @@ class ReproducibleTests(OESelftestTestCase):
227 deploy_A = vars_A['DEPLOY_DIR_' + c.upper()] 229 deploy_A = vars_A['DEPLOY_DIR_' + c.upper()]
228 deploy_B = vars_B['DEPLOY_DIR_' + c.upper()] 230 deploy_B = vars_B['DEPLOY_DIR_' + c.upper()]
229 231
232 self.logger.info('Checking %s packages for differences...' % c)
230 result = self.compare_packages(deploy_A, deploy_B, diffutils_sysroot) 233 result = self.compare_packages(deploy_A, deploy_B, diffutils_sysroot)
231 234
232 self.logger.info('Reproducibility summary for %s: %s' % (c, result)) 235 self.logger.info('Reproducibility summary for %s: %s' % (c, result))
diff --git a/meta/lib/oeqa/selftest/cases/tinfoil.py b/meta/lib/oeqa/selftest/cases/tinfoil.py
index 206168ed00..a51c6048d3 100644
--- a/meta/lib/oeqa/selftest/cases/tinfoil.py
+++ b/meta/lib/oeqa/selftest/cases/tinfoil.py
@@ -100,9 +100,11 @@ class TinfoilTests(OESelftestTestCase):
100 eventreceived = False 100 eventreceived = False
101 commandcomplete = False 101 commandcomplete = False
102 start = time.time() 102 start = time.time()
103 # Wait for 10s in total so we'd detect spurious heartbeat events for example 103 # Wait for maximum 60s in total so we'd detect spurious heartbeat events for example
104 # The test is IO load sensitive too 104 # The test is IO load sensitive too
105 while time.time() - start < 10: 105 while (not (eventreceived == True and commandcomplete == True)
106 and (time.time() - start < 60)):
107 # if we received both events (on let's say a good day), we are done
106 event = tinfoil.wait_event(1) 108 event = tinfoil.wait_event(1)
107 if event: 109 if event:
108 if isinstance(event, bb.command.CommandCompleted): 110 if isinstance(event, bb.command.CommandCompleted):
diff --git a/meta/lib/oeqa/selftest/cases/wic.py b/meta/lib/oeqa/selftest/cases/wic.py
index 714637ec1e..39c6828f59 100644
--- a/meta/lib/oeqa/selftest/cases/wic.py
+++ b/meta/lib/oeqa/selftest/cases/wic.py
@@ -318,6 +318,7 @@ class Wic(WicTestCase):
318 "--image-name=core-image-minimal " 318 "--image-name=core-image-minimal "
319 "-D -o %s" % self.resultdir) 319 "-D -o %s" % self.resultdir)
320 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) 320 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
321 self.assertEqual(1, len(glob(self.resultdir + "tmp.wic*")))
321 322
322 def test_debug_long(self): 323 def test_debug_long(self):
323 """Test --debug option""" 324 """Test --debug option"""
@@ -325,6 +326,7 @@ class Wic(WicTestCase):
325 "--image-name=core-image-minimal " 326 "--image-name=core-image-minimal "
326 "--debug -o %s" % self.resultdir) 327 "--debug -o %s" % self.resultdir)
327 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) 328 self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
329 self.assertEqual(1, len(glob(self.resultdir + "tmp.wic*")))
328 330
329 def test_skip_build_check_short(self): 331 def test_skip_build_check_short(self):
330 """Test -s option""" 332 """Test -s option"""
@@ -588,6 +590,9 @@ part / --source rootfs --fstype=ext4 --include-path %s --include-path core-imag
588 def test_permissions(self): 590 def test_permissions(self):
589 """Test permissions are respected""" 591 """Test permissions are respected"""
590 592
593 # prepare wicenv and rootfs
594 bitbake('core-image-minimal core-image-minimal-mtdutils -c do_rootfs_wicenv')
595
591 oldpath = os.environ['PATH'] 596 oldpath = os.environ['PATH']
592 os.environ['PATH'] = get_bb_var("PATH", "wic-tools") 597 os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
593 598
@@ -621,6 +626,19 @@ part /etc --source rootfs --fstype=ext4 --change-directory=etc
621 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part)) 626 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part))
622 self.assertEqual(True, files_own_by_root(res.output)) 627 self.assertEqual(True, files_own_by_root(res.output))
623 628
629 config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "%s"\n' % wks_file
630 self.append_config(config)
631 bitbake('core-image-minimal')
632 tmpdir = os.path.join(get_bb_var('WORKDIR', 'core-image-minimal'),'build-wic')
633
634 # check each partition for permission
635 for part in glob(os.path.join(tmpdir, 'temp-*.direct.p*')):
636 res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % (part))
637 self.assertTrue(files_own_by_root(res.output)
638 ,msg='Files permission incorrect using wks set "%s"' % test)
639
640 # clean config and result directory for next cases
641 self.remove_config(config)
624 rmtree(self.resultdir, ignore_errors=True) 642 rmtree(self.resultdir, ignore_errors=True)
625 643
626 finally: 644 finally:
@@ -961,14 +979,18 @@ class Wic2(WicTestCase):
961 @only_for_arch(['i586', 'i686', 'x86_64']) 979 @only_for_arch(['i586', 'i686', 'x86_64'])
962 def test_rawcopy_plugin_qemu(self): 980 def test_rawcopy_plugin_qemu(self):
963 """Test rawcopy plugin in qemu""" 981 """Test rawcopy plugin in qemu"""
964 # build ext4 and wic images 982 # build ext4 and then use it for a wic image
965 for fstype in ("ext4", "wic"): 983 config = 'IMAGE_FSTYPES = "ext4"\n'
966 config = 'IMAGE_FSTYPES = "%s"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' % fstype 984 self.append_config(config)
967 self.append_config(config) 985 self.assertEqual(0, bitbake('core-image-minimal').status)
968 self.assertEqual(0, bitbake('core-image-minimal').status) 986 self.remove_config(config)
969 self.remove_config(config)
970 987
971 with runqemu('core-image-minimal', ssh=False, image_fstype='wic') as qemu: 988 config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n'
989 self.append_config(config)
990 self.assertEqual(0, bitbake('core-image-minimal-mtdutils').status)
991 self.remove_config(config)
992
993 with runqemu('core-image-minimal-mtdutils', ssh=False, image_fstype='wic') as qemu:
972 cmd = "grep sda. /proc/partitions |wc -l" 994 cmd = "grep sda. /proc/partitions |wc -l"
973 status, output = qemu.run_serial(cmd) 995 status, output = qemu.run_serial(cmd)
974 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) 996 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
diff --git a/meta/lib/oeqa/selftest/context.py b/meta/lib/oeqa/selftest/context.py
index dd3609c1d6..1659926975 100644
--- a/meta/lib/oeqa/selftest/context.py
+++ b/meta/lib/oeqa/selftest/context.py
@@ -34,7 +34,7 @@ class NonConcurrentTestSuite(unittest.TestSuite):
34 (builddir, newbuilddir) = self.setupfunc("-st", None, self.suite) 34 (builddir, newbuilddir) = self.setupfunc("-st", None, self.suite)
35 ret = super().run(result) 35 ret = super().run(result)
36 os.chdir(builddir) 36 os.chdir(builddir)
37 if newbuilddir and ret.wasSuccessful(): 37 if newbuilddir and ret.wasSuccessful() and self.removefunc:
38 self.removefunc(newbuilddir) 38 self.removefunc(newbuilddir)
39 39
40def removebuilddir(d): 40def removebuilddir(d):
@@ -54,7 +54,7 @@ def removebuilddir(d):
54 bb.utils.prunedir(d, ionice=True) 54 bb.utils.prunedir(d, ionice=True)
55 55
56class OESelftestTestContext(OETestContext): 56class OESelftestTestContext(OETestContext):
57 def __init__(self, td=None, logger=None, machines=None, config_paths=None, newbuilddir=None): 57 def __init__(self, td=None, logger=None, machines=None, config_paths=None, newbuilddir=None, keep_builddir=None):
58 super(OESelftestTestContext, self).__init__(td, logger) 58 super(OESelftestTestContext, self).__init__(td, logger)
59 59
60 self.machines = machines 60 self.machines = machines
@@ -62,6 +62,11 @@ class OESelftestTestContext(OETestContext):
62 self.config_paths = config_paths 62 self.config_paths = config_paths
63 self.newbuilddir = newbuilddir 63 self.newbuilddir = newbuilddir
64 64
65 if keep_builddir:
66 self.removebuilddir = None
67 else:
68 self.removebuilddir = removebuilddir
69
65 def setup_builddir(self, suffix, selftestdir, suite): 70 def setup_builddir(self, suffix, selftestdir, suite):
66 builddir = os.environ['BUILDDIR'] 71 builddir = os.environ['BUILDDIR']
67 if not selftestdir: 72 if not selftestdir:
@@ -119,9 +124,9 @@ class OESelftestTestContext(OETestContext):
119 if processes: 124 if processes:
120 from oeqa.core.utils.concurrencytest import ConcurrentTestSuite 125 from oeqa.core.utils.concurrencytest import ConcurrentTestSuite
121 126
122 return ConcurrentTestSuite(suites, processes, self.setup_builddir, removebuilddir) 127 return ConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
123 else: 128 else:
124 return NonConcurrentTestSuite(suites, processes, self.setup_builddir, removebuilddir) 129 return NonConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
125 130
126 def runTests(self, processes=None, machine=None, skips=[]): 131 def runTests(self, processes=None, machine=None, skips=[]):
127 if machine: 132 if machine:
@@ -179,6 +184,9 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
179 action='append', default=None, 184 action='append', default=None,
180 help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)') 185 help='Exclude all (unhidden) tests that match any of the specified tag(s). (exclude applies before select)')
181 186
187 parser.add_argument('-K', '--keep-builddir', action='store_true',
188 help='Keep the test build directory even if all tests pass')
189
182 parser.add_argument('-B', '--newbuilddir', help='New build directory to use for tests.') 190 parser.add_argument('-B', '--newbuilddir', help='New build directory to use for tests.')
183 parser.add_argument('-v', '--verbose', action='store_true') 191 parser.add_argument('-v', '--verbose', action='store_true')
184 parser.set_defaults(func=self.run) 192 parser.set_defaults(func=self.run)
@@ -236,6 +244,7 @@ class OESelftestTestContextExecutor(OETestContextExecutor):
236 self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf") 244 self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf")
237 self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf") 245 self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf")
238 self.tc_kwargs['init']['newbuilddir'] = args.newbuilddir 246 self.tc_kwargs['init']['newbuilddir'] = args.newbuilddir
247 self.tc_kwargs['init']['keep_builddir'] = args.keep_builddir
239 248
240 def tag_filter(tags): 249 def tag_filter(tags):
241 if args.exclude_tags: 250 if args.exclude_tags:
diff --git a/meta/lib/oeqa/utils/commands.py b/meta/lib/oeqa/utils/commands.py
index 8059cbce3e..a71c16ab14 100644
--- a/meta/lib/oeqa/utils/commands.py
+++ b/meta/lib/oeqa/utils/commands.py
@@ -125,11 +125,11 @@ class Command(object):
125 125
126 def stop(self): 126 def stop(self):
127 for thread in self.threads: 127 for thread in self.threads:
128 if thread.isAlive(): 128 if thread.is_alive():
129 self.process.terminate() 129 self.process.terminate()
130 # let's give it more time to terminate gracefully before killing it 130 # let's give it more time to terminate gracefully before killing it
131 thread.join(5) 131 thread.join(5)
132 if thread.isAlive(): 132 if thread.is_alive():
133 self.process.kill() 133 self.process.kill()
134 thread.join() 134 thread.join()
135 135
@@ -188,7 +188,10 @@ def runCmd(command, ignore_status=False, timeout=None, assert_error=True, sync=T
188 # call sync around the tests to ensure the IO queue doesn't get too large, taking any IO 188 # call sync around the tests to ensure the IO queue doesn't get too large, taking any IO
189 # hit here rather than in bitbake shutdown. 189 # hit here rather than in bitbake shutdown.
190 if sync: 190 if sync:
191 p = os.environ['PATH']
192 os.environ['PATH'] = "/usr/bin:/bin:/usr/sbin:/sbin:" + p
191 os.system("sync") 193 os.system("sync")
194 os.environ['PATH'] = p
192 195
193 result.command = command 196 result.command = command
194 result.status = cmd.status 197 result.status = cmd.status