diff options
Diffstat (limited to 'meta/lib/oeqa/selftest')
-rw-r--r-- | meta/lib/oeqa/selftest/__init__.py | 2 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/_sstatetests_noauto.py | 95 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/base.py | 129 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/bblayers.py | 37 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/bbtests.py | 104 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/buildhistory.py | 45 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/buildoptions.py | 113 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/oescripts.py | 60 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/prservice.py | 113 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/sstate.py | 53 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/sstatetests.py | 193 |
11 files changed, 944 insertions, 0 deletions
diff --git a/meta/lib/oeqa/selftest/__init__.py b/meta/lib/oeqa/selftest/__init__.py new file mode 100644 index 0000000000..3ad9513f40 --- /dev/null +++ b/meta/lib/oeqa/selftest/__init__.py | |||
@@ -0,0 +1,2 @@ | |||
1 | from pkgutil import extend_path | ||
2 | __path__ = extend_path(__path__, __name__) | ||
diff --git a/meta/lib/oeqa/selftest/_sstatetests_noauto.py b/meta/lib/oeqa/selftest/_sstatetests_noauto.py new file mode 100644 index 0000000000..fc9ae7efb9 --- /dev/null +++ b/meta/lib/oeqa/selftest/_sstatetests_noauto.py | |||
@@ -0,0 +1,95 @@ | |||
1 | import datetime | ||
2 | import unittest | ||
3 | import os | ||
4 | import re | ||
5 | import shutil | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer | ||
10 | from oeqa.selftest.sstate import SStateBase | ||
11 | |||
12 | |||
13 | class RebuildFromSState(SStateBase): | ||
14 | |||
15 | @classmethod | ||
16 | def setUpClass(self): | ||
17 | self.builddir = os.path.join(os.environ.get('BUILDDIR')) | ||
18 | |||
19 | def get_dep_targets(self, primary_targets): | ||
20 | found_targets = [] | ||
21 | bitbake("-g " + ' '.join(map(str, primary_targets))) | ||
22 | with open(os.path.join(self.builddir, 'pn-buildlist'), 'r') as pnfile: | ||
23 | found_targets = pnfile.read().splitlines() | ||
24 | return found_targets | ||
25 | |||
26 | def configure_builddir(self, builddir): | ||
27 | os.mkdir(builddir) | ||
28 | self.track_for_cleanup(builddir) | ||
29 | os.mkdir(os.path.join(builddir, 'conf')) | ||
30 | shutil.copyfile(os.path.join(os.environ.get('BUILDDIR'), 'conf/local.conf'), os.path.join(builddir, 'conf/local.conf')) | ||
31 | config = {} | ||
32 | config['default_sstate_dir'] = "SSTATE_DIR ?= \"${TOPDIR}/sstate-cache\"" | ||
33 | config['null_sstate_mirrors'] = "SSTATE_MIRRORS = \"\"" | ||
34 | config['default_tmp_dir'] = "TMPDIR = \"${TOPDIR}/tmp\"" | ||
35 | for key in config: | ||
36 | ftools.append_file(os.path.join(builddir, 'conf/selftest.inc'), config[key]) | ||
37 | shutil.copyfile(os.path.join(os.environ.get('BUILDDIR'), 'conf/bblayers.conf'), os.path.join(builddir, 'conf/bblayers.conf')) | ||
38 | try: | ||
39 | shutil.copyfile(os.path.join(os.environ.get('BUILDDIR'), 'conf/auto.conf'), os.path.join(builddir, 'conf/auto.conf')) | ||
40 | except: | ||
41 | pass | ||
42 | |||
43 | def hardlink_tree(self, src, dst): | ||
44 | os.mkdir(dst) | ||
45 | self.track_for_cleanup(dst) | ||
46 | for root, dirs, files in os.walk(src): | ||
47 | if root == src: | ||
48 | continue | ||
49 | os.mkdir(os.path.join(dst, root.split(src)[1][1:])) | ||
50 | for sstate_file in files: | ||
51 | os.link(os.path.join(root, sstate_file), os.path.join(dst, root.split(src)[1][1:], sstate_file)) | ||
52 | |||
53 | def run_test_sstate_rebuild(self, primary_targets, relocate=False, rebuild_dependencies=False): | ||
54 | buildA = os.path.join(self.builddir, 'buildA') | ||
55 | if relocate: | ||
56 | buildB = os.path.join(self.builddir, 'buildB') | ||
57 | else: | ||
58 | buildB = buildA | ||
59 | |||
60 | if rebuild_dependencies: | ||
61 | rebuild_targets = self.get_dep_targets(primary_targets) | ||
62 | else: | ||
63 | rebuild_targets = primary_targets | ||
64 | |||
65 | self.configure_builddir(buildA) | ||
66 | runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildA)) + 'bitbake ' + ' '.join(map(str, primary_targets)), shell=True, executable='/bin/bash') | ||
67 | self.hardlink_tree(os.path.join(buildA, 'sstate-cache'), os.path.join(self.builddir, 'sstate-cache-buildA')) | ||
68 | shutil.rmtree(buildA) | ||
69 | |||
70 | failed_rebuild = [] | ||
71 | failed_cleansstate = [] | ||
72 | for target in rebuild_targets: | ||
73 | self.configure_builddir(buildB) | ||
74 | self.hardlink_tree(os.path.join(self.builddir, 'sstate-cache-buildA'), os.path.join(buildB, 'sstate-cache')) | ||
75 | |||
76 | result_cleansstate = runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildB)) + 'bitbake -ccleansstate ' + target, ignore_status=True, shell=True, executable='/bin/bash') | ||
77 | if not result_cleansstate.status == 0: | ||
78 | failed_cleansstate.append(target) | ||
79 | shutil.rmtree(buildB) | ||
80 | continue | ||
81 | |||
82 | result_build = runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildB)) + 'bitbake ' + target, ignore_status=True, shell=True, executable='/bin/bash') | ||
83 | if not result_build.status == 0: | ||
84 | failed_rebuild.append(target) | ||
85 | |||
86 | shutil.rmtree(buildB) | ||
87 | |||
88 | self.assertFalse(failed_rebuild, msg="The following recipes have failed to rebuild: %s" % ' '.join(map(str, failed_rebuild))) | ||
89 | self.assertFalse(failed_cleansstate, msg="The following recipes have failed cleansstate(all others have passed both cleansstate and rebuild from sstate tests): %s" % ' '.join(map(str, failed_cleansstate))) | ||
90 | |||
91 | def test_sstate_relocation(self): | ||
92 | self.run_test_sstate_rebuild(['core-image-sato-sdk'], relocate=True, rebuild_dependencies=True) | ||
93 | |||
94 | def test_sstate_rebuild(self): | ||
95 | self.run_test_sstate_rebuild(['core-image-sato-sdk'], relocate=False, rebuild_dependencies=True) | ||
diff --git a/meta/lib/oeqa/selftest/base.py b/meta/lib/oeqa/selftest/base.py new file mode 100644 index 0000000000..fc880e9d26 --- /dev/null +++ b/meta/lib/oeqa/selftest/base.py | |||
@@ -0,0 +1,129 @@ | |||
1 | # Copyright (c) 2013 Intel Corporation | ||
2 | # | ||
3 | # Released under the MIT license (see COPYING.MIT) | ||
4 | |||
5 | |||
6 | # DESCRIPTION | ||
7 | # Base class inherited by test classes in meta/lib/selftest | ||
8 | |||
9 | import unittest | ||
10 | import os | ||
11 | import sys | ||
12 | import shutil | ||
13 | import logging | ||
14 | import errno | ||
15 | |||
16 | import oeqa.utils.ftools as ftools | ||
17 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer | ||
18 | |||
19 | class oeSelfTest(unittest.TestCase): | ||
20 | |||
21 | log = logging.getLogger("selftest.base") | ||
22 | longMessage = True | ||
23 | |||
24 | def __init__(self, methodName="runTest"): | ||
25 | self.builddir = os.environ.get("BUILDDIR") | ||
26 | self.localconf_path = os.path.join(self.builddir, "conf/local.conf") | ||
27 | self.testinc_path = os.path.join(self.builddir, "conf/selftest.inc") | ||
28 | self.testlayer_path = oeSelfTest.testlayer_path | ||
29 | self._extra_tear_down_commands = [] | ||
30 | self._track_for_cleanup = [] | ||
31 | super(oeSelfTest, self).__init__(methodName) | ||
32 | |||
33 | def setUp(self): | ||
34 | os.chdir(self.builddir) | ||
35 | # we don't know what the previous test left around in config or inc files | ||
36 | # if it failed so we need a fresh start | ||
37 | try: | ||
38 | os.remove(self.testinc_path) | ||
39 | except OSError as e: | ||
40 | if e.errno != errno.ENOENT: | ||
41 | raise | ||
42 | for root, _, files in os.walk(self.testlayer_path): | ||
43 | for f in files: | ||
44 | if f == 'test_recipe.inc': | ||
45 | os.remove(os.path.join(root, f)) | ||
46 | # tests might need their own setup | ||
47 | # but if they overwrite this one they have to call | ||
48 | # super each time, so let's give them an alternative | ||
49 | self.setUpLocal() | ||
50 | |||
51 | def setUpLocal(self): | ||
52 | pass | ||
53 | |||
54 | def tearDown(self): | ||
55 | if self._extra_tear_down_commands: | ||
56 | failed_extra_commands = [] | ||
57 | for command in self._extra_tear_down_commands: | ||
58 | result = runCmd(command, ignore_status=True) | ||
59 | if not result.status == 0: | ||
60 | failed_extra_commands.append(command) | ||
61 | if failed_extra_commands: | ||
62 | self.log.warning("tearDown commands have failed: %s" % ', '.join(map(str, failed_extra_commands))) | ||
63 | self.log.debug("Trying to move on.") | ||
64 | self._extra_tear_down_commands = [] | ||
65 | |||
66 | if self._track_for_cleanup: | ||
67 | for path in self._track_for_cleanup: | ||
68 | if os.path.isdir(path): | ||
69 | shutil.rmtree(path) | ||
70 | if os.path.isfile(path): | ||
71 | os.remove(path) | ||
72 | self._track_for_cleanup = [] | ||
73 | |||
74 | self.tearDownLocal() | ||
75 | |||
76 | def tearDownLocal(self): | ||
77 | pass | ||
78 | |||
79 | # add test specific commands to the tearDown method. | ||
80 | def add_command_to_tearDown(self, command): | ||
81 | self.log.debug("Adding command '%s' to tearDown for this test." % command) | ||
82 | self._extra_tear_down_commands.append(command) | ||
83 | # add test specific files or directories to be removed in the tearDown method | ||
84 | def track_for_cleanup(self, path): | ||
85 | self.log.debug("Adding path '%s' to be cleaned up when test is over" % path) | ||
86 | self._track_for_cleanup.append(path) | ||
87 | |||
88 | # write to <builddir>/conf/selftest.inc | ||
89 | def write_config(self, data): | ||
90 | self.log.debug("Writing to: %s\n%s\n" % (self.testinc_path, data)) | ||
91 | ftools.write_file(self.testinc_path, data) | ||
92 | |||
93 | # append to <builddir>/conf/selftest.inc | ||
94 | def append_config(self, data): | ||
95 | self.log.debug("Appending to: %s\n%s\n" % (self.testinc_path, data)) | ||
96 | ftools.append_file(self.testinc_path, data) | ||
97 | |||
98 | # remove data from <builddir>/conf/selftest.inc | ||
99 | def remove_config(self, data): | ||
100 | self.log.debug("Removing from: %s\n\%s\n" % (self.testinc_path, data)) | ||
101 | ftools.remove_from_file(self.testinc_path, data) | ||
102 | |||
103 | # write to meta-sefltest/recipes-test/<recipe>/test_recipe.inc | ||
104 | def write_recipeinc(self, recipe, data): | ||
105 | inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc') | ||
106 | self.log.debug("Writing to: %s\n%s\n" % (inc_file, data)) | ||
107 | ftools.write_file(inc_file, data) | ||
108 | |||
109 | # append data to meta-sefltest/recipes-test/<recipe>/test_recipe.inc | ||
110 | def append_recipeinc(self, recipe, data): | ||
111 | inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc') | ||
112 | self.log.debug("Appending to: %s\n%s\n" % (inc_file, data)) | ||
113 | ftools.append_file(inc_file, data) | ||
114 | |||
115 | # remove data from meta-sefltest/recipes-test/<recipe>/test_recipe.inc | ||
116 | def remove_recipeinc(self, recipe, data): | ||
117 | inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc') | ||
118 | self.log.debug("Removing from: %s\n%s\n" % (inc_file, data)) | ||
119 | ftools.remove_from_file(inc_file, data) | ||
120 | |||
121 | # delete meta-sefltest/recipes-test/<recipe>/test_recipe.inc file | ||
122 | def delete_recipeinc(self, recipe): | ||
123 | inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc') | ||
124 | self.log.debug("Deleting file: %s" % inc_file) | ||
125 | try: | ||
126 | os.remove(inc_file) | ||
127 | except OSError as e: | ||
128 | if e.errno != errno.ENOENT: | ||
129 | raise | ||
diff --git a/meta/lib/oeqa/selftest/bblayers.py b/meta/lib/oeqa/selftest/bblayers.py new file mode 100644 index 0000000000..52aa4f8112 --- /dev/null +++ b/meta/lib/oeqa/selftest/bblayers.py | |||
@@ -0,0 +1,37 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import logging | ||
4 | import re | ||
5 | import shutil | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.utils.commands import runCmd | ||
10 | |||
11 | class BitbakeLayers(oeSelfTest): | ||
12 | |||
13 | def test_bitbakelayers_showcrossdepends(self): | ||
14 | result = runCmd('bitbake-layers show-cross-depends') | ||
15 | self.assertTrue('aspell' in result.output) | ||
16 | |||
17 | def test_bitbakelayers_showlayers(self): | ||
18 | result = runCmd('bitbake-layers show_layers') | ||
19 | self.assertTrue('meta-selftest' in result.output) | ||
20 | |||
21 | def test_bitbakelayers_showappends(self): | ||
22 | result = runCmd('bitbake-layers show_appends') | ||
23 | self.assertTrue('xcursor-transparent-theme_0.1.1.bbappend' in result.output, msg='xcursor-transparent-theme_0.1.1.bbappend file was not recognised') | ||
24 | |||
25 | def test_bitbakelayers_showoverlayed(self): | ||
26 | result = runCmd('bitbake-layers show_overlayed') | ||
27 | self.assertTrue('aspell' in result.output, msg='xcursor-transparent-theme_0.1.1.bbappend file was not recognised') | ||
28 | |||
29 | def test_bitbakelayers_flatten(self): | ||
30 | self.assertFalse(os.path.isdir(os.path.join(self.builddir, 'test'))) | ||
31 | result = runCmd('bitbake-layers flatten test') | ||
32 | bb_file = os.path.join(self.builddir, 'test/recipes-graphics/xcursor-transparent-theme/xcursor-transparent-theme_0.1.1.bb') | ||
33 | self.assertTrue(os.path.isfile(bb_file)) | ||
34 | contents = ftools.read_file(bb_file) | ||
35 | find_in_contents = re.search("##### bbappended from meta-selftest #####\n(.*\n)*include test_recipe.inc", contents) | ||
36 | shutil.rmtree(os.path.join(self.builddir, 'test')) | ||
37 | self.assertTrue(find_in_contents) | ||
diff --git a/meta/lib/oeqa/selftest/bbtests.py b/meta/lib/oeqa/selftest/bbtests.py new file mode 100644 index 0000000000..6815ecfe0b --- /dev/null +++ b/meta/lib/oeqa/selftest/bbtests.py | |||
@@ -0,0 +1,104 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import logging | ||
4 | import re | ||
5 | import shutil | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var | ||
10 | |||
11 | class BitbakeTests(oeSelfTest): | ||
12 | |||
13 | def test_run_bitbake_from_dir_1(self): | ||
14 | os.chdir(os.path.join(self.builddir, 'conf')) | ||
15 | bitbake('-e') | ||
16 | |||
17 | def test_run_bitbake_from_dir_2(self): | ||
18 | my_env = os.environ.copy() | ||
19 | my_env['BBPATH'] = my_env['BUILDDIR'] | ||
20 | os.chdir(os.path.dirname(os.environ['BUILDDIR'])) | ||
21 | bitbake('-e', env=my_env) | ||
22 | |||
23 | def test_event_handler(self): | ||
24 | self.write_config("INHERIT += \"test_events\"") | ||
25 | result = bitbake('m4-native') | ||
26 | find_build_started = re.search("NOTE: Test for bb\.event\.BuildStarted(\n.*)*NOTE: Preparing runqueue", result.output) | ||
27 | find_build_completed = re.search("Tasks Summary:.*(\n.*)*NOTE: Test for bb\.event\.BuildCompleted", result.output) | ||
28 | self.assertTrue(find_build_started, msg = "Match failed in:\n%s" % result.output) | ||
29 | self.assertTrue(find_build_completed, msg = "Match failed in:\n%s" % result.output) | ||
30 | self.assertFalse('Test for bb.event.InvalidEvent' in result.output) | ||
31 | |||
32 | def test_local_sstate(self): | ||
33 | bitbake('m4-native -ccleansstate') | ||
34 | bitbake('m4-native') | ||
35 | bitbake('m4-native -cclean') | ||
36 | result = bitbake('m4-native') | ||
37 | find_setscene = re.search("m4-native.*do_.*_setscene", result.output) | ||
38 | self.assertTrue(find_setscene) | ||
39 | |||
40 | def test_bitbake_invalid_recipe(self): | ||
41 | result = bitbake('-b asdf', ignore_status=True) | ||
42 | self.assertTrue("ERROR: Unable to find any recipe file matching 'asdf'" in result.output) | ||
43 | |||
44 | def test_bitbake_invalid_target(self): | ||
45 | result = bitbake('asdf', ignore_status=True) | ||
46 | self.assertTrue("ERROR: Nothing PROVIDES 'asdf'" in result.output) | ||
47 | |||
48 | def test_warnings_errors(self): | ||
49 | result = bitbake('-b asdf', ignore_status=True) | ||
50 | find_warnings = re.search("Summary: There w.{2,3}? [1-9][0-9]* WARNING messages* shown", result.output) | ||
51 | find_errors = re.search("Summary: There w.{2,3}? [1-9][0-9]* ERROR messages* shown", result.output) | ||
52 | self.assertTrue(find_warnings, msg="Did not find the mumber of warnings at the end of the build:\n" + result.output) | ||
53 | self.assertTrue(find_errors, msg="Did not find the mumber of errors at the end of the build:\n" + result.output) | ||
54 | |||
55 | def test_invalid_patch(self): | ||
56 | self.write_recipeinc('man', 'SRC_URI += "file://man-1.5h1-make.patch"') | ||
57 | result = bitbake('man -c patch', ignore_status=True) | ||
58 | self.delete_recipeinc('man') | ||
59 | bitbake('-cclean man') | ||
60 | self.assertTrue("ERROR: Function failed: patch_do_patch" in result.output) | ||
61 | |||
62 | def test_force_task(self): | ||
63 | bitbake('m4-native') | ||
64 | result = bitbake('-C compile m4-native') | ||
65 | look_for_tasks = ['do_compile', 'do_install', 'do_populate_sysroot'] | ||
66 | for task in look_for_tasks: | ||
67 | find_task = re.search("m4-native.*%s" % task, result.output) | ||
68 | self.assertTrue(find_task) | ||
69 | |||
70 | def test_bitbake_g(self): | ||
71 | result = bitbake('-g core-image-full-cmdline') | ||
72 | self.assertTrue('NOTE: PN build list saved to \'pn-buildlist\'' in result.output) | ||
73 | self.assertTrue('openssh' in ftools.read_file(os.path.join(self.builddir, 'pn-buildlist'))) | ||
74 | for f in ['pn-buildlist', 'pn-depends.dot', 'package-depends.dot', 'task-depends.dot']: | ||
75 | os.remove(f) | ||
76 | |||
77 | def test_image_manifest(self): | ||
78 | bitbake('core-image-minimal') | ||
79 | deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal") | ||
80 | imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal") | ||
81 | manifest = os.path.join(deploydir, imagename + ".manifest") | ||
82 | self.assertTrue(os.path.islink(manifest), msg="No manifest file created for image") | ||
83 | |||
84 | def test_invalid_recipe_src_uri(self): | ||
85 | data = 'SRC_URI = "file://invalid"' | ||
86 | self.write_recipeinc('man', data) | ||
87 | bitbake('-ccleanall man') | ||
88 | result = bitbake('-c fetch man', ignore_status=True) | ||
89 | bitbake('-ccleanall man') | ||
90 | self.delete_recipeinc('man') | ||
91 | self.assertEqual(result.status, 1, msg='Command succeded when it should have failed') | ||
92 | self.assertTrue('ERROR: Fetcher failure: Unable to find file file://invalid anywhere. The paths that were searched were:' in result.output) | ||
93 | self.assertTrue('ERROR: Function failed: Fetcher failure for URL: \'file://invalid\'. Unable to fetch URL from any source.' in result.output) | ||
94 | |||
95 | def test_rename_downloaded_file(self): | ||
96 | data = 'SRC_URI_append = ";downloadfilename=test-aspell.tar.gz"' | ||
97 | self.write_recipeinc('aspell', data) | ||
98 | bitbake('-ccleanall aspell') | ||
99 | result = bitbake('-c fetch aspell', ignore_status=True) | ||
100 | self.delete_recipeinc('aspell') | ||
101 | self.assertEqual(result.status, 0) | ||
102 | self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz'))) | ||
103 | self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz.done'))) | ||
104 | bitbake('-ccleanall aspell') | ||
diff --git a/meta/lib/oeqa/selftest/buildhistory.py b/meta/lib/oeqa/selftest/buildhistory.py new file mode 100644 index 0000000000..d8cae4664b --- /dev/null +++ b/meta/lib/oeqa/selftest/buildhistory.py | |||
@@ -0,0 +1,45 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import re | ||
4 | import shutil | ||
5 | import datetime | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.utils.commands import Command, runCmd, bitbake, get_bb_var, get_test_layer | ||
10 | |||
11 | |||
12 | class BuildhistoryBase(oeSelfTest): | ||
13 | |||
14 | def config_buildhistory(self, tmp_bh_location=False): | ||
15 | if (not 'buildhistory' in get_bb_var('USER_CLASSES')) and (not 'buildhistory' in get_bb_var('INHERIT')): | ||
16 | add_buildhistory_config = 'INHERIT += "buildhistory"\nBUILDHISTORY_COMMIT = "1"' | ||
17 | self.append_config(add_buildhistory_config) | ||
18 | |||
19 | if tmp_bh_location: | ||
20 | # Using a temporary buildhistory location for testing | ||
21 | tmp_bh_dir = os.path.join(self.builddir, "tmp_buildhistory_%s" % datetime.datetime.now().strftime('%Y%m%d%H%M%S')) | ||
22 | buildhistory_dir_config = "BUILDHISTORY_DIR = \"%s\"" % tmp_bh_dir | ||
23 | self.append_config(buildhistory_dir_config) | ||
24 | self.track_for_cleanup(tmp_bh_dir) | ||
25 | |||
26 | def run_buildhistory_operation(self, target, global_config='', target_config='', change_bh_location=False, expect_error=False, error_regex=''): | ||
27 | if change_bh_location: | ||
28 | tmp_bh_location = True | ||
29 | else: | ||
30 | tmp_bh_location = False | ||
31 | self.config_buildhistory(tmp_bh_location) | ||
32 | |||
33 | self.append_config(global_config) | ||
34 | self.append_recipeinc(target, target_config) | ||
35 | bitbake("-cclean %s" % target) | ||
36 | result = bitbake(target, ignore_status=True) | ||
37 | self.remove_config(global_config) | ||
38 | self.remove_recipeinc(target, target_config) | ||
39 | |||
40 | if expect_error: | ||
41 | self.assertEqual(result.status, 1, msg="Error expected for global config '%s' and target config '%s'" % (global_config, target_config)) | ||
42 | search_for_error = re.search(error_regex, result.output) | ||
43 | self.assertTrue(search_for_error, msg="Could not find desired error in output: %s" % error_regex) | ||
44 | else: | ||
45 | self.assertEqual(result.status, 0, msg="Command 'bitbake %s' has failed unexpectedly: %s" % (target, result.output)) | ||
diff --git a/meta/lib/oeqa/selftest/buildoptions.py b/meta/lib/oeqa/selftest/buildoptions.py new file mode 100644 index 0000000000..8ff40baddc --- /dev/null +++ b/meta/lib/oeqa/selftest/buildoptions.py | |||
@@ -0,0 +1,113 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import logging | ||
4 | import re | ||
5 | |||
6 | from oeqa.selftest.base import oeSelfTest | ||
7 | from oeqa.selftest.buildhistory import BuildhistoryBase | ||
8 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var | ||
9 | import oeqa.utils.ftools as ftools | ||
10 | |||
11 | class ImageOptionsTests(oeSelfTest): | ||
12 | |||
13 | def test_incremental_image_generation(self): | ||
14 | bitbake("-c cleanall core-image-minimal") | ||
15 | self.write_config('INC_RPM_IMAGE_GEN = "1"') | ||
16 | self.append_config('IMAGE_FEATURES += "ssh-server-openssh"') | ||
17 | bitbake("core-image-minimal") | ||
18 | res = runCmd("grep 'Installing openssh-sshd' %s" % (os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs")), ignore_status=True) | ||
19 | self.remove_config('IMAGE_FEATURES += "ssh-server-openssh"') | ||
20 | self.assertEqual(0, res.status, msg="No match for openssh-sshd in log.do_rootfs") | ||
21 | bitbake("core-image-minimal") | ||
22 | res = runCmd("grep 'Removing openssh-sshd' %s" %(os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs")),ignore_status=True) | ||
23 | self.assertEqual(0, res.status, msg="openssh-sshd was not removed from image") | ||
24 | |||
25 | def test_rm_old_image(self): | ||
26 | bitbake("core-image-minimal") | ||
27 | deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal") | ||
28 | imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal") | ||
29 | deploydir_files = os.listdir(deploydir) | ||
30 | track_original_files = [] | ||
31 | for image_file in deploydir_files: | ||
32 | if imagename in image_file and os.path.islink(os.path.join(deploydir, image_file)): | ||
33 | track_original_files.append(os.path.realpath(os.path.join(deploydir, image_file))) | ||
34 | self.append_config("RM_OLD_IMAGE = \"1\"") | ||
35 | bitbake("-C rootfs core-image-minimal") | ||
36 | deploydir_files = os.listdir(deploydir) | ||
37 | remaining_not_expected = [path for path in track_original_files if os.path.basename(path) in deploydir_files] | ||
38 | self.assertFalse(remaining_not_expected, msg="\nThe following image files ware not removed: %s" % ', '.join(map(str, remaining_not_expected))) | ||
39 | |||
40 | def test_ccache_tool(self): | ||
41 | bitbake("ccache-native") | ||
42 | self.assertTrue(os.path.isfile(os.path.join(get_bb_var('STAGING_BINDIR_NATIVE', 'ccache-native'), "ccache"))) | ||
43 | self.write_config('INHERIT += "ccache"') | ||
44 | bitbake("m4 -c cleansstate") | ||
45 | bitbake("m4 -c compile") | ||
46 | res = runCmd("grep ccache %s" % (os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile")), ignore_status=True) | ||
47 | self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile") | ||
48 | bitbake("ccache-native -ccleansstate") | ||
49 | |||
50 | |||
51 | class DiskMonTest(oeSelfTest): | ||
52 | |||
53 | def test_stoptask_behavior(self): | ||
54 | result = runCmd("df -Pk %s" % os.getcwd()) | ||
55 | size = result.output.split("\n")[1].split()[3] | ||
56 | self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},%sK,4510K"' % size) | ||
57 | res = bitbake("m4", ignore_status = True) | ||
58 | self.assertTrue('ERROR: No new tasks can be executed since the disk space monitor action is "STOPTASKS"!' in res.output) | ||
59 | self.assertEqual(res.status, 1) | ||
60 | self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},%sK,4510K"' % size) | ||
61 | res = bitbake("m4", ignore_status = True) | ||
62 | self.assertTrue('ERROR: Immediately abort since the disk space monitor action is "ABORT"!' in res.output) | ||
63 | self.assertEqual(res.status, 1) | ||
64 | self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},%sK,4510K"' % size) | ||
65 | res = bitbake("m4") | ||
66 | self.assertTrue('WARNING: The free space' in res.output) | ||
67 | |||
68 | class SanityOptionsTest(oeSelfTest): | ||
69 | |||
70 | def test_options_warnqa_errorqa_switch(self): | ||
71 | bitbake("xcursor-transparent-theme -ccleansstate") | ||
72 | |||
73 | if "packages-list" not in get_bb_var("ERROR_QA"): | ||
74 | self.write_config("ERROR_QA_append = \" packages-list\"") | ||
75 | |||
76 | self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"') | ||
77 | res = bitbake("xcursor-transparent-theme", ignore_status=True) | ||
78 | self.delete_recipeinc('xcursor-transparent-theme') | ||
79 | self.assertTrue("ERROR: QA Issue: xcursor-transparent-theme-dbg is listed in PACKAGES multiple times, this leads to packaging errors." in res.output) | ||
80 | self.assertEqual(res.status, 1) | ||
81 | self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"') | ||
82 | self.append_config('ERROR_QA_remove = "packages-list"') | ||
83 | self.append_config('WARN_QA_append = " packages-list"') | ||
84 | res = bitbake("xcursor-transparent-theme") | ||
85 | bitbake("xcursor-transparent-theme -ccleansstate") | ||
86 | self.delete_recipeinc('xcursor-transparent-theme') | ||
87 | self.assertTrue("WARNING: QA Issue: xcursor-transparent-theme-dbg is listed in PACKAGES multiple times, this leads to packaging errors." in res.output) | ||
88 | |||
89 | def test_sanity_userspace_dependency(self): | ||
90 | self.append_config('WARN_QA_append = " unsafe-references-in-binaries unsafe-references-in-scripts"') | ||
91 | bitbake("-ccleansstate gzip nfs-utils") | ||
92 | res = bitbake("gzip nfs-utils") | ||
93 | self.assertTrue("WARNING: QA Issue: gzip" in res.output) | ||
94 | self.assertTrue("WARNING: QA Issue: nfs-utils" in res.output) | ||
95 | |||
96 | class BuildhistoryTests(BuildhistoryBase): | ||
97 | |||
98 | def test_buildhistory_basic(self): | ||
99 | self.run_buildhistory_operation('xcursor-transparent-theme') | ||
100 | self.assertTrue(os.path.isdir(get_bb_var('BUILDHISTORY_DIR'))) | ||
101 | |||
102 | def test_buildhistory_buildtime_pr_backwards(self): | ||
103 | self.add_command_to_tearDown('cleanup-workdir') | ||
104 | target = 'xcursor-transparent-theme' | ||
105 | error = "ERROR: QA Issue: Package version for package %s went backwards which would break package feeds from (.*-r1 to .*-r0)" % target | ||
106 | self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True) | ||
107 | self.run_buildhistory_operation(target, target_config="PR = \"r0\"", change_bh_location=False, expect_error=True, error_regex=error) | ||
108 | |||
109 | |||
110 | |||
111 | |||
112 | |||
113 | |||
diff --git a/meta/lib/oeqa/selftest/oescripts.py b/meta/lib/oeqa/selftest/oescripts.py new file mode 100644 index 0000000000..4aab2ed095 --- /dev/null +++ b/meta/lib/oeqa/selftest/oescripts.py | |||
@@ -0,0 +1,60 @@ | |||
1 | import datetime | ||
2 | import unittest | ||
3 | import os | ||
4 | import re | ||
5 | import shutil | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.selftest.buildhistory import BuildhistoryBase | ||
10 | from oeqa.utils.commands import Command, runCmd, bitbake, get_bb_var, get_test_layer | ||
11 | |||
12 | class TestScripts(oeSelfTest): | ||
13 | |||
14 | def test_cleanup_workdir(self): | ||
15 | path = os.path.dirname(get_bb_var('WORKDIR', 'gzip')) | ||
16 | old_version_recipe = os.path.join(get_bb_var('COREBASE'), 'meta/recipes-extended/gzip/gzip_1.3.12.bb') | ||
17 | old_version = '1.3.12' | ||
18 | bitbake("-ccleansstate gzip") | ||
19 | bitbake("-ccleansstate -b %s" % old_version_recipe) | ||
20 | if os.path.exists(get_bb_var('WORKDIR', "-b %s" % old_version_recipe)): | ||
21 | shutil.rmtree(get_bb_var('WORKDIR', "-b %s" % old_version_recipe)) | ||
22 | if os.path.exists(get_bb_var('WORKDIR', 'gzip')): | ||
23 | shutil.rmtree(get_bb_var('WORKDIR', 'gzip')) | ||
24 | |||
25 | if os.path.exists(path): | ||
26 | initial_contents = os.listdir(path) | ||
27 | else: | ||
28 | initial_contents = [] | ||
29 | |||
30 | bitbake('gzip') | ||
31 | intermediary_contents = os.listdir(path) | ||
32 | bitbake("-b %s" % old_version_recipe) | ||
33 | runCmd('cleanup-workdir') | ||
34 | remaining_contents = os.listdir(path) | ||
35 | |||
36 | expected_contents = [x for x in intermediary_contents if x not in initial_contents] | ||
37 | remaining_not_expected = [x for x in remaining_contents if x not in expected_contents] | ||
38 | self.assertFalse(remaining_not_expected, msg="Not all necessary content has been deleted from %s: %s" % (path, ', '.join(map(str, remaining_not_expected)))) | ||
39 | expected_not_remaining = [x for x in expected_contents if x not in remaining_contents] | ||
40 | self.assertFalse(expected_not_remaining, msg="The script removed extra contents from %s: %s" % (path, ', '.join(map(str, expected_not_remaining)))) | ||
41 | |||
42 | class BuildhistoryDiffTests(BuildhistoryBase): | ||
43 | |||
44 | def test_buildhistory_diff(self): | ||
45 | self.add_command_to_tearDown('cleanup-workdir') | ||
46 | target = 'xcursor-transparent-theme' | ||
47 | self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True) | ||
48 | self.run_buildhistory_operation(target, target_config="PR = \"r0\"", change_bh_location=False, expect_error=True) | ||
49 | result = runCmd("buildhistory-diff -p %s" % get_bb_var('BUILDHISTORY_DIR')) | ||
50 | expected_output = 'PR changed from "r1" to "r0"' | ||
51 | self.assertTrue(expected_output in result.output, msg="Did not find expected output: %s" % result.output) | ||
52 | |||
53 | |||
54 | |||
55 | |||
56 | |||
57 | |||
58 | |||
59 | |||
60 | |||
diff --git a/meta/lib/oeqa/selftest/prservice.py b/meta/lib/oeqa/selftest/prservice.py new file mode 100644 index 0000000000..789c05f1e5 --- /dev/null +++ b/meta/lib/oeqa/selftest/prservice.py | |||
@@ -0,0 +1,113 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import logging | ||
4 | import re | ||
5 | import shutil | ||
6 | import datetime | ||
7 | |||
8 | import oeqa.utils.ftools as ftools | ||
9 | from oeqa.selftest.base import oeSelfTest | ||
10 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var | ||
11 | |||
12 | class BitbakePrTests(oeSelfTest): | ||
13 | |||
14 | def get_pr_version(self, package_name): | ||
15 | pkgdata_dir = get_bb_var('PKGDATA_DIR') | ||
16 | package_data_file = os.path.join(pkgdata_dir, 'runtime', package_name) | ||
17 | package_data = ftools.read_file(package_data_file) | ||
18 | find_pr = re.search("PKGR: r[0-9]+\.([0-9]+)", package_data) | ||
19 | self.assertTrue(find_pr) | ||
20 | return int(find_pr.group(1)) | ||
21 | |||
22 | def get_task_stamp(self, package_name, recipe_task): | ||
23 | stampdata = get_bb_var('STAMP', target=package_name).split('/') | ||
24 | prefix = stampdata[-1] | ||
25 | package_stamps_path = "/".join(stampdata[:-1]) | ||
26 | stamps = [] | ||
27 | for stamp in os.listdir(package_stamps_path): | ||
28 | find_stamp = re.match("%s\.%s\.([a-z0-9]{32})" % (prefix, recipe_task), stamp) | ||
29 | if find_stamp: | ||
30 | stamps.append(find_stamp.group(1)) | ||
31 | self.assertFalse(len(stamps) == 0, msg="Cound not find stamp for task %s for recipe %s" % (recipe_task, package_name)) | ||
32 | self.assertFalse(len(stamps) > 1, msg="Found multiple %s stamps for the %s recipe in the %s directory." % (recipe_task, package_name, package_stamps_path)) | ||
33 | return str(stamps[0]) | ||
34 | |||
35 | def increment_package_pr(self, package_name): | ||
36 | inc_data = "do_package_append() {\nbb.build.exec_func('do_test_prserv', d)\n}\ndo_test_prserv() {\necho \"The current date is: %s\"\n}" % datetime.datetime.now() | ||
37 | self.write_recipeinc(package_name, inc_data) | ||
38 | bitbake("-ccleansstate %s" % package_name) | ||
39 | res = bitbake(package_name, ignore_status=True) | ||
40 | self.delete_recipeinc(package_name) | ||
41 | self.assertEqual(res.status, 0, msg=res.output) | ||
42 | self.assertTrue("NOTE: Started PRServer with DBfile" in res.output, msg=res.output) | ||
43 | |||
44 | def config_pr_tests(self, package_name, package_type='rpm', pr_socket='localhost:0'): | ||
45 | config_package_data = 'PACKAGE_CLASSES = "package_%s"' % package_type | ||
46 | self.write_config(config_package_data) | ||
47 | config_server_data = 'PRSERV_HOST = "%s"' % pr_socket | ||
48 | self.append_config(config_server_data) | ||
49 | |||
50 | def run_test_pr_service(self, package_name, package_type='rpm', track_task='do_package', pr_socket='localhost:0'): | ||
51 | self.config_pr_tests(package_name, package_type, pr_socket) | ||
52 | |||
53 | self.increment_package_pr(package_name) | ||
54 | pr_1 = self.get_pr_version(package_name) | ||
55 | stamp_1 = self.get_task_stamp(package_name, track_task) | ||
56 | |||
57 | self.increment_package_pr(package_name) | ||
58 | pr_2 = self.get_pr_version(package_name) | ||
59 | stamp_2 = self.get_task_stamp(package_name, track_task) | ||
60 | |||
61 | bitbake("-ccleansstate %s" % package_name) | ||
62 | self.assertTrue(pr_2 - pr_1 == 1) | ||
63 | self.assertTrue(stamp_1 != stamp_2) | ||
64 | |||
65 | def run_test_pr_export_import(self, package_name, replace_current_db=True): | ||
66 | self.config_pr_tests(package_name) | ||
67 | |||
68 | self.increment_package_pr(package_name) | ||
69 | pr_1 = self.get_pr_version(package_name) | ||
70 | |||
71 | exported_db_path = os.path.join(self.builddir, 'export.inc') | ||
72 | export_result = runCmd("bitbake-prserv-tool export %s" % exported_db_path, ignore_status=True) | ||
73 | self.assertEqual(export_result.status, 0, msg="PR Service database export failed: %s" % export_result.output) | ||
74 | |||
75 | if replace_current_db: | ||
76 | current_db_path = os.path.join(get_bb_var('PERSISTENT_DIR'), 'prserv.sqlite3') | ||
77 | self.assertTrue(os.path.exists(current_db_path), msg="Path to current PR Service database is invalid: %s" % current_db_path) | ||
78 | os.remove(current_db_path) | ||
79 | |||
80 | import_result = runCmd("bitbake-prserv-tool import %s" % exported_db_path, ignore_status=True) | ||
81 | os.remove(exported_db_path) | ||
82 | self.assertEqual(import_result.status, 0, msg="PR Service database import failed: %s" % import_result.output) | ||
83 | |||
84 | self.increment_package_pr(package_name) | ||
85 | pr_2 = self.get_pr_version(package_name) | ||
86 | |||
87 | bitbake("-ccleansstate %s" % package_name) | ||
88 | self.assertTrue(pr_2 - pr_1 == 1) | ||
89 | |||
90 | |||
91 | def test_import_export_replace_db(self): | ||
92 | self.run_test_pr_export_import('m4') | ||
93 | |||
94 | def test_import_export_override_db(self): | ||
95 | self.run_test_pr_export_import('m4', replace_current_db=False) | ||
96 | |||
97 | def test_pr_service_rpm_arch_dep(self): | ||
98 | self.run_test_pr_service('m4', 'rpm', 'do_package') | ||
99 | |||
100 | def test_pr_service_deb_arch_dep(self): | ||
101 | self.run_test_pr_service('m4', 'deb', 'do_package') | ||
102 | |||
103 | def test_pr_service_ipk_arch_dep(self): | ||
104 | self.run_test_pr_service('m4', 'ipk', 'do_package') | ||
105 | |||
106 | def test_pr_service_rpm_arch_indep(self): | ||
107 | self.run_test_pr_service('xcursor-transparent-theme', 'rpm', 'do_package') | ||
108 | |||
109 | def test_pr_service_deb_arch_indep(self): | ||
110 | self.run_test_pr_service('xcursor-transparent-theme', 'deb', 'do_package') | ||
111 | |||
112 | def test_pr_service_ipk_arch_indep(self): | ||
113 | self.run_test_pr_service('xcursor-transparent-theme', 'ipk', 'do_package') | ||
diff --git a/meta/lib/oeqa/selftest/sstate.py b/meta/lib/oeqa/selftest/sstate.py new file mode 100644 index 0000000000..5989724432 --- /dev/null +++ b/meta/lib/oeqa/selftest/sstate.py | |||
@@ -0,0 +1,53 @@ | |||
1 | import datetime | ||
2 | import unittest | ||
3 | import os | ||
4 | import re | ||
5 | import shutil | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer | ||
10 | |||
11 | |||
12 | class SStateBase(oeSelfTest): | ||
13 | |||
14 | def setUpLocal(self): | ||
15 | self.temp_sstate_location = None | ||
16 | self.sstate_path = get_bb_var('SSTATE_DIR') | ||
17 | self.distro = get_bb_var('NATIVELSBSTRING') | ||
18 | self.distro_specific_sstate = os.path.join(self.sstate_path, self.distro) | ||
19 | |||
20 | # Creates a special sstate configuration with the option to add sstate mirrors | ||
21 | def config_sstate(self, temp_sstate_location=False, add_local_mirrors=[]): | ||
22 | self.temp_sstate_location = temp_sstate_location | ||
23 | |||
24 | if self.temp_sstate_location: | ||
25 | temp_sstate_path = os.path.join(self.builddir, "temp_sstate_%s" % datetime.datetime.now().strftime('%Y%m%d%H%M%S')) | ||
26 | config_temp_sstate = "SSTATE_DIR = \"%s\"" % temp_sstate_path | ||
27 | self.append_config(config_temp_sstate) | ||
28 | self.track_for_cleanup(temp_sstate_path) | ||
29 | self.sstate_path = get_bb_var('SSTATE_DIR') | ||
30 | self.distro = get_bb_var('NATIVELSBSTRING') | ||
31 | self.distro_specific_sstate = os.path.join(self.sstate_path, self.distro) | ||
32 | |||
33 | if add_local_mirrors: | ||
34 | config_set_sstate_if_not_set = 'SSTATE_MIRRORS ?= ""' | ||
35 | self.append_config(config_set_sstate_if_not_set) | ||
36 | for local_mirror in add_local_mirrors: | ||
37 | self.assertFalse(os.path.join(local_mirror) == os.path.join(self.sstate_path), msg='Cannot add the current sstate path as a sstate mirror') | ||
38 | config_sstate_mirror = "SSTATE_MIRRORS += \"file://.* file:///%s/PATH\"" % local_mirror | ||
39 | self.append_config(config_sstate_mirror) | ||
40 | |||
41 | # Returns a list containing sstate files | ||
42 | def search_sstate(self, filename_regex, distro_specific=True, distro_nonspecific=True): | ||
43 | result = [] | ||
44 | for root, dirs, files in os.walk(self.sstate_path): | ||
45 | if distro_specific and re.search("%s/[a-z0-9]{2}$" % self.distro, root): | ||
46 | for f in files: | ||
47 | if re.search(filename_regex, f): | ||
48 | result.append(f) | ||
49 | if distro_nonspecific and re.search("%s/[a-z0-9]{2}$" % self.sstate_path, root): | ||
50 | for f in files: | ||
51 | if re.search(filename_regex, f): | ||
52 | result.append(f) | ||
53 | return result | ||
diff --git a/meta/lib/oeqa/selftest/sstatetests.py b/meta/lib/oeqa/selftest/sstatetests.py new file mode 100644 index 0000000000..35ff28b04a --- /dev/null +++ b/meta/lib/oeqa/selftest/sstatetests.py | |||
@@ -0,0 +1,193 @@ | |||
1 | import datetime | ||
2 | import unittest | ||
3 | import os | ||
4 | import re | ||
5 | import shutil | ||
6 | |||
7 | import oeqa.utils.ftools as ftools | ||
8 | from oeqa.selftest.base import oeSelfTest | ||
9 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer | ||
10 | from oeqa.selftest.sstate import SStateBase | ||
11 | |||
12 | |||
13 | class SStateTests(SStateBase): | ||
14 | |||
15 | # Test sstate files creation and their location | ||
16 | def run_test_sstate_creation(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True, should_pass=True): | ||
17 | self.config_sstate(temp_sstate_location) | ||
18 | |||
19 | if self.temp_sstate_location: | ||
20 | bitbake(['-cclean'] + targets) | ||
21 | else: | ||
22 | bitbake(['-ccleansstate'] + targets) | ||
23 | |||
24 | bitbake(targets) | ||
25 | file_tracker = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific) | ||
26 | if should_pass: | ||
27 | self.assertTrue(file_tracker , msg="Could not find sstate files for: %s" % ', '.join(map(str, targets))) | ||
28 | else: | ||
29 | self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s" % ', '.join(map(str, targets))) | ||
30 | |||
31 | def test_sstate_creation_distro_specific_pass(self): | ||
32 | self.run_test_sstate_creation(['binutils-cross', 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) | ||
33 | |||
34 | def test_sstate_creation_distro_specific_fail(self): | ||
35 | self.run_test_sstate_creation(['binutils-cross', 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False) | ||
36 | |||
37 | def test_sstate_creation_distro_nonspecific_pass(self): | ||
38 | self.run_test_sstate_creation(['eglibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) | ||
39 | |||
40 | def test_sstate_creation_distro_nonspecific_fail(self): | ||
41 | self.run_test_sstate_creation(['eglibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False) | ||
42 | |||
43 | |||
44 | # Test the sstate files deletion part of the do_cleansstate task | ||
45 | def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True): | ||
46 | self.config_sstate(temp_sstate_location) | ||
47 | |||
48 | bitbake(['-ccleansstate'] + targets) | ||
49 | |||
50 | bitbake(targets) | ||
51 | tgz_created = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific) | ||
52 | self.assertTrue(tgz_created, msg="Could not find sstate .tgz files for: %s" % ', '.join(map(str, targets))) | ||
53 | |||
54 | siginfo_created = self.search_sstate('|'.join(map(str, [s + '.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific) | ||
55 | self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s" % ', '.join(map(str, targets))) | ||
56 | |||
57 | bitbake(['-ccleansstate'] + targets) | ||
58 | tgz_removed = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific) | ||
59 | self.assertTrue(not tgz_removed, msg="do_cleansstate didn't remove .tgz sstate files for: %s" % ', '.join(map(str, targets))) | ||
60 | |||
61 | def test_cleansstate_task_distro_specific_nonspecific(self): | ||
62 | self.run_test_cleansstate_task(['binutils-cross', 'binutils-native', 'eglibc-initial'], distro_specific=True, distro_nonspecific=True, temp_sstate_location=True) | ||
63 | |||
64 | def test_cleansstate_task_distro_nonspecific(self): | ||
65 | self.run_test_cleansstate_task(['eglibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) | ||
66 | |||
67 | def test_cleansstate_task_distro_specific(self): | ||
68 | self.run_test_cleansstate_task(['binutils-cross', 'binutils-native', 'eglibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) | ||
69 | |||
70 | |||
71 | # Test rebuilding of distro-specific sstate files | ||
72 | def run_test_rebuild_distro_specific_sstate(self, targets, temp_sstate_location=True): | ||
73 | self.config_sstate(temp_sstate_location) | ||
74 | |||
75 | bitbake(['-ccleansstate'] + targets) | ||
76 | |||
77 | bitbake(targets) | ||
78 | self.assertTrue(self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific=False, distro_nonspecific=True) == [], msg="Found distro non-specific sstate for: %s" % ', '.join(map(str, targets))) | ||
79 | file_tracker_1 = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False) | ||
80 | self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets))) | ||
81 | |||
82 | self.track_for_cleanup(self.distro_specific_sstate + "_old") | ||
83 | shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old") | ||
84 | shutil.rmtree(self.distro_specific_sstate) | ||
85 | |||
86 | bitbake(['-cclean'] + targets) | ||
87 | bitbake(targets) | ||
88 | file_tracker_2 = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False) | ||
89 | self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets))) | ||
90 | |||
91 | not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2] | ||
92 | self.assertTrue(not_recreated == [], msg="The following sstate files ware not recreated: %s" % ', '.join(map(str, not_recreated))) | ||
93 | |||
94 | created_once = [x for x in file_tracker_2 if x not in file_tracker_1] | ||
95 | self.assertTrue(created_once == [], msg="The following sstate files ware created only in the second run: %s" % ', '.join(map(str, created_once))) | ||
96 | |||
97 | def test_rebuild_distro_specific_sstate_cross_native_targets(self): | ||
98 | self.run_test_rebuild_distro_specific_sstate(['binutils-cross', 'binutils-native'], temp_sstate_location=True) | ||
99 | |||
100 | def test_rebuild_distro_specific_sstate_cross_target(self): | ||
101 | self.run_test_rebuild_distro_specific_sstate(['binutils-cross'], temp_sstate_location=True) | ||
102 | |||
103 | def test_rebuild_distro_specific_sstate_native_target(self): | ||
104 | self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True) | ||
105 | |||
106 | |||
107 | # Test the sstate-cache-management script. Each element in the global_config list is used with the corresponding element in the target_config list | ||
108 | # global_config elements are expected to not generate any sstate files that would be removed by sstate-cache-management.sh (such as changing the value of MACHINE) | ||
109 | def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]): | ||
110 | self.assertTrue(global_config) | ||
111 | self.assertTrue(target_config) | ||
112 | self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements') | ||
113 | self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path]) | ||
114 | |||
115 | # If buildhistory is enabled, we need to disable version-going-backwards QA checks for this test. It may report errors otherwise. | ||
116 | if ('buildhistory' in get_bb_var('USER_CLASSES')) or ('buildhistory' in get_bb_var('INHERIT')): | ||
117 | remove_errors_config = 'ERROR_QA_remove = "version-going-backwards"' | ||
118 | self.append_config(remove_errors_config) | ||
119 | |||
120 | # For not this only checks if random sstate tasks are handled correctly as a group. | ||
121 | # In the future we should add control over what tasks we check for. | ||
122 | |||
123 | sstate_archs_list = [] | ||
124 | expected_remaining_sstate = [] | ||
125 | for idx in range(len(target_config)): | ||
126 | self.append_config(global_config[idx]) | ||
127 | self.append_recipeinc(target, target_config[idx]) | ||
128 | sstate_arch = get_bb_var('SSTATE_PKGARCH', target) | ||
129 | if not sstate_arch in sstate_archs_list: | ||
130 | sstate_archs_list.append(sstate_arch) | ||
131 | if target_config[idx] == target_config[-1]: | ||
132 | target_sstate_before_build = self.search_sstate(target + '.*?\.tgz$') | ||
133 | bitbake("-cclean %s" % target) | ||
134 | result = bitbake(target, ignore_status=True) | ||
135 | if target_config[idx] == target_config[-1]: | ||
136 | target_sstate_after_build = self.search_sstate(target + '.*?\.tgz$') | ||
137 | expected_remaining_sstate += [x for x in target_sstate_after_build if x not in target_sstate_before_build if not any(pattern in x for pattern in ignore_patterns)] | ||
138 | self.remove_config(global_config[idx]) | ||
139 | self.remove_recipeinc(target, target_config[idx]) | ||
140 | self.assertEqual(result.status, 0) | ||
141 | |||
142 | runCmd("sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ','.join(map(str, sstate_archs_list)))) | ||
143 | actual_remaining_sstate = [x for x in self.search_sstate(target + '.*?\.tgz$') if not any(pattern in x for pattern in ignore_patterns)] | ||
144 | |||
145 | actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate] | ||
146 | self.assertFalse(actual_not_expected, msg="Files should have been removed but ware not: %s" % ', '.join(map(str, actual_not_expected))) | ||
147 | expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate] | ||
148 | self.assertFalse(expected_not_actual, msg="Extra files ware removed: %s" ', '.join(map(str, expected_not_actual))) | ||
149 | |||
150 | |||
151 | def test_sstate_cache_management_script_using_pr_1(self): | ||
152 | global_config = [] | ||
153 | target_config = [] | ||
154 | global_config.append('') | ||
155 | target_config.append('PR = "0"') | ||
156 | self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) | ||
157 | |||
158 | def test_sstate_cache_management_script_using_pr_2(self): | ||
159 | global_config = [] | ||
160 | target_config = [] | ||
161 | global_config.append('') | ||
162 | target_config.append('PR = "0"') | ||
163 | global_config.append('') | ||
164 | target_config.append('PR = "1"') | ||
165 | self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) | ||
166 | |||
167 | def test_sstate_cache_management_script_using_pr_3(self): | ||
168 | global_config = [] | ||
169 | target_config = [] | ||
170 | global_config.append('MACHINE = "qemux86-64"') | ||
171 | target_config.append('PR = "0"') | ||
172 | global_config.append(global_config[0]) | ||
173 | target_config.append('PR = "1"') | ||
174 | global_config.append('MACHINE = "qemux86"') | ||
175 | target_config.append('PR = "1"') | ||
176 | self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) | ||
177 | |||
178 | def test_sstate_cache_management_script_using_machine(self): | ||
179 | global_config = [] | ||
180 | target_config = [] | ||
181 | global_config.append('MACHINE = "qemux86-64"') | ||
182 | target_config.append('') | ||
183 | global_config.append('MACHINE = "qemux86"') | ||
184 | target_config.append('') | ||
185 | self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) | ||
186 | |||
187 | |||
188 | |||
189 | |||
190 | |||
191 | |||
192 | |||
193 | |||