]> git.apps.os.sepia.ceph.com Git - teuthology.git/commitdiff
suite/test/test_run.py: Add tests for SHA1 handling with --newest 2055/head
authorKamoltat Sirivadhna <ksirivad@redhat.com>
Thu, 12 Jun 2025 21:03:59 +0000 (17:03 -0400)
committerKamoltat Sirivadhna <ksirivad@redhat.com>
Fri, 13 Jun 2025 18:00:32 +0000 (18:00 +0000)
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 <ksirivad@redhat.com>
teuthology/suite/test/test_run_.py

index c97e26e5c2826d493a64ffbc9fd9eef015cfc4bf..31a23a98e811086a1ad5b0962672436183f547e2 100644 (file)
@@ -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]