OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | |
6 """Helper script to generate unit test lists for the Chromecast build scripts. | 5 """Helper script to generate unit test lists for the Chromecast build scripts. |
7 """ | 6 """ |
8 | 7 |
9 import glob | 8 import glob |
| 9 import json |
10 import optparse | 10 import optparse |
| 11 import os |
11 import sys | 12 import sys |
12 | 13 |
13 | 14 |
14 def CombineList(test_files_dir, list_output_file, include_filters, | 15 def CombineList(test_files_dir, list_output_file, include_filters, |
15 additional_runtime_options): | 16 additional_runtime_options): |
16 """Writes a unit test file in a format compatible for Chromecast scripts. | 17 """Writes a unit test file in a format compatible for Chromecast scripts. |
17 | 18 |
18 If include_filters is True, uses filters to create a test runner list | 19 If include_filters is True, uses filters to create a test runner list |
19 and also include additional options, if any. | 20 and also include additional options, if any. |
20 Otherwise, creates a list only of the tests to build. | 21 Otherwise, creates a list only of the tests to build. |
21 | 22 |
22 Args: | 23 Args: |
23 test_files_dir: Path to the intermediate directory containing tests/filters. | 24 test_files_dir: Path to the intermediate directory containing tests/filters. |
24 list_output_file: Path to write the unit test file out to. | 25 list_output_file: Path to write the unit test file out to. |
25 include_filters: Whether or not to include the filters when generating | 26 include_filters: Whether or not to include the filters when generating |
26 the test list. | 27 the test list. |
27 additional_runtime_options: Arguments to be applied to all tests. These are | 28 additional_runtime_options: Arguments to be applied to all tests. These are |
28 applied before filters (so test-specific filters take precedence). | 29 applied before filters (so test-specific filters take precedence). |
| 30 |
| 31 Raises: |
| 32 Exception: if filter is found for an unknown target. |
29 """ | 33 """ |
30 | 34 |
31 # GYP targets may provide a numbered priority for the filename. Sort to | 35 # GYP targets may provide a numbered priority for the filename. Sort to |
32 # use that priority. | 36 # use that priority. |
33 test_files = sorted(glob.glob(test_files_dir + "/*.tests")) | 37 test_files = sorted(glob.glob(test_files_dir + "/*.tests")) |
34 filter_files = sorted(glob.glob(test_files_dir + "/*.filters")) | 38 filter_files = sorted(glob.glob(test_files_dir + "/*.filters")) |
35 | 39 |
36 test_bin_set = set() | 40 test_bin_set = set() |
37 for test_filename in test_files: | 41 for test_filename in test_files: |
38 with open(test_filename, "r") as test_file: | 42 with open(test_filename, "r") as test_file: |
39 for test_file_line in test_file: | 43 for test_file_line in test_file: |
40 # Binary name may be a simple test target (cast_net_unittests) or be a | 44 # Binary name may be a simple test target (cast_net_unittests) or be a |
41 # qualified gyp path (../base.gyp:base_unittests). | 45 # qualified gyp path (../base.gyp:base_unittests). |
42 test_binary_name = test_file_line.split(":")[-1].strip() | 46 test_binary_name = test_file_line.split(":")[-1].strip() |
43 test_bin_set.add(test_binary_name) | 47 test_bin_set.add(test_binary_name) |
44 | 48 |
45 test_filters = {} | 49 test_filters = {} |
46 if include_filters: | 50 if include_filters: |
47 for filter_filename in filter_files: | 51 for filter_filename in filter_files: |
48 with open(filter_filename, "r") as filter_file: | 52 with open(filter_filename, "r") as filter_file: |
49 for filter_line in filter_file: | 53 for filter_line in filter_file: |
50 (test_binary_name, filter) = filter_line.strip().split(" ", 1) | 54 (test_binary_name, filter) = filter_line.strip().split(" ", 1) |
51 | 55 |
52 if test_binary_name not in test_bin_set: | 56 if test_binary_name not in test_bin_set: |
53 raise Exception("Filter found for unknown target: " + | 57 raise Exception("Filter found for unknown target: " + |
54 test_binary_name) | 58 test_binary_name) |
55 | 59 |
56 # Note: This may overwrite a previous rule. This is okay, since higher | 60 # Note: This may overwrite a previous rule. This is okay, since higher |
57 # priority files are evaluated after lower priority files. | 61 # priority files are evaluated after lower priority files. |
58 test_filters[test_binary_name] = filter | 62 test_filters[test_binary_name] = filter |
59 | 63 |
60 test_binaries = [ | 64 test_binaries = [ |
61 binary + " " + (additional_runtime_options or "") | 65 binary + " " + (additional_runtime_options or "") + |
62 + (" " + test_filters[binary] if binary in test_filters else "") | 66 (" " + test_filters[binary] if binary in test_filters else "") |
63 for binary in test_bin_set] | 67 for binary in test_bin_set |
| 68 ] |
64 | 69 |
65 with open(list_output_file, "w") as f: | 70 with open(list_output_file, "w") as f: |
66 f.write("\n".join(sorted(test_binaries))) | 71 f.write("\n".join(sorted(test_binaries))) |
67 | 72 |
68 | 73 |
| 74 def CombineRuntimeDeps(test_files_dir, deps_output_file): |
| 75 """Writes a JSON file that lists the runtime dependecies for each test. |
| 76 |
| 77 The output will consist of a JSON dictionary where the keys are names of the |
| 78 unittests and the values are arrays of files and directories needed at runtime |
| 79 by the unittest. Of note, the unittest itself is always listed as a runtime |
| 80 dependency of itself. |
| 81 |
| 82 The paths are all relative to the root output directory (where the unittest |
| 83 binaries live). |
| 84 |
| 85 { |
| 86 "base_unittests": ["./base_unittests", "../../base/test/data/"], |
| 87 "cast_media_unittests": [...], |
| 88 ... |
| 89 } |
| 90 |
| 91 Args: |
| 92 test_files_dir: path to the intermediate directory containing the invidual |
| 93 runtime deps files. |
| 94 deps_output_file: Path to write the JSON file out to. |
| 95 """ |
| 96 runtime_deps = {} |
| 97 runtime_deps_dir = os.path.join(test_files_dir, "runtime_deps") |
| 98 for runtime_deps_file in glob.glob(runtime_deps_dir + "/*_runtime_deps.txt"): |
| 99 test_name = os.path.basename(runtime_deps_file).replace("_runtime_deps.txt", |
| 100 "") |
| 101 with open(runtime_deps_file, "r") as f: |
| 102 runtime_deps[test_name] = [dep.strip() for dep in f] |
| 103 assert runtime_deps[test_name][0] == os.path.join(".", test_name) |
| 104 |
| 105 with open(deps_output_file, "w") as outfile: |
| 106 json.dump( |
| 107 runtime_deps, outfile, sort_keys=True, indent=2, separators=(",", ": ")) |
| 108 |
| 109 |
69 def CreateList(inputs, list_output_file): | 110 def CreateList(inputs, list_output_file): |
70 with open(list_output_file, "w") as f: | 111 with open(list_output_file, "w") as f: |
71 f.write("\n".join(inputs)) | 112 f.write("\n".join(inputs)) |
72 | 113 |
73 | 114 |
74 def DoMain(argv): | 115 def DoMain(argv): |
75 """Main method. Runs helper commands for generating unit test lists.""" | 116 """Main method. Runs helper commands for generating unit test lists.""" |
76 parser = optparse.OptionParser( | 117 parser = optparse.OptionParser( |
77 """usage: %prog [<options>] <command> [<test names>] | 118 """usage: %prog [<options>] <command> [<test names>] |
78 | 119 |
79 Valid commands: | 120 Valid commands: |
80 create_list prints all given test names/args to a file, one line | 121 create_list prints all given test names/args to a file, one line |
81 per string | 122 per string |
82 pack_build packs all test files from the given output directory | 123 pack_build packs all test files from the given output directory |
83 into a single test list file | 124 into a single test list file |
84 pack_run packs all test and filter files from the given | 125 pack_run packs all test and filter files from the given |
85 output directory into a single test list file | 126 output directory into a single test list file |
86 """) | 127 """) |
87 parser.add_option("-o", action="store", dest="list_output_file", | 128 parser.add_option( |
88 help="Output path in which to write the test list.") | 129 "-o", |
89 parser.add_option("-t", action="store", dest="test_files_dir", | 130 action="store", |
90 help="Intermediate test list directory.") | 131 dest="list_output_file", |
91 parser.add_option("-a", action="store", dest="additional_runtime_options", | 132 help="Output path in which to write the test list.") |
92 help="Additional options applied to all tests.") | 133 parser.add_option( |
| 134 "-d", |
| 135 action="store", |
| 136 dest="deps_output_file", |
| 137 help="Output path in which to write the runtime deps.") |
| 138 parser.add_option( |
| 139 "-t", |
| 140 action="store", |
| 141 dest="test_files_dir", |
| 142 help="Intermediate test list directory.") |
| 143 parser.add_option( |
| 144 "-a", |
| 145 action="store", |
| 146 dest="additional_runtime_options", |
| 147 help="Additional options applied to all tests.") |
93 options, inputs = parser.parse_args(argv) | 148 options, inputs = parser.parse_args(argv) |
94 | 149 |
95 list_output_file = options.list_output_file | 150 list_output_file = options.list_output_file |
| 151 deps_output_file = options.deps_output_file |
96 test_files_dir = options.test_files_dir | 152 test_files_dir = options.test_files_dir |
97 additional_runtime_options = options.additional_runtime_options | 153 additional_runtime_options = options.additional_runtime_options |
98 | 154 |
99 if len(inputs) < 1: | 155 if len(inputs) < 1: |
100 parser.error("No command given.\n") | 156 parser.error("No command given.\n") |
101 command = inputs[0] | 157 command = inputs[0] |
102 test_names = inputs[1:] | 158 test_names = inputs[1:] |
103 | 159 |
104 if not list_output_file: | 160 if not list_output_file: |
105 parser.error("Output path (-o) is required.\n") | 161 parser.error("Output path (-o) is required.\n") |
106 | 162 |
107 if command == "create_list": | 163 if command == "create_list": |
108 return CreateList(test_names, list_output_file) | 164 return CreateList(test_names, list_output_file) |
109 | 165 |
110 if command == "pack_build": | 166 if command == "pack_build": |
111 if not test_files_dir: | 167 if not test_files_dir: |
112 parser.error("pack_build require a test files directory (-t).\n") | 168 parser.error("pack_build require a test files directory (-t).\n") |
113 return CombineList(test_files_dir, list_output_file, False, None) | 169 return CombineList(test_files_dir, list_output_file, False, None) |
114 | 170 |
115 if command == "pack_run": | 171 if command == "pack_run": |
116 if not test_files_dir: | 172 if not test_files_dir: |
117 parser.error("pack_run require a test files directory (-t).\n") | 173 parser.error("pack_run require a test files directory (-t).\n") |
| 174 if deps_output_file: |
| 175 CombineRuntimeDeps(test_files_dir, deps_output_file) |
118 return CombineList(test_files_dir, list_output_file, True, | 176 return CombineList(test_files_dir, list_output_file, True, |
119 additional_runtime_options) | 177 additional_runtime_options) |
120 | 178 |
121 parser.error("Invalid command specified.") | 179 parser.error("Invalid command specified.") |
122 | 180 |
123 | 181 |
124 if __name__ == "__main__": | 182 if __name__ == "__main__": |
125 DoMain(sys.argv[1:]) | 183 DoMain(sys.argv[1:]) |
OLD | NEW |