blob: bdad9088d3730a926609dcdaaa0e01bbab4c2a6b [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
17
Andrew Geissler595f6302022-01-24 19:11:47 +000018import oe
Brad Bishopd7bf8c12018-02-25 22:55:05 -050019import bb.siggen
20
Patrick Williamsb542dec2023-06-09 01:26:37 -050021# Set to True to preserve stamp files after test execution for debugging failures
22keep_temp_files = False
23
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050024class SStateBase(OESelftestTestCase):
25
26 def setUpLocal(self):
27 super(SStateBase, self).setUpLocal()
28 self.temp_sstate_location = None
29 needed_vars = ['SSTATE_DIR', 'NATIVELSBSTRING', 'TCLIBC', 'TUNE_ARCH',
30 'TOPDIR', 'TARGET_VENDOR', 'TARGET_OS']
31 bb_vars = get_bb_vars(needed_vars)
32 self.sstate_path = bb_vars['SSTATE_DIR']
33 self.hostdistro = bb_vars['NATIVELSBSTRING']
34 self.tclibc = bb_vars['TCLIBC']
35 self.tune_arch = bb_vars['TUNE_ARCH']
36 self.topdir = bb_vars['TOPDIR']
37 self.target_vendor = bb_vars['TARGET_VENDOR']
38 self.target_os = bb_vars['TARGET_OS']
39 self.distro_specific_sstate = os.path.join(self.sstate_path, self.hostdistro)
40
Patrick Williamsb542dec2023-06-09 01:26:37 -050041 def track_for_cleanup(self, path):
42 if not keep_temp_files:
43 super().track_for_cleanup(path)
44
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050045 # Creates a special sstate configuration with the option to add sstate mirrors
46 def config_sstate(self, temp_sstate_location=False, add_local_mirrors=[]):
47 self.temp_sstate_location = temp_sstate_location
48
49 if self.temp_sstate_location:
50 temp_sstate_path = os.path.join(self.builddir, "temp_sstate_%s" % datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
51 config_temp_sstate = "SSTATE_DIR = \"%s\"" % temp_sstate_path
52 self.append_config(config_temp_sstate)
53 self.track_for_cleanup(temp_sstate_path)
54 bb_vars = get_bb_vars(['SSTATE_DIR', 'NATIVELSBSTRING'])
55 self.sstate_path = bb_vars['SSTATE_DIR']
56 self.hostdistro = bb_vars['NATIVELSBSTRING']
57 self.distro_specific_sstate = os.path.join(self.sstate_path, self.hostdistro)
58
59 if add_local_mirrors:
60 config_set_sstate_if_not_set = 'SSTATE_MIRRORS ?= ""'
61 self.append_config(config_set_sstate_if_not_set)
62 for local_mirror in add_local_mirrors:
63 self.assertFalse(os.path.join(local_mirror) == os.path.join(self.sstate_path), msg='Cannot add the current sstate path as a sstate mirror')
64 config_sstate_mirror = "SSTATE_MIRRORS += \"file://.* file:///%s/PATH\"" % local_mirror
65 self.append_config(config_sstate_mirror)
66
67 # Returns a list containing sstate files
68 def search_sstate(self, filename_regex, distro_specific=True, distro_nonspecific=True):
69 result = []
70 for root, dirs, files in os.walk(self.sstate_path):
71 if distro_specific and re.search(r"%s/%s/[a-z0-9]{2}/[a-z0-9]{2}$" % (self.sstate_path, self.hostdistro), root):
72 for f in files:
73 if re.search(filename_regex, f):
74 result.append(f)
75 if distro_nonspecific and re.search(r"%s/[a-z0-9]{2}/[a-z0-9]{2}$" % self.sstate_path, root):
76 for f in files:
77 if re.search(filename_regex, f):
78 result.append(f)
79 return result
80
81 # Test sstate files creation and their location
82 def run_test_sstate_creation(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True, should_pass=True):
83 self.config_sstate(temp_sstate_location, [self.sstate_path])
84
85 if self.temp_sstate_location:
86 bitbake(['-cclean'] + targets)
87 else:
88 bitbake(['-ccleansstate'] + targets)
89
90 bitbake(targets)
91 file_tracker = []
92 results = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific)
93 if distro_nonspecific:
94 for r in results:
95 if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo", "_fetch.tar.zst.siginfo", "_unpack.tar.zst.siginfo", "_patch.tar.zst.siginfo")):
96 continue
97 file_tracker.append(r)
98 else:
99 file_tracker = results
100
101 if should_pass:
102 self.assertTrue(file_tracker , msg="Could not find sstate files for: %s" % ', '.join(map(str, targets)))
103 else:
104 self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s (found %s)" % (', '.join(map(str, targets)), str(file_tracker)))
105
106 # Test the sstate files deletion part of the do_cleansstate task
107 def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True):
108 self.config_sstate(temp_sstate_location, [self.sstate_path])
109
110 bitbake(['-ccleansstate'] + targets)
111
112 bitbake(targets)
113 archives_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific)
114 self.assertTrue(archives_created, msg="Could not find sstate .tar.zst files for: %s (%s)" % (', '.join(map(str, targets)), str(archives_created)))
115
116 siginfo_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific)
117 self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s (%s)" % (', '.join(map(str, targets)), str(siginfo_created)))
118
119 bitbake(['-ccleansstate'] + targets)
120 archives_removed = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific, distro_nonspecific)
121 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)))
122
123 # Test rebuilding of distro-specific sstate files
124 def run_test_rebuild_distro_specific_sstate(self, targets, temp_sstate_location=True):
125 self.config_sstate(temp_sstate_location, [self.sstate_path])
126
127 bitbake(['-ccleansstate'] + targets)
128
129 bitbake(targets)
130 results = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=False, distro_nonspecific=True)
131 filtered_results = []
132 for r in results:
133 if r.endswith(("_populate_lic.tar.zst", "_populate_lic.tar.zst.siginfo")):
134 continue
135 filtered_results.append(r)
136 self.assertTrue(filtered_results == [], msg="Found distro non-specific sstate for: %s (%s)" % (', '.join(map(str, targets)), str(filtered_results)))
137 file_tracker_1 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False)
138 self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets)))
139
140 self.track_for_cleanup(self.distro_specific_sstate + "_old")
141 shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old")
142 shutil.rmtree(self.distro_specific_sstate)
143
144 bitbake(['-cclean'] + targets)
145 bitbake(targets)
146 file_tracker_2 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tar.zst$' for s in targets])), distro_specific=True, distro_nonspecific=False)
147 self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files were created for: %s" % ', '.join(map(str, targets)))
148
149 not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2]
150 self.assertTrue(not_recreated == [], msg="The following sstate files were not recreated: %s" % ', '.join(map(str, not_recreated)))
151
152 created_once = [x for x in file_tracker_2 if x not in file_tracker_1]
153 self.assertTrue(created_once == [], msg="The following sstate files were created only in the second run: %s" % ', '.join(map(str, created_once)))
154
155 def sstate_common_samesigs(self, configA, configB, allarch=False):
156
157 self.write_config(configA)
158 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
159 bitbake("world meta-toolchain -S none")
160 self.write_config(configB)
161 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
162 bitbake("world meta-toolchain -S none")
163
164 def get_files(d, result):
165 for root, dirs, files in os.walk(d):
166 for name in files:
167 if "meta-environment" in root or "cross-canadian" in root:
168 continue
169 if "do_build" not in name:
170 # 1.4.1+gitAUTOINC+302fca9f4c-r0.do_package_write_ipk.sigdata.f3a2a38697da743f0dbed8b56aafcf79
171 (_, task, _, shash) = name.rsplit(".", 3)
172 result[os.path.join(os.path.basename(root), task)] = shash
173
174 files1 = {}
175 files2 = {}
176 subdirs = sorted(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux"))
177 if allarch:
178 subdirs.extend(sorted(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/all-*-linux")))
179
180 for subdir in subdirs:
181 nativesdkdir = os.path.basename(subdir)
182 get_files(self.topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir, files1)
183 get_files(self.topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir, files2)
184
185 self.maxDiff = None
186 self.assertEqual(files1, files2)
187
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500188class SStateTests(SStateBase):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400189 def test_autorev_sstate_works(self):
190 # Test that a git repository which changes is correctly handled by SRCREV = ${AUTOREV}
Brad Bishop316dfdd2018-06-25 12:45:53 -0400191
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500192 tempdir = tempfile.mkdtemp(prefix='sstate_autorev')
193 tempdldir = tempfile.mkdtemp(prefix='sstate_autorev_dldir')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400194 self.track_for_cleanup(tempdir)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500195 self.track_for_cleanup(tempdldir)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400196 create_temp_layer(tempdir, 'selftestrecipetool')
197 self.add_command_to_tearDown('bitbake-layers remove-layer %s' % tempdir)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500198 self.append_config("DL_DIR = \"%s\"" % tempdldir)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400199 runCmd('bitbake-layers add-layer %s' % tempdir)
200
201 # Use dbus-wait as a local git repo we can add a commit between two builds in
202 pn = 'dbus-wait'
203 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
204 url = 'git://git.yoctoproject.org/dbus-wait'
205 result = runCmd('git clone %s noname' % url, cwd=tempdir)
206 srcdir = os.path.join(tempdir, 'noname')
207 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
208 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
209
210 recipefile = os.path.join(tempdir, "recipes-test", "dbus-wait-test", 'dbus-wait-test_git.bb')
211 os.makedirs(os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000212 srcuri = 'git://' + srcdir + ';protocol=file;branch=master'
Brad Bishop316dfdd2018-06-25 12:45:53 -0400213 result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri])
214 self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output)
215
216 with open(recipefile, 'a') as f:
217 f.write('SRCREV = "${AUTOREV}"\n')
218 f.write('PV = "1.0"\n')
219
220 bitbake("dbus-wait-test -c fetch")
221 with open(os.path.join(srcdir, "bar.txt"), "w") as f:
222 f.write("foo")
223 result = runCmd('git add bar.txt; git commit -asm "add bar"', cwd=srcdir)
224 bitbake("dbus-wait-test -c unpack")
225
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500226class SStateCreation(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500227 def test_sstate_creation_distro_specific_pass(self):
228 self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
229
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500230 def test_sstate_creation_distro_specific_fail(self):
231 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)
232
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500233 def test_sstate_creation_distro_nonspecific_pass(self):
234 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
235
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500236 def test_sstate_creation_distro_nonspecific_fail(self):
237 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False)
238
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500239class SStateCleanup(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500240 def test_cleansstate_task_distro_specific_nonspecific(self):
241 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
242 targets.append('linux-libc-headers')
243 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True)
244
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500245 def test_cleansstate_task_distro_nonspecific(self):
246 self.run_test_cleansstate_task(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
247
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500248 def test_cleansstate_task_distro_specific(self):
249 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native']
250 targets.append('linux-libc-headers')
251 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
252
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500253class SStateDistroTests(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500254 def test_rebuild_distro_specific_sstate_cross_native_targets(self):
255 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch, 'binutils-native'], temp_sstate_location=True)
256
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500257 def test_rebuild_distro_specific_sstate_cross_target(self):
258 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch], temp_sstate_location=True)
259
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500260 def test_rebuild_distro_specific_sstate_native_target(self):
261 self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True)
262
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500263class SStateCacheManagement(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500264 # Test the sstate-cache-management script. Each element in the global_config list is used with the corresponding element in the target_config list
265 # global_config elements are expected to not generate any sstate files that would be removed by sstate-cache-management.sh (such as changing the value of MACHINE)
266 def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]):
267 self.assertTrue(global_config)
268 self.assertTrue(target_config)
269 self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements')
270 self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path])
271
272 # If buildhistory is enabled, we need to disable version-going-backwards
273 # QA checks for this test. It may report errors otherwise.
Patrick Williams213cb262021-08-07 19:21:33 -0500274 self.append_config('ERROR_QA:remove = "version-going-backwards"')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500275
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000276 # For now this only checks if random sstate tasks are handled correctly as a group.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500277 # In the future we should add control over what tasks we check for.
278
279 sstate_archs_list = []
280 expected_remaining_sstate = []
281 for idx in range(len(target_config)):
282 self.append_config(global_config[idx])
283 self.append_recipeinc(target, target_config[idx])
284 sstate_arch = get_bb_var('SSTATE_PKGARCH', target)
285 if not sstate_arch in sstate_archs_list:
286 sstate_archs_list.append(sstate_arch)
287 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500288 target_sstate_before_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500289 bitbake("-cclean %s" % target)
290 result = bitbake(target, ignore_status=True)
291 if target_config[idx] == target_config[-1]:
Andrew Geisslereff27472021-10-29 15:35:00 -0500292 target_sstate_after_build = self.search_sstate(target + r'.*?\.tar.zst$')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500293 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)]
294 self.remove_config(global_config[idx])
295 self.remove_recipeinc(target, target_config[idx])
296 self.assertEqual(result.status, 0, msg = "build of %s failed with %s" % (target, result.output))
297
298 runCmd("sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ','.join(map(str, sstate_archs_list))))
Andrew Geisslereff27472021-10-29 15:35:00 -0500299 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 -0500300
301 actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500302 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 -0500303 expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate]
Andrew Geisslereff27472021-10-29 15:35:00 -0500304 self.assertFalse(expected_not_actual, msg="Extra files were removed: %s" ', '.join(map(str, expected_not_actual)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500305
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500306 def test_sstate_cache_management_script_using_pr_1(self):
307 global_config = []
308 target_config = []
309 global_config.append('')
310 target_config.append('PR = "0"')
311 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
312
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500313 def test_sstate_cache_management_script_using_pr_2(self):
314 global_config = []
315 target_config = []
316 global_config.append('')
317 target_config.append('PR = "0"')
318 global_config.append('')
319 target_config.append('PR = "1"')
320 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
321
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500322 def test_sstate_cache_management_script_using_pr_3(self):
323 global_config = []
324 target_config = []
325 global_config.append('MACHINE = "qemux86-64"')
326 target_config.append('PR = "0"')
327 global_config.append(global_config[0])
328 target_config.append('PR = "1"')
329 global_config.append('MACHINE = "qemux86"')
330 target_config.append('PR = "1"')
331 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
332
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500333 def test_sstate_cache_management_script_using_machine(self):
334 global_config = []
335 target_config = []
336 global_config.append('MACHINE = "qemux86-64"')
337 target_config.append('')
338 global_config.append('MACHINE = "qemux86"')
339 target_config.append('')
340 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
341
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500342class SStateHashSameSigs(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500343 def test_sstate_32_64_same_hash(self):
344 """
345 The sstate checksums for both native and target should not vary whether
346 they're built on a 32 or 64 bit system. Rather than requiring two different
347 build machines and running a builds, override the variables calling uname()
348 manually and check using bitbake -S.
349 """
350
351 self.write_config("""
352MACHINE = "qemux86"
353TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800354TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500355BUILD_ARCH = "x86_64"
356BUILD_OS = "linux"
357SDKMACHINE = "x86_64"
358PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500359BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360""")
361 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500362 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500363 self.write_config("""
364MACHINE = "qemux86"
365TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800366TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500367BUILD_ARCH = "i686"
368BUILD_OS = "linux"
369SDKMACHINE = "i686"
370PACKAGE_CLASSES = "package_rpm package_ipk package_deb"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500371BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500372""")
373 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500374 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500375
376 def get_files(d):
377 f = []
378 for root, dirs, files in os.walk(d):
Andrew Geisslerc926e172021-05-07 16:11:35 -0500379 if "core-image-weston" in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500380 # SDKMACHINE changing will change
381 # do_rootfs/do_testimage/do_build stamps of images which
382 # is safe to ignore.
383 continue
384 f.extend(os.path.join(root, name) for name in files)
385 return f
386 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
387 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
388 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]
389 self.maxDiff = None
390 self.assertCountEqual(files1, files2)
391
392
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500393 def test_sstate_nativelsbstring_same_hash(self):
394 """
395 The sstate checksums should be independent of whichever NATIVELSBSTRING is
396 detected. Rather than requiring two different build machines and running
397 builds, override the variables manually and check using bitbake -S.
398 """
399
400 self.write_config("""
401TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800402TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500403NATIVELSBSTRING = \"DistroA\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500404BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500405""")
406 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500407 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500408 self.write_config("""
409TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800410TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500411NATIVELSBSTRING = \"DistroB\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500412BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500413""")
414 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500415 bitbake("core-image-weston -S none")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500416
417 def get_files(d):
418 f = []
419 for root, dirs, files in os.walk(d):
420 f.extend(os.path.join(root, name) for name in files)
421 return f
422 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
423 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
424 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
425 self.maxDiff = None
426 self.assertCountEqual(files1, files2)
427
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500428class SStateHashSameSigs2(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500429 def test_sstate_allarch_samesigs(self):
430 """
431 The sstate checksums of allarch packages should be independent of whichever
432 MACHINE is set. Check this using bitbake -S.
433 Also, rather than duplicate the test, check nativesdk stamps are the same between
434 the two MACHINE values.
435 """
436
437 configA = """
438TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800439TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500440MACHINE = \"qemux86-64\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500441BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500442"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000443 #OLDEST_KERNEL is arch specific so set to a different value here for testing
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500444 configB = """
445TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800446TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500447MACHINE = \"qemuarm\"
Andrew Geissler595f6302022-01-24 19:11:47 +0000448OLDEST_KERNEL = \"3.3.0\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500449BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500450"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000451 self.sstate_common_samesigs(configA, configB, allarch=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500452
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800453 def test_sstate_nativesdk_samesigs_multilib(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500454 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800455 check nativesdk stamps are the same between the two MACHINE values.
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500456 """
457
458 configA = """
459TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800460TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500461MACHINE = \"qemux86-64\"
462require conf/multilib.conf
463MULTILIBS = \"multilib:lib32\"
Patrick Williams213cb262021-08-07 19:21:33 -0500464DEFAULTTUNE:virtclass-multilib-lib32 = \"x86\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500465BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500466"""
467 configB = """
468TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800469TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500470MACHINE = \"qemuarm\"
471require conf/multilib.conf
472MULTILIBS = \"\"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500473BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500474"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000475 self.sstate_common_samesigs(configA, configB)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500476
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500477class SStateHashSameSigs3(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500478 def test_sstate_sametune_samesigs(self):
479 """
480 The sstate checksums of two identical machines (using the same tune) should be the
481 same, apart from changes within the machine specific stamps directory. We use the
482 qemux86copy machine to test this. Also include multilibs in the test.
483 """
484
485 self.write_config("""
486TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800487TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500488MACHINE = \"qemux86\"
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 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
495 bitbake("world meta-toolchain -S none")
496 self.write_config("""
497TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800498TCLIBCAPPEND = \"\"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500499MACHINE = \"qemux86copy\"
500require conf/multilib.conf
501MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500502DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500503BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500504""")
505 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
506 bitbake("world meta-toolchain -S none")
507
508 def get_files(d):
509 f = []
510 for root, dirs, files in os.walk(d):
511 for name in files:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500512 if "meta-environment" in root or "cross-canadian" in root or 'meta-ide-support' in root:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500513 continue
514 if "qemux86copy-" in root or "qemux86-" in root:
515 continue
516 if "do_build" not in name and "do_populate_sdk" not in name:
517 f.append(os.path.join(root, name))
518 return f
519 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
520 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
521 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
522 self.maxDiff = None
523 self.assertCountEqual(files1, files2)
524
525
Andrew Geissler82c905d2020-04-13 13:39:40 -0500526 def test_sstate_multilib_or_not_native_samesigs(self):
527 """The sstate checksums of two native recipes (and their dependencies)
528 where the target is using multilib in one but not the other
529 should be the same. We use the qemux86copy machine to test
530 this.
531 """
532
533 self.write_config("""
534TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\"
535TCLIBCAPPEND = \"\"
536MACHINE = \"qemux86\"
537require conf/multilib.conf
538MULTILIBS = "multilib:lib32"
Patrick Williams213cb262021-08-07 19:21:33 -0500539DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
Andrew Geissler82c905d2020-04-13 13:39:40 -0500540BB_SIGNATURE_HANDLER = "OEBasicHash"
541""")
542 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
543 bitbake("binutils-native -S none")
544 self.write_config("""
545TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\"
546TCLIBCAPPEND = \"\"
547MACHINE = \"qemux86copy\"
548BB_SIGNATURE_HANDLER = "OEBasicHash"
549""")
550 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
551 bitbake("binutils-native -S none")
552
553 def get_files(d):
554 f = []
555 for root, dirs, files in os.walk(d):
556 for name in files:
557 f.append(os.path.join(root, name))
558 return f
559 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
560 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
561 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
562 self.maxDiff = None
563 self.assertCountEqual(files1, files2)
564
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500565class SStateHashSameSigs4(SStateBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500566 def test_sstate_noop_samesigs(self):
567 """
568 The sstate checksums of two builds with these variables changed or
569 classes inherits should be the same.
570 """
571
572 self.write_config("""
573TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800574TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500575BB_NUMBER_THREADS = "${@oe.utils.cpu_count()}"
576PARALLEL_MAKE = "-j 1"
577DL_DIR = "${TOPDIR}/download1"
578TIME = "111111"
579DATE = "20161111"
Patrick Williams213cb262021-08-07 19:21:33 -0500580INHERIT:remove = "buildstats-summary buildhistory uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500581http_proxy = ""
Brad Bishop6dbb3162019-11-25 09:41:34 -0500582BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500583""")
584 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
585 self.track_for_cleanup(self.topdir + "/download1")
586 bitbake("world meta-toolchain -S none")
587 self.write_config("""
588TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800589TCLIBCAPPEND = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500590BB_NUMBER_THREADS = "${@oe.utils.cpu_count()+1}"
591PARALLEL_MAKE = "-j 2"
592DL_DIR = "${TOPDIR}/download2"
593TIME = "222222"
594DATE = "20161212"
595# Always remove uninative as we're changing proxies
Patrick Williams213cb262021-08-07 19:21:33 -0500596INHERIT:remove = "uninative"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500597INHERIT += "buildstats-summary buildhistory"
598http_proxy = "http://example.com/"
Brad Bishop6dbb3162019-11-25 09:41:34 -0500599BB_SIGNATURE_HANDLER = "OEBasicHash"
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500600""")
601 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
602 self.track_for_cleanup(self.topdir + "/download2")
603 bitbake("world meta-toolchain -S none")
604
605 def get_files(d):
606 f = {}
607 for root, dirs, files in os.walk(d):
608 for name in files:
609 name, shash = name.rsplit('.', 1)
610 # Extract just the machine and recipe name
611 base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name])
612 f[base] = shash
613 return f
614
615 def compare_sigfiles(files, files1, files2, compare=False):
616 for k in files:
617 if k in files1 and k in files2:
618 print("%s differs:" % k)
619 if compare:
620 sigdatafile1 = self.topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k]
621 sigdatafile2 = self.topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]
622 output = bb.siggen.compare_sigfiles(sigdatafile1, sigdatafile2)
623 if output:
624 print('\n'.join(output))
625 elif k in files1 and k not in files2:
626 print("%s in files1" % k)
627 elif k not in files1 and k in files2:
628 print("%s in files2" % k)
629 else:
630 assert "shouldn't reach here"
631
632 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/")
633 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/")
634 # Remove items that are identical in both sets
635 for k,v in files1.items() & files2.items():
636 del files1[k]
637 del files2[k]
638 if not files1 and not files2:
639 # No changes, so we're done
640 return
641
642 files = list(files1.keys() | files2.keys())
643 # this is an expensive computation, thus just compare the first 'max_sigfiles_to_compare' k files
644 max_sigfiles_to_compare = 20
645 first, rest = files[:max_sigfiles_to_compare], files[max_sigfiles_to_compare:]
Brad Bishop316dfdd2018-06-25 12:45:53 -0400646 compare_sigfiles(first, files1, files2, compare=True)
647 compare_sigfiles(rest, files1, files2, compare=False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500648
649 self.fail("sstate hashes not identical.")
Andrew Geissler595f6302022-01-24 19:11:47 +0000650
651 def test_sstate_movelayer_samesigs(self):
652 """
653 The sstate checksums of two builds with the same oe-core layer in two
654 different locations should be the same.
655 """
656 core_layer = os.path.join(
657 self.tc.td["COREBASE"], 'meta')
658 copy_layer_1 = self.topdir + "/meta-copy1/meta"
659 copy_layer_2 = self.topdir + "/meta-copy2/meta"
660
661 oe.path.copytree(core_layer, copy_layer_1)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500662 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy1/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000663 self.write_config("""
664TMPDIR = "${TOPDIR}/tmp-sstatesamehash"
665""")
666 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_1, core_layer)
667 self.write_bblayers_config(bblayers_conf)
668 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash")
669 bitbake("bash -S none")
670
671 oe.path.copytree(core_layer, copy_layer_2)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500672 os.symlink(os.path.dirname(core_layer) + "/scripts", self.topdir + "/meta-copy2/scripts")
Andrew Geissler595f6302022-01-24 19:11:47 +0000673 self.write_config("""
674TMPDIR = "${TOPDIR}/tmp-sstatesamehash2"
675""")
676 bblayers_conf = 'BBLAYERS += "%s"\nBBLAYERS:remove = "%s"' % (copy_layer_2, core_layer)
677 self.write_bblayers_config(bblayers_conf)
678 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2")
679 bitbake("bash -S none")
680
681 def get_files(d):
682 f = []
683 for root, dirs, files in os.walk(d):
684 for name in files:
685 f.append(os.path.join(root, name))
686 return f
687 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps")
688 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps")
689 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2]
690 self.maxDiff = None
691 self.assertCountEqual(files1, files2)
692
Patrick Williams2a254922023-08-11 09:48:11 -0500693class SStateFindSiginfo(SStateBase):
694 def test_sstate_compare_sigfiles_and_find_siginfo(self):
695 """
696 Test the functionality of the find_siginfo: basic function and callback in compare_sigfiles
697 """
698 self.write_config("""
699TMPDIR = \"${TOPDIR}/tmp-sstates-findsiginfo\"
700TCLIBCAPPEND = \"\"
701MACHINE = \"qemux86-64\"
702require conf/multilib.conf
703MULTILIBS = "multilib:lib32"
704DEFAULTTUNE:virtclass-multilib-lib32 = "x86"
705BB_SIGNATURE_HANDLER = "OEBasicHash"
706""")
707 self.track_for_cleanup(self.topdir + "/tmp-sstates-findsiginfo")
708
709 pns = ["binutils", "binutils-native", "lib32-binutils"]
710 target_configs = [
711"""
712TMPVAL1 = "tmpval1"
713TMPVAL2 = "tmpval2"
714do_tmptask1() {
715 echo ${TMPVAL1}
716}
717do_tmptask2() {
718 echo ${TMPVAL2}
719}
720addtask do_tmptask1
721addtask tmptask2 before do_tmptask1
722""",
723"""
724TMPVAL3 = "tmpval3"
725TMPVAL4 = "tmpval4"
726do_tmptask1() {
727 echo ${TMPVAL3}
728}
729do_tmptask2() {
730 echo ${TMPVAL4}
731}
732addtask do_tmptask1
733addtask tmptask2 before do_tmptask1
734"""
735 ]
736
737 for target_config in target_configs:
738 self.write_recipeinc("binutils", target_config)
739 for pn in pns:
740 bitbake("%s -c do_tmptask1 -S none" % pn)
741 self.delete_recipeinc("binutils")
742
743 with bb.tinfoil.Tinfoil() as tinfoil:
744 tinfoil.prepare(config_only=True)
745
746 def find_siginfo(pn, taskname, sigs=None):
747 result = None
748 tinfoil.set_event_mask(["bb.event.FindSigInfoResult",
749 "bb.command.CommandCompleted"])
750 ret = tinfoil.run_command("findSigInfo", pn, taskname, sigs)
751 if ret:
752 while True:
753 event = tinfoil.wait_event(1)
754 if event:
755 if isinstance(event, bb.command.CommandCompleted):
756 break
757 elif isinstance(event, bb.event.FindSigInfoResult):
758 result = event.result
759 return result
760
761 def recursecb(key, hash1, hash2):
762 nonlocal recursecb_count
763 recursecb_count += 1
764 hashes = [hash1, hash2]
765 hashfiles = find_siginfo(key, None, hashes)
766 self.assertCountEqual(hashes, hashfiles)
767 bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb)
768
769 for pn in pns:
770 recursecb_count = 0
771 filedates = find_siginfo(pn, "do_tmptask1")
772 self.assertGreaterEqual(len(filedates), 2)
773 latestfiles = sorted(filedates.keys(), key=lambda f: filedates[f])[-2:]
774 bb.siggen.compare_sigfiles(latestfiles[-2], latestfiles[-1], recursecb)
775 self.assertEqual(recursecb_count,1)