From: Kamoltat Sirivadhna Date: Thu, 12 Jun 2025 21:03:59 +0000 (-0400) Subject: suite/test/test_run.py: Add tests for SHA1 handling with --newest X-Git-Tag: 1.2.2~20^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=e895b180dc888ca16adaadc441d9b92d6766054a;p=teuthology.git suite/test/test_run.py: Add tests for SHA1 handling with --newest Added two test cases to verify SHA1 handling when using --newest backtracking: 1. test_newest_success_same_branch_same_repo: Tests when ceph_branch and suite_branch are the same. Verifies that both ceph_hash and suite_hash are updated to the backtracked working SHA1. 2. test_newest_success_diff_branch_diff_repo: Tests when ceph_branch and suite_branch differ. Verifies that only ceph_hash is updated to the working SHA1, while suite_hash remains as the original suite_sha1. Both tests verify the complete flow through collect_jobs() and schedule_suite(), ensuring the YAML files generated for each job contain the correct SHA1 references. Fixes: https://tracker.ceph.com/issues/71668 Signed-off-by: Kamoltat Sirivadhna --- diff --git a/teuthology/suite/test/test_run_.py b/teuthology/suite/test/test_run_.py index c97e26e5c2..31a23a98e8 100644 --- a/teuthology/suite/test/test_run_.py +++ b/teuthology/suite/test/test_run_.py @@ -207,7 +207,9 @@ class TestScheduleSuite(object): suite_relpath='', suite_dir='suite_dir', suite_branch='main', - ceph_branch='ceph_branch', + suite_repo='main', + ceph_repo='main', + ceph_branch='main', ceph_sha1='ceph_sha1', teuthology_branch='main', kernel_branch=None, @@ -385,7 +387,7 @@ class TestScheduleSuite(object): @patch('teuthology.suite.util.package_version_for_hash') @patch('teuthology.suite.util.git_validate_sha1') @patch('teuthology.suite.util.get_arch') - def test_newest_success( + def test_newest_success_same_branch_same_repo( self, m_get_arch, m_git_validate_sha1, @@ -398,12 +400,28 @@ class TestScheduleSuite(object): m_schedule_jobs, m_find_git_parents, ): + """ + Test that we can successfully schedule a job with newest + backtracking when the ceph and suite branches are the same + and the ceph_sha1 is not supplied. We should expect that the + ceph_hash and suite_hash will be updated to the working sha1 + """ m_get_arch.return_value = 'x86_64' # rig has_packages_for_distro to fail this many times, so # everything will run NUM_FAILS+1 times NUM_FAILS = 5 + # Here we just assume that even fi ceph_sha1 is not supplied, + # in git_valid_sha1, util.git_ls_remote will give us ceph_sha1 m_git_validate_sha1.return_value = self.args.ceph_sha1 - m_git_ls_remote.return_value = 'suite_hash' + # Here we know that in create_initial_config, we call + # git_ls_remote 3 times, choose_ceph_hash, choose_suite_hash, + # and choose_teuthology_branch + sha1_side_effect = [ + self.args.ceph_sha1, # ceph_sha1 + 'suite_sha1', # suite_sha1 + 'teuthology_sha1', # teuthology_sha1 + ] + m_git_ls_remote.side_effect = sha1_side_effect build_matrix_desc = 'desc' build_matrix_frags = ['frag.yml'] build_matrix_output = [ @@ -412,21 +430,172 @@ class TestScheduleSuite(object): m_build_matrix.return_value = build_matrix_output m_config_merge.return_value = [(a, b, {}) for a, b in build_matrix_output] m_get_install_task_flavor.return_value = 'default' - # NUM_FAILS, then success + + # Generate backtracked parent sha1s + parent_sha1s = [f"ceph_sha1_{i}" for i in range(NUM_FAILS)] + assert len(parent_sha1s) + # Last sha1 will be the one that works! + working_sha1 = parent_sha1s[-1] + + # NUM_FAILS attempts, then success on the last parent sha1 m_package_version_for_hash.side_effect = \ [None for i in range(NUM_FAILS)] + ["ceph_version"] - m_find_git_parents.side_effect = lambda proj, sha1, count: [f"{sha1}_{i}" for i in range(NUM_FAILS)] + m_find_git_parents.return_value = parent_sha1s self.args.newest = 10 runobj = self.klass(self.args) runobj.base_args = list() + + # Call schedule_suite() count = runobj.schedule_suite() + # Epect only 1 job to be scheduled assert count == 1 + # Expect that we called package_version_for_hash NUM_FAILS times + 1 for the working sha1 m_package_version_for_hash.assert_has_calls( + [call(self.args.ceph_sha1, 'default', 'ubuntu', '14.04', 'machine_type')] + [call(f"ceph_sha1_{i}", 'default', 'ubuntu', '14.04', 'machine_type') - for i in range(NUM_FAILS)] + for i in range(0, NUM_FAILS)] ) - m_find_git_parents.assert_has_calls( - [call('ceph', 'ceph_sha1', 10)] + # (ceph, base_config.sha1, newest) called once to get grab the backtrace + m_find_git_parents.assert_called_once_with('ceph', 'ceph_sha1', 10) + + # Verify that base_config was updated with the working SHA1 + assert runobj.base_config.sha1 == working_sha1 + + # Verify that config_input's ceph_hash and suite_hash was updated + assert runobj.config_input['ceph_hash'] == working_sha1 + assert runobj.config_input['suite_hash'] == working_sha1 + + # Verify that config_input's ceph_hash and suite_hash are not the same as the original sha1s + assert runobj.config_input['ceph_hash'] != sha1_side_effect[0] # ceph_sha1 + assert runobj.config_input['suite_hash'] != sha1_side_effect[1] # suite_sha1 + + # Verify the sha1 in scheduled jobs + args = m_schedule_jobs.call_args.args + scheduled_jobs = args[1] + + # Check each job has the correct SHA1 + for job in scheduled_jobs: + assert job['sha1'] == working_sha1 + + # Parse YAML from stdin to check for sha1 and suite_hash + if 'stdin' in job: + job_yaml = yaml.safe_load(job['stdin']) + assert job_yaml.get('sha1') == working_sha1 + assert job_yaml.get('suite_sha1') == working_sha1 + + @patch('teuthology.suite.util.find_git_parents') + @patch('teuthology.suite.run.Run.schedule_jobs') + @patch('teuthology.suite.run.Run.write_rerun_memo') + @patch('teuthology.suite.util.get_install_task_flavor') + @patch('teuthology.suite.run.config_merge') + @patch('teuthology.suite.run.build_matrix') + @patch('teuthology.suite.util.git_ls_remote') + @patch('teuthology.suite.util.package_version_for_hash') + @patch('teuthology.suite.util.git_validate_sha1') + @patch('teuthology.suite.util.get_arch') + def test_newest_success_diff_branch_diff_repo( + self, + m_get_arch, + m_git_validate_sha1, + m_package_version_for_hash, + m_git_ls_remote, + m_build_matrix, + m_config_merge, + m_get_install_task_flavor, + m_write_rerun_memo, + m_schedule_jobs, + m_find_git_parents, + ): + """ + Test that we can successfully schedule a job with newest + backtracking when the ceph and suite branches are different + and the ceph_sha1 is not supplied. We should expect that the + ceph_hash will be updated to the working sha1, + but the suite_hash will remain the original suite_sha1. + """ + m_get_arch.return_value = 'x86_64' + # Set different branches + self.args.ceph_branch = 'ceph_different_branch' + self.args.suite_branch = 'suite_different_branch' + + # rig has_packages_for_distro to fail this many times, so + # everything will run NUM_FAILS+1 times + NUM_FAILS = 5 + # Here we just assume that even fi ceph_sha1 is not supplied, + # in git_valid_sha1, util.git_ls_remote will give us ceph_sha1 + m_git_validate_sha1.return_value = self.args.ceph_sha1 + # Here we know that in create_initial_config, we call + # git_ls_remote 3 times, choose_ceph_hash, choose_suite_hash, + # and choose_teuthology_branch + sha1_side_effect = [ + self.args.ceph_sha1, # ceph_sha1 + 'suite_sha1', # suite_sha1 + 'teuthology_sha1', # teuthology_sha1 + ] + m_git_ls_remote.side_effect = sha1_side_effect + build_matrix_desc = 'desc' + build_matrix_frags = ['frag.yml'] + build_matrix_output = [ + (build_matrix_desc, build_matrix_frags), + ] + m_build_matrix.return_value = build_matrix_output + m_config_merge.return_value = [(a, b, {}) for a, b in build_matrix_output] + m_get_install_task_flavor.return_value = 'default' + + # Generate backtracked parent sha1s + parent_sha1s = [f"ceph_sha1_{i}" for i in range(NUM_FAILS)] + assert len(parent_sha1s) + # Last sha1 will be the one that works! + working_sha1 = parent_sha1s[-1] + + # NUM_FAILS attempts, then success on the last parent sha1 + m_package_version_for_hash.side_effect = \ + [None for i in range(NUM_FAILS)] + ["ceph_version"] + + m_find_git_parents.return_value = parent_sha1s + + self.args.newest = 10 + runobj = self.klass(self.args) + runobj.base_args = list() + + # Call schedule_suite() + count = runobj.schedule_suite() + # Epect only 1 job to be scheduled + assert count == 1 + # Expect that we called package_version_for_hash NUM_FAILS times + 1 for the working sha1 + m_package_version_for_hash.assert_has_calls( + [call(self.args.ceph_sha1, 'default', 'ubuntu', '14.04', 'machine_type')] + + [call(f"ceph_sha1_{i}", 'default', 'ubuntu', '14.04', 'machine_type') + for i in range(0, NUM_FAILS)] ) + # (ceph, base_config.sha1, newest) called once to get grab the backtrace + m_find_git_parents.assert_called_once_with('ceph', 'ceph_sha1', 10) + + # Verify that base_config was updated with the working SHA1 + assert runobj.base_config.sha1 == working_sha1 + + # Verify that config_input's ceph_hash was updated, + # but suite_hash is still the original suite_sha1 + assert runobj.config_input['ceph_hash'] == working_sha1 + assert runobj.config_input['suite_hash'] != working_sha1 + + # Verify that config_input's ceph_hash is not the same as the original sha1s + # but suite_hash is still the original suite_sha1 + assert runobj.config_input['ceph_hash'] != sha1_side_effect[0] # ceph_sha1 + assert runobj.config_input['suite_hash'] == sha1_side_effect[1] # suite_sha1 + + # Verify the sha1 in scheduled jobs + args = m_schedule_jobs.call_args.args + scheduled_jobs = args[1] + + # Check each job has the correct SHA1 + for job in scheduled_jobs: + assert job['sha1'] == working_sha1 + + # Parse YAML from stdin to check for sha1 and suite_hash + if 'stdin' in job: + job_yaml = yaml.safe_load(job['stdin']) + assert job_yaml.get('sha1') == working_sha1 + assert job_yaml.get('suite_sha1') == sha1_side_effect[1]