1# 2# SPDX-License-Identifier: MIT 3# 4 5import os 6import shutil 7import glob 8import subprocess 9import tempfile 10 11from oeqa.selftest.case import OESelftestTestCase 12from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer, create_temp_layer 13from oeqa.selftest.cases.sstate import SStateBase 14 15import bb.siggen 16 17class SStateTests(SStateBase): 18 def test_autorev_sstate_works(self): 19 # Test that a git repository which changes is correctly handled by SRCREV = ${AUTOREV} 20 # when PV does not contain SRCPV 21 22 tempdir = tempfile.mkdtemp(prefix='sstate_autorev') 23 tempdldir = tempfile.mkdtemp(prefix='sstate_autorev_dldir') 24 self.track_for_cleanup(tempdir) 25 self.track_for_cleanup(tempdldir) 26 create_temp_layer(tempdir, 'selftestrecipetool') 27 self.add_command_to_tearDown('bitbake-layers remove-layer %s' % tempdir) 28 self.append_config("DL_DIR = \"%s\"" % tempdldir) 29 runCmd('bitbake-layers add-layer %s' % tempdir) 30 31 # Use dbus-wait as a local git repo we can add a commit between two builds in 32 pn = 'dbus-wait' 33 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517' 34 url = 'git://git.yoctoproject.org/dbus-wait' 35 result = runCmd('git clone %s noname' % url, cwd=tempdir) 36 srcdir = os.path.join(tempdir, 'noname') 37 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir) 38 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory') 39 40 recipefile = os.path.join(tempdir, "recipes-test", "dbus-wait-test", 'dbus-wait-test_git.bb') 41 os.makedirs(os.path.dirname(recipefile)) 42 srcuri = 'git://' + srcdir + ';protocol=file' 43 result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri]) 44 self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output) 45 46 with open(recipefile, 'a') as f: 47 f.write('SRCREV = "${AUTOREV}"\n') 48 f.write('PV = "1.0"\n') 49 50 bitbake("dbus-wait-test -c fetch") 51 with open(os.path.join(srcdir, "bar.txt"), "w") as f: 52 f.write("foo") 53 result = runCmd('git add bar.txt; git commit -asm "add bar"', cwd=srcdir) 54 bitbake("dbus-wait-test -c unpack") 55 56 57 # Test sstate files creation and their location 58 def run_test_sstate_creation(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True, should_pass=True): 59 self.config_sstate(temp_sstate_location, [self.sstate_path]) 60 61 if self.temp_sstate_location: 62 bitbake(['-cclean'] + targets) 63 else: 64 bitbake(['-ccleansstate'] + targets) 65 66 bitbake(targets) 67 file_tracker = [] 68 results = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific) 69 if distro_nonspecific: 70 for r in results: 71 if r.endswith(("_populate_lic.tgz", "_populate_lic.tgz.siginfo", "_fetch.tgz.siginfo", "_unpack.tgz.siginfo", "_patch.tgz.siginfo")): 72 continue 73 file_tracker.append(r) 74 else: 75 file_tracker = results 76 77 if should_pass: 78 self.assertTrue(file_tracker , msg="Could not find sstate files for: %s" % ', '.join(map(str, targets))) 79 else: 80 self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s (found %s)" % (', '.join(map(str, targets)), str(file_tracker))) 81 82 def test_sstate_creation_distro_specific_pass(self): 83 self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) 84 85 def test_sstate_creation_distro_specific_fail(self): 86 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) 87 88 def test_sstate_creation_distro_nonspecific_pass(self): 89 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) 90 91 def test_sstate_creation_distro_nonspecific_fail(self): 92 self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False) 93 94 # Test the sstate files deletion part of the do_cleansstate task 95 def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True): 96 self.config_sstate(temp_sstate_location, [self.sstate_path]) 97 98 bitbake(['-ccleansstate'] + targets) 99 100 bitbake(targets) 101 tgz_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific) 102 self.assertTrue(tgz_created, msg="Could not find sstate .tgz files for: %s (%s)" % (', '.join(map(str, targets)), str(tgz_created))) 103 104 siginfo_created = self.search_sstate('|'.join(map(str, [s + r'.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific) 105 self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s (%s)" % (', '.join(map(str, targets)), str(siginfo_created))) 106 107 bitbake(['-ccleansstate'] + targets) 108 tgz_removed = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific) 109 self.assertTrue(not tgz_removed, msg="do_cleansstate didn't remove .tgz sstate files for: %s (%s)" % (', '.join(map(str, targets)), str(tgz_removed))) 110 111 def test_cleansstate_task_distro_specific_nonspecific(self): 112 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native'] 113 targets.append('linux-libc-headers') 114 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True) 115 116 def test_cleansstate_task_distro_nonspecific(self): 117 self.run_test_cleansstate_task(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) 118 119 def test_cleansstate_task_distro_specific(self): 120 targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native'] 121 targets.append('linux-libc-headers') 122 self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) 123 124 125 # Test rebuilding of distro-specific sstate files 126 def run_test_rebuild_distro_specific_sstate(self, targets, temp_sstate_location=True): 127 self.config_sstate(temp_sstate_location, [self.sstate_path]) 128 129 bitbake(['-ccleansstate'] + targets) 130 131 bitbake(targets) 132 results = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific=False, distro_nonspecific=True) 133 filtered_results = [] 134 for r in results: 135 if r.endswith(("_populate_lic.tgz", "_populate_lic.tgz.siginfo")): 136 continue 137 filtered_results.append(r) 138 self.assertTrue(filtered_results == [], msg="Found distro non-specific sstate for: %s (%s)" % (', '.join(map(str, targets)), str(filtered_results))) 139 file_tracker_1 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False) 140 self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets))) 141 142 self.track_for_cleanup(self.distro_specific_sstate + "_old") 143 shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old") 144 shutil.rmtree(self.distro_specific_sstate) 145 146 bitbake(['-cclean'] + targets) 147 bitbake(targets) 148 file_tracker_2 = self.search_sstate('|'.join(map(str, [s + r'.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False) 149 self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets))) 150 151 not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2] 152 self.assertTrue(not_recreated == [], msg="The following sstate files ware not recreated: %s" % ', '.join(map(str, not_recreated))) 153 154 created_once = [x for x in file_tracker_2 if x not in file_tracker_1] 155 self.assertTrue(created_once == [], msg="The following sstate files ware created only in the second run: %s" % ', '.join(map(str, created_once))) 156 157 def test_rebuild_distro_specific_sstate_cross_native_targets(self): 158 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch, 'binutils-native'], temp_sstate_location=True) 159 160 def test_rebuild_distro_specific_sstate_cross_target(self): 161 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch], temp_sstate_location=True) 162 163 def test_rebuild_distro_specific_sstate_native_target(self): 164 self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True) 165 166 167 # Test the sstate-cache-management script. Each element in the global_config list is used with the corresponding element in the target_config list 168 # 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) 169 def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]): 170 self.assertTrue(global_config) 171 self.assertTrue(target_config) 172 self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements') 173 self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path]) 174 175 # If buildhistory is enabled, we need to disable version-going-backwards 176 # QA checks for this test. It may report errors otherwise. 177 self.append_config('ERROR_QA:remove = "version-going-backwards"') 178 179 # For not this only checks if random sstate tasks are handled correctly as a group. 180 # In the future we should add control over what tasks we check for. 181 182 sstate_archs_list = [] 183 expected_remaining_sstate = [] 184 for idx in range(len(target_config)): 185 self.append_config(global_config[idx]) 186 self.append_recipeinc(target, target_config[idx]) 187 sstate_arch = get_bb_var('SSTATE_PKGARCH', target) 188 if not sstate_arch in sstate_archs_list: 189 sstate_archs_list.append(sstate_arch) 190 if target_config[idx] == target_config[-1]: 191 target_sstate_before_build = self.search_sstate(target + r'.*?\.tgz$') 192 bitbake("-cclean %s" % target) 193 result = bitbake(target, ignore_status=True) 194 if target_config[idx] == target_config[-1]: 195 target_sstate_after_build = self.search_sstate(target + r'.*?\.tgz$') 196 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)] 197 self.remove_config(global_config[idx]) 198 self.remove_recipeinc(target, target_config[idx]) 199 self.assertEqual(result.status, 0, msg = "build of %s failed with %s" % (target, result.output)) 200 201 runCmd("sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ','.join(map(str, sstate_archs_list)))) 202 actual_remaining_sstate = [x for x in self.search_sstate(target + r'.*?\.tgz$') if not any(pattern in x for pattern in ignore_patterns)] 203 204 actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate] 205 self.assertFalse(actual_not_expected, msg="Files should have been removed but ware not: %s" % ', '.join(map(str, actual_not_expected))) 206 expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate] 207 self.assertFalse(expected_not_actual, msg="Extra files ware removed: %s" ', '.join(map(str, expected_not_actual))) 208 209 def test_sstate_cache_management_script_using_pr_1(self): 210 global_config = [] 211 target_config = [] 212 global_config.append('') 213 target_config.append('PR = "0"') 214 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) 215 216 def test_sstate_cache_management_script_using_pr_2(self): 217 global_config = [] 218 target_config = [] 219 global_config.append('') 220 target_config.append('PR = "0"') 221 global_config.append('') 222 target_config.append('PR = "1"') 223 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) 224 225 def test_sstate_cache_management_script_using_pr_3(self): 226 global_config = [] 227 target_config = [] 228 global_config.append('MACHINE = "qemux86-64"') 229 target_config.append('PR = "0"') 230 global_config.append(global_config[0]) 231 target_config.append('PR = "1"') 232 global_config.append('MACHINE = "qemux86"') 233 target_config.append('PR = "1"') 234 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) 235 236 def test_sstate_cache_management_script_using_machine(self): 237 global_config = [] 238 target_config = [] 239 global_config.append('MACHINE = "qemux86-64"') 240 target_config.append('') 241 global_config.append('MACHINE = "qemux86"') 242 target_config.append('') 243 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic']) 244 245 def test_sstate_32_64_same_hash(self): 246 """ 247 The sstate checksums for both native and target should not vary whether 248 they're built on a 32 or 64 bit system. Rather than requiring two different 249 build machines and running a builds, override the variables calling uname() 250 manually and check using bitbake -S. 251 """ 252 253 self.write_config(""" 254MACHINE = "qemux86" 255TMPDIR = "${TOPDIR}/tmp-sstatesamehash" 256TCLIBCAPPEND = "" 257BUILD_ARCH = "x86_64" 258BUILD_OS = "linux" 259SDKMACHINE = "x86_64" 260PACKAGE_CLASSES = "package_rpm package_ipk package_deb" 261BB_SIGNATURE_HANDLER = "OEBasicHash" 262""") 263 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") 264 bitbake("core-image-weston -S none") 265 self.write_config(""" 266MACHINE = "qemux86" 267TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" 268TCLIBCAPPEND = "" 269BUILD_ARCH = "i686" 270BUILD_OS = "linux" 271SDKMACHINE = "i686" 272PACKAGE_CLASSES = "package_rpm package_ipk package_deb" 273BB_SIGNATURE_HANDLER = "OEBasicHash" 274""") 275 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") 276 bitbake("core-image-weston -S none") 277 278 def get_files(d): 279 f = [] 280 for root, dirs, files in os.walk(d): 281 if "core-image-weston" in root: 282 # SDKMACHINE changing will change 283 # do_rootfs/do_testimage/do_build stamps of images which 284 # is safe to ignore. 285 continue 286 f.extend(os.path.join(root, name) for name in files) 287 return f 288 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/") 289 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/") 290 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] 291 self.maxDiff = None 292 self.assertCountEqual(files1, files2) 293 294 295 def test_sstate_nativelsbstring_same_hash(self): 296 """ 297 The sstate checksums should be independent of whichever NATIVELSBSTRING is 298 detected. Rather than requiring two different build machines and running 299 builds, override the variables manually and check using bitbake -S. 300 """ 301 302 self.write_config(""" 303TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" 304TCLIBCAPPEND = \"\" 305NATIVELSBSTRING = \"DistroA\" 306BB_SIGNATURE_HANDLER = "OEBasicHash" 307""") 308 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") 309 bitbake("core-image-weston -S none") 310 self.write_config(""" 311TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" 312TCLIBCAPPEND = \"\" 313NATIVELSBSTRING = \"DistroB\" 314BB_SIGNATURE_HANDLER = "OEBasicHash" 315""") 316 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") 317 bitbake("core-image-weston -S none") 318 319 def get_files(d): 320 f = [] 321 for root, dirs, files in os.walk(d): 322 f.extend(os.path.join(root, name) for name in files) 323 return f 324 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/") 325 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/") 326 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] 327 self.maxDiff = None 328 self.assertCountEqual(files1, files2) 329 330 def test_sstate_allarch_samesigs(self): 331 """ 332 The sstate checksums of allarch packages should be independent of whichever 333 MACHINE is set. Check this using bitbake -S. 334 Also, rather than duplicate the test, check nativesdk stamps are the same between 335 the two MACHINE values. 336 """ 337 338 configA = """ 339TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" 340TCLIBCAPPEND = \"\" 341MACHINE = \"qemux86-64\" 342BB_SIGNATURE_HANDLER = "OEBasicHash" 343""" 344 configB = """ 345TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" 346TCLIBCAPPEND = \"\" 347MACHINE = \"qemuarm\" 348BB_SIGNATURE_HANDLER = "OEBasicHash" 349""" 350 self.sstate_allarch_samesigs(configA, configB) 351 352 def test_sstate_nativesdk_samesigs_multilib(self): 353 """ 354 check nativesdk stamps are the same between the two MACHINE values. 355 """ 356 357 configA = """ 358TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" 359TCLIBCAPPEND = \"\" 360MACHINE = \"qemux86-64\" 361require conf/multilib.conf 362MULTILIBS = \"multilib:lib32\" 363DEFAULTTUNE:virtclass-multilib-lib32 = \"x86\" 364BB_SIGNATURE_HANDLER = "OEBasicHash" 365""" 366 configB = """ 367TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" 368TCLIBCAPPEND = \"\" 369MACHINE = \"qemuarm\" 370require conf/multilib.conf 371MULTILIBS = \"\" 372BB_SIGNATURE_HANDLER = "OEBasicHash" 373""" 374 self.sstate_allarch_samesigs(configA, configB) 375 376 def sstate_allarch_samesigs(self, configA, configB): 377 378 self.write_config(configA) 379 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") 380 bitbake("world meta-toolchain -S none") 381 self.write_config(configB) 382 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") 383 bitbake("world meta-toolchain -S none") 384 385 def get_files(d): 386 f = {} 387 for root, dirs, files in os.walk(d): 388 for name in files: 389 if "meta-environment" in root or "cross-canadian" in root: 390 continue 391 if "do_build" not in name: 392 # 1.4.1+gitAUTOINC+302fca9f4c-r0.do_package_write_ipk.sigdata.f3a2a38697da743f0dbed8b56aafcf79 393 (_, task, _, shash) = name.rsplit(".", 3) 394 f[os.path.join(os.path.basename(root), task)] = shash 395 return f 396 397 nativesdkdir = os.path.basename(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux")[0]) 398 399 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir) 400 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir) 401 self.maxDiff = None 402 self.assertEqual(files1, files2) 403 404 def test_sstate_sametune_samesigs(self): 405 """ 406 The sstate checksums of two identical machines (using the same tune) should be the 407 same, apart from changes within the machine specific stamps directory. We use the 408 qemux86copy machine to test this. Also include multilibs in the test. 409 """ 410 411 self.write_config(""" 412TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" 413TCLIBCAPPEND = \"\" 414MACHINE = \"qemux86\" 415require conf/multilib.conf 416MULTILIBS = "multilib:lib32" 417DEFAULTTUNE:virtclass-multilib-lib32 = "x86" 418BB_SIGNATURE_HANDLER = "OEBasicHash" 419""") 420 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") 421 bitbake("world meta-toolchain -S none") 422 self.write_config(""" 423TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" 424TCLIBCAPPEND = \"\" 425MACHINE = \"qemux86copy\" 426require conf/multilib.conf 427MULTILIBS = "multilib:lib32" 428DEFAULTTUNE:virtclass-multilib-lib32 = "x86" 429BB_SIGNATURE_HANDLER = "OEBasicHash" 430""") 431 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") 432 bitbake("world meta-toolchain -S none") 433 434 def get_files(d): 435 f = [] 436 for root, dirs, files in os.walk(d): 437 for name in files: 438 if "meta-environment" in root or "cross-canadian" in root: 439 continue 440 if "qemux86copy-" in root or "qemux86-" in root: 441 continue 442 if "do_build" not in name and "do_populate_sdk" not in name: 443 f.append(os.path.join(root, name)) 444 return f 445 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps") 446 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps") 447 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] 448 self.maxDiff = None 449 self.assertCountEqual(files1, files2) 450 451 452 def test_sstate_multilib_or_not_native_samesigs(self): 453 """The sstate checksums of two native recipes (and their dependencies) 454 where the target is using multilib in one but not the other 455 should be the same. We use the qemux86copy machine to test 456 this. 457 """ 458 459 self.write_config(""" 460TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" 461TCLIBCAPPEND = \"\" 462MACHINE = \"qemux86\" 463require conf/multilib.conf 464MULTILIBS = "multilib:lib32" 465DEFAULTTUNE:virtclass-multilib-lib32 = "x86" 466BB_SIGNATURE_HANDLER = "OEBasicHash" 467""") 468 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") 469 bitbake("binutils-native -S none") 470 self.write_config(""" 471TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" 472TCLIBCAPPEND = \"\" 473MACHINE = \"qemux86copy\" 474BB_SIGNATURE_HANDLER = "OEBasicHash" 475""") 476 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") 477 bitbake("binutils-native -S none") 478 479 def get_files(d): 480 f = [] 481 for root, dirs, files in os.walk(d): 482 for name in files: 483 f.append(os.path.join(root, name)) 484 return f 485 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps") 486 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps") 487 files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] 488 self.maxDiff = None 489 self.assertCountEqual(files1, files2) 490 491 492 def test_sstate_noop_samesigs(self): 493 """ 494 The sstate checksums of two builds with these variables changed or 495 classes inherits should be the same. 496 """ 497 498 self.write_config(""" 499TMPDIR = "${TOPDIR}/tmp-sstatesamehash" 500TCLIBCAPPEND = "" 501BB_NUMBER_THREADS = "${@oe.utils.cpu_count()}" 502PARALLEL_MAKE = "-j 1" 503DL_DIR = "${TOPDIR}/download1" 504TIME = "111111" 505DATE = "20161111" 506INHERIT:remove = "buildstats-summary buildhistory uninative" 507http_proxy = "" 508BB_SIGNATURE_HANDLER = "OEBasicHash" 509""") 510 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") 511 self.track_for_cleanup(self.topdir + "/download1") 512 bitbake("world meta-toolchain -S none") 513 self.write_config(""" 514TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" 515TCLIBCAPPEND = "" 516BB_NUMBER_THREADS = "${@oe.utils.cpu_count()+1}" 517PARALLEL_MAKE = "-j 2" 518DL_DIR = "${TOPDIR}/download2" 519TIME = "222222" 520DATE = "20161212" 521# Always remove uninative as we're changing proxies 522INHERIT:remove = "uninative" 523INHERIT += "buildstats-summary buildhistory" 524http_proxy = "http://example.com/" 525BB_SIGNATURE_HANDLER = "OEBasicHash" 526""") 527 self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") 528 self.track_for_cleanup(self.topdir + "/download2") 529 bitbake("world meta-toolchain -S none") 530 531 def get_files(d): 532 f = {} 533 for root, dirs, files in os.walk(d): 534 for name in files: 535 name, shash = name.rsplit('.', 1) 536 # Extract just the machine and recipe name 537 base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name]) 538 f[base] = shash 539 return f 540 541 def compare_sigfiles(files, files1, files2, compare=False): 542 for k in files: 543 if k in files1 and k in files2: 544 print("%s differs:" % k) 545 if compare: 546 sigdatafile1 = self.topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k] 547 sigdatafile2 = self.topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k] 548 output = bb.siggen.compare_sigfiles(sigdatafile1, sigdatafile2) 549 if output: 550 print('\n'.join(output)) 551 elif k in files1 and k not in files2: 552 print("%s in files1" % k) 553 elif k not in files1 and k in files2: 554 print("%s in files2" % k) 555 else: 556 assert "shouldn't reach here" 557 558 files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/") 559 files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/") 560 # Remove items that are identical in both sets 561 for k,v in files1.items() & files2.items(): 562 del files1[k] 563 del files2[k] 564 if not files1 and not files2: 565 # No changes, so we're done 566 return 567 568 files = list(files1.keys() | files2.keys()) 569 # this is an expensive computation, thus just compare the first 'max_sigfiles_to_compare' k files 570 max_sigfiles_to_compare = 20 571 first, rest = files[:max_sigfiles_to_compare], files[max_sigfiles_to_compare:] 572 compare_sigfiles(first, files1, files2, compare=True) 573 compare_sigfiles(rest, files1, files2, compare=False) 574 575 self.fail("sstate hashes not identical.") 576