blob: f763228645064166531e3c300553ef31c618d588 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright OpenEmbedded Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: MIT
5#
6
Brad Bishopd7bf8c12018-02-25 22:55:05 -05007import os
8import shutil
9import glob
10import subprocess
Brad Bishop316dfdd2018-06-25 12:45:53 -040011import tempfile
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050012import datetime
13import re
Brad Bishopd7bf8c12018-02-25 22:55:05 -050014
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050015from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer, get_bb_vars
16from oeqa.selftest.case import OESelftestTestCase
Patrick Williamsac13d5f2023-11-24 18:59:46 -060017from oeqa.core.decorator import OETestTag
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050018
Andrew Geissler595f6302022-01-24 19:11:47 +000019import oe
Brad Bishopd7bf8c12018-02-25 22:55:05 -050020import bb.siggen
21
Patrick Williamsb542dec2023-06-09 01:26:37 -050022# Set to True to preserve stamp files after test execution for debugging failures
23keep_temp_files = False
24
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050025class SStateBase(OESelftestTestCase):
26
27 def setUpLocal(self):
28 super(SStateBase, self).setUpLocal()
29 self.temp_sstate_location = None
30 needed_vars = ['SSTATE_DIR', 'NATIVELSBSTRING', 'TCLIBC', 'TUNE_ARCH',
31 'TOPDIR', 'TARGET_VENDOR', 'TARGET_OS']
32 bb_vars = get_bb_vars(needed_vars)
33 self.sstate_path = bb_vars['SSTATE_DIR']
34 self.hostdistro = bb_vars['NATIVELSBSTRING']
35 self.tclibc = bb_vars['TCLIBC']
36 self.tune_arch = bb_vars['TUNE_ARCH']
37 self.topdir = bb_vars['TOPDIR']
38 self.target_vendor = bb_vars['TARGET_VENDOR']
39 self.target_os = bb_vars['TARGET_OS']
40 self.distro_specific_sstate = os.path.join(self.sstate_path, self.hostdistro)
41
Patrick Williamsb542dec2023-06-09 01:26:37 -050042 def track_for_cleanup(self, path):
43 if not keep_temp_files:
44 super().track_for_cleanup(path)
45
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050046 # Creates a special sstate configuration with the option to add sstate mirrors
47 def config_sstate(self, temp_sstate_location=False, add_local_mirrors=[]):
48 self.temp_sstate_location = temp_sstate_location
49
50 if self.temp_sstate_location:
51 temp_sstate_path = os.path.join(self.builddir, "temp_sstate_%s" % datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
52 config_temp_sstate = "SSTATE_DIR = \"%s\"" % temp_sstate_path
53 self.append_config(config_temp_sstate)
54 self.track_for_cleanup(temp_sstate_path)
55 bb_vars = get_bb_vars(['SSTATE_DIR', 'NATIVELSBSTRING'])
56 self.sstate_path = bb_vars['SSTATE_DIR']
57 self.hostdistro = bb_vars['NATIVELSBSTRING']
58 self.distro_specific_sstate = os.path.join(self.sstate_path, self.hostdistro)
59
60 if add_local_mirrors:
61 config_set_sstate_if_not_set = 'SSTATE_MIRRORS ?= ""'
62 self.append_config(config_set_sstate_if_not_set)
63 for local_mirror in add_local_mirrors:
64 self.assertFalse(os.path.join(local_mirror) == os.path.join(self.sstate_path), msg='Cannot add the current sstate path as a sstate mirror')
65 config_sstate_mirror = "SSTATE_MIRRORS += \"file://.* file:///%s/PATH\"" % local_mirror
66 self.append_config(config_sstate_mirror)
67
68 # Returns a list containing sstate files
69 def search_sstate(self, filename_regex, distro_specific=True, distro_nonspecific=True):
70 result = []
71 for root, dirs, files in os.walk(self.sstate_path):
72 if distro_specific and re.search(r"%s/%s/[a-z0-9]{2}/[a-z0-9]{2}$" % (self.sstate_path, self.hostdistro), root):
73 for f in files:
74 if re.search(filename_regex, f):
75 result.append(f)
76 if distro_nonspecific and re.search(r"%s/[a-z0-9]{2}/[a-z0-9]{2}$" % self.sstate_path, root):
77 for f in files:
78 if re.search(filename_regex, f):
79 result.append(f)
80 return result
81
82 # Test sstate files creation and their location
83 def run_test_sstate_creation(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True, should_pass=True):
84 self.config_sstate(temp_sstate_location, [self.sstate_path])
85
86 if self.temp_sstate_location:
87 bitbake(['-cclean'] + targets)
88 else:
89 bitbake(['-ccleansstate'] + targets)
90
91 bitbake(targets)
92 file_tracker = []
93 results = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific)
94 if distro_nonspecific:
95 for r in results:
96 if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo", "_fetch.tar.zst.siginfo", "_unpack.tar.zst.siginfo", "_patch.tar.zst.siginfo")):
97 continue
98 file_tracker.append(r)
99 else:
100 file_tracker = results
101
102 if should_pass:
103 self.assertTrue(file_tracker , msg="Could not find sstate files for: %s" % ', '.join(map(str, targets)))
104 else:
105 self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s (found %s)" % (', '.join(map(str, targets)), str(file_tracker)))
106
107 # Test the sstate files deletion part of the do_cleansstate task
108 def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True):
109 self.config_sstate(temp_sstate_location, [self.sstate_path])
110
111 bitbake(['-ccleansstate'] + targets)
112
113 bitbake(targets)
114 archives_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific)
115 self.assertTrue(archives_created, msg="Could not find sstate .tar.zst files for: %s (%s)" % (', '.join(map(str, targets)), str(archives_created)))
116
117 siginfo_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific)
118 self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s (%s)" % (', '.join(map(str, targets)), str(siginfo_created)))
119
120 bitbake(['-ccleansstate'] + targets)
121 archives_removed = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific)
122 self.assertTrue(not archives_removed, msg="do_cleansstate didn't remove .tar.zst sstate files for: %s (%s)" % (', '.join(map(str, targets)), str(archives_removed)))
123
124 # Test rebuilding of distro-specific sstate files
125 def run_test_rebuild_distro_specific_sstate(self, targets, temp_sstate_location=True):
126 self.config_sstate(temp_sstate_location, [self.sstate_path])
127
128 bitbake(['-ccleansstate'] + targets)
129
130 bitbake(targets)
131 results = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=False, distro_nonspecific=True)
132 filtered_results = []
133 for r in results:
134 if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo")):
135 continue
136 filtered_results.append(r)
137 self.assertTrue(filtered_results == [], msg="Found distro non-specific sstate for: %s (%s)" % (', '.join(map(str, targets)), str(filtered_results)))
138 file_tracker_1 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False)
139 self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets)))
140
141 self.track_for_cleanup(self.distro_specific_sstate + "_old")
142 shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old")
143 shutil.rmtree(self.distro_specific_sstate)
144
145 bitbake(['-cclean'] + targets)
146 bitbake(targets)
147 file_tracker_2 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False)
148 self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets)))
149
150 not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2]
151 self.assertTrue(not_recreated == [], msg="The following sstate files were not recreated: %s" % ', '.join(map(str, not_recreated)))
152
153 created_once = [x for x in file_tracker_2 if x not in file_tracker_1]
154 self.assertTrue(created_once == [], msg="The following sstate files were created only in the second run: %s" % ', '.join(map(str, created_once)))
155
156 def sstate_common_samesigs(self, configA, configB, allarch=False):
157
158 self.write_config(configA)
159 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
160 bitbake("world meta-toolchain -S none")
161 self.write_config(configB)
162 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
163 bitbake("world meta-toolchain -S none")
164
165 def get_files(d, result):
166 for root, dirs, files in os.walk(d):
167 for name in files:
168 if "meta-environment" in root or "cross-canadian" in root:
169 continue
170 if "do_build" not in name:
171 # 1.4.1+gitAUTOINC+302fca9f4c-r0.do_package_write_ipk.sigdata.f3a2a38697da743f0dbed8b56aafcf79
172 (_, task, _, shash) = name.rsplit(".", 3)
173 result[os.path.join(os.path.basename(root), task)] = shash
174
175 files1 = {}
176 files2 = {}
177 subdirs = sorted(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux"))
178 if allarch:
179 subdirs.extend(sorted(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/all-*-linux")))
180
181 for subdir in subdirs:
182 nativesdkdir = os.path.basename(subdir)
183 get_files(self.topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir, files1)
184 get_files(self.topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir, files2)
185
186 self.maxDiff = None
187 self.assertEqual(files1, files2)
188
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500189class SStateTests(SStateBase):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400190 def test_autorev_sstate_works(self):
191 # Test that a git repository which changes is correctly handled by SRCREV = ${AUTOREV}
Brad Bishop316dfdd2018-06-25 12:45:53 -0400192
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500193 tempdir = tempfile.mkdtemp(prefix='sstate_autorev')
194 tempdldir = tempfile.mkdtemp(prefix='sstate_autorev_dldir')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400195 self.track_for_cleanup(tempdir)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500196 self.track_for_cleanup(tempdldir)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400197 create_temp_layer(tempdir, 'selftestrecipetool')
198 self.add_command_to_tearDown('bitbake-layers remove-layer %s' % tempdir)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500199 self.append_config("DL_DIR = \"%s\"" % tempdldir)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400200 runCmd('bitbake-layers add-layer %s' % tempdir)
201
202 # Use dbus-wait as a local git repo we can add a commit between two builds in
203 pn = 'dbus-wait'
204 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
205 url = 'git://git.yoctoproject.org/dbus-wait'
206 result = runCmd('git clone %s noname' % url, cwd=tempdir)
207 srcdir = os.path.join(tempdir, 'noname')
208 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
209 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
210
211 recipefile = os.path.join(tempdir, "recipes-test", "dbus-wait-test", 'dbus-wait-test_git.bb')
212 os.makedirs(os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000213 srcuri = 'git://' + srcdir + ';protocol=file;branch=master'
Brad Bishop316dfdd2018-06-25 12:45:53 -0400214 result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri])
215 self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output)
216
217 with open(recipefile, 'a') as f:
218 f.write('SRCREV = "${AUTOREV}"\n')
219 f.write('PV = "1.0"\n')
220
221 bitbake("dbus-wait-test -c fetch")
222 with open(os.path.join(srcdir, "bar.txt"), "w") as f:
223 f.write("foo")
224 result = runCmd('git add bar.txt; git commit -asm "add bar"', cwd=srcdir)
225 bitbake("dbus-wait-test -c unpack")
226
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500227class SStateCreation(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500228 def test_sstate_creation_distro_specific_pass(self):
229 self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
230
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500231 def test_sstate_creation_distro_specific_fail(self):
232 self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False)
233
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500234 def test_sstate_creation_distro_nonspecific_pass(self):
235 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
236
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500237 def test_sstate_creation_distro_nonspecific_fail(self):
238 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False)
239
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500240class SStateCleanup(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500241 def test_cleansstate_task_distro_specific_nonspecific(self):
242 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
243 targets.append('linux-libc-headers')
244 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True)
245
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500246 def test_cleansstate_task_distro_nonspecific(self):
247 self.run_test_cleansstate_task(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
248
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500249 def test_cleansstate_task_distro_specific(self):
250 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
251 targets.append('linux-libc-headers')
252 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
253
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500254class SStateDistroTests(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500255 def test_rebuild_distro_specific_sstate_cross_native_targets(self):
256 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch, 'binutils-native'], temp_sstate_location=True)
257
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500258 def test_rebuild_distro_specific_sstate_cross_target(self):
259 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch], temp_sstate_location=True)
260
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500261 def test_rebuild_distro_specific_sstate_native_target(self):
262 self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True)
263
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500264class SStateCacheManagement(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500265 # Test the sstate-cache-management script. Each element in the global_config list is used with the corresponding element in the target_config list
Patrick Williams169d7bc2024-01-05 11:33:25 -0600266 # global_config elements are expected to not generate any sstate files that would be removed by sstate-cache-management.py (such as changing the value of MACHINE)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500267 def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]):
268 self.assertTrue(global_config)
269 self.assertTrue(target_config)
270 self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements')
271 self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path])
272
273 # If buildhistory is enabled, we need to disable version-going-backwards
274 # QA checks for this test. It may report errors otherwise.
Patrick Williams213cb262021-08-07 19:21:33 -0500275 self.append_config('ERROR_QA:remove = "version-going-backwards"')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500276
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000277 # For now this only checks if random sstate tasks are handled correctly as a group.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500278 # In the future we should add control over what tasks we check for.
279
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500280 expected_remaining_sstate = []
281 for idx in range(len(target_config)):
282 self.append_config(global_config[idx])
283 self.append_recipeinc(target, target_config[idx])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500284 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500285 target_sstate_before_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500286 bitbake("-cclean %s" % target)
287 result = bitbake(target, ignore_status=True)
288 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500289 target_sstate_after_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500290 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)]
291 self.remove_config(global_config[idx])
292 self.remove_recipeinc(target, target_config[idx])
293 self.assertEqual(result.status, 0, msg = "build of %s failed with %s" % (target, result.output))
294
Patrick Williams169d7bc2024-01-05 11:33:25 -0600295 runCmd("sstate-cache-management.py -y --cache-dir=%s --remove-duplicated" % (self.sstate_path))
Andrew Geisslereff27472021-10-29 15:35:00 -0500296 actual_remaining_sstate = [x for x in self.search_sstate(target + r'.*?\.tar.zst$') if not any(pattern in x for pattern in ignore_patterns)]
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500297
298 actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500299 self.assertFalse(actual_not_expected, msg="Files should have been removed but were not: %s" % ', '.join(map(str, actual_not_expected)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500300 expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500301 self.assertFalse(expected_not_actual, msg="Extra files were removed: %s" ', '.join(map(str, expected_not_actual)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500303 def test_sstate_cache_management_script_using_pr_1(self):
304 global_config = []
305 target_config = []
306 global_config.append('')
307 target_config.append('PR = "0"')
308 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
309
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 def test_sstate_cache_management_script_using_pr_2(self):
311 global_config = []
312 target_config = []
313 global_config.append('')
314 target_config.append('PR = "0"')
315 global_config.append('')
316 target_config.append('PR = "1"')
317 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
318
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500319 def test_sstate_cache_management_script_using_pr_3(self):
320 global_config = []
321 target_config = []
322 global_config.append('MACHINE = "qemux86-64"')
323 target_config.append('PR = "0"')
324 global_config.append(global_config[0])
325 target_config.append('PR = "1"')
326 global_config.append('MACHINE = "qemux86"')
327 target_config.append('PR = "1"')
328 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
329
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500330 def test_sstate_cache_management_script_using_machine(self):
331 global_config = []
332 target_config = []
333 global_config.append('MACHINE = "qemux86-64"')
334 target_config.append('')
335 global_config.append('MACHINE = "qemux86"')
336 target_config.append('')
337 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
338
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500339class SStateHashSameSigs(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500340 def test_sstate_32_64_same_hash(self):
341 """
342 The sstate checksums for both native and target should not vary whether
343 they're built on a 32 or 64 bit system. Rather than requiring two different
344 build machines and running a builds, override the variables calling uname()
345 manually and check using bitbake -S.
346 """
347
348 self.write_config("""
349MACHINE = "qemux86"
350TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800351TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500352BUILD_ARCH = "x86_64"
353BUILD_OS = "linux"
354SDKMACHINE = "x86_64"
355PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500356BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500357""")
358 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500359 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360 self.write_config("""
361MACHINE = "qemux86"
362TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800363TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500364BUILD_ARCH = "i686"
365BUILD_OS = "linux"
366SDKMACHINE = "i686"
367PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500368BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500369""")
370 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500371 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500372
373 def get_files(d):
374 f = []
375 for root, dirs, files in os.walk(d):
Andrew Geisslerc926e172021-05-07 16:11:35 -0500376 if "core-image-weston" in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500377 # SDKMACHINE changing will change
378 # do_rootfs/do_testimage/do_build stamps of images which
379 # is safe to ignore.
380 continue
381 f.extend(os.path.join(root, name) for name in files)
382 return f
383 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
384 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
385 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash").replace("i686-linux", "x86_64-linux").replace("i686" + self.target_vendor + "-linux", "x86_64" + self.target_vendor + "-linux", ) for x in files2]
386 self.maxDiff = None
387 self.assertCountEqual(files1, files2)
388
389
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500390 def test_sstate_nativelsbstring_same_hash(self):
391 """
392 The sstate checksums should be independent of whichever NATIVELSBSTRING is
393 detected. Rather than requiring two different build machines and running
394 builds, override the variables manually and check using bitbake -S.
395 """
396
397 self.write_config("""
398TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800399TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500400NATIVELSBSTRING = \"DistroA\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500401BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500402""")
403 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500404 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500405 self.write_config("""
406TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800407TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500408NATIVELSBSTRING = \"DistroB\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500409BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500410""")
411 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500412 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500413
414 def get_files(d):
415 f = []
416 for root, dirs, files in os.walk(d):
417 f.extend(os.path.join(root, name) for name in files)
418 return f
419 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
420 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
421 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
422 self.maxDiff = None
423 self.assertCountEqual(files1, files2)
424
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500425class SStateHashSameSigs2(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500426 def test_sstate_allarch_samesigs(self):
427 """
428 The sstate checksums of allarch packages should be independent of whichever
429 MACHINE is set. Check this using bitbake -S.
430 Also, rather than duplicate the test, check nativesdk stamps are the same between
431 the two MACHINE values.
432 """
433
434 configA = """
435TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800436TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500437MACHINE = \"qemux86-64\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500438BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500439"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000440 #OLDEST_KERNEL is arch specific so set to a different value here for testing
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500441 configB = """
442TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800443TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500444MACHINE = \"qemuarm\"
Andrew Geissler595f6302022-01-24 19:11:47 +0000445OLDEST_KERNEL = \"3.3.0\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500446BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500447"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000448 self.sstate_common_samesigs(configA, configB, allarch=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500449
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800450 def test_sstate_nativesdk_samesigs_multilib(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500451 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800452 check nativesdk stamps are the same between the two MACHINE values.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500453 """
454
455 configA = """
456TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800457TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500458MACHINE = \"qemux86-64\"
459require conf/multilib.conf
460MULTILIBS = \"multilib:lib32\"
Patrick Williams213cb262021-08-07 19:21:33 -0500461DEFAULTTUNE:virtclass-multilib-lib32 = \"x86\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500462BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500463"""
464 configB = """
465TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800466TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500467MACHINE = \"qemuarm\"
468require conf/multilib.conf
469MULTILIBS = \"\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500470BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500471"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000472 self.sstate_common_samesigs(configA, configB)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500473
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500474class SStateHashSameSigs3(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500475 def test_sstate_sametune_samesigs(self):
476 """
477 The sstate checksums of two identical machines (using the same tune) should be the
478 same, apart from changes within the machine specific stamps directory. We use the
479 qemux86copy machine to test this. Also include multilibs in the test.
480 """
481
482 self.write_config("""
483TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800484TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500485MACHINE = \"qemux86\"
486require conf/multilib.conf
487MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500488DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500489BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500490""")
491 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
492 bitbake("world meta-toolchain -S none")
493 self.write_config("""
494TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800495TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500496MACHINE = \"qemux86copy\"
497require conf/multilib.conf
498MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500499DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500500BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500501""")
502 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
503 bitbake("world meta-toolchain -S none")
504
505 def get_files(d):
506 f = []
507 for root, dirs, files in os.walk(d):
508 for name in files:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500509 if "meta-environment" in root or "cross-canadian" in root or 'meta-ide-support' in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500510 continue
511 if "qemux86copy-" in root or "qemux86-" in root:
512 continue
513 if "do_build" not in name and "do_populate_sdk" not in name:
514 f.append(os.path.join(root, name))
515 return f
516 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
517 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
518 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
519 self.maxDiff = None
520 self.assertCountEqual(files1, files2)
521
522
Andrew Geissler82c905d2020-04-13 13:39:40 -0500523 def test_sstate_multilib_or_not_native_samesigs(self):
524 """The sstate checksums of two native recipes (and their dependencies)
525 where the target is using multilib in one but not the other
526 should be the same. We use the qemux86copy machine to test
527 this.
528 """
529
530 self.write_config("""
531TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
532TCLIBCAPPEND = \"\"
533MACHINE = \"qemux86\"
534require conf/multilib.conf
535MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500536DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Andrew Geissler82c905d2020-04-13 13:39:40 -0500537BB_SIGNATURE_HANDLER = "OEBasicHash"
538""")
539 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
540 bitbake("binutils-native -S none")
541 self.write_config("""
542TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
543TCLIBCAPPEND = \"\"
544MACHINE = \"qemux86copy\"
545BB_SIGNATURE_HANDLER = "OEBasicHash"
546""")
547 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
548 bitbake("binutils-native -S none")
549
550 def get_files(d):
551 f = []
552 for root, dirs, files in os.walk(d):
553 for name in files:
554 f.append(os.path.join(root, name))
555 return f
556 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
557 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
558 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
559 self.maxDiff = None
560 self.assertCountEqual(files1, files2)
561
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500562class SStateHashSameSigs4(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500563 def test_sstate_noop_samesigs(self):
564 """
565 The sstate checksums of two builds with these variables changed or
566 classes inherits should be the same.
567 """
568
569 self.write_config("""
570TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800571TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500572BB_NUMBER_THREADS = "${@oe.utils.cpu_count()}"
573PARALLEL_MAKE = "-j 1"
574DL_DIR = "${TOPDIR}/download1"
575TIME = "111111"
576DATE = "20161111"
Patrick Williams213cb262021-08-07 19:21:33 -0500577INHERIT:remove = "buildstats-summary buildhistory uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500578http_proxy = ""
Brad Bishop6dbb3162019-11-25 09:41:34 -0500579BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500580""")
581 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
582 self.track_for_cleanup(self.topdir + "/download1")
583 bitbake("world meta-toolchain -S none")
584 self.write_config("""
585TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800586TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500587BB_NUMBER_THREADS = "${@oe.utils.cpu_count()+1}"
588PARALLEL_MAKE = "-j 2"
589DL_DIR = "${TOPDIR}/download2"
590TIME = "222222"
591DATE = "20161212"
592# Always remove uninative as we're changing proxies
Patrick Williams213cb262021-08-07 19:21:33 -0500593INHERIT:remove = "uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500594INHERIT += "buildstats-summary buildhistory"
595http_proxy = "http://example.com/"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500596BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500597""")
598 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
599 self.track_for_cleanup(self.topdir + "/download2")
600 bitbake("world meta-toolchain -S none")
601
602 def get_files(d):
603 f = {}
604 for root, dirs, files in os.walk(d):
605 for name in files:
606 name, shash = name.rsplit('.', 1)
607 # Extract just the machine and recipe name
608 base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name])
609 f[base] = shash
610 return f
611
612 def compare_sigfiles(files, files1, files2, compare=False):
613 for k in files:
614 if k in files1 and k in files2:
615 print("%s differs:" % k)
616 if compare:
617 sigdatafile1 = self.topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k]
618 sigdatafile2 = self.topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]
619 output = bb.siggen.compare_sigfiles(sigdatafile1, sigdatafile2)
620 if output:
621 print('\n'.join(output))
622 elif k in files1 and k not in files2:
623 print("%s in files1" % k)
624 elif k not in files1 and k in files2:
625 print("%s in files2" % k)
626 else:
627 assert "shouldn't reach here"
628
629 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
630 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
631 # Remove items that are identical in both sets
632 for k,v in files1.items() & files2.items():
633 del files1[k]
634 del files2[k]
635 if not files1 and not files2:
636 # No changes, so we're done
637 return
638
639 files = list(files1.keys() | files2.keys())
640 # this is an expensive computation, thus just compare the first 'max_sigfiles_to_compare' k files
641 max_sigfiles_to_compare = 20
642 first, rest = files[:max_sigfiles_to_compare], files[max_sigfiles_to_compare:]
Brad Bishop316dfdd2018-06-25 12:45:53 -0400643 compare_sigfiles(first, files1, files2, compare=True)
644 compare_sigfiles(rest, files1, files2, compare=False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500645
646 self.fail("sstate hashes not identical.")
Andrew Geissler595f6302022-01-24 19:11:47 +0000647
648 def test_sstate_movelayer_samesigs(self):
649 """
650 The sstate checksums of two builds with the same oe-core layer in two
651 different locations should be the same.
652 """
653 core_layer = os.path.join(
654 self.tc.td["COREBASE"], 'meta')
655 copy_layer_1 = self.topdir + "/meta-copy1/meta"
656 copy_layer_2 = self.topdir + "/meta-copy2/meta"
657
658 oe.path.copytree(core_layer, copy_layer_1)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500659 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy1/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000660 self.write_config("""
661TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
662""")
663 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_1, core_layer)
664 self.write_bblayers_config(bblayers_conf)
665 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
666 bitbake("bash -S none")
667
668 oe.path.copytree(core_layer, copy_layer_2)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500669 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy2/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000670 self.write_config("""
671TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
672""")
673 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_2, core_layer)
674 self.write_bblayers_config(bblayers_conf)
675 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
676 bitbake("bash -S none")
677
678 def get_files(d):
679 f = []
680 for root, dirs, files in os.walk(d):
681 for name in files:
682 f.append(os.path.join(root, name))
683 return f
684 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
685 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
686 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
687 self.maxDiff = None
688 self.assertCountEqual(files1, files2)
689
Patrick Williams2a254922023-08-11 09:48:11 -0500690class SStateFindSiginfo(SStateBase):
691 def test_sstate_compare_sigfiles_and_find_siginfo(self):
692 """
693 Test the functionality of the find_siginfo: basic function and callback in compare_sigfiles
694 """
695 self.write_config("""
696TMPDIR = \"${TOPDIR}/tmp-sstates-findsiginfo\"
697TCLIBCAPPEND = \"\"
698MACHINE = \"qemux86-64\"
699require conf/multilib.conf
700MULTILIBS = "multilib:lib32"
701DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
702BB_SIGNATURE_HANDLER = "OEBasicHash"
703""")
704 self.track_for_cleanup(self.topdir + "/tmp-sstates-findsiginfo")
705
706 pns = ["binutils", "binutils-native", "lib32-binutils"]
707 target_configs = [
708"""
709TMPVAL1 = "tmpval1"
710TMPVAL2 = "tmpval2"
711do_tmptask1() {
712 echo ${TMPVAL1}
713}
714do_tmptask2() {
715 echo ${TMPVAL2}
716}
717addtask do_tmptask1
718addtask tmptask2 before do_tmptask1
719""",
720"""
721TMPVAL3 = "tmpval3"
722TMPVAL4 = "tmpval4"
723do_tmptask1() {
724 echo ${TMPVAL3}
725}
726do_tmptask2() {
727 echo ${TMPVAL4}
728}
729addtask do_tmptask1
730addtask tmptask2 before do_tmptask1
731"""
732 ]
733
734 for target_config in target_configs:
735 self.write_recipeinc("binutils", target_config)
736 for pn in pns:
737 bitbake("%s -c do_tmptask1 -S none" % pn)
738 self.delete_recipeinc("binutils")
739
740 with bb.tinfoil.Tinfoil() as tinfoil:
741 tinfoil.prepare(config_only=True)
742
743 def find_siginfo(pn, taskname, sigs=None):
744 result = None
745 tinfoil.set_event_mask(["bb.event.FindSigInfoResult",
746 "bb.command.CommandCompleted"])
747 ret = tinfoil.run_command("findSigInfo", pn, taskname, sigs)
748 if ret:
749 while True:
750 event = tinfoil.wait_event(1)
751 if event:
752 if isinstance(event, bb.command.CommandCompleted):
753 break
754 elif isinstance(event, bb.event.FindSigInfoResult):
755 result = event.result
756 return result
757
758 def recursecb(key, hash1, hash2):
759 nonlocal recursecb_count
760 recursecb_count += 1
761 hashes = [hash1, hash2]
762 hashfiles = find_siginfo(key, None, hashes)
763 self.assertCountEqual(hashes, hashfiles)
Patrick Williams169d7bc2024-01-05 11:33:25 -0600764 bb.siggen.compare_sigfiles(hashfiles[hash1]['path'], hashfiles[hash2]['path'], recursecb)
Patrick Williams2a254922023-08-11 09:48:11 -0500765
766 for pn in pns:
767 recursecb_count = 0
Patrick Williams169d7bc2024-01-05 11:33:25 -0600768 matches = find_siginfo(pn, "do_tmptask1")
769 self.assertGreaterEqual(len(matches), 2)
770 latesthashes = sorted(matches.keys(), key=lambda h: matches[h]['time'])[-2:]
771 bb.siggen.compare_sigfiles(matches[latesthashes[-2]]['path'], matches[latesthashes[-1]]['path'], recursecb)
Patrick Williams2a254922023-08-11 09:48:11 -0500772 self.assertEqual(recursecb_count,1)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600773
774class SStatePrintdiff(SStateBase):
775 def run_test_printdiff_changerecipe(self, target, change_recipe, change_bbtask, change_content, expected_sametmp_output, expected_difftmp_output):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600776 import time
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600777 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600778TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-sametmp-{}"
779""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600780 # Use runall do_build to ensure any indirect sstate is created, e.g. tzcode-native on both x86 and
781 # aarch64 hosts since only allarch target recipes depend upon it and it may not be built otherwise.
782 # A bitbake -c cleansstate tzcode-native would cause some of these tests to error for example.
783 bitbake("--runall build --runall deploy_source_date_epoch {}".format(target))
784 bitbake("-S none {}".format(target))
785 bitbake(change_bbtask)
786 self.write_recipeinc(change_recipe, change_content)
787 result_sametmp = bitbake("-S printdiff {}".format(target))
788
789 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600790TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-difftmp-{}"
791""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600792 result_difftmp = bitbake("-S printdiff {}".format(target))
793
794 self.delete_recipeinc(change_recipe)
795 for item in expected_sametmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600796 self.assertIn(item, result_sametmp.output, msg = "Item {} not found in output:\n{}".format(item, result_sametmp.output))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600797 for item in expected_difftmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600798 self.assertIn(item, result_difftmp.output, msg = "Item {} not found in output:\n{}".format(item, result_difftmp.output))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600799
Patrick Williams705982a2024-01-12 09:51:57 -0600800 def run_test_printdiff_changeconfig(self, target, change_bbtasks, change_content, expected_sametmp_output, expected_difftmp_output):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600801 import time
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600802 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600803TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-sametmp-{}"
804""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600805 bitbake("--runall build --runall deploy_source_date_epoch {}".format(target))
806 bitbake("-S none {}".format(target))
Patrick Williams705982a2024-01-12 09:51:57 -0600807 bitbake(" ".join(change_bbtasks))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600808 self.append_config(change_content)
809 result_sametmp = bitbake("-S printdiff {}".format(target))
810
811 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600812TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-difftmp-{}"
813""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600814 self.append_config(change_content)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600815 result_difftmp = bitbake("-S printdiff {}".format(target))
816
817 for item in expected_sametmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600818 self.assertIn(item, result_sametmp.output, msg = "Item {} not found in output:\n{}".format(item, result_sametmp.output))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600819 for item in expected_difftmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600820 self.assertIn(item, result_difftmp.output, msg = "Item {} not found in output:\n{}".format(item, result_difftmp.output))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600821
822
823 # Check if printdiff walks the full dependency chain from the image target to where the change is in a specific recipe
Patrick Williams705982a2024-01-12 09:51:57 -0600824 def test_image_minimal_vs_perlcross(self):
825 expected_output = ("Task perlcross-native:do_install couldn't be used from the cache because:",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600826"We need hash",
827"most recent matching task was")
Patrick Williams705982a2024-01-12 09:51:57 -0600828 expected_sametmp_output = expected_output + (
829"Variable do_install value changed",
830'+ echo "this changes the task signature"')
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600831 expected_difftmp_output = expected_output
832
Patrick Williams705982a2024-01-12 09:51:57 -0600833 self.run_test_printdiff_changerecipe("core-image-minimal", "perlcross", "-c do_install perlcross-native",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600834"""
835do_install:append() {
836 echo "this changes the task signature"
837}
838""",
839expected_sametmp_output, expected_difftmp_output)
840
841 # Check if changes to gcc-source (which uses tmp/work-shared) are correctly discovered
Patrick Williams705982a2024-01-12 09:51:57 -0600842 def test_gcc_runtime_vs_gcc_source(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600843 gcc_source_pn = 'gcc-source-%s' % get_bb_vars(['PV'], 'gcc')['PV']
844
845 expected_output = ("Task {}:do_preconfigure couldn't be used from the cache because:".format(gcc_source_pn),
846"We need hash",
847"most recent matching task was")
Patrick Williams705982a2024-01-12 09:51:57 -0600848 expected_sametmp_output = expected_output + (
849"Variable do_preconfigure value changed",
850'+ print("this changes the task signature")')
851 expected_difftmp_output = expected_output
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600852
853 self.run_test_printdiff_changerecipe("gcc-runtime", "gcc-source", "-c do_preconfigure {}".format(gcc_source_pn),
854"""
855python do_preconfigure:append() {
856 print("this changes the task signature")
857}
858""",
859expected_sametmp_output, expected_difftmp_output)
860
861 # Check if changing a really base task definiton is reported against multiple core recipes using it
862 def test_image_minimal_vs_base_do_configure(self):
Patrick Williams705982a2024-01-12 09:51:57 -0600863 change_bbtasks = ('zstd-native:do_configure',
864'texinfo-dummy-native:do_configure',
865'ldconfig-native:do_configure',
866'gettext-minimal-native:do_configure',
867'tzcode-native:do_configure',
868'makedevs-native:do_configure',
869'pigz-native:do_configure',
870'update-rc.d-native:do_configure',
871'unzip-native:do_configure',
872'gnu-config-native:do_configure')
873
874 expected_output = ["Task {} couldn't be used from the cache because:".format(t) for t in change_bbtasks] + [
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600875"We need hash",
Patrick Williams705982a2024-01-12 09:51:57 -0600876"most recent matching task was"]
877
878 expected_sametmp_output = expected_output + [
879"Variable base_do_configure value changed",
880'+ echo "this changes base_do_configure() definiton "']
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600881 expected_difftmp_output = expected_output
882
Patrick Williams705982a2024-01-12 09:51:57 -0600883 self.run_test_printdiff_changeconfig("core-image-minimal",change_bbtasks,
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600884"""
885INHERIT += "base-do-configure-modified"
886""",
887expected_sametmp_output, expected_difftmp_output)
888
889@OETestTag("yocto-mirrors")
890class SStateMirrors(SStateBase):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600891 def check_bb_output(self, output, exceptions, check_cdn):
892 def is_exception(object, exceptions):
893 for e in exceptions:
894 if re.search(e, object):
895 return True
896 return False
897
898 output_l = output.splitlines()
899 for l in output_l:
900 if l.startswith("Sstate summary"):
901 for idx, item in enumerate(l.split()):
902 if item == 'Missed':
903 missing_objects = int(l.split()[idx+1])
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600904 break
905 else:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600906 self.fail("Did not find missing objects amount in sstate summary: {}".format(l))
907 break
908 else:
909 self.fail("Did not find 'Sstate summary' line in bitbake output")
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600910
Patrick Williams169d7bc2024-01-05 11:33:25 -0600911 failed_urls = []
Patrick Williams705982a2024-01-12 09:51:57 -0600912 failed_urls_extrainfo = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600913 for l in output_l:
914 if "SState: Unsuccessful fetch test for" in l and check_cdn:
915 missing_object = l.split()[6]
916 elif "SState: Looked for but didn't find file" in l and not check_cdn:
917 missing_object = l.split()[8]
918 else:
919 missing_object = None
920 if missing_object:
921 if not is_exception(missing_object, exceptions):
922 failed_urls.append(missing_object)
923 else:
924 missing_objects -= 1
925
Patrick Williams705982a2024-01-12 09:51:57 -0600926 if "urlopen failed for" in l:
927 failed_urls_extrainfo.append(l)
928
929 self.assertEqual(len(failed_urls), missing_objects, "Amount of reported missing objects does not match failed URLs: {}\nFailed URLs:\n{}\nFetcher diagnostics:\n{}".format(missing_objects, "\n".join(failed_urls), "\n".join(failed_urls_extrainfo)))
930 self.assertEqual(len(failed_urls), 0, "Missing objects in the cache:\n{}\nFetcher diagnostics:\n{}".format("\n".join(failed_urls), "\n".join(failed_urls_extrainfo)))
Patrick Williams169d7bc2024-01-05 11:33:25 -0600931
932 def run_test(self, machine, targets, exceptions, check_cdn = True):
933 # sstate is checked for existence of these, but they never get written out to begin with
934 exceptions += ["{}.*image_qa".format(t) for t in targets.split()]
935 exceptions += ["{}.*deploy_source_date_epoch".format(t) for t in targets.split()]
936 exceptions += ["{}.*image_complete".format(t) for t in targets.split()]
937 exceptions += ["linux-yocto.*shared_workdir"]
938 # these get influnced by IMAGE_FSTYPES tweaks in yocto-autobuilder-helper's config.json (on x86-64)
939 # additionally, they depend on noexec (thus, absent stamps) package, install, etc. image tasks,
940 # which makes tracing other changes difficult
941 exceptions += ["{}.*create_spdx".format(t) for t in targets.split()]
942 exceptions += ["{}.*create_runtime_spdx".format(t) for t in targets.split()]
943
944 if check_cdn:
945 self.config_sstate(True)
946 self.append_config("""
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600947MACHINE = "{}"
948BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"
949SSTATE_MIRRORS ?= "file://.* http://cdn.jsdelivr.net/yocto/sstate/all/PATH;downloadfilename=PATH"
950""".format(machine))
Patrick Williams169d7bc2024-01-05 11:33:25 -0600951 else:
952 self.append_config("""
953MACHINE = "{}"
954""".format(machine))
955 result = bitbake("-DD -n {}".format(targets))
956 bitbake("-S none {}".format(targets))
957 self.check_bb_output(result.output, exceptions, check_cdn)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600958
959 def test_cdn_mirror_qemux86_64(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600960 exceptions = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600961 self.run_test("qemux86-64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600962
963 def test_cdn_mirror_qemuarm64(self):
964 exceptions = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600965 self.run_test("qemuarm64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions)
966
967 def test_local_cache_qemux86_64(self):
968 exceptions = []
969 self.run_test("qemux86-64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions, check_cdn = False)
970
971 def test_local_cache_qemuarm64(self):
972 exceptions = []
973 self.run_test("qemuarm64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions, check_cdn = False)