blob: 56dfcdb0f39b495eddc7b7048a9012225f9eb301 [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')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500271
Patrick Williams73bd93f2024-02-20 08:07:48 -0600272 for idx in range(len(target_config)):
273 self.append_config(global_config[idx])
274 self.append_recipeinc(target, target_config[idx])
275 bitbake(target)
276 self.remove_config(global_config[idx])
277 self.remove_recipeinc(target, target_config[idx])
278
279 self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500280
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000281 # For now this only checks if random sstate tasks are handled correctly as a group.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500282 # In the future we should add control over what tasks we check for.
283
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500284 expected_remaining_sstate = []
285 for idx in range(len(target_config)):
286 self.append_config(global_config[idx])
287 self.append_recipeinc(target, target_config[idx])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500288 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500289 target_sstate_before_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500290 bitbake("-cclean %s" % target)
291 result = bitbake(target, ignore_status=True)
292 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500293 target_sstate_after_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500294 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)]
295 self.remove_config(global_config[idx])
296 self.remove_recipeinc(target, target_config[idx])
297 self.assertEqual(result.status, 0, msg = "build of %s failed with %s" % (target, result.output))
298
Patrick Williams169d7bc2024-01-05 11:33:25 -0600299 runCmd("sstate-cache-management.py -y --cache-dir=%s --remove-duplicated" % (self.sstate_path))
Andrew Geisslereff27472021-10-29 15:35:00 -0500300 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 -0500301
302 actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500303 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 -0500304 expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500305 self.assertFalse(expected_not_actual, msg="Extra files were removed: %s" ', '.join(map(str, expected_not_actual)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500306
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500307 def test_sstate_cache_management_script_using_pr_1(self):
308 global_config = []
309 target_config = []
310 global_config.append('')
311 target_config.append('PR = "0"')
312 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
313
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500314 def test_sstate_cache_management_script_using_pr_2(self):
315 global_config = []
316 target_config = []
317 global_config.append('')
318 target_config.append('PR = "0"')
319 global_config.append('')
320 target_config.append('PR = "1"')
321 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
322
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500323 def test_sstate_cache_management_script_using_pr_3(self):
324 global_config = []
325 target_config = []
326 global_config.append('MACHINE = "qemux86-64"')
327 target_config.append('PR = "0"')
328 global_config.append(global_config[0])
329 target_config.append('PR = "1"')
330 global_config.append('MACHINE = "qemux86"')
331 target_config.append('PR = "1"')
332 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
333
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500334 def test_sstate_cache_management_script_using_machine(self):
335 global_config = []
336 target_config = []
337 global_config.append('MACHINE = "qemux86-64"')
338 target_config.append('')
339 global_config.append('MACHINE = "qemux86"')
340 target_config.append('')
341 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
342
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500343class SStateHashSameSigs(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500344 def test_sstate_32_64_same_hash(self):
345 """
346 The sstate checksums for both native and target should not vary whether
347 they're built on a 32 or 64 bit system. Rather than requiring two different
348 build machines and running a builds, override the variables calling uname()
349 manually and check using bitbake -S.
350 """
351
352 self.write_config("""
353MACHINE = "qemux86"
354TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800355TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500356BUILD_ARCH = "x86_64"
357BUILD_OS = "linux"
358SDKMACHINE = "x86_64"
359PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500360BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500361""")
362 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500363 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500364 self.write_config("""
365MACHINE = "qemux86"
366TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800367TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500368BUILD_ARCH = "i686"
369BUILD_OS = "linux"
370SDKMACHINE = "i686"
371PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500372BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500373""")
374 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500375 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500376
377 def get_files(d):
378 f = []
379 for root, dirs, files in os.walk(d):
Andrew Geisslerc926e172021-05-07 16:11:35 -0500380 if "core-image-weston" in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500381 # SDKMACHINE changing will change
382 # do_rootfs/do_testimage/do_build stamps of images which
383 # is safe to ignore.
384 continue
385 f.extend(os.path.join(root, name) for name in files)
386 return f
387 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
388 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
389 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]
390 self.maxDiff = None
391 self.assertCountEqual(files1, files2)
392
393
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500394 def test_sstate_nativelsbstring_same_hash(self):
395 """
396 The sstate checksums should be independent of whichever NATIVELSBSTRING is
397 detected. Rather than requiring two different build machines and running
398 builds, override the variables manually and check using bitbake -S.
399 """
400
401 self.write_config("""
402TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800403TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500404NATIVELSBSTRING = \"DistroA\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500405BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500406""")
407 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500408 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500409 self.write_config("""
410TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800411TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500412NATIVELSBSTRING = \"DistroB\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500413BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500414""")
415 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500416 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500417
418 def get_files(d):
419 f = []
420 for root, dirs, files in os.walk(d):
421 f.extend(os.path.join(root, name) for name in files)
422 return f
423 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
424 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
425 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
426 self.maxDiff = None
427 self.assertCountEqual(files1, files2)
428
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500429class SStateHashSameSigs2(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500430 def test_sstate_allarch_samesigs(self):
431 """
432 The sstate checksums of allarch packages should be independent of whichever
433 MACHINE is set. Check this using bitbake -S.
434 Also, rather than duplicate the test, check nativesdk stamps are the same between
435 the two MACHINE values.
436 """
437
438 configA = """
439TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800440TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500441MACHINE = \"qemux86-64\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500442BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500443"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000444 #OLDEST_KERNEL is arch specific so set to a different value here for testing
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500445 configB = """
446TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800447TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500448MACHINE = \"qemuarm\"
Andrew Geissler595f6302022-01-24 19:11:47 +0000449OLDEST_KERNEL = \"3.3.0\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500450BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500451"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000452 self.sstate_common_samesigs(configA, configB, allarch=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500453
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800454 def test_sstate_nativesdk_samesigs_multilib(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500455 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800456 check nativesdk stamps are the same between the two MACHINE values.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500457 """
458
459 configA = """
460TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800461TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500462MACHINE = \"qemux86-64\"
463require conf/multilib.conf
464MULTILIBS = \"multilib:lib32\"
Patrick Williams213cb262021-08-07 19:21:33 -0500465DEFAULTTUNE:virtclass-multilib-lib32 = \"x86\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500466BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500467"""
468 configB = """
469TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800470TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500471MACHINE = \"qemuarm\"
472require conf/multilib.conf
473MULTILIBS = \"\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500474BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500475"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000476 self.sstate_common_samesigs(configA, configB)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500477
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500478class SStateHashSameSigs3(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500479 def test_sstate_sametune_samesigs(self):
480 """
481 The sstate checksums of two identical machines (using the same tune) should be the
482 same, apart from changes within the machine specific stamps directory. We use the
483 qemux86copy machine to test this. Also include multilibs in the test.
484 """
485
486 self.write_config("""
487TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800488TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500489MACHINE = \"qemux86\"
490require conf/multilib.conf
491MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500492DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500493BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500494""")
495 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
496 bitbake("world meta-toolchain -S none")
497 self.write_config("""
498TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800499TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500500MACHINE = \"qemux86copy\"
501require conf/multilib.conf
502MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500503DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500504BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500505""")
506 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
507 bitbake("world meta-toolchain -S none")
508
509 def get_files(d):
510 f = []
511 for root, dirs, files in os.walk(d):
512 for name in files:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500513 if "meta-environment" in root or "cross-canadian" in root or 'meta-ide-support' in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500514 continue
515 if "qemux86copy-" in root or "qemux86-" in root:
516 continue
517 if "do_build" not in name and "do_populate_sdk" not in name:
518 f.append(os.path.join(root, name))
519 return f
520 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
521 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
522 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
523 self.maxDiff = None
524 self.assertCountEqual(files1, files2)
525
526
Andrew Geissler82c905d2020-04-13 13:39:40 -0500527 def test_sstate_multilib_or_not_native_samesigs(self):
528 """The sstate checksums of two native recipes (and their dependencies)
529 where the target is using multilib in one but not the other
530 should be the same. We use the qemux86copy machine to test
531 this.
532 """
533
534 self.write_config("""
535TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
536TCLIBCAPPEND = \"\"
537MACHINE = \"qemux86\"
538require conf/multilib.conf
539MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500540DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Andrew Geissler82c905d2020-04-13 13:39:40 -0500541BB_SIGNATURE_HANDLER = "OEBasicHash"
542""")
543 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
544 bitbake("binutils-native -S none")
545 self.write_config("""
546TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
547TCLIBCAPPEND = \"\"
548MACHINE = \"qemux86copy\"
549BB_SIGNATURE_HANDLER = "OEBasicHash"
550""")
551 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
552 bitbake("binutils-native -S none")
553
554 def get_files(d):
555 f = []
556 for root, dirs, files in os.walk(d):
557 for name in files:
558 f.append(os.path.join(root, name))
559 return f
560 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
561 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
562 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
563 self.maxDiff = None
564 self.assertCountEqual(files1, files2)
565
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500566class SStateHashSameSigs4(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500567 def test_sstate_noop_samesigs(self):
568 """
569 The sstate checksums of two builds with these variables changed or
570 classes inherits should be the same.
571 """
572
573 self.write_config("""
574TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800575TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500576BB_NUMBER_THREADS = "${@oe.utils.cpu_count()}"
577PARALLEL_MAKE = "-j 1"
578DL_DIR = "${TOPDIR}/download1"
579TIME = "111111"
580DATE = "20161111"
Patrick Williams213cb262021-08-07 19:21:33 -0500581INHERIT:remove = "buildstats-summary buildhistory uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500582http_proxy = ""
Brad Bishop6dbb3162019-11-25 09:41:34 -0500583BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500584""")
585 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
586 self.track_for_cleanup(self.topdir + "/download1")
587 bitbake("world meta-toolchain -S none")
588 self.write_config("""
589TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800590TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500591BB_NUMBER_THREADS = "${@oe.utils.cpu_count()+1}"
592PARALLEL_MAKE = "-j 2"
593DL_DIR = "${TOPDIR}/download2"
594TIME = "222222"
595DATE = "20161212"
596# Always remove uninative as we're changing proxies
Patrick Williams213cb262021-08-07 19:21:33 -0500597INHERIT:remove = "uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500598INHERIT += "buildstats-summary buildhistory"
599http_proxy = "http://example.com/"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500600BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500601""")
602 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
603 self.track_for_cleanup(self.topdir + "/download2")
604 bitbake("world meta-toolchain -S none")
605
606 def get_files(d):
607 f = {}
608 for root, dirs, files in os.walk(d):
609 for name in files:
610 name, shash = name.rsplit('.', 1)
611 # Extract just the machine and recipe name
612 base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name])
613 f[base] = shash
614 return f
615
616 def compare_sigfiles(files, files1, files2, compare=False):
617 for k in files:
618 if k in files1 and k in files2:
619 print("%s differs:" % k)
620 if compare:
621 sigdatafile1 = self.topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k]
622 sigdatafile2 = self.topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]
623 output = bb.siggen.compare_sigfiles(sigdatafile1, sigdatafile2)
624 if output:
625 print('\n'.join(output))
626 elif k in files1 and k not in files2:
627 print("%s in files1" % k)
628 elif k not in files1 and k in files2:
629 print("%s in files2" % k)
630 else:
631 assert "shouldn't reach here"
632
633 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
634 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
635 # Remove items that are identical in both sets
636 for k,v in files1.items() & files2.items():
637 del files1[k]
638 del files2[k]
639 if not files1 and not files2:
640 # No changes, so we're done
641 return
642
643 files = list(files1.keys() | files2.keys())
644 # this is an expensive computation, thus just compare the first 'max_sigfiles_to_compare' k files
645 max_sigfiles_to_compare = 20
646 first, rest = files[:max_sigfiles_to_compare], files[max_sigfiles_to_compare:]
Brad Bishop316dfdd2018-06-25 12:45:53 -0400647 compare_sigfiles(first, files1, files2, compare=True)
648 compare_sigfiles(rest, files1, files2, compare=False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500649
650 self.fail("sstate hashes not identical.")
Andrew Geissler595f6302022-01-24 19:11:47 +0000651
652 def test_sstate_movelayer_samesigs(self):
653 """
654 The sstate checksums of two builds with the same oe-core layer in two
655 different locations should be the same.
656 """
657 core_layer = os.path.join(
658 self.tc.td["COREBASE"], 'meta')
659 copy_layer_1 = self.topdir + "/meta-copy1/meta"
660 copy_layer_2 = self.topdir + "/meta-copy2/meta"
661
662 oe.path.copytree(core_layer, copy_layer_1)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500663 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy1/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000664 self.write_config("""
665TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
666""")
667 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_1, core_layer)
668 self.write_bblayers_config(bblayers_conf)
669 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
670 bitbake("bash -S none")
671
672 oe.path.copytree(core_layer, copy_layer_2)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500673 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy2/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000674 self.write_config("""
675TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
676""")
677 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_2, core_layer)
678 self.write_bblayers_config(bblayers_conf)
679 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
680 bitbake("bash -S none")
681
682 def get_files(d):
683 f = []
684 for root, dirs, files in os.walk(d):
685 for name in files:
686 f.append(os.path.join(root, name))
687 return f
688 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
689 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
690 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
691 self.maxDiff = None
692 self.assertCountEqual(files1, files2)
693
Patrick Williams2a254922023-08-11 09:48:11 -0500694class SStateFindSiginfo(SStateBase):
695 def test_sstate_compare_sigfiles_and_find_siginfo(self):
696 """
697 Test the functionality of the find_siginfo: basic function and callback in compare_sigfiles
698 """
699 self.write_config("""
700TMPDIR = \"${TOPDIR}/tmp-sstates-findsiginfo\"
701TCLIBCAPPEND = \"\"
702MACHINE = \"qemux86-64\"
703require conf/multilib.conf
704MULTILIBS = "multilib:lib32"
705DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
706BB_SIGNATURE_HANDLER = "OEBasicHash"
707""")
708 self.track_for_cleanup(self.topdir + "/tmp-sstates-findsiginfo")
709
710 pns = ["binutils", "binutils-native", "lib32-binutils"]
711 target_configs = [
712"""
713TMPVAL1 = "tmpval1"
714TMPVAL2 = "tmpval2"
715do_tmptask1() {
716 echo ${TMPVAL1}
717}
718do_tmptask2() {
719 echo ${TMPVAL2}
720}
721addtask do_tmptask1
722addtask tmptask2 before do_tmptask1
723""",
724"""
725TMPVAL3 = "tmpval3"
726TMPVAL4 = "tmpval4"
727do_tmptask1() {
728 echo ${TMPVAL3}
729}
730do_tmptask2() {
731 echo ${TMPVAL4}
732}
733addtask do_tmptask1
734addtask tmptask2 before do_tmptask1
735"""
736 ]
737
738 for target_config in target_configs:
739 self.write_recipeinc("binutils", target_config)
740 for pn in pns:
741 bitbake("%s -c do_tmptask1 -S none" % pn)
742 self.delete_recipeinc("binutils")
743
744 with bb.tinfoil.Tinfoil() as tinfoil:
745 tinfoil.prepare(config_only=True)
746
747 def find_siginfo(pn, taskname, sigs=None):
748 result = None
749 tinfoil.set_event_mask(["bb.event.FindSigInfoResult",
750 "bb.command.CommandCompleted"])
751 ret = tinfoil.run_command("findSigInfo", pn, taskname, sigs)
752 if ret:
753 while True:
754 event = tinfoil.wait_event(1)
755 if event:
756 if isinstance(event, bb.command.CommandCompleted):
757 break
758 elif isinstance(event, bb.event.FindSigInfoResult):
759 result = event.result
760 return result
761
762 def recursecb(key, hash1, hash2):
763 nonlocal recursecb_count
764 recursecb_count += 1
765 hashes = [hash1, hash2]
766 hashfiles = find_siginfo(key, None, hashes)
767 self.assertCountEqual(hashes, hashfiles)
Patrick Williams169d7bc2024-01-05 11:33:25 -0600768 bb.siggen.compare_sigfiles(hashfiles[hash1]['path'], hashfiles[hash2]['path'], recursecb)
Patrick Williams2a254922023-08-11 09:48:11 -0500769
770 for pn in pns:
771 recursecb_count = 0
Patrick Williams169d7bc2024-01-05 11:33:25 -0600772 matches = find_siginfo(pn, "do_tmptask1")
773 self.assertGreaterEqual(len(matches), 2)
774 latesthashes = sorted(matches.keys(), key=lambda h: matches[h]['time'])[-2:]
775 bb.siggen.compare_sigfiles(matches[latesthashes[-2]]['path'], matches[latesthashes[-1]]['path'], recursecb)
Patrick Williams2a254922023-08-11 09:48:11 -0500776 self.assertEqual(recursecb_count,1)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600777
778class SStatePrintdiff(SStateBase):
779 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 -0600780 import time
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600781 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600782TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-sametmp-{}"
783""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600784 # Use runall do_build to ensure any indirect sstate is created, e.g. tzcode-native on both x86 and
785 # aarch64 hosts since only allarch target recipes depend upon it and it may not be built otherwise.
786 # A bitbake -c cleansstate tzcode-native would cause some of these tests to error for example.
787 bitbake("--runall build --runall deploy_source_date_epoch {}".format(target))
788 bitbake("-S none {}".format(target))
789 bitbake(change_bbtask)
790 self.write_recipeinc(change_recipe, change_content)
791 result_sametmp = bitbake("-S printdiff {}".format(target))
792
793 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600794TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-difftmp-{}"
795""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600796 result_difftmp = bitbake("-S printdiff {}".format(target))
797
798 self.delete_recipeinc(change_recipe)
799 for item in expected_sametmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600800 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 -0600801 for item in expected_difftmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600802 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 -0600803
Patrick Williams705982a2024-01-12 09:51:57 -0600804 def run_test_printdiff_changeconfig(self, target, change_bbtasks, change_content, expected_sametmp_output, expected_difftmp_output):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600805 import time
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600806 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600807TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-sametmp-{}"
808""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600809 bitbake("--runall build --runall deploy_source_date_epoch {}".format(target))
810 bitbake("-S none {}".format(target))
Patrick Williams705982a2024-01-12 09:51:57 -0600811 bitbake(" ".join(change_bbtasks))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600812 self.append_config(change_content)
813 result_sametmp = bitbake("-S printdiff {}".format(target))
814
815 self.write_config("""
Patrick Williams169d7bc2024-01-05 11:33:25 -0600816TMPDIR = "${{TOPDIR}}/tmp-sstateprintdiff-difftmp-{}"
817""".format(time.time()))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600818 self.append_config(change_content)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600819 result_difftmp = bitbake("-S printdiff {}".format(target))
820
821 for item in expected_sametmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600822 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 -0600823 for item in expected_difftmp_output:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600824 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 -0600825
826
827 # 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 -0600828 def test_image_minimal_vs_perlcross(self):
829 expected_output = ("Task perlcross-native:do_install couldn't be used from the cache because:",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600830"We need hash",
831"most recent matching task was")
Patrick Williams705982a2024-01-12 09:51:57 -0600832 expected_sametmp_output = expected_output + (
833"Variable do_install value changed",
834'+ echo "this changes the task signature"')
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600835 expected_difftmp_output = expected_output
836
Patrick Williams705982a2024-01-12 09:51:57 -0600837 self.run_test_printdiff_changerecipe("core-image-minimal", "perlcross", "-c do_install perlcross-native",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600838"""
839do_install:append() {
840 echo "this changes the task signature"
841}
842""",
843expected_sametmp_output, expected_difftmp_output)
844
845 # Check if changes to gcc-source (which uses tmp/work-shared) are correctly discovered
Patrick Williams705982a2024-01-12 09:51:57 -0600846 def test_gcc_runtime_vs_gcc_source(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600847 gcc_source_pn = 'gcc-source-%s' % get_bb_vars(['PV'], 'gcc')['PV']
848
849 expected_output = ("Task {}:do_preconfigure couldn't be used from the cache because:".format(gcc_source_pn),
850"We need hash",
851"most recent matching task was")
Patrick Williams705982a2024-01-12 09:51:57 -0600852 expected_sametmp_output = expected_output + (
853"Variable do_preconfigure value changed",
854'+ print("this changes the task signature")')
855 expected_difftmp_output = expected_output
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600856
857 self.run_test_printdiff_changerecipe("gcc-runtime", "gcc-source", "-c do_preconfigure {}".format(gcc_source_pn),
858"""
859python do_preconfigure:append() {
860 print("this changes the task signature")
861}
862""",
863expected_sametmp_output, expected_difftmp_output)
864
865 # Check if changing a really base task definiton is reported against multiple core recipes using it
866 def test_image_minimal_vs_base_do_configure(self):
Patrick Williams705982a2024-01-12 09:51:57 -0600867 change_bbtasks = ('zstd-native:do_configure',
868'texinfo-dummy-native:do_configure',
869'ldconfig-native:do_configure',
870'gettext-minimal-native:do_configure',
871'tzcode-native:do_configure',
872'makedevs-native:do_configure',
873'pigz-native:do_configure',
874'update-rc.d-native:do_configure',
875'unzip-native:do_configure',
876'gnu-config-native:do_configure')
877
878 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 -0600879"We need hash",
Patrick Williams705982a2024-01-12 09:51:57 -0600880"most recent matching task was"]
881
882 expected_sametmp_output = expected_output + [
883"Variable base_do_configure value changed",
884'+ echo "this changes base_do_configure() definiton "']
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600885 expected_difftmp_output = expected_output
886
Patrick Williams705982a2024-01-12 09:51:57 -0600887 self.run_test_printdiff_changeconfig("core-image-minimal",change_bbtasks,
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600888"""
889INHERIT += "base-do-configure-modified"
890""",
891expected_sametmp_output, expected_difftmp_output)
892
893@OETestTag("yocto-mirrors")
894class SStateMirrors(SStateBase):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600895 def check_bb_output(self, output, exceptions, check_cdn):
896 def is_exception(object, exceptions):
897 for e in exceptions:
898 if re.search(e, object):
899 return True
900 return False
901
902 output_l = output.splitlines()
903 for l in output_l:
904 if l.startswith("Sstate summary"):
905 for idx, item in enumerate(l.split()):
906 if item == 'Missed':
907 missing_objects = int(l.split()[idx+1])
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600908 break
909 else:
Patrick Williams169d7bc2024-01-05 11:33:25 -0600910 self.fail("Did not find missing objects amount in sstate summary: {}".format(l))
911 break
912 else:
913 self.fail("Did not find 'Sstate summary' line in bitbake output")
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600914
Patrick Williams169d7bc2024-01-05 11:33:25 -0600915 failed_urls = []
Patrick Williams705982a2024-01-12 09:51:57 -0600916 failed_urls_extrainfo = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600917 for l in output_l:
918 if "SState: Unsuccessful fetch test for" in l and check_cdn:
919 missing_object = l.split()[6]
920 elif "SState: Looked for but didn't find file" in l and not check_cdn:
921 missing_object = l.split()[8]
922 else:
923 missing_object = None
924 if missing_object:
925 if not is_exception(missing_object, exceptions):
926 failed_urls.append(missing_object)
927 else:
928 missing_objects -= 1
929
Patrick Williams73bd93f2024-02-20 08:07:48 -0600930 if "urlopen failed for" in l and not is_exception(l, exceptions):
Patrick Williams705982a2024-01-12 09:51:57 -0600931 failed_urls_extrainfo.append(l)
932
933 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)))
934 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 -0600935
936 def run_test(self, machine, targets, exceptions, check_cdn = True):
937 # sstate is checked for existence of these, but they never get written out to begin with
938 exceptions += ["{}.*image_qa".format(t) for t in targets.split()]
939 exceptions += ["{}.*deploy_source_date_epoch".format(t) for t in targets.split()]
940 exceptions += ["{}.*image_complete".format(t) for t in targets.split()]
941 exceptions += ["linux-yocto.*shared_workdir"]
942 # these get influnced by IMAGE_FSTYPES tweaks in yocto-autobuilder-helper's config.json (on x86-64)
943 # additionally, they depend on noexec (thus, absent stamps) package, install, etc. image tasks,
944 # which makes tracing other changes difficult
945 exceptions += ["{}.*create_spdx".format(t) for t in targets.split()]
946 exceptions += ["{}.*create_runtime_spdx".format(t) for t in targets.split()]
947
948 if check_cdn:
949 self.config_sstate(True)
950 self.append_config("""
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600951MACHINE = "{}"
952BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"
953SSTATE_MIRRORS ?= "file://.* http://cdn.jsdelivr.net/yocto/sstate/all/PATH;downloadfilename=PATH"
954""".format(machine))
Patrick Williams169d7bc2024-01-05 11:33:25 -0600955 else:
956 self.append_config("""
957MACHINE = "{}"
958""".format(machine))
959 result = bitbake("-DD -n {}".format(targets))
960 bitbake("-S none {}".format(targets))
961 self.check_bb_output(result.output, exceptions, check_cdn)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600962
963 def test_cdn_mirror_qemux86_64(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600964 exceptions = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600965 self.run_test("qemux86-64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600966
967 def test_cdn_mirror_qemuarm64(self):
968 exceptions = []
Patrick Williams169d7bc2024-01-05 11:33:25 -0600969 self.run_test("qemuarm64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions)
970
971 def test_local_cache_qemux86_64(self):
972 exceptions = []
973 self.run_test("qemux86-64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions, check_cdn = False)
974
975 def test_local_cache_qemuarm64(self):
976 exceptions = []
977 self.run_test("qemuarm64", "core-image-minimal core-image-full-cmdline core-image-sato-sdk", exceptions, check_cdn = False)