autoninja_test.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #!/usr/bin/env vpython3
  2. # Copyright (c) 2022 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. import glob
  6. import multiprocessing
  7. import os
  8. import os.path
  9. import io
  10. import sys
  11. import unittest
  12. import contextlib
  13. from unittest import mock
  14. from parameterized import parameterized
  15. ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  16. sys.path.insert(0, ROOT_DIR)
  17. import autoninja
  18. from testing_support import trial_dir
  19. def write(filename, content):
  20. """Writes the content of a file and create the directories as needed."""
  21. filename = os.path.abspath(filename)
  22. dirname = os.path.dirname(filename)
  23. if not os.path.isdir(dirname):
  24. os.makedirs(dirname)
  25. with open(filename, 'w') as f:
  26. f.write(content)
  27. class AutoninjaTest(trial_dir.TestCase):
  28. def setUp(self):
  29. super(AutoninjaTest, self).setUp()
  30. self.previous_dir = os.getcwd()
  31. os.chdir(self.root_dir)
  32. def tearDown(self):
  33. os.chdir(self.previous_dir)
  34. super(AutoninjaTest, self).tearDown()
  35. def test_autoninja(self):
  36. """Test that by default (= no GN args) autoninja delegates to ninja."""
  37. with mock.patch('ninja.main', return_value=0) as ninja_main:
  38. out_dir = os.path.join('out', 'dir')
  39. write(os.path.join(out_dir, 'args.gn'), '')
  40. autoninja.main(['autoninja.py', '-C', out_dir])
  41. ninja_main.assert_called_once()
  42. args = ninja_main.call_args.args[0]
  43. self.assertIn('-C', args)
  44. self.assertEqual(args[args.index('-C') + 1], out_dir)
  45. @mock.patch('sys.platform', 'win32')
  46. def test_autoninja_splits_args_on_windows(self):
  47. """
  48. Test that autoninja correctly handles the special case of being
  49. passed its arguments as a quoted, whitespace-delimited string on
  50. Windows.
  51. """
  52. with mock.patch('ninja.main', return_value=0) as ninja_main:
  53. out_dir = os.path.join('out', 'dir')
  54. write(os.path.join(out_dir, 'args.gn'), '')
  55. autoninja.main([
  56. 'autoninja.py',
  57. '-C {} base'.format(out_dir),
  58. ])
  59. ninja_main.assert_called_once()
  60. args = ninja_main.call_args.args[0]
  61. self.assertIn('-C', args)
  62. self.assertEqual(args[args.index('-C') + 1], out_dir)
  63. self.assertIn('base', args)
  64. def test_autoninja_reclient(self):
  65. """
  66. Test that when specifying use_remoteexec=true, autoninja delegates to
  67. reclient_helper.
  68. """
  69. with mock.patch('reclient_helper.run_ninja',
  70. return_value=0) as run_ninja:
  71. out_dir = os.path.join('out', 'dir')
  72. write(os.path.join(out_dir, 'args.gn'), 'use_remoteexec=true')
  73. write(os.path.join('build', 'toolchain', 'use_reclient_value.py'),
  74. """
  75. def use_reclient_value(output_dir):
  76. return True
  77. """)
  78. write(os.path.join('buildtools', 'reclient_cfgs', 'reproxy.cfg'),
  79. 'RBE_v=2')
  80. write(os.path.join('buildtools', 'reclient', 'version.txt'), '0.0')
  81. write(
  82. os.path.join('buildtools', 'reclient_cfgs', 'reproxy.cfg'),
  83. 'instance=projects/rbe-chromium-untrusted-test/'
  84. 'instances/default_instance')
  85. autoninja.main(['autoninja.py', '-C', out_dir])
  86. run_ninja.assert_called_once()
  87. args = run_ninja.call_args.args[0]
  88. self.assertIn('-C', args)
  89. self.assertEqual(args[args.index('-C') + 1], out_dir)
  90. # Check that autoninja correctly calculated the number of jobs to use
  91. # as required for remote execution, instead of using the value for
  92. # local execution.
  93. self.assertIn('-j', args)
  94. parallel_j = int(args[args.index('-j') + 1])
  95. self.assertGreater(parallel_j, multiprocessing.cpu_count() * 2)
  96. def test_autoninja_siso(self):
  97. """
  98. Test that when specifying use_siso=true, autoninja delegates to siso.
  99. """
  100. with mock.patch('siso.main', return_value=0) as siso_main:
  101. out_dir = os.path.join('out', 'dir')
  102. write(os.path.join(out_dir, 'args.gn'), 'use_siso=true')
  103. write(os.path.join('build', 'config', 'siso', '.sisoenv'),
  104. 'SISO_PROJECT=rbe-chromium-untrusted-test')
  105. autoninja.main(['autoninja.py', '-C', out_dir])
  106. siso_main.assert_called_once()
  107. args = siso_main.call_args.args[0]
  108. self.assertIn('-C', args)
  109. self.assertEqual(args[args.index('-C') + 1], out_dir)
  110. def test_autoninja_siso_reclient(self):
  111. """
  112. Test that when specifying use_siso=true and use_remoteexec=true,
  113. autoninja starts reproxy using reclient_helper and calls 'siso ninja'.
  114. """
  115. reclient_helper_calls = []
  116. @contextlib.contextmanager
  117. def reclient_helper_mock(argv, tool, _should_collect_logs):
  118. reclient_helper_calls.append([argv, tool])
  119. yield 0
  120. with mock.patch('reclient_helper.build_context', reclient_helper_mock):
  121. with mock.patch('siso.main', return_value=0) as siso_main:
  122. out_dir = os.path.join('out', 'dir')
  123. write(os.path.join(out_dir, 'args.gn'),
  124. 'use_siso=true\nuse_remoteexec=true')
  125. write(
  126. os.path.join('build', 'toolchain', 'use_reclient_value.py'),
  127. """
  128. def use_reclient_value(output_dir):
  129. return True
  130. """)
  131. write(
  132. os.path.join('buildtools', 'reclient_cfgs', 'reproxy.cfg'),
  133. 'instance=projects/rbe-chromium-untrusted-test/'
  134. 'instances/default_instance\n'
  135. 'RBE_v=2')
  136. write(os.path.join('buildtools', 'reclient', 'version.txt'),
  137. '0.0')
  138. autoninja.main(['autoninja.py', '-C', out_dir])
  139. siso_main.assert_called_once_with([
  140. 'siso', 'ninja', '-project=', '-reapi_instance=', '-C',
  141. out_dir
  142. ])
  143. self.assertEqual(len(reclient_helper_calls), 1)
  144. self.assertEqual(
  145. reclient_helper_calls[0][0],
  146. ['siso', 'ninja', '-project=', '-reapi_instance=', '-C', out_dir])
  147. self.assertEqual(reclient_helper_calls[0][1], 'autosiso')
  148. @mock.patch('sys.platform', 'win32')
  149. def test_print_cmd_windows(self):
  150. args = [
  151. 'C:\\Program Files\\Python 3\\bin\\python3.exe', 'ninja.py', '-C',
  152. 'out\\direc tory\\',
  153. '../../base/types/expected_macros_unittest.cc^', '-j', '140'
  154. ]
  155. with contextlib.redirect_stderr(io.StringIO()) as f:
  156. autoninja._print_cmd(args)
  157. self.assertEqual(
  158. f.getvalue(),
  159. '"C:\\Program Files\\Python 3\\bin\\python3.exe" ninja.py -C ' +
  160. '"out\\direc tory\\" ' +
  161. '../../base/types/expected_macros_unittest.cc^^ -j 140\n')
  162. @mock.patch('sys.platform', 'linux')
  163. def test_print_cmd_linux(self):
  164. args = [
  165. '/home/user name/bin/python3', 'ninja.py', '-C', 'out/direc tory/',
  166. '../../base/types/expected_macros_unittest.cc^', '-j', '140'
  167. ]
  168. with contextlib.redirect_stderr(io.StringIO()) as f:
  169. autoninja._print_cmd(args)
  170. self.assertEqual(
  171. f.getvalue(),
  172. "'/home/user name/bin/python3' ninja.py -C 'out/direc tory/' " +
  173. "'../../base/types/expected_macros_unittest.cc^' -j 140\n")
  174. if __name__ == '__main__':
  175. unittest.main()