@@ -1938,6 +1938,11 @@ class Builder:
def _show_not_built(board_selected, board_dict):
"""Show boards that were not built
+ This reports boards that are in board_selected but have no outcome in
+ board_dict. In practice this is unlikely to happen since
+ get_result_summary() creates an outcome for every board, even if just
+ OUTCOME_UNKNOWN.
+
Args:
board_selected (dict): Dict of selected boards, keyed by target
board_dict (dict): Dict of boards that were built, keyed by target
@@ -590,6 +590,31 @@ Some images are invalid'''
f"No tool chain found for arch '{brd.arch}'"])
fd.close()
+ def testToolchainErrors(self):
+ """Test that toolchain errors are reported in the summary
+
+ When toolchains are missing, boards fail to build. The summary
+ should report which boards had errors, grouped by architecture.
+ """
+ self.setupToolchains()
+ # Build with missing toolchains - only sandbox will succeed
+ self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
+
+ # Now show summary - should report boards with errors
+ terminal.get_print_test_lines() # Clear
+ self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, '-s',
+ clean_dir=False)
+ lines = terminal.get_print_test_lines()
+ text = '\n'.join(line.text for line in lines)
+
+ # Check that boards with missing toolchains are shown with errors
+ # The '+' prefix indicates new errors for these boards
+ self.assertIn('arm:', text)
+ self.assertIn('board0', text)
+ self.assertIn('board1', text)
+ self.assertIn('powerpc:', text)
+ self.assertIn('board2', text)
+
def testBranch(self):
"""Test building a branch with all toolchains present"""
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
@@ -56,6 +56,7 @@ def run_tests(skip_net_tests, debug, verbose, args):
test_builder.TestPrintFuncSizeDetail,
test_builder.TestPrepareThread,
test_builder.TestPrepareWorkingSpace,
+ test_builder.TestShowNotBuilt,
test_builder.TestPrepareOutputSpace,
'buildman.toolchain'])
@@ -339,6 +339,59 @@ class TestPrepareWorkingSpace(unittest.TestCase):
mock_prepare_thread.assert_any_call(1, True)
+class TestShowNotBuilt(unittest.TestCase):
+ """Tests for Builder._show_not_built()"""
+
+ def setUp(self):
+ """Set up test fixtures"""
+ terminal.set_print_test_mode()
+
+ def tearDown(self):
+ """Clean up after tests"""
+ terminal.set_print_test_mode(False)
+
+ def test_all_boards_built(self):
+ """Test when all selected boards were built"""
+ board_selected = {'board1': None, 'board2': None}
+ board_dict = {'board1': None, 'board2': None}
+
+ terminal.get_print_test_lines() # Clear
+ builder.Builder._show_not_built(board_selected, board_dict)
+ lines = terminal.get_print_test_lines()
+
+ # No output when all boards were built
+ self.assertEqual(len(lines), 0)
+
+ def test_some_boards_not_built(self):
+ """Test when some boards were not built"""
+ board_selected = {'board1': None, 'board2': None, 'board3': None}
+ board_dict = {'board1': None} # Only board1 was built
+
+ terminal.get_print_test_lines() # Clear
+ builder.Builder._show_not_built(board_selected, board_dict)
+ lines = terminal.get_print_test_lines()
+
+ self.assertEqual(len(lines), 1)
+ self.assertIn('Boards not built', lines[0].text)
+ self.assertIn('2', lines[0].text) # Count of not-built boards
+ self.assertIn('board2', lines[0].text)
+ self.assertIn('board3', lines[0].text)
+
+ def test_no_boards_built(self):
+ """Test when no boards were built"""
+ board_selected = {'board1': None, 'board2': None}
+ board_dict = {} # No boards built
+
+ terminal.get_print_test_lines() # Clear
+ builder.Builder._show_not_built(board_selected, board_dict)
+ lines = terminal.get_print_test_lines()
+
+ self.assertEqual(len(lines), 1)
+ self.assertIn('Boards not built', lines[0].text)
+ self.assertIn('board1', lines[0].text)
+ self.assertIn('board2', lines[0].text)
+
+
class TestPrepareOutputSpace(unittest.TestCase):
"""Tests for Builder._prepare_output_space() and _get_output_space_removals()"""