blob: 031c2266acead858e931a93cf5a110f642d4a5ad [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
Patrick Williamsb58112e2024-03-07 11:16:36 -060082 # Test sstate files creation and their location and directory perms
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050083 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
Patrick Williamsb58112e2024-03-07 11:16:36 -060091 # We need to test that the env umask have does not effect sstate directory creation
92 # So, first, we'll get the current umask and set it to something we know incorrect
93 # See: sstate_task_postfunc for correct umask of os.umask(0o002)
94 import os
95 def current_umask():
96 current_umask = os.umask(0)
97 os.umask(current_umask)
98 return current_umask
99
100 orig_umask = current_umask()
101 # Set it to a umask we know will be 'wrong'
102 os.umask(0o022)
103
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500104 bitbake(targets)
105 file_tracker = []
106 results = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific)
107 if distro_nonspecific:
108 for r in results:
109 if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo", "_fetch.tar.zst.siginfo", "_unpack.tar.zst.siginfo", "_patch.tar.zst.siginfo")):
110 continue
111 file_tracker.append(r)
112 else:
113 file_tracker = results
114
115 if should_pass:
116 self.assertTrue(file_tracker , msg="Could not find sstate files for: %s" % ', '.join(map(str, targets)))
117 else:
118 self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s (found %s)" % (', '.join(map(str, targets)), str(file_tracker)))
119
Patrick Williamsb58112e2024-03-07 11:16:36 -0600120 # Now we'll walk the tree to check the mode and see if things are incorrect.
121 badperms = []
122 for root, dirs, files in os.walk(self.sstate_path):
123 for directory in dirs:
124 if (os.stat(os.path.join(root, directory)).st_mode & 0o777) != 0o775:
125 badperms.append(os.path.join(root, directory))
126
127 # Return to original umask
128 os.umask(orig_umask)
129
130 if should_pass:
131 self.assertTrue(badperms , msg="Found sstate directories with the wrong permissions: %s (found %s)" % (', '.join(map(str, targets)), str(badperms)))
132
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500133 # Test the sstate files deletion part of the do_cleansstate task
134 def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True):
135 self.config_sstate(temp_sstate_location, [self.sstate_path])
136
137 bitbake(['-ccleansstate'] + targets)
138
139 bitbake(targets)
140 archives_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific)
141 self.assertTrue(archives_created, msg="Could not find sstate .tar.zst files for: %s (%s)" % (', '.join(map(str, targets)), str(archives_created)))
142
143 siginfo_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific)
144 self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s (%s)" % (', '.join(map(str, targets)), str(siginfo_created)))
145
146 bitbake(['-ccleansstate'] + targets)
147 archives_removed = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific)
148 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)))
149
150 # Test rebuilding of distro-specific sstate files
151 def run_test_rebuild_distro_specific_sstate(self, targets, temp_sstate_location=True):
152 self.config_sstate(temp_sstate_location, [self.sstate_path])
153
154 bitbake(['-ccleansstate'] + targets)
155
156 bitbake(targets)
157 results = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=False, distro_nonspecific=True)
158 filtered_results = []
159 for r in results:
160 if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo")):
161 continue
162 filtered_results.append(r)
163 self.assertTrue(filtered_results == [], msg="Found distro non-specific sstate for: %s (%s)" % (', '.join(map(str, targets)), str(filtered_results)))
164 file_tracker_1 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False)
165 self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets)))
166
167 self.track_for_cleanup(self.distro_specific_sstate + "_old")
168 shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old")
169 shutil.rmtree(self.distro_specific_sstate)
170
171 bitbake(['-cclean'] + targets)
172 bitbake(targets)
173 file_tracker_2 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False)
174 self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets)))
175
176 not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2]
177 self.assertTrue(not_recreated == [], msg="The following sstate files were not recreated: %s" % ', '.join(map(str, not_recreated)))
178
179 created_once = [x for x in file_tracker_2 if x not in file_tracker_1]
180 self.assertTrue(created_once == [], msg="The following sstate files were created only in the second run: %s" % ', '.join(map(str, created_once)))
181
182 def sstate_common_samesigs(self, configA, configB, allarch=False):
183
184 self.write_config(configA)
185 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
186 bitbake("world meta-toolchain -S none")
187 self.write_config(configB)
188 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
189 bitbake("world meta-toolchain -S none")
190
191 def get_files(d, result):
192 for root, dirs, files in os.walk(d):
193 for name in files:
194 if "meta-environment" in root or "cross-canadian" in root:
195 continue
196 if "do_build" not in name:
197 # 1.4.1+gitAUTOINC+302fca9f4c-r0.do_package_write_ipk.sigdata.f3a2a38697da743f0dbed8b56aafcf79
198 (_, task, _, shash) = name.rsplit(".", 3)
199 result[os.path.join(os.path.basename(root), task)] = shash
200
201 files1 = {}
202 files2 = {}
203 subdirs = sorted(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux"))
204 if allarch:
205 subdirs.extend(sorted(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/all-*-linux")))
206
207 for subdir in subdirs:
208 nativesdkdir = os.path.basename(subdir)
209 get_files(self.topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir, files1)
210 get_files(self.topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir, files2)
211
212 self.maxDiff = None
213 self.assertEqual(files1, files2)
214
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500215class SStateTests(SStateBase):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400216 def test_autorev_sstate_works(self):
217 # Test that a git repository which changes is correctly handled by SRCREV = ${AUTOREV}
Brad Bishop316dfdd2018-06-25 12:45:53 -0400218
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500219 tempdir = tempfile.mkdtemp(prefix='sstate_autorev')
220 tempdldir = tempfile.mkdtemp(prefix='sstate_autorev_dldir')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400221 self.track_for_cleanup(tempdir)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500222 self.track_for_cleanup(tempdldir)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400223 create_temp_layer(tempdir, 'selftestrecipetool')
224 self.add_command_to_tearDown('bitbake-layers remove-layer %s' % tempdir)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500225 self.append_config("DL_DIR = \"%s\"" % tempdldir)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400226 runCmd('bitbake-layers add-layer %s' % tempdir)
227
228 # Use dbus-wait as a local git repo we can add a commit between two builds in
229 pn = 'dbus-wait'
230 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
231 url = 'git://git.yoctoproject.org/dbus-wait'
232 result = runCmd('git clone %s noname' % url, cwd=tempdir)
233 srcdir = os.path.join(tempdir, 'noname')
234 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
235 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
236
237 recipefile = os.path.join(tempdir, "recipes-test", "dbus-wait-test", 'dbus-wait-test_git.bb')
238 os.makedirs(os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000239 srcuri = 'git://' + srcdir + ';protocol=file;branch=master'
Brad Bishop316dfdd2018-06-25 12:45:53 -0400240 result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri])
241 self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output)
242
243 with open(recipefile, 'a') as f:
244 f.write('SRCREV = "${AUTOREV}"\n')
245 f.write('PV = "1.0"\n')
246
247 bitbake("dbus-wait-test -c fetch")
248 with open(os.path.join(srcdir, "bar.txt"), "w") as f:
249 f.write("foo")
250 result = runCmd('git add bar.txt; git commit -asm "add bar"', cwd=srcdir)
251 bitbake("dbus-wait-test -c unpack")
252
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500253class SStateCreation(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500254 def test_sstate_creation_distro_specific_pass(self):
255 self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
256
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500257 def test_sstate_creation_distro_specific_fail(self):
258 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)
259
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500260 def test_sstate_creation_distro_nonspecific_pass(self):
261 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
262
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500263 def test_sstate_creation_distro_nonspecific_fail(self):
264 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False)
265
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500266class SStateCleanup(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500267 def test_cleansstate_task_distro_specific_nonspecific(self):
268 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
269 targets.append('linux-libc-headers')
270 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True)
271
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500272 def test_cleansstate_task_distro_nonspecific(self):
273 self.run_test_cleansstate_task(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
274
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500275 def test_cleansstate_task_distro_specific(self):
276 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
277 targets.append('linux-libc-headers')
278 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
279
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500280class SStateDistroTests(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500281 def test_rebuild_distro_specific_sstate_cross_native_targets(self):
282 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch, 'binutils-native'], temp_sstate_location=True)
283
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500284 def test_rebuild_distro_specific_sstate_cross_target(self):
285 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch], temp_sstate_location=True)
286
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500287 def test_rebuild_distro_specific_sstate_native_target(self):
288 self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True)
289
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500290class SStateCacheManagement(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500291 # 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 -0600292 # 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 -0500293 def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]):
294 self.assertTrue(global_config)
295 self.assertTrue(target_config)
296 self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500297
Patrick Williams73bd93f2024-02-20 08:07:48 -0600298 for idx in range(len(target_config)):
299 self.append_config(global_config[idx])
300 self.append_recipeinc(target, target_config[idx])
301 bitbake(target)
302 self.remove_config(global_config[idx])
303 self.remove_recipeinc(target, target_config[idx])
304
305 self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500306
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000307 # For now this only checks if random sstate tasks are handled correctly as a group.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500308 # In the future we should add control over what tasks we check for.
309
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 expected_remaining_sstate = []
311 for idx in range(len(target_config)):
312 self.append_config(global_config[idx])
313 self.append_recipeinc(target, target_config[idx])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500314 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500315 target_sstate_before_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500316 bitbake("-cclean %s" % target)
317 result = bitbake(target, ignore_status=True)
318 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500319 target_sstate_after_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500320 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)]
321 self.remove_config(global_config[idx])
322 self.remove_recipeinc(target, target_config[idx])
323 self.assertEqual(result.status, 0, msg = "build of %s failed with %s" % (target, result.output))
324
Patrick Williams169d7bc2024-01-05 11:33:25 -0600325 runCmd("sstate-cache-management.py -y --cache-dir=%s --remove-duplicated" % (self.sstate_path))
Andrew Geisslereff27472021-10-29 15:35:00 -0500326 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 -0500327
328 actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500329 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 -0500330 expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500331 self.assertFalse(expected_not_actual, msg="Extra files were removed: %s" ', '.join(map(str, expected_not_actual)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500332
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500333 def test_sstate_cache_management_script_using_pr_1(self):
334 global_config = []
335 target_config = []
336 global_config.append('')
337 target_config.append('PR = "0"')
338 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
339
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500340 def test_sstate_cache_management_script_using_pr_2(self):
341 global_config = []
342 target_config = []
343 global_config.append('')
344 target_config.append('PR = "0"')
345 global_config.append('')
346 target_config.append('PR = "1"')
347 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
348
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500349 def test_sstate_cache_management_script_using_pr_3(self):
350 global_config = []
351 target_config = []
352 global_config.append('MACHINE = "qemux86-64"')
353 target_config.append('PR = "0"')
354 global_config.append(global_config[0])
355 target_config.append('PR = "1"')
356 global_config.append('MACHINE = "qemux86"')
357 target_config.append('PR = "1"')
358 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
359
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360 def test_sstate_cache_management_script_using_machine(self):
361 global_config = []
362 target_config = []
363 global_config.append('MACHINE = "qemux86-64"')
364 target_config.append('')
365 global_config.append('MACHINE = "qemux86"')
366 target_config.append('')
367 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
368
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500369class SStateHashSameSigs(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500370 def test_sstate_32_64_same_hash(self):
371 """
372 The sstate checksums for both native and target should not vary whether
373 they're built on a 32 or 64 bit system. Rather than requiring two different
374 build machines and running a builds, override the variables calling uname()
375 manually and check using bitbake -S.
376 """
377
378 self.write_config("""
379MACHINE = "qemux86"
380TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800381TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500382BUILD_ARCH = "x86_64"
383BUILD_OS = "linux"
384SDKMACHINE = "x86_64"
385PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500386BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500387""")
388 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500389 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500390 self.write_config("""
391MACHINE = "qemux86"
392TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800393TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500394BUILD_ARCH = "i686"
395BUILD_OS = "linux"
396SDKMACHINE = "i686"
397PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500398BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500399""")
400 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500401 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500402
403 def get_files(d):
404 f = []
405 for root, dirs, files in os.walk(d):
Andrew Geisslerc926e172021-05-07 16:11:35 -0500406 if "core-image-weston" in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500407 # SDKMACHINE changing will change
408 # do_rootfs/do_testimage/do_build stamps of images which
409 # is safe to ignore.
410 continue
411 f.extend(os.path.join(root, name) for name in files)
412 return f
413 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
414 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
415 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]
416 self.maxDiff = None
417 self.assertCountEqual(files1, files2)
418
419
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500420 def test_sstate_nativelsbstring_same_hash(self):
421 """
422 The sstate checksums should be independent of whichever NATIVELSBSTRING is
423 detected. Rather than requiring two different build machines and running
424 builds, override the variables manually and check using bitbake -S.
425 """
426
427 self.write_config("""
428TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800429TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500430NATIVELSBSTRING = \"DistroA\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500431BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500432""")
433 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500434 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500435 self.write_config("""
436TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800437TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500438NATIVELSBSTRING = \"DistroB\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500439BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500440""")
441 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500442 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500443
444 def get_files(d):
445 f = []
446 for root, dirs, files in os.walk(d):
447 f.extend(os.path.join(root, name) for name in files)
448 return f
449 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
450 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
451 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
452 self.maxDiff = None
453 self.assertCountEqual(files1, files2)
454
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500455class SStateHashSameSigs2(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500456 def test_sstate_allarch_samesigs(self):
457 """
458 The sstate checksums of allarch packages should be independent of whichever
459 MACHINE is set. Check this using bitbake -S.
460 Also, rather than duplicate the test, check nativesdk stamps are the same between
461 the two MACHINE values.
462 """
463
464 configA = """
465TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800466TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500467MACHINE = \"qemux86-64\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500468BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500469"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000470 #OLDEST_KERNEL is arch specific so set to a different value here for testing
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500471 configB = """
472TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800473TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500474MACHINE = \"qemuarm\"
Andrew Geissler595f6302022-01-24 19:11:47 +0000475OLDEST_KERNEL = \"3.3.0\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500476BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500477"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000478 self.sstate_common_samesigs(configA, configB, allarch=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500479
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800480 def test_sstate_nativesdk_samesigs_multilib(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500481 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800482 check nativesdk stamps are the same between the two MACHINE values.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500483 """
484
485 configA = """
486TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800487TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500488MACHINE = \"qemux86-64\"
489require conf/multilib.conf
490MULTILIBS = \"multilib:lib32\"
Patrick Williams213cb262021-08-07 19:21:33 -0500491DEFAULTTUNE:virtclass-multilib-lib32 = \"x86\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500492BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500493"""
494 configB = """
495TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800496TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500497MACHINE = \"qemuarm\"
498require conf/multilib.conf
499MULTILIBS = \"\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500500BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500501"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000502 self.sstate_common_samesigs(configA, configB)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500503
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500504class SStateHashSameSigs3(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500505 def test_sstate_sametune_samesigs(self):
506 """
507 The sstate checksums of two identical machines (using the same tune) should be the
508 same, apart from changes within the machine specific stamps directory. We use the
509 qemux86copy machine to test this. Also include multilibs in the test.
510 """
511
512 self.write_config("""
513TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800514TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515MACHINE = \"qemux86\"
516require conf/multilib.conf
517MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500518DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500519BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500520""")
521 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
522 bitbake("world meta-toolchain -S none")
523 self.write_config("""
524TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800525TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500526MACHINE = \"qemux86copy\"
527require conf/multilib.conf
528MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500529DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500530BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500531""")
532 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
533 bitbake("world meta-toolchain -S none")
534
535 def get_files(d):
536 f = []
537 for root, dirs, files in os.walk(d):
538 for name in files:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500539 if "meta-environment" in root or "cross-canadian" in root or 'meta-ide-support' in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500540 continue
541 if "qemux86copy-" in root or "qemux86-" in root:
542 continue
543 if "do_build" not in name and "do_populate_sdk" not in name:
544 f.append(os.path.join(root, name))
545 return f
546 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
547 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
548 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
549 self.maxDiff = None
550 self.assertCountEqual(files1, files2)
551
552
Andrew Geissler82c905d2020-04-13 13:39:40 -0500553 def test_sstate_multilib_or_not_native_samesigs(self):
554 """The sstate checksums of two native recipes (and their dependencies)
555 where the target is using multilib in one but not the other
556 should be the same. We use the qemux86copy machine to test
557 this.
558 """
559
560 self.write_config("""
561TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
562TCLIBCAPPEND = \"\"
563MACHINE = \"qemux86\"
564require conf/multilib.conf
565MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500566DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Andrew Geissler82c905d2020-04-13 13:39:40 -0500567BB_SIGNATURE_HANDLER = "OEBasicHash"
568""")
569 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
570 bitbake("binutils-native -S none")
571 self.write_config("""
572TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
573TCLIBCAPPEND = \"\"
574MACHINE = \"qemux86copy\"
575BB_SIGNATURE_HANDLER = "OEBasicHash"
576""")
577 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
578 bitbake("binutils-native -S none")
579
580 def get_files(d):
581 f = []
582 for root, dirs, files in os.walk(d):
583 for name in files:
584 f.append(os.path.join(root, name))
585 return f
586 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
587 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
588 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
589 self.maxDiff = None
590 self.assertCountEqual(files1, files2)
591
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500592class SStateHashSameSigs4(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500593 def test_sstate_noop_samesigs(self):
594 """
595 The sstate checksums of two builds with these variables changed or
596 classes inherits should be the same.
597 """
598
599 self.write_config("""
600TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800601TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500602BB_NUMBER_THREADS = "${@oe.utils.cpu_count()}"
603PARALLEL_MAKE = "-j 1"
604DL_DIR = "${TOPDIR}/download1"
605TIME = "111111"
606DATE = "20161111"
Patrick Williams213cb262021-08-07 19:21:33 -0500607INHERIT:remove = "buildstats-summary buildhistory uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500608http_proxy = ""
Brad Bishop6dbb3162019-11-25 09:41:34 -0500609BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500610""")
611 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
612 self.track_for_cleanup(self.topdir + "/download1")
613 bitbake("world meta-toolchain -S none")
614 self.write_config("""
615TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800616TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500617BB_NUMBER_THREADS = "${@oe.utils.cpu_count()+1}"
618PARALLEL_MAKE = "-j 2"
619DL_DIR = "${TOPDIR}/download2"
620TIME = "222222"
621DATE = "20161212"
622# Always remove uninative as we're changing proxies
Patrick Williams213cb262021-08-07 19:21:33 -0500623INHERIT:remove = "uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624INHERIT += "buildstats-summary buildhistory"
625http_proxy = "http://example.com/"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500626BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500627""")
628 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
629 self.track_for_cleanup(self.topdir + "/download2")
630 bitbake("world meta-toolchain -S none")
631
632 def get_files(d):
633 f = {}
634 for root, dirs, files in os.walk(d):
635 for name in files:
636 name, shash = name.rsplit('.', 1)
637 # Extract just the machine and recipe name
638 base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name])
639 f[base] = shash
640 return f
641
642 def compare_sigfiles(files, files1, files2, compare=False):
643 for k in files:
644 if k in files1 and k in files2:
645 print("%s differs:" % k)
646 if compare:
647 sigdatafile1 = self.topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k]
648 sigdatafile2 = self.topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]
649 output = bb.siggen.compare_sigfiles(sigdatafile1, sigdatafile2)
650 if output:
651 print('\n'.join(output))
652 elif k in files1 and k not in files2:
653 print("%s in files1" % k)
654 elif k not in files1 and k in files2:
655 print("%s in files2" % k)
656 else:
657 assert "shouldn't reach here"
658
659 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
660 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
661 # Remove items that are identical in both sets
662 for k,v in files1.items() & files2.items():
663 del files1[k]
664 del files2[k]
665 if not files1 and not files2:
666 # No changes, so we're done
667 return
668
669 files = list(files1.keys() | files2.keys())
670 # this is an expensive computation, thus just compare the first 'max_sigfiles_to_compare' k files
671 max_sigfiles_to_compare = 20
672 first, rest = files[:max_sigfiles_to_compare], files[max_sigfiles_to_compare:]
Brad Bishop316dfdd2018-06-25 12:45:53 -0400673 compare_sigfiles(first, files1, files2, compare=True)
674 compare_sigfiles(rest, files1, files2, compare=False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500675
676 self.fail("sstate hashes not identical.")
Andrew Geissler595f6302022-01-24 19:11:47 +0000677
678 def test_sstate_movelayer_samesigs(self):
679 """
680 The sstate checksums of two builds with the same oe-core layer in two
681 different locations should be the same.
682 """
683 core_layer = os.path.join(
684 self.tc.td["COREBASE"], 'meta')
685 copy_layer_1 = self.topdir + "/meta-copy1/meta"
686 copy_layer_2 = self.topdir + "/meta-copy2/meta"
687
688 oe.path.copytree(core_layer, copy_layer_1)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500689 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy1/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000690 self.write_config("""
691TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
692""")
693 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_1, core_layer)
694 self.write_bblayers_config(bblayers_conf)
695 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
696 bitbake("bash -S none")
697
698 oe.path.copytree(core_layer, copy_layer_2)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500699 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy2/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000700 self.write_config("""
701TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
702""")
703 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_2, core_layer)
704 self.write_bblayers_config(bblayers_conf)
705 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
706 bitbake("bash -S none")
707
708 def get_files(d):
709 f = []
710 for root, dirs, files in os.walk(d):
711 for name in files:
712 f.append(os.path.join(root, name))
713 return f
714 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
715 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
716 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
717 self.maxDiff = None
718 self.assertCountEqual(files1, files2)
719
Patrick Williams2a254922023-08-11 09:48:11 -0500720class SStateFindSiginfo(SStateBase):
721 def test_sstate_compare_sigfiles_and_find_siginfo(self):
722 """
723 Test the functionality of the find_siginfo: basic function and callback in compare_sigfiles
724 """
725 self.write_config("""
726TMPDIR = \"${TOPDIR}/tmp-sstates-findsiginfo\"
727TCLIBCAPPEND = \"\"
728MACHINE = \"qemux86-64\"
729require conf/multilib.conf
730MULTILIBS = "multilib:lib32"
731DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
732BB_SIGNATURE_HANDLER = "OEBasicHash"
733""")
734 self.track_for_cleanup(self.topdir + "/tmp-sstates-findsiginfo")
735
736 pns = ["binutils", "binutils-native", "lib32-binutils"]
737 target_configs = [
738"""
739TMPVAL1 = "tmpval1"
740TMPVAL2 = "tmpval2"
741do_tmptask1() {
742 echo ${TMPVAL1}
743}
744do_tmptask2() {
745 echo ${TMPVAL2}
746}
747addtask do_tmptask1
748addtask tmptask2 before do_tmptask1
749""",
750"""
751TMPVAL3 = "tmpval3"
752TMPVAL4 = "tmpval4"
753do_tmptask1() {
754 echo ${TMPVAL3}
755}
756do_tmptask2() {
757 echo ${TMPVAL4}
758}
759addtask do_tmptask1
760addtask tmptask2 before do_tmptask1
761"""
762 ]
763
764 for target_config in target_configs:
765 self.write_recipeinc("binutils", target_config)
766 for pn in pns:
767 bitbake("%s -c do_tmptask1 -S none" % pn)
768 self.delete_recipeinc("binutils")
769
770 with bb.tinfoil.Tinfoil() as tinfoil:
771 tinfoil.prepare(config_only=True)
772
773 def find_siginfo(pn, taskname, sigs=None):
774 result = None
775 tinfoil.set_event_mask(["bb.event.FindSigInfoResult",
776 "bb.command.CommandCompleted"])
777 ret = tinfoil.run_command("findSigInfo", pn, taskname, sigs)
778 if ret:
779 while True:
780 event = tinfoil.wait_event(1)
781 if event:
782 if isinstance(event, bb.command.CommandCompleted):
783 break
784 elif isinstance(event, bb.event.FindSigInfoResult):
785 result = event.result
786 return result
787
788 def recursecb(key, hash1, hash2):
789 nonlocal recursecb_count
790 recursecb_count += 1
791 hashes = [hash1, hash2]
792 hashfiles = find_siginfo(key, None, hashes)
793 self.assertCountEqual(hashes, hashfiles)
Patrick Williams169d7bc2024-01-05 11:33:25 -0600794 bb.siggen.compare_sigfiles(hashfiles[hash1]['path'], hashfiles[hash2]['path'], recursecb)
Patrick Williams2a254922023-08-11 09:48:11 -0500795
796 for pn in pns:
797 recursecb_count = 0
Patrick Williams169d7bc2024-01-05 11:33:25 -0600798 matches = find_siginfo(pn, "do_tmptask1")
799 self.assertGreaterEqual(len(matches), 2)
800 latesthashes = sorted(matches.keys(), key=lambda h: matches[h]['time'])[-2:]
801 bb.siggen.compare_sigfiles(matches[latesthashes[-2]]['path'], matches[latesthashes[-1]]['path'], recursecb)
Patrick Williams2a254922023-08-11 09:48:11 -0500802 self.assertEqual(recursecb_count,1)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600803
804class SStatePrintdiff(SStateBase):
805 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 -0600806 import time
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600807 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600808TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-sametmp-{}"
809""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600810 # Use runall do_build to ensure any indirect sstate is created, e.g. tzcode-native on both x86 and
811 # aarch64 hosts since only allarch target recipes depend upon it and it may not be built otherwise.
812 # A bitbake -c cleansstate tzcode-native would cause some of these tests to error for example.
813 bitbake("--runall build --runall deploy_source_date_epoch {}".format(target))
814 bitbake("-S none {}".format(target))
815 bitbake(change_bbtask)
816 self.write_recipeinc(change_recipe, change_content)
817 result_sametmp = bitbake("-S printdiff {}".format(target))
818
819 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600820TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-difftmp-{}"
821""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600822 result_difftmp = bitbake("-S printdiff {}".format(target))
823
824 self.delete_recipeinc(change_recipe)
825 for item in expected_sametmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600826 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 -0600827 for item in expected_difftmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600828 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 -0600829
Patrick Williams705982a2024-01-12 09:51:57 -0600830 def run_test_printdiff_changeconfig(self, target, change_bbtasks, change_content, expected_sametmp_output, expected_difftmp_output):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600831 import time
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600832 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600833TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-sametmp-{}"
834""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600835 bitbake("--runall build --runall deploy_source_date_epoch {}".format(target))
836 bitbake("-S none {}".format(target))
Patrick Williams705982a2024-01-12 09:51:57 -0600837 bitbake(" ".join(change_bbtasks))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600838 self.append_config(change_content)
839 result_sametmp = bitbake("-S printdiff {}".format(target))
840
841 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600842TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-difftmp-{}"
843""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600844 self.append_config(change_content)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600845 result_difftmp = bitbake("-S printdiff {}".format(target))
846
847 for item in expected_sametmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600848 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 -0600849 for item in expected_difftmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600850 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 -0600851
852
853 # 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 -0600854 def test_image_minimal_vs_perlcross(self):
855 expected_output = ("Task perlcross-native:do_install couldn't be used from the cache because:",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600856"We need hash",
857"most recent matching task was")
Patrick Williams705982a2024-01-12 09:51:57 -0600858 expected_sametmp_output = expected_output + (
859"Variable do_install value changed",
860'+ echo "this changes the task signature"')
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600861 expected_difftmp_output = expected_output
862
Patrick Williams705982a2024-01-12 09:51:57 -0600863 self.run_test_printdiff_changerecipe("core-image-minimal", "perlcross", "-c do_install perlcross-native",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600864"""
865do_install:append() {
866 echo "this changes the task signature"
867}
868""",
869expected_sametmp_output, expected_difftmp_output)
870
871 # Check if changes to gcc-source (which uses tmp/work-shared) are correctly discovered
Patrick Williams705982a2024-01-12 09:51:57 -0600872 def test_gcc_runtime_vs_gcc_source(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600873 gcc_source_pn = 'gcc-source-%s' % get_bb_vars(['PV'], 'gcc')['PV']
874
875 expected_output = ("Task {}:do_preconfigure couldn't be used from the cache because:".format(gcc_source_pn),
876"We need hash",
877"most recent matching task was")
Patrick Williams705982a2024-01-12 09:51:57 -0600878 expected_sametmp_output = expected_output + (
879"Variable do_preconfigure value changed",
880'+ print("this changes the task signature")')
881 expected_difftmp_output = expected_output
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600882
883 self.run_test_printdiff_changerecipe("gcc-runtime", "gcc-source", "-c do_preconfigure {}".format(gcc_source_pn),
884"""
885python do_preconfigure:append() {
886 print("this changes the task signature")
887}
888""",
889expected_sametmp_output, expected_difftmp_output)
890
891 # Check if changing a really base task definiton is reported against multiple core recipes using it
892 def test_image_minimal_vs_base_do_configure(self):
Patrick Williams705982a2024-01-12 09:51:57 -0600893 change_bbtasks = ('zstd-native:do_configure',
894'texinfo-dummy-native:do_configure',
895'ldconfig-native:do_configure',
896'gettext-minimal-native:do_configure',
897'tzcode-native:do_configure',
898'makedevs-native:do_configure',
899'pigz-native:do_configure',
900'update-rc.d-native:do_configure',
901'unzip-native:do_configure',
902'gnu-config-native:do_configure')
903
904 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 -0600905"We need hash",
Patrick Williams705982a2024-01-12 09:51:57 -0600906"most recent matching task was"]
907
908 expected_sametmp_output = expected_output + [
909"Variable base_do_configure value changed",
910'+ echo "this changes base_do_configure() definiton "']
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600911 expected_difftmp_output = expected_output
912
Patrick Williams705982a2024-01-12 09:51:57 -0600913 self.run_test_printdiff_changeconfig("core-image-minimal",change_bbtasks,
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600914"""
915INHERIT += "base-do-configure-modified"
916""",
917expected_sametmp_output, expected_difftmp_output)
918
919@OETestTag("yocto-mirrors")
920class SStateMirrors(SStateBase):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600921 def check_bb_output(self, output, exceptions, check_cdn):
922 def is_exception(object, exceptions):
923 for e in exceptions:
924 if re.search(e, object):
925 return True
926 return False
927
928 output_l = output.splitlines()
929 for l in output_l:
930 if l.startswith("Sstate summary"):
931 for idx, item in enumerate(l.split()):
932 if item == 'Missed':
933 missing_objects = int(l.split()[idx+1])
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600934 break
935 else:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600936 self.fail("Did not find missing objects amount in sstate summary: {}".format(l))
937 break
938 else:
939 self.fail("Did not find 'Sstate summary' line in bitbake output")
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600940
Patrick Williams169d7bc2024-01-05 11:33:25 -0600941 failed_urls = []
Patrick Williams705982a2024-01-12 09:51:57 -0600942 failed_urls_extrainfo = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600943 for l in output_l:
944 if "SState: Unsuccessful fetch test for" in l and check_cdn:
945 missing_object = l.split()[6]
946 elif "SState: Looked for but didn't find file" in l and not check_cdn:
947 missing_object = l.split()[8]
948 else:
949 missing_object = None
950 if missing_object:
951 if not is_exception(missing_object, exceptions):
952 failed_urls.append(missing_object)
953 else:
954 missing_objects -= 1
955
Patrick Williams73bd93f2024-02-20 08:07:48 -0600956 if "urlopen failed for" in l and not is_exception(l, exceptions):
Patrick Williams705982a2024-01-12 09:51:57 -0600957 failed_urls_extrainfo.append(l)
958
959 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)))
960 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 -0600961
962 def run_test(self, machine, targets, exceptions, check_cdn = True):
963 # sstate is checked for existence of these, but they never get written out to begin with
964 exceptions += ["{}.*image_qa".format(t) for t in targets.split()]
965 exceptions += ["{}.*deploy_source_date_epoch".format(t) for t in targets.split()]
966 exceptions += ["{}.*image_complete".format(t) for t in targets.split()]
967 exceptions += ["linux-yocto.*shared_workdir"]
968 # these get influnced by IMAGE_FSTYPES tweaks in yocto-autobuilder-helper's config.json (on x86-64)
969 # additionally, they depend on noexec (thus, absent stamps) package, install, etc. image tasks,
970 # which makes tracing other changes difficult
971 exceptions += ["{}.*create_spdx".format(t) for t in targets.split()]
972 exceptions += ["{}.*create_runtime_spdx".format(t) for t in targets.split()]
973
974 if check_cdn:
975 self.config_sstate(True)
976 self.append_config("""
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600977MACHINE = "{}"
978BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"
979SSTATE_MIRRORS ?= "file://.* http://cdn.jsdelivr.net/yocto/sstate/all/PATH;downloadfilename=PATH"
980""".format(machine))
Patrick Williams169d7bc2024-01-05 11:33:25 -0600981 else:
982 self.append_config("""
983MACHINE = "{}"
984""".format(machine))
985 result = bitbake("-DD -n {}".format(targets))
986 bitbake("-S none {}".format(targets))
987 self.check_bb_output(result.output, exceptions, check_cdn)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600988
989 def test_cdn_mirror_qemux86_64(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600990 exceptions = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600991 self.run_test("qemux86-64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600992
993 def test_cdn_mirror_qemuarm64(self):
994 exceptions = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600995 self.run_test("qemuarm64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions)
996
997 def test_local_cache_qemux86_64(self):
998 exceptions = []
999 self.run_test("qemux86-64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions, check_cdn = False)
1000
1001 def test_local_cache_qemuarm64(self):
1002 exceptions = []
1003 self.run_test("qemuarm64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions, check_cdn = False)