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