[Concept,11/18] buildman: Add unit tests for _prepare_working_space()

Message ID 20260109183116.3262115-12-sjg@u-boot.org
State New
Headers
Series buildman: Improve test coverage for builder.py |

Commit Message

Simon Glass Jan. 9, 2026, 6:31 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add TestPrepareWorkingSpace class to test_builder.py with tests covering:
- No git setup (setup_git=False)
- Worktree available (uses worktree and prunes)
- Worktree not available (falls back to clone)
- Zero threads (should still prepare 1 thread)
- No git_dir set (skips git operations)

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 tools/buildman/main.py         |  1 +
 tools/buildman/test_builder.py | 80 ++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+)
  

Patch

diff --git a/tools/buildman/main.py b/tools/buildman/main.py
index 6e780b9e07e..74da226c2cf 100755
--- a/tools/buildman/main.py
+++ b/tools/buildman/main.py
@@ -55,6 +55,7 @@  def run_tests(skip_net_tests, debug, verbose, args):
          test_boards.TestBoards, test_bsettings.TestBsettings,
          test_builder.TestPrintFuncSizeDetail,
          test_builder.TestPrepareThread,
+         test_builder.TestPrepareWorkingSpace,
          'buildman.toolchain'])
 
     return (0 if result.wasSuccessful() else 1)
diff --git a/tools/buildman/test_builder.py b/tools/buildman/test_builder.py
index 042dacc2f34..d7359477ef2 100644
--- a/tools/buildman/test_builder.py
+++ b/tools/buildman/test_builder.py
@@ -258,5 +258,85 @@  class TestPrepareThread(unittest.TestCase):
         self.assertIn("Can't setup git repo", str(ctx.exception))
 
 
+class TestPrepareWorkingSpace(unittest.TestCase):
+    """Tests for Builder._prepare_working_space()"""
+
+    def setUp(self):
+        """Set up test fixtures"""
+        self.builder = builder.Builder(
+            toolchains=None, base_dir='/tmp/test', git_dir='/src/repo',
+            num_threads=4, num_jobs=1)
+        terminal.set_print_test_mode()
+
+    def tearDown(self):
+        """Clean up after tests"""
+        terminal.set_print_test_mode(False)
+
+    @mock.patch.object(builder.Builder, '_prepare_thread')
+    @mock.patch.object(builderthread, 'mkdir')
+    def test_no_setup_git(self, mock_mkdir, mock_prepare_thread):
+        """Test with setup_git=False"""
+        self.builder._prepare_working_space(2, False)
+
+        mock_mkdir.assert_called_once()
+        # Should prepare 2 threads with setup_git=False
+        self.assertEqual(mock_prepare_thread.call_count, 2)
+        mock_prepare_thread.assert_any_call(0, False)
+        mock_prepare_thread.assert_any_call(1, False)
+
+    @mock.patch.object(builder.Builder, '_prepare_thread')
+    @mock.patch.object(gitutil, 'prune_worktrees')
+    @mock.patch.object(gitutil, 'check_worktree_is_available', return_value=True)
+    @mock.patch.object(builderthread, 'mkdir')
+    def test_worktree_available(self, mock_mkdir, mock_check_worktree,
+                                mock_prune, mock_prepare_thread):
+        """Test when worktree is available"""
+        self.builder._prepare_working_space(3, True)
+
+        mock_check_worktree.assert_called_once()
+        mock_prune.assert_called_once()
+        # Should prepare 3 threads with setup_git='worktree'
+        self.assertEqual(mock_prepare_thread.call_count, 3)
+        mock_prepare_thread.assert_any_call(0, 'worktree')
+        mock_prepare_thread.assert_any_call(1, 'worktree')
+        mock_prepare_thread.assert_any_call(2, 'worktree')
+
+    @mock.patch.object(builder.Builder, '_prepare_thread')
+    @mock.patch.object(gitutil, 'check_worktree_is_available', return_value=False)
+    @mock.patch.object(builderthread, 'mkdir')
+    def test_worktree_not_available(self, mock_mkdir, mock_check_worktree,
+                                    mock_prepare_thread):
+        """Test when worktree is not available (falls back to clone)"""
+        self.builder._prepare_working_space(2, True)
+
+        mock_check_worktree.assert_called_once()
+        # Should prepare 2 threads with setup_git='clone'
+        self.assertEqual(mock_prepare_thread.call_count, 2)
+        mock_prepare_thread.assert_any_call(0, 'clone')
+        mock_prepare_thread.assert_any_call(1, 'clone')
+
+    @mock.patch.object(builder.Builder, '_prepare_thread')
+    @mock.patch.object(builderthread, 'mkdir')
+    def test_zero_threads(self, mock_mkdir, mock_prepare_thread):
+        """Test with max_threads=0 (should still prepare 1 thread)"""
+        self.builder._prepare_working_space(0, False)
+
+        # Should prepare at least 1 thread
+        self.assertEqual(mock_prepare_thread.call_count, 1)
+        mock_prepare_thread.assert_called_with(0, False)
+
+    @mock.patch.object(builder.Builder, '_prepare_thread')
+    @mock.patch.object(builderthread, 'mkdir')
+    def test_no_git_dir(self, mock_mkdir, mock_prepare_thread):
+        """Test with no git_dir set"""
+        self.builder.git_dir = None
+        self.builder._prepare_working_space(2, True)
+
+        # setup_git should remain True but git operations skipped
+        self.assertEqual(mock_prepare_thread.call_count, 2)
+        mock_prepare_thread.assert_any_call(0, True)
+        mock_prepare_thread.assert_any_call(1, True)
+
+
 if __name__ == '__main__':
     unittest.main()