func_test.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #
  2. # Copyright (c) 2014 Google, Inc
  3. #
  4. # SPDX-License-Identifier: GPL-2.0+
  5. #
  6. import os
  7. import shutil
  8. import sys
  9. import tempfile
  10. import unittest
  11. import cmdline
  12. import command
  13. import control
  14. import gitutil
  15. import terminal
  16. import toolchain
  17. class TestFunctional(unittest.TestCase):
  18. """Functional test for buildman.
  19. This aims to test from just below the invocation of buildman (parsing
  20. of arguments) to 'make' and 'git' invocation. It is not a true
  21. emd-to-end test, as it mocks git, make and the tool chain. But this
  22. makes it easier to detect when the builder is doing the wrong thing,
  23. since in many cases this test code will fail. For example, only a
  24. very limited subset of 'git' arguments is supported - anything
  25. unexpected will fail.
  26. """
  27. def setUp(self):
  28. self._base_dir = tempfile.mkdtemp()
  29. self._git_dir = os.path.join(self._base_dir, 'src')
  30. self._buildman_pathname = sys.argv[0]
  31. self._buildman_dir = os.path.dirname(sys.argv[0])
  32. command.test_result = self._HandleCommand
  33. self._toolchains = toolchain.Toolchains()
  34. self._toolchains.Add('gcc', test=False)
  35. def tearDown(self):
  36. shutil.rmtree(self._base_dir)
  37. def _RunBuildman(self, *args):
  38. return command.RunPipe([[self._buildman_pathname] + list(args)],
  39. capture=True, capture_stderr=True)
  40. def _RunControl(self, *args):
  41. sys.argv = [sys.argv[0]] + list(args)
  42. options, args = cmdline.ParseArgs()
  43. return control.DoBuildman(options, args, toolchains=self._toolchains,
  44. make_func=self._HandleMake)
  45. def testFullHelp(self):
  46. command.test_result = None
  47. result = self._RunBuildman('-H')
  48. help_file = os.path.join(self._buildman_dir, 'README')
  49. self.assertEqual(len(result.stdout), os.path.getsize(help_file))
  50. self.assertEqual(0, len(result.stderr))
  51. self.assertEqual(0, result.return_code)
  52. def testHelp(self):
  53. command.test_result = None
  54. result = self._RunBuildman('-h')
  55. help_file = os.path.join(self._buildman_dir, 'README')
  56. self.assertTrue(len(result.stdout) > 1000)
  57. self.assertEqual(0, len(result.stderr))
  58. self.assertEqual(0, result.return_code)
  59. def testGitSetup(self):
  60. """Test gitutils.Setup(), from outside the module itself"""
  61. command.test_result = command.CommandResult(return_code=1)
  62. gitutil.Setup()
  63. self.assertEqual(gitutil.use_no_decorate, False)
  64. command.test_result = command.CommandResult(return_code=0)
  65. gitutil.Setup()
  66. self.assertEqual(gitutil.use_no_decorate, True)
  67. def _HandleCommandGitLog(self, args):
  68. if '-n0' in args:
  69. return command.CommandResult(return_code=0)
  70. # Not handled, so abort
  71. print 'git log', args
  72. sys.exit(1)
  73. def _HandleCommandGit(self, in_args):
  74. """Handle execution of a git command
  75. This uses a hacked-up parser.
  76. Args:
  77. in_args: Arguments after 'git' from the command line
  78. """
  79. git_args = [] # Top-level arguments to git itself
  80. sub_cmd = None # Git sub-command selected
  81. args = [] # Arguments to the git sub-command
  82. for arg in in_args:
  83. if sub_cmd:
  84. args.append(arg)
  85. elif arg[0] == '-':
  86. git_args.append(arg)
  87. else:
  88. sub_cmd = arg
  89. if sub_cmd == 'config':
  90. return command.CommandResult(return_code=0)
  91. elif sub_cmd == 'log':
  92. return self._HandleCommandGitLog(args)
  93. # Not handled, so abort
  94. print 'git', git_args, sub_cmd, args
  95. sys.exit(1)
  96. def _HandleCommandNm(self, args):
  97. return command.CommandResult(return_code=0)
  98. def _HandleCommandObjdump(self, args):
  99. return command.CommandResult(return_code=0)
  100. def _HandleCommandSize(self, args):
  101. return command.CommandResult(return_code=0)
  102. def _HandleCommand(self, **kwargs):
  103. """Handle a command execution.
  104. The command is in kwargs['pipe-list'], as a list of pipes, each a
  105. list of commands. The command should be emulated as required for
  106. testing purposes.
  107. Returns:
  108. A CommandResult object
  109. """
  110. pipe_list = kwargs['pipe_list']
  111. if len(pipe_list) != 1:
  112. print 'invalid pipe', kwargs
  113. sys.exit(1)
  114. cmd = pipe_list[0][0]
  115. args = pipe_list[0][1:]
  116. if cmd == 'git':
  117. return self._HandleCommandGit(args)
  118. elif cmd == './scripts/show-gnu-make':
  119. return command.CommandResult(return_code=0, stdout='make')
  120. elif cmd == 'nm':
  121. return self._HandleCommandNm(args)
  122. elif cmd == 'objdump':
  123. return self._HandleCommandObjdump(args)
  124. elif cmd == 'size':
  125. return self._HandleCommandSize(args)
  126. # Not handled, so abort
  127. print 'unknown command', kwargs
  128. sys.exit(1)
  129. return command.CommandResult(return_code=0)
  130. def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs):
  131. """Handle execution of 'make'
  132. Args:
  133. commit: Commit object that is being built
  134. brd: Board object that is being built
  135. stage: Stage that we are at (mrproper, config, build)
  136. cwd: Directory where make should be run
  137. args: Arguments to pass to make
  138. kwargs: Arguments to pass to command.RunPipe()
  139. """
  140. if stage == 'mrproper':
  141. return command.CommandResult(return_code=0)
  142. elif stage == 'config':
  143. return command.CommandResult(return_code=0,
  144. combined='Test configuration complete')
  145. elif stage == 'build':
  146. return command.CommandResult(return_code=0)
  147. # Not handled, so abort
  148. print 'make', stage
  149. sys.exit(1)
  150. def testCurrentSource(self):
  151. """Very simple test to invoke buildman on the current source"""
  152. self._RunControl()
  153. lines = terminal.GetPrintTestLines()
  154. self.assertTrue(lines[0].text.startswith('Building current source'))