generate_skylab_deps.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright 2022 The Chromium Authors. All rights reserved.
  4. # Use of this source code is governed by a BSD-style license that can be
  5. # found in the LICENSE file.
  6. import argparse
  7. import json
  8. import os
  9. import re
  10. import sys
  11. # The basic shell script for client test run in Skylab. The arguments listed
  12. # here will be fed by autotest at the run time.
  13. #
  14. # * test-launcher-summary-output: the path for the json result. It will be
  15. # assigned by autotest, who will upload it to GCS upon test completion.
  16. # * test-launcher-shard-index: the index for this test run.
  17. # * test-launcher-total-shards: the total test shards.
  18. # * test_args: arbitrary runtime arguments configured in test_suites.pyl,
  19. # attached after '--'.
  20. BASIC_SHELL_SCRIPT = """
  21. #!/bin/sh
  22. while [[ $# -gt 0 ]]; do
  23. case "$1" in
  24. --test-launcher-summary-output)
  25. summary_output=$2
  26. shift 2
  27. ;;
  28. --test-launcher-shard-index)
  29. shard_index=$2
  30. shift 2
  31. ;;
  32. --test-launcher-total-shards)
  33. total_shards=$2
  34. shift 2
  35. ;;
  36. --)
  37. test_args=$2
  38. break
  39. ;;
  40. *)
  41. break
  42. ;;
  43. esac
  44. done
  45. if [ ! -d $(dirname $summary_output) ] ; then
  46. mkdir -p $(dirname $summary_output)
  47. fi
  48. cd `dirname $0` && cd ..
  49. """
  50. def build_test_script(args):
  51. # Build the shell script that will be used on the device to invoke the test.
  52. # Stored here as a list of lines.
  53. device_test_script_contents = BASIC_SHELL_SCRIPT.split('\n')
  54. test_invocation = ('LD_LIBRARY_PATH=./ ./%s '
  55. ' --test-launcher-summary-output=$summary_output'
  56. ' --test-launcher-shard-index=$shard_index'
  57. ' --test-launcher-total-shards=$total_shards'
  58. ' $test_args' % args.test_exe)
  59. device_test_script_contents.append(test_invocation)
  60. with open(args.output, 'w') as w:
  61. w.write('\n'.join(device_test_script_contents))
  62. os.chmod(args.output, 0o755)
  63. def build_filter_file(args):
  64. # TODO(b/227381644): This expression is hard to follow and should be
  65. # simplified. This would require a change on the cros infra side as well
  66. tast_expr_dict = {}
  67. default_disabled_tests = []
  68. if args.disabled_tests is not None:
  69. default_disabled_tests = [
  70. '!"name:{0}"'.format(test) for test in args.disabled_tests
  71. ]
  72. default_enabled_test_term = ''
  73. if args.enabled_tests is not None:
  74. default_enabled_test_term = (' || ').join(
  75. ['"name:{0}"'.format(test) for test in args.enabled_tests])
  76. # Generate the default expression to be used when there is no known key
  77. tast_expr = args.tast_expr if args.tast_expr else ""
  78. if default_disabled_tests:
  79. default_disabled_term = " && ".join(default_disabled_tests)
  80. tast_expr = "{0} && {1}".format(tast_expr, default_disabled_term) if \
  81. tast_expr else default_disabled_term
  82. if default_enabled_test_term:
  83. tast_expr = "{0} && ({1})".format(
  84. tast_expr,
  85. default_enabled_test_term) if tast_expr else default_enabled_test_term
  86. tast_expr_dict['default'] = "({0})".format(tast_expr)
  87. # Generate an expression for each collection in the gni file
  88. if args.tast_control is not None:
  89. with open(args.tast_control, 'r') as tast_control_file:
  90. gni = tast_control_file.read()
  91. filter_lists = re.findall(r'(.*) = \[([^\]]*)\]', gni)
  92. for filter_list in filter_lists:
  93. tast_expr = args.tast_expr if args.tast_expr else ""
  94. milestone_disabled_tests = {
  95. '!"name:{0}"'.format(test)
  96. for test in re.findall(r'"([^"]+)"', filter_list[1])
  97. }
  98. milestone_disabled_tests.update(default_disabled_tests)
  99. if milestone_disabled_tests:
  100. tast_expr = "{0} && {1}".format(
  101. tast_expr, " && ".join(milestone_disabled_tests)
  102. ) if tast_expr else " && ".join(milestone_disabled_tests)
  103. if default_enabled_test_term:
  104. tast_expr = "{0} && ({1})".format(
  105. tast_expr, default_enabled_test_term
  106. ) if tast_expr else default_enabled_test_term
  107. if tast_expr:
  108. tast_expr_dict[filter_list[0]] = "({0})".format(tast_expr)
  109. if len(tast_expr_dict) > 0:
  110. with open(args.output, "w") as file:
  111. json.dump(tast_expr_dict, file, indent=2)
  112. os.chmod(args.output, 0o644)
  113. def main():
  114. parser = argparse.ArgumentParser()
  115. subparsers = parser.add_subparsers(dest='command')
  116. script_gen_parser = subparsers.add_parser('generate-runner')
  117. script_gen_parser.add_argument(
  118. '--test-exe',
  119. type=str,
  120. required=True,
  121. help='Path to test executable to run inside the device.')
  122. script_gen_parser.add_argument('--verbose', '-v', action='store_true')
  123. script_gen_parser.add_argument(
  124. '--output',
  125. required=True,
  126. type=str,
  127. help='Path to create the runner script.')
  128. script_gen_parser.set_defaults(func=build_test_script)
  129. filter_gen_parser = subparsers.add_parser('generate-filter')
  130. filter_gen_parser.add_argument(
  131. '--tast-expr',
  132. type=str,
  133. required=False,
  134. help='Tast expression to determine tests to run. This creates the '
  135. 'initial set of tests that can be further filtered.')
  136. filter_gen_parser.add_argument(
  137. '--enabled-tests',
  138. type=str,
  139. required=False,
  140. action='append',
  141. help='Name of tests to allow to test (unnamed tests will not run).')
  142. filter_gen_parser.add_argument(
  143. '--disabled-tests',
  144. type=str,
  145. required=False,
  146. action='append',
  147. help='Names of tests to disable from running')
  148. filter_gen_parser.add_argument(
  149. '--tast-control',
  150. type=str,
  151. required=False,
  152. help='Filename for the tast_control file containing version skew '
  153. 'test filters to generate.')
  154. filter_gen_parser.add_argument(
  155. '--output',
  156. required=True,
  157. type=str,
  158. help='Path to create the plain text filter file.')
  159. filter_gen_parser.set_defaults(func=build_filter_file)
  160. args = parser.parse_args()
  161. if (args.command == "generate-filter" and args.disabled_tests is None and
  162. args.enabled_tests is None and args.tast_expr is None):
  163. parser.error(
  164. '--disabled-tests, --enabled-tests, or --tast-expr must be provided '
  165. 'to generate-filter')
  166. args.func(args)
  167. return 0
  168. if __name__ == '__main__':
  169. sys.exit(main())