1# SPDX-License-Identifier: GPL-2.0+ 2# Copyright (c) 2012 The Chromium OS Authors. 3# 4 5import os 6import shutil 7import sys 8import tempfile 9import time 10import unittest 11 12from buildman import board 13from buildman import boards 14from buildman import bsettings 15from buildman import builder 16from buildman import cfgutil 17from buildman import control 18from buildman import toolchain 19from patman import commit 20from u_boot_pylib import command 21from u_boot_pylib import terminal 22from u_boot_pylib import test_util 23from u_boot_pylib import tools 24 25use_network = True 26 27settings_data = ''' 28# Buildman settings file 29 30[toolchain] 31main: /usr/sbin 32 33[toolchain-alias] 34x86: i386 x86_64 35''' 36 37migration = '''===================== WARNING ====================== 38This board does not use CONFIG_DM. CONFIG_DM will be 39compulsory starting with the v2020.01 release. 40Failure to update may result in board removal. 41See doc/develop/driver-model/migration.rst for more info. 42==================================================== 43''' 44 45errors = [ 46 '''main.c: In function 'main_loop': 47main.c:260:6: warning: unused variable 'joe' [-Wunused-variable] 48''', 49 '''main.c: In function 'main_loop2': 50main.c:295:2: error: 'fred' undeclared (first use in this function) 51main.c:295:2: note: each undeclared identifier is reported only once for each function it appears in 52make[1]: *** [main.o] Error 1 53make: *** [common/libcommon.o] Error 2 54Make failed 55''', 56 '''arch/arm/dts/socfpga_arria10_socdk_sdmmc.dtb: Warning \ 57(avoid_unnecessary_addr_size): /clocks: unnecessary #address-cells/#size-cells \ 58without "ranges" or child "reg" property 59''', 60 '''powerpc-linux-ld: warning: dot moved backwards before `.bss' 61powerpc-linux-ld: warning: dot moved backwards before `.bss' 62powerpc-linux-ld: u-boot: section .text lma 0xfffc0000 overlaps previous sections 63powerpc-linux-ld: u-boot: section .rodata lma 0xfffef3ec overlaps previous sections 64powerpc-linux-ld: u-boot: section .reloc lma 0xffffa400 overlaps previous sections 65powerpc-linux-ld: u-boot: section .data lma 0xffffcd38 overlaps previous sections 66powerpc-linux-ld: u-boot: section .u_boot_cmd lma 0xffffeb40 overlaps previous sections 67powerpc-linux-ld: u-boot: section .bootpg lma 0xfffff198 overlaps previous sections 68''', 69 '''In file included from %(basedir)sarch/sandbox/cpu/cpu.c:9:0: 70%(basedir)sarch/sandbox/include/asm/state.h:44:0: warning: "xxxx" redefined [enabled by default] 71%(basedir)sarch/sandbox/include/asm/state.h:43:0: note: this is the location of the previous definition 72%(basedir)sarch/sandbox/cpu/cpu.c: In function 'do_reset': 73%(basedir)sarch/sandbox/cpu/cpu.c:27:1: error: unknown type name 'blah' 74%(basedir)sarch/sandbox/cpu/cpu.c:28:12: error: expected declaration specifiers or '...' before numeric constant 75make[2]: *** [arch/sandbox/cpu/cpu.o] Error 1 76make[1]: *** [arch/sandbox/cpu] Error 2 77make[1]: *** Waiting for unfinished jobs.... 78In file included from %(basedir)scommon/board_f.c:55:0: 79%(basedir)sarch/sandbox/include/asm/state.h:44:0: warning: "xxxx" redefined [enabled by default] 80%(basedir)sarch/sandbox/include/asm/state.h:43:0: note: this is the location of the previous definition 81make: *** [sub-make] Error 2 82''' 83] 84 85 86# hash, subject, return code, list of errors/warnings 87commits = [ 88 ['1234', 'upstream/master, migration warning', 0, []], 89 ['5678', 'Second commit, a warning', 0, errors[0:1]], 90 ['9012', 'Third commit, error', 1, errors[0:2]], 91 ['3456', 'Fourth commit, warning', 0, [errors[0], errors[2]]], 92 ['7890', 'Fifth commit, link errors', 1, [errors[0], errors[3]]], 93 ['abcd', 'Sixth commit, fixes all errors', 0, []], 94 ['ef01', 'Seventh commit, fix migration, check directory suppression', 1, 95 [errors[4]]], 96] 97 98BOARDS = [ 99 ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0', ''], 100 ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''], 101 ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''], 102 ['Active', 'powerpc', 'mpc83xx', '', 'Tester', 'PowerPC board 2', 'board3', ''], 103 ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''], 104] 105 106BASE_DIR = 'base' 107 108OUTCOME_OK, OUTCOME_WARN, OUTCOME_ERR = range(3) 109 110class Options: 111 """Class that holds build options""" 112 pass 113 114class TestBuild(unittest.TestCase): 115 """Test buildman 116 117 TODO: Write tests for the rest of the functionality 118 """ 119 def setUp(self): 120 # Set up commits to build 121 self.commits = [] 122 sequence = 0 123 for commit_info in commits: 124 comm = commit.Commit(commit_info[0]) 125 comm.subject = commit_info[1] 126 comm.return_code = commit_info[2] 127 comm.error_list = commit_info[3] 128 if sequence < 6: 129 comm.error_list += [migration] 130 comm.sequence = sequence 131 sequence += 1 132 self.commits.append(comm) 133 134 # Set up boards to build 135 self.brds = boards.Boards() 136 for brd in BOARDS: 137 self.brds.add_board(board.Board(*brd)) 138 self.brds.select_boards([]) 139 140 # Add some test settings 141 bsettings.setup(None) 142 bsettings.add_file(settings_data) 143 144 # Set up the toolchains 145 self.toolchains = toolchain.Toolchains() 146 self.toolchains.Add('arm-linux-gcc', test=False) 147 self.toolchains.Add('sparc-linux-gcc', test=False) 148 self.toolchains.Add('powerpc-linux-gcc', test=False) 149 self.toolchains.Add('gcc', test=False) 150 151 # Avoid sending any output 152 terminal.set_print_test_mode() 153 self._col = terminal.Color() 154 155 self.base_dir = tempfile.mkdtemp() 156 if not os.path.isdir(self.base_dir): 157 os.mkdir(self.base_dir) 158 159 def tearDown(self): 160 shutil.rmtree(self.base_dir) 161 162 def Make(self, commit, brd, stage, *args, **kwargs): 163 result = command.CommandResult() 164 boardnum = int(brd.target[-1]) 165 result.return_code = 0 166 result.stderr = '' 167 result.stdout = ('This is the test output for board %s, commit %s' % 168 (brd.target, commit.hash)) 169 if ((boardnum >= 1 and boardnum >= commit.sequence) or 170 boardnum == 4 and commit.sequence == 6): 171 result.return_code = commit.return_code 172 result.stderr = (''.join(commit.error_list) 173 % {'basedir' : self.base_dir + '/.bm-work/00/'}) 174 elif commit.sequence < 6: 175 result.stderr = migration 176 177 result.combined = result.stdout + result.stderr 178 return result 179 180 def assertSummary(self, text, arch, plus, brds, outcome=OUTCOME_ERR): 181 col = self._col 182 expected_colour = (col.GREEN if outcome == OUTCOME_OK else 183 col.YELLOW if outcome == OUTCOME_WARN else col.RED) 184 expect = '%10s: ' % arch 185 # TODO(sjg@chromium.org): If plus is '', we shouldn't need this 186 expect += ' ' + col.build(expected_colour, plus) 187 expect += ' ' 188 for brd in brds: 189 expect += col.build(expected_colour, ' %s' % brd) 190 self.assertEqual(text, expect) 191 192 def _SetupTest(self, echo_lines=False, threads=1, **kwdisplay_args): 193 """Set up the test by running a build and summary 194 195 Args: 196 echo_lines: True to echo lines to the terminal to aid test 197 development 198 kwdisplay_args: Dict of arguments to pass to 199 Builder.SetDisplayOptions() 200 201 Returns: 202 Iterator containing the output lines, each a PrintLine() object 203 """ 204 build = builder.Builder(self.toolchains, self.base_dir, None, threads, 205 2, checkout=False, show_unknown=False) 206 build.do_make = self.Make 207 board_selected = self.brds.get_selected_dict() 208 209 # Build the boards for the pre-defined commits and warnings/errors 210 # associated with each. This calls our Make() to inject the fake output. 211 build.build_boards(self.commits, board_selected, keep_outputs=False, 212 verbose=False) 213 lines = terminal.get_print_test_lines() 214 count = 0 215 for line in lines: 216 if line.text.strip(): 217 count += 1 218 219 # We should get two starting messages, an update for every commit built 220 # and a summary message 221 self.assertEqual(count, len(commits) * len(BOARDS) + 3) 222 build.set_display_options(**kwdisplay_args); 223 build.show_summary(self.commits, board_selected) 224 if echo_lines: 225 terminal.echo_print_test_lines() 226 return iter(terminal.get_print_test_lines()) 227 228 def _CheckOutput(self, lines, list_error_boards=False, 229 filter_dtb_warnings=False, 230 filter_migration_warnings=False): 231 """Check for expected output from the build summary 232 233 Args: 234 lines: Iterator containing the lines returned from the summary 235 list_error_boards: Adjust the check for output produced with the 236 --list-error-boards flag 237 filter_dtb_warnings: Adjust the check for output produced with the 238 --filter-dtb-warnings flag 239 """ 240 def add_line_prefix(prefix, brds, error_str, colour): 241 """Add a prefix to each line of a string 242 243 The training \n in error_str is removed before processing 244 245 Args: 246 prefix: String prefix to add 247 error_str: Error string containing the lines 248 colour: Expected colour for the line. Note that the board list, 249 if present, always appears in magenta 250 251 Returns: 252 New string where each line has the prefix added 253 """ 254 lines = error_str.strip().splitlines() 255 new_lines = [] 256 for line in lines: 257 if brds: 258 expect = self._col.build(colour, prefix + '(') 259 expect += self._col.build(self._col.MAGENTA, brds, 260 bright=False) 261 expect += self._col.build(colour, ') %s' % line) 262 else: 263 expect = self._col.build(colour, prefix + line) 264 new_lines.append(expect) 265 return '\n'.join(new_lines) 266 267 col = terminal.Color() 268 boards01234 = ('board0 board1 board2 board3 board4' 269 if list_error_boards else '') 270 boards1234 = 'board1 board2 board3 board4' if list_error_boards else '' 271 boards234 = 'board2 board3 board4' if list_error_boards else '' 272 boards34 = 'board3 board4' if list_error_boards else '' 273 boards4 = 'board4' if list_error_boards else '' 274 275 # Upstream commit: migration warnings only 276 self.assertEqual(next(lines).text, '01: %s' % commits[0][1]) 277 278 if not filter_migration_warnings: 279 self.assertSummary(next(lines).text, 'arm', 'w+', 280 ['board0', 'board1'], outcome=OUTCOME_WARN) 281 self.assertSummary(next(lines).text, 'powerpc', 'w+', 282 ['board2', 'board3'], outcome=OUTCOME_WARN) 283 self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'], 284 outcome=OUTCOME_WARN) 285 286 self.assertEqual(next(lines).text, 287 add_line_prefix('+', boards01234, migration, col.RED)) 288 289 # Second commit: all archs should fail with warnings 290 self.assertEqual(next(lines).text, '02: %s' % commits[1][1]) 291 292 if filter_migration_warnings: 293 self.assertSummary(next(lines).text, 'arm', 'w+', 294 ['board1'], outcome=OUTCOME_WARN) 295 self.assertSummary(next(lines).text, 'powerpc', 'w+', 296 ['board2', 'board3'], outcome=OUTCOME_WARN) 297 self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'], 298 outcome=OUTCOME_WARN) 299 300 # Second commit: The warnings should be listed 301 self.assertEqual(next(lines).text, 302 add_line_prefix('w+', boards1234, errors[0], col.YELLOW)) 303 304 # Third commit: Still fails 305 self.assertEqual(next(lines).text, '03: %s' % commits[2][1]) 306 if filter_migration_warnings: 307 self.assertSummary(next(lines).text, 'arm', '', 308 ['board1'], outcome=OUTCOME_OK) 309 self.assertSummary(next(lines).text, 'powerpc', '+', 310 ['board2', 'board3']) 311 self.assertSummary(next(lines).text, 'sandbox', '+', ['board4']) 312 313 # Expect a compiler error 314 self.assertEqual(next(lines).text, 315 add_line_prefix('+', boards234, errors[1], col.RED)) 316 317 # Fourth commit: Compile errors are fixed, just have warning for board3 318 self.assertEqual(next(lines).text, '04: %s' % commits[3][1]) 319 if filter_migration_warnings: 320 expect = '%10s: ' % 'powerpc' 321 expect += ' ' + col.build(col.GREEN, '') 322 expect += ' ' 323 expect += col.build(col.GREEN, ' %s' % 'board2') 324 expect += ' ' + col.build(col.YELLOW, 'w+') 325 expect += ' ' 326 expect += col.build(col.YELLOW, ' %s' % 'board3') 327 self.assertEqual(next(lines).text, expect) 328 else: 329 self.assertSummary(next(lines).text, 'powerpc', 'w+', 330 ['board2', 'board3'], outcome=OUTCOME_WARN) 331 self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'], 332 outcome=OUTCOME_WARN) 333 334 # Compile error fixed 335 self.assertEqual(next(lines).text, 336 add_line_prefix('-', boards234, errors[1], col.GREEN)) 337 338 if not filter_dtb_warnings: 339 self.assertEqual( 340 next(lines).text, 341 add_line_prefix('w+', boards34, errors[2], col.YELLOW)) 342 343 # Fifth commit 344 self.assertEqual(next(lines).text, '05: %s' % commits[4][1]) 345 if filter_migration_warnings: 346 self.assertSummary(next(lines).text, 'powerpc', '', ['board3'], 347 outcome=OUTCOME_OK) 348 self.assertSummary(next(lines).text, 'sandbox', '+', ['board4']) 349 350 # The second line of errors[3] is a duplicate, so buildman will drop it 351 expect = errors[3].rstrip().split('\n') 352 expect = [expect[0]] + expect[2:] 353 expect = '\n'.join(expect) 354 self.assertEqual(next(lines).text, 355 add_line_prefix('+', boards4, expect, col.RED)) 356 357 if not filter_dtb_warnings: 358 self.assertEqual( 359 next(lines).text, 360 add_line_prefix('w-', boards34, errors[2], col.CYAN)) 361 362 # Sixth commit 363 self.assertEqual(next(lines).text, '06: %s' % commits[5][1]) 364 if filter_migration_warnings: 365 self.assertSummary(next(lines).text, 'sandbox', '', ['board4'], 366 outcome=OUTCOME_OK) 367 else: 368 self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'], 369 outcome=OUTCOME_WARN) 370 371 # The second line of errors[3] is a duplicate, so buildman will drop it 372 expect = errors[3].rstrip().split('\n') 373 expect = [expect[0]] + expect[2:] 374 expect = '\n'.join(expect) 375 self.assertEqual(next(lines).text, 376 add_line_prefix('-', boards4, expect, col.GREEN)) 377 self.assertEqual(next(lines).text, 378 add_line_prefix('w-', boards4, errors[0], col.CYAN)) 379 380 # Seventh commit 381 self.assertEqual(next(lines).text, '07: %s' % commits[6][1]) 382 if filter_migration_warnings: 383 self.assertSummary(next(lines).text, 'sandbox', '+', ['board4']) 384 else: 385 self.assertSummary(next(lines).text, 'arm', '', ['board0', 'board1'], 386 outcome=OUTCOME_OK) 387 self.assertSummary(next(lines).text, 'powerpc', '', 388 ['board2', 'board3'], outcome=OUTCOME_OK) 389 self.assertSummary(next(lines).text, 'sandbox', '+', ['board4']) 390 391 # Pick out the correct error lines 392 expect_str = errors[4].rstrip().replace('%(basedir)s', '').split('\n') 393 expect = expect_str[3:8] + [expect_str[-1]] 394 expect = '\n'.join(expect) 395 if not filter_migration_warnings: 396 self.assertEqual( 397 next(lines).text, 398 add_line_prefix('-', boards01234, migration, col.GREEN)) 399 400 self.assertEqual(next(lines).text, 401 add_line_prefix('+', boards4, expect, col.RED)) 402 403 # Now the warnings lines 404 expect = [expect_str[0]] + expect_str[10:12] + [expect_str[9]] 405 expect = '\n'.join(expect) 406 self.assertEqual(next(lines).text, 407 add_line_prefix('w+', boards4, expect, col.YELLOW)) 408 409 def testOutput(self): 410 """Test basic builder operation and output 411 412 This does a line-by-line verification of the summary output. 413 """ 414 lines = self._SetupTest(show_errors=True) 415 self._CheckOutput(lines, list_error_boards=False, 416 filter_dtb_warnings=False) 417 418 def testErrorBoards(self): 419 """Test output with --list-error-boards 420 421 This does a line-by-line verification of the summary output. 422 """ 423 lines = self._SetupTest(show_errors=True, list_error_boards=True) 424 self._CheckOutput(lines, list_error_boards=True) 425 426 def testFilterDtb(self): 427 """Test output with --filter-dtb-warnings 428 429 This does a line-by-line verification of the summary output. 430 """ 431 lines = self._SetupTest(show_errors=True, filter_dtb_warnings=True) 432 self._CheckOutput(lines, filter_dtb_warnings=True) 433 434 def testFilterMigration(self): 435 """Test output with --filter-migration-warnings 436 437 This does a line-by-line verification of the summary output. 438 """ 439 lines = self._SetupTest(show_errors=True, 440 filter_migration_warnings=True) 441 self._CheckOutput(lines, filter_migration_warnings=True) 442 443 def testSingleThread(self): 444 """Test operation without threading""" 445 lines = self._SetupTest(show_errors=True, threads=0) 446 self._CheckOutput(lines, list_error_boards=False, 447 filter_dtb_warnings=False) 448 449 def _testGit(self): 450 """Test basic builder operation by building a branch""" 451 options = Options() 452 options.git = os.getcwd() 453 options.summary = False 454 options.jobs = None 455 options.dry_run = False 456 #options.git = os.path.join(self.base_dir, 'repo') 457 options.branch = 'test-buildman' 458 options.force_build = False 459 options.list_tool_chains = False 460 options.count = -1 461 options.git_dir = None 462 options.threads = None 463 options.show_unknown = False 464 options.quick = False 465 options.show_errors = False 466 options.keep_outputs = False 467 args = ['tegra20'] 468 control.do_buildman(options, args) 469 470 def testBoardSingle(self): 471 """Test single board selection""" 472 self.assertEqual(self.brds.select_boards(['sandbox']), 473 ({'all': ['board4'], 'sandbox': ['board4']}, [])) 474 475 def testBoardArch(self): 476 """Test single board selection""" 477 self.assertEqual(self.brds.select_boards(['arm']), 478 ({'all': ['board0', 'board1'], 479 'arm': ['board0', 'board1']}, [])) 480 481 def testBoardArchSingle(self): 482 """Test single board selection""" 483 self.assertEqual(self.brds.select_boards(['arm sandbox']), 484 ({'sandbox': ['board4'], 485 'all': ['board0', 'board1', 'board4'], 486 'arm': ['board0', 'board1']}, [])) 487 488 489 def testBoardArchSingleMultiWord(self): 490 """Test single board selection""" 491 self.assertEqual(self.brds.select_boards(['arm', 'sandbox']), 492 ({'sandbox': ['board4'], 493 'all': ['board0', 'board1', 'board4'], 494 'arm': ['board0', 'board1']}, [])) 495 496 def testBoardSingleAnd(self): 497 """Test single board selection""" 498 self.assertEqual(self.brds.select_boards(['Tester & arm']), 499 ({'Tester&arm': ['board0', 'board1'], 500 'all': ['board0', 'board1']}, [])) 501 502 def testBoardTwoAnd(self): 503 """Test single board selection""" 504 self.assertEqual(self.brds.select_boards(['Tester', '&', 'arm', 505 'Tester' '&', 'powerpc', 506 'sandbox']), 507 ({'sandbox': ['board4'], 508 'all': ['board0', 'board1', 'board2', 'board3', 509 'board4'], 510 'Tester&powerpc': ['board2', 'board3'], 511 'Tester&arm': ['board0', 'board1']}, [])) 512 513 def testBoardAll(self): 514 """Test single board selection""" 515 self.assertEqual(self.brds.select_boards([]), 516 ({'all': ['board0', 'board1', 'board2', 'board3', 517 'board4']}, [])) 518 519 def testBoardRegularExpression(self): 520 """Test single board selection""" 521 self.assertEqual(self.brds.select_boards(['T.*r&^Po']), 522 ({'all': ['board2', 'board3'], 523 'T.*r&^Po': ['board2', 'board3']}, [])) 524 525 def testBoardDuplicate(self): 526 """Test single board selection""" 527 self.assertEqual(self.brds.select_boards(['sandbox sandbox', 528 'sandbox']), 529 ({'all': ['board4'], 'sandbox': ['board4']}, [])) 530 def CheckDirs(self, build, dirname): 531 self.assertEqual('base%s' % dirname, build.get_output_dir(1)) 532 self.assertEqual('base%s/fred' % dirname, 533 build.get_build_dir(1, 'fred')) 534 self.assertEqual('base%s/fred/done' % dirname, 535 build.get_done_file(1, 'fred')) 536 self.assertEqual('base%s/fred/u-boot.sizes' % dirname, 537 build.get_func_sizes_file(1, 'fred', 'u-boot')) 538 self.assertEqual('base%s/fred/u-boot.objdump' % dirname, 539 build.get_objdump_file(1, 'fred', 'u-boot')) 540 self.assertEqual('base%s/fred/err' % dirname, 541 build.get_err_file(1, 'fred')) 542 543 def testOutputDir(self): 544 build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2, 545 checkout=False, show_unknown=False) 546 build.commits = self.commits 547 build.commit_count = len(self.commits) 548 subject = self.commits[1].subject.translate(builder.trans_valid_chars) 549 dirname ='/%02d_g%s_%s' % (2, commits[1][0], subject[:20]) 550 self.CheckDirs(build, dirname) 551 552 def testOutputDirCurrent(self): 553 build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2, 554 checkout=False, show_unknown=False) 555 build.commits = None 556 build.commit_count = 0 557 self.CheckDirs(build, '/current') 558 559 def testOutputDirNoSubdirs(self): 560 build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2, 561 checkout=False, show_unknown=False, 562 no_subdirs=True) 563 build.commits = None 564 build.commit_count = 0 565 self.CheckDirs(build, '') 566 567 def testToolchainAliases(self): 568 self.assertTrue(self.toolchains.Select('arm') != None) 569 with self.assertRaises(ValueError): 570 self.toolchains.Select('no-arch') 571 with self.assertRaises(ValueError): 572 self.toolchains.Select('x86') 573 574 self.toolchains = toolchain.Toolchains() 575 self.toolchains.Add('x86_64-linux-gcc', test=False) 576 self.assertTrue(self.toolchains.Select('x86') != None) 577 578 self.toolchains = toolchain.Toolchains() 579 self.toolchains.Add('i386-linux-gcc', test=False) 580 self.assertTrue(self.toolchains.Select('x86') != None) 581 582 def testToolchainDownload(self): 583 """Test that we can download toolchains""" 584 if use_network: 585 with test_util.capture_sys_output() as (stdout, stderr): 586 url = self.toolchains.LocateArchUrl('arm') 587 self.assertRegexpMatches(url, 'https://www.kernel.org/pub/tools/' 588 'crosstool/files/bin/x86_64/.*/' 589 'x86_64-gcc-.*-nolibc[-_]arm-.*linux-gnueabi.tar.xz') 590 591 def testGetEnvArgs(self): 592 """Test the GetEnvArgs() function""" 593 tc = self.toolchains.Select('arm') 594 self.assertEqual('arm-linux-', 595 tc.GetEnvArgs(toolchain.VAR_CROSS_COMPILE)) 596 self.assertEqual('', tc.GetEnvArgs(toolchain.VAR_PATH)) 597 self.assertEqual('arm', 598 tc.GetEnvArgs(toolchain.VAR_ARCH)) 599 self.assertEqual('', tc.GetEnvArgs(toolchain.VAR_MAKE_ARGS)) 600 601 self.toolchains.Add('/path/to/x86_64-linux-gcc', test=False) 602 tc = self.toolchains.Select('x86') 603 self.assertEqual('/path/to', 604 tc.GetEnvArgs(toolchain.VAR_PATH)) 605 tc.override_toolchain = 'clang' 606 self.assertEqual('HOSTCC=clang CC=clang', 607 tc.GetEnvArgs(toolchain.VAR_MAKE_ARGS)) 608 609 def testPrepareOutputSpace(self): 610 def _Touch(fname): 611 tools.write_file(os.path.join(base_dir, fname), b'') 612 613 base_dir = tempfile.mkdtemp() 614 615 # Add various files that we want removed and left alone 616 to_remove = ['01_g0982734987_title', '102_g92bf_title', 617 '01_g2938abd8_title'] 618 to_leave = ['something_else', '01-something.patch', '01_another'] 619 for name in to_remove + to_leave: 620 _Touch(name) 621 622 build = builder.Builder(self.toolchains, base_dir, None, 1, 2) 623 build.commits = self.commits 624 build.commit_count = len(commits) 625 result = set(build._get_output_space_removals()) 626 expected = set([os.path.join(base_dir, f) for f in to_remove]) 627 self.assertEqual(expected, result) 628 629 def test_adjust_cfg_nop(self): 630 """check various adjustments of config that are nops""" 631 # enable an enabled CONFIG 632 self.assertEqual( 633 'CONFIG_FRED=y', 634 cfgutil.adjust_cfg_line('CONFIG_FRED=y', {'FRED':'FRED'})[0]) 635 636 # disable a disabled CONFIG 637 self.assertEqual( 638 '# CONFIG_FRED is not set', 639 cfgutil.adjust_cfg_line( 640 '# CONFIG_FRED is not set', {'FRED':'~FRED'})[0]) 641 642 # use the adjust_cfg_lines() function 643 self.assertEqual( 644 ['CONFIG_FRED=y'], 645 cfgutil.adjust_cfg_lines(['CONFIG_FRED=y'], {'FRED':'FRED'})) 646 self.assertEqual( 647 ['# CONFIG_FRED is not set'], 648 cfgutil.adjust_cfg_lines(['CONFIG_FRED=y'], {'FRED':'~FRED'})) 649 650 # handling an empty line 651 self.assertEqual('#', cfgutil.adjust_cfg_line('#', {'FRED':'~FRED'})[0]) 652 653 def test_adjust_cfg(self): 654 """check various adjustments of config""" 655 # disable a CONFIG 656 self.assertEqual( 657 '# CONFIG_FRED is not set', 658 cfgutil.adjust_cfg_line('CONFIG_FRED=1' , {'FRED':'~FRED'})[0]) 659 660 # enable a disabled CONFIG 661 self.assertEqual( 662 'CONFIG_FRED=y', 663 cfgutil.adjust_cfg_line( 664 '# CONFIG_FRED is not set', {'FRED':'FRED'})[0]) 665 666 # enable a CONFIG that doesn't exist 667 self.assertEqual( 668 ['CONFIG_FRED=y'], 669 cfgutil.adjust_cfg_lines([], {'FRED':'FRED'})) 670 671 # disable a CONFIG that doesn't exist 672 self.assertEqual( 673 ['# CONFIG_FRED is not set'], 674 cfgutil.adjust_cfg_lines([], {'FRED':'~FRED'})) 675 676 # disable a value CONFIG 677 self.assertEqual( 678 '# CONFIG_FRED is not set', 679 cfgutil.adjust_cfg_line('CONFIG_FRED="fred"' , {'FRED':'~FRED'})[0]) 680 681 # setting a value CONFIG 682 self.assertEqual( 683 'CONFIG_FRED="fred"', 684 cfgutil.adjust_cfg_line('# CONFIG_FRED is not set' , 685 {'FRED':'FRED="fred"'})[0]) 686 687 # changing a value CONFIG 688 self.assertEqual( 689 'CONFIG_FRED="fred"', 690 cfgutil.adjust_cfg_line('CONFIG_FRED="ernie"' , 691 {'FRED':'FRED="fred"'})[0]) 692 693 # setting a value for a CONFIG that doesn't exist 694 self.assertEqual( 695 ['CONFIG_FRED="fred"'], 696 cfgutil.adjust_cfg_lines([], {'FRED':'FRED="fred"'})) 697 698 def test_convert_adjust_cfg_list(self): 699 """Check conversion of the list of changes into a dict""" 700 self.assertEqual({}, cfgutil.convert_list_to_dict(None)) 701 702 expect = { 703 'FRED':'FRED', 704 'MARY':'~MARY', 705 'JOHN':'JOHN=0x123', 706 'ALICE':'ALICE="alice"', 707 'AMY':'AMY', 708 'ABE':'~ABE', 709 'MARK':'MARK=0x456', 710 'ANNA':'ANNA="anna"', 711 } 712 actual = cfgutil.convert_list_to_dict( 713 ['FRED', '~MARY', 'JOHN=0x123', 'ALICE="alice"', 714 'CONFIG_AMY', '~CONFIG_ABE', 'CONFIG_MARK=0x456', 715 'CONFIG_ANNA="anna"']) 716 self.assertEqual(expect, actual) 717 718 def test_check_cfg_file(self): 719 """Test check_cfg_file detects conflicts as expected""" 720 # Check failure to disable CONFIG 721 result = cfgutil.check_cfg_lines(['CONFIG_FRED=1'], {'FRED':'~FRED'}) 722 self.assertEqual([['~FRED', 'CONFIG_FRED=1']], result) 723 724 result = cfgutil.check_cfg_lines( 725 ['CONFIG_FRED=1', 'CONFIG_MARY="mary"'], {'FRED':'~FRED'}) 726 self.assertEqual([['~FRED', 'CONFIG_FRED=1']], result) 727 728 result = cfgutil.check_cfg_lines( 729 ['CONFIG_FRED=1', 'CONFIG_MARY="mary"'], {'MARY':'~MARY'}) 730 self.assertEqual([['~MARY', 'CONFIG_MARY="mary"']], result) 731 732 # Check failure to enable CONFIG 733 result = cfgutil.check_cfg_lines( 734 ['# CONFIG_FRED is not set'], {'FRED':'FRED'}) 735 self.assertEqual([['FRED', '# CONFIG_FRED is not set']], result) 736 737 # Check failure to set CONFIG value 738 result = cfgutil.check_cfg_lines( 739 ['# CONFIG_FRED is not set', 'CONFIG_MARY="not"'], 740 {'MARY':'MARY="mary"', 'FRED':'FRED'}) 741 self.assertEqual([ 742 ['FRED', '# CONFIG_FRED is not set'], 743 ['MARY="mary"', 'CONFIG_MARY="not"']], result) 744 745 # Check failure to add CONFIG value 746 result = cfgutil.check_cfg_lines([], {'MARY':'MARY="mary"'}) 747 self.assertEqual([ 748 ['MARY="mary"', 'Missing expected line: CONFIG_MARY="mary"']], result) 749 750 751if __name__ == "__main__": 752 unittest.main() 753