blob: 780ac74b4a1eb38db26322eb46116c3496dd0365 [file] [log] [blame]
Dennis Kempin22c7c4d2012-07-26 13:04:24 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4#
5# This module is the main module for the console interface. It takes care
6# of parsing the command line arguments and formating the output
Harry Cutts684f78c2020-04-09 18:37:05 -07007from __future__ import absolute_import
8from __future__ import division
9from __future__ import print_function
10
Dennis Kempinc2b59862013-02-20 14:02:25 -080011from optparse import OptionParser
Dennis Kempin1c7ffab2013-02-28 11:43:45 -080012from subprocess import Popen, PIPE, STDOUT
Dennis Kempinc2b59862013-02-20 14:02:25 -080013from tempfile import NamedTemporaryFile
Dennis Kempin725ee5b2012-08-10 14:17:15 -070014import json
Dennis Kempind97cd722014-01-31 13:32:07 -080015import logging
Dennis Kempin725ee5b2012-08-10 14:17:15 -070016import math
Dennis Kempina44de382013-04-29 14:53:31 -070017import multiprocessing
Dennis Kempin725ee5b2012-08-10 14:17:15 -070018import os
Dennis Kempin725ee5b2012-08-10 14:17:15 -070019import sys
20
Dennis Kempin5495f8a2013-06-13 13:42:03 -070021from mtedit import MTEdit
Dennis Kempin07e90e72014-04-15 13:54:39 -070022from mtlib import Log, PlatformDatabase
Dennis Kempinc2b59862013-02-20 14:02:25 -080023
Dennis Kempin725ee5b2012-08-10 14:17:15 -070024from table import Table
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070025from test_case import TestCase
Dennis Kempin31c0fbd2012-07-30 13:20:37 -070026from test_factory import TestFactory
Dennis Kempin93a71412014-01-10 13:39:37 -080027from test_robot import RobotTestGenerator
Andrew de los Reyes8063b662014-07-11 14:58:30 -070028from test_collector import TestCollector
Dennis Kempin963fb152013-01-11 15:40:19 -080029from test_runner import ParallelTestRunner as TestRunner
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070030
Dennis Kempin1c7ffab2013-02-28 11:43:45 -080031
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070032_help_text = """\
Dennis Kempinc2b59862013-02-20 14:02:25 -080033Multitouch Regression Test Suite:
34---------------------------------
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070035
Dennis Kempinc2b59862013-02-20 14:02:25 -080036$ %prog [all|glob]
37Executes tests. Either all of them or selected tests by providing a glob match
38In order to test for regressions use:
39$ %prog all --out filename
40make a change
41$ %prog all --ref filename
42Which will display the changes in test results compared to before the change
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070043
Dennis Kempinc2b59862013-02-20 14:02:25 -080044$ %prog testname -v %info%
45Run test and display information. %info% can be:
46- a or activity: to view the touchpad activity in mtedit
47- g or gestures: to view the generated gestures
48- al or activity-log: to view the generated activity log
49- gl or gestures-log: to view the generated gestures log
50- el or evdev-log: to view the generated evdev log
51
52$ %prog test_name -c %source%
53Create a new test case from %source%. Source can be:
54- A feedback URL
55- A device IP
56- The path to an activity log file
57When using a file name test.log, %prog will look at test.log.evdev
58for the evdev log file. You can optionally supply -e to override this path.
59%prog will display an URL where you can trim the log file, the trimmed
60log file will then be used to create the new test case. Specify --no-edit in
61case you do not want to use the original files without trimming.
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070062
Dennis Kempin462c8752013-04-04 16:01:54 -070063$ %prog test_name --gdb
64Run the test using gdb for debugging the gestures library
65
Dennis Kempin22c7c4d2012-07-26 13:04:24 -070066General Info:
67-------------
68testname arguments:
69Tests are always names as [platform]/[name of test case]. You can find the tests
70available in the tests folder.
71For example: lumpy/scroll_test
72
73Tests Folder:
74The tests folder contains a folder for each platform and all the test cases.
75Each test case is made up of 3 files:
76[testcase].py which contains the validation script
77[testcase].log which contains the input_event log
78[testcase].props which contains user_defined properties passed to gestures lib.
79
80Platform folders:
81To add a new platform you need to add a new folder to the Tests folder, and
82generate a platform.dat file. This can be done using the evemu-describe tool
83on the target platform:
84
85$ gmerge utouch-evemu
86$ evemu-describe /path/to/device > platform.dat
87"""
88
Dennis Kempin1c7ffab2013-02-28 11:43:45 -080089
90def Compile():
91 if "SRC_DIR" not in os.environ:
Harry Cutts684f78c2020-04-09 18:37:05 -070092 print("Requires SRC_DIR env-var. Re-run $ sudo make setup-in-place")
Harry Cutts91c0d252020-04-28 17:10:02 -070093 sys.exit(1)
Dennis Kempin1c7ffab2013-02-28 11:43:45 -080094
95 dir = os.environ["SRC_DIR"]
Harry Cutts684f78c2020-04-09 18:37:05 -070096 print("Recompiling gestures/libevdev/replay...")
97 print("SRC_DIR is %s" % dir)
Dennis Kempina44de382013-04-29 14:53:31 -070098 process = Popen(["make", "-j", str(multiprocessing.cpu_count()),
99 "in-place"], cwd=dir, stdout=PIPE, stderr=STDOUT)
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800100 ret = process.wait()
101 if ret != 0:
Harry Cuttsf0236142020-07-22 15:37:02 -0700102 print(process.stdout.read().decode(errors='replace'))
Harry Cutts91c0d252020-04-28 17:10:02 -0700103 sys.exit(1)
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800104
105
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700106def RunAndCompare(glob, ref_file=None, autotest=False):
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800107 if not autotest:
108 Compile()
Harry Cutts684f78c2020-04-09 18:37:05 -0700109 print("Running tests...")
Dennis Kempinaad2bbb2013-06-18 13:48:35 -0700110 runner = TestRunner(os.environ["TESTS_DIR"])
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700111 results = runner.RunAll(glob)
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700112
Dennis Kempin97397c62013-02-28 10:49:59 -0800113 # load reference
114 ref = {}
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700115 deltas = {}
Dennis Kempin97397c62013-02-28 10:49:59 -0800116 if ref_file:
117 ref = json.load(open(ref_file))
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700118 for name, res in results.items():
119 if name in ref:
120 deltas[name] = res["score"] - ref[name]["score"]
121
122 return (results, ref, deltas)
123
124def MakeResultsTable(title, names_to_include, results, ref, deltas):
125 """Returns a table of test results."""
126 def ResultStr(value):
127 if value["result"] == "success":
128 msg = "success" if value["score"] >= 0.5 else "bad"
129 return "%s (%.4f)" % (msg, value["score"])
130 else:
131 return value["result"]
132
133 def ColoredDelta(delta):
134 if math.fabs(delta) < 1e-10:
135 return "\x1b[0m%.4f\x1b[0m" % delta # default color
136 elif delta < 0:
137 return "\x1b[31m%+.4f\x1b[0m" % delta # red
138 else:
139 return "\x1b[32m%+.4f\x1b[0m" % delta # green
140
141 table = Table()
142 table.title = title
143 table.header("Test", "reference score", "new score", "delta")
144 for name in sorted(names_to_include):
145 ref_score = ResultStr(ref[name]) if name in ref else "(new)"
146 delta_str = ColoredDelta(deltas[name]) if name in deltas else ""
147 table.row(name, ref_score, ResultStr(results[name]), delta_str)
148
149 return table
150
151def ManualRun(glob, out_file=None, ref_file=None, autotest=False,
152 compact_results=False):
153 """
154 Runs the specified tests, printing a table of results as well as logs for
155 failures (if ref_file isn't specified) or regressions (if it is).
156 """
157 results, ref, deltas = RunAndCompare(glob, ref_file, autotest)
Dennis Kempin97397c62013-02-28 10:49:59 -0800158
Dennis Kempin725ee5b2012-08-10 14:17:15 -0700159 # print reports
Andrew de los Reyesbf5fa422012-10-17 16:45:45 -0700160 sorted_results_items = sorted(results.items())
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700161 for case_name, value in sorted_results_items:
162 if case_name in ref:
163 should_show_report = math.fabs(deltas[case_name]) >= 1e-10
164 else:
165 should_show_report = value["result"] != "success"
166 if not should_show_report and len(results) > 1:
167 continue
Dennis Kempin97397c62013-02-28 10:49:59 -0800168
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700169 print("### Validation report for", case_name)
Harry Cutts684f78c2020-04-09 18:37:05 -0700170 print(value["description"])
Dennis Kempin9cfc4842013-02-28 10:39:24 -0800171 if value["disabled"]:
Harry Cutts684f78c2020-04-09 18:37:05 -0700172 print("DISABLED")
Dennis Kempin9cfc4842013-02-28 10:39:24 -0800173 else:
Harry Cutts684f78c2020-04-09 18:37:05 -0700174 print(value["logs"]["validation"])
175 print(value["error"])
Dennis Kempin4bc397b2012-08-08 16:51:47 -0700176
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700177 print(MakeResultsTable("Test Results", results.keys(), results, ref, deltas))
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700178
Dennis Kempin12968302012-08-09 15:37:09 -0700179 if out_file:
Harry Cuttsffcfa772020-04-22 16:17:10 -0700180 if compact_results:
181 for test_name in results:
182 r = results[test_name]
183 del r["logs"], r["events"], r["gestures"]
184
Dennis Kempin12968302012-08-09 15:37:09 -0700185 json.dump(results, open(out_file, "w"), indent=2)
Harry Cutts684f78c2020-04-09 18:37:05 -0700186 print("results stored in:", out_file)
Dennis Kempin12968302012-08-09 15:37:09 -0700187
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700188 regression = any(name in ref and deltas[name] < 0 for name in results.keys())
Dennis Kempin725ee5b2012-08-10 14:17:15 -0700189 if regression:
Harry Cutts684f78c2020-04-09 18:37:05 -0700190 print("\x1b[91mThere are regressions present in this test run!\x1b[0m")
Harry Cutts91c0d252020-04-28 17:10:02 -0700191 sys.exit(1)
Dennis Kempin725ee5b2012-08-10 14:17:15 -0700192
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800193
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700194_IMPROVEMENT_MESSAGE = """
195Some tests have been fixed or had their scores improved! Please update
196tools/touchtests-report.json by running the following in the chroot:
197
198 $ touchtests --compact-results \\
199 --out ~/trunk/src/platform/gestures/tools/touchtests-report.json
200
201Then add commit the JSON file changes to your CL.
202"""
203
204def PresubmitRun(ref_file, autotest=False):
205 """
206 Runs a gestures library presubmit, meaning it runs all tests, and exits with
207 an error if any have regressed or been fixed (so that the user can update the
208 reference file).
209 """
210 results, ref, deltas = RunAndCompare("all", ref_file, autotest)
211
212 new_tests = results.keys() - ref.keys()
213 failing_new_tests = set(filter(lambda n: results[n]["result"] != "success",
214 new_tests))
215 regressions = set(filter(lambda name: deltas[name] <= -1e-10, deltas.keys()))
216 problems = regressions | failing_new_tests
217 if len(problems) > 0:
218 print(MakeResultsTable("Regressions or failures", problems, results, ref,
219 deltas))
220
221 if len(problems) > 0:
222 print("\x1b[91mPlease fix these failures or regressions, then re-run the "
223 "presubmit.\x1b[0m")
224 sys.exit(1)
225
226 fixed_tests = set(filter(lambda name: deltas[name] >= 1e-10, deltas.keys()))
227 if len(fixed_tests) > 0:
228 print(MakeResultsTable("Improvements", fixed_tests, results, ref, deltas))
229 print(_IMPROVEMENT_MESSAGE)
230 sys.exit(1)
231
232
Dennis Kempin64f513f2012-08-10 15:09:18 -0700233def Get(test_name, what, file=None):
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800234 Compile()
Dennis Kempin64f513f2012-08-10 15:09:18 -0700235 if file:
236 data = json.load(open(file))
237 results = data[test_name]
238 else:
Dennis Kempinaad2bbb2013-06-18 13:48:35 -0700239 runner = TestRunner(os.environ["TESTS_DIR"])
Dennis Kempin64f513f2012-08-10 15:09:18 -0700240 data = runner.RunAll(test_name)
241 results = data[test_name]
242
243 if what == "gestures-log":
Harry Cutts684f78c2020-04-09 18:37:05 -0700244 print(results["logs"]["gestures"])
Dennis Kempin64f513f2012-08-10 15:09:18 -0700245 elif what == "evdev-log":
Harry Cutts684f78c2020-04-09 18:37:05 -0700246 print(results["logs"]["evdev"])
Dennis Kempin64f513f2012-08-10 15:09:18 -0700247 elif what == "activity-log":
Harry Cutts684f78c2020-04-09 18:37:05 -0700248 print(results["logs"]["activity"])
Dennis Kempin64f513f2012-08-10 15:09:18 -0700249 elif what == "gestures":
Harry Cutts684f78c2020-04-09 18:37:05 -0700250 print(results["gestures"])
Dennis Kempin64f513f2012-08-10 15:09:18 -0700251 elif what == "events":
Harry Cutts684f78c2020-04-09 18:37:05 -0700252 print(results["events"])
Dennis Kempin3b1fca72014-01-09 11:54:59 -0800253 elif what == "activity":
254 log = Log(activity=results["logs"]["activity"])
255 editor = MTEdit()
256 editor.View(log)
Dennis Kempin64f513f2012-08-10 15:09:18 -0700257
Dennis Kempin462c8752013-04-04 16:01:54 -0700258def GDB(test_name):
259 Compile()
Dennis Kempinaad2bbb2013-06-18 13:48:35 -0700260 runner = TestRunner(os.environ["TESTS_DIR"])
Dennis Kempin462c8752013-04-04 16:01:54 -0700261 data = runner.RunGDB(test_name)
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800262
Dennis Kempin3b1fca72014-01-09 11:54:59 -0800263def Add(testname, log, gdb):
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700264 """
265 Adds a new test case.
266 """
267 # determine test name from activity_log name
Dennis Kempinaad2bbb2013-06-18 13:48:35 -0700268 factory = TestFactory(os.environ["TESTS_DIR"])
Dennis Kempin3b1fca72014-01-09 11:54:59 -0800269 case = factory.CreateTest(testname, log, gdb)
Dennis Kempin15967a42013-02-25 12:41:54 -0800270 if case:
Harry Cutts684f78c2020-04-09 18:37:05 -0700271 print("Test \"" + case.name + "\" created")
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700272
Dennis Kempin07e90e72014-04-15 13:54:39 -0700273def AddPlatform(ip):
274 name = PlatformDatabase.RegisterPlatformFromDevice(ip)
275 if not name:
276 return
277 dirname = os.path.join(os.environ["TESTS_DIR"], name)
278 propsfile = os.path.join(dirname, "platform.props")
Dennis Kempin544dfde2014-06-09 14:02:55 -0700279 if not os.path.exists(dirname):
280 os.mkdir(dirname)
Dennis Kempin07e90e72014-04-15 13:54:39 -0700281 open(propsfile, "w").write("{\"platform\": \"%s\"}" % name)
Harry Cutts684f78c2020-04-09 18:37:05 -0700282 print(" ", propsfile)
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800283
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700284def Main():
285 """
286 Main entry point for the console interface
287 """
288
289 # setup paths from environment variables
290 if "TESTS_DIR" not in os.environ:
Harry Cutts684f78c2020-04-09 18:37:05 -0700291 print("Require TESTS_DIR environment variable")
Harry Cutts91c0d252020-04-28 17:10:02 -0700292 sys.exit(1)
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700293
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700294 TestCase.tests_path = os.environ["TESTS_DIR"]
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700295
Dennis Kempinc2b59862013-02-20 14:02:25 -0800296 parser = OptionParser(usage=_help_text)
297 parser.add_option("-c", "--create",
298 dest="create", default=None,
299 help="create new test case from URL/IP or log file")
Andrew de los Reyes408678b2015-01-09 14:21:55 -0800300 parser.add_option("-p", "--platform",
301 dest="platform", default=None,
302 help="specify platform when using --create")
Dennis Kempinc2b59862013-02-20 14:02:25 -0800303 parser.add_option("-e", "--evdev",
304 dest="evdev", default=None,
305 help="path to evdev log for creating a new test")
306 parser.add_option("-v", "--view",
307 dest="view", default=None,
308 help="view generated gestures(g), activity in mtedit(a) " +
309 "gestures-log(gl), evdev-log(el) or activity-log(al)")
310 parser.add_option("-r", "--ref",
311 dest="ref", default=None,
312 help="reference test results for detecting regressions")
313 parser.add_option("-o", "--out",
314 dest="out", default=None,
315 help="output test results to file.")
Harry Cuttsffcfa772020-04-22 16:17:10 -0700316 parser.add_option("--compact-results",
317 dest="compact_results", action="store_true", default=False,
318 help="exclude logs from the test result file when using "
319 "--out, making it much smaller")
Dennis Kempinc2b59862013-02-20 14:02:25 -0800320 parser.add_option("-n", "--new",
321 dest="new", action="store_true", default=False,
322 help="Create new device logs before downloading. " +
323 "[Default: False]")
324 parser.add_option("--no-edit",
325 dest="noedit", action="store_true", default=False,
326 help="Skip editing when creating tests. Add original log " +
327 "[Default: False]")
Dennis Kempin8e3201c2013-03-14 13:49:01 -0700328 parser.add_option("--autotest",
329 dest="autotest", action="store_true", default=False,
330 help="Run in autotest mode. Skips recompilation.")
Dennis Kempin462c8752013-04-04 16:01:54 -0700331 parser.add_option("--gdb",
332 dest="gdb", action="store_true", default=False,
Dennis Kempin93a71412014-01-10 13:39:37 -0800333 help="Run the test case in GDB"),
Dennis Kempind97cd722014-01-31 13:32:07 -0800334 parser.add_option("--verbose",
335 dest="verbose", action="store_true", default=False,
Dennis Kempin93a71412014-01-10 13:39:37 -0800336 help="Verbose debug output"),
337 parser.add_option("--robot",
338 dest="robot", default=None,
339 help="Instruct robot to generate test cases")
Andrew de los Reyes8063b662014-07-11 14:58:30 -0700340 parser.add_option("--collect_from",
341 dest="collect_ip", default=None,
342 help="Interactively collect tests at given device IP");
343 parser.add_option(
344 "--overwrite",
345 dest="overwrite", action="store_true", default=False,
346 help="(use with --robot or --collect_from) Overwrite existing tests")
Dennis Kempin93a71412014-01-10 13:39:37 -0800347 parser.add_option("--no-calib",
348 dest="nocalib", action="store_true", default=False,
349 help="(use with --robot) Skip calibration step.")
350 parser.add_option("--manual-fingertips",
351 dest="manual_fingertips", action="store_true",
352 default=False,
353 help="(use with --robot) Use fingertips that are present.")
354 parser.add_option("--slow",
355 dest="slow", action="store_true", default=False,
356 help="(use with --robot) Force slow movement.")
Dennis Kempin07e90e72014-04-15 13:54:39 -0700357 parser.add_option("--add-platform",
358 dest="add_platform", default=None,
359 help="add platform from IP address of remote device.")
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700360 parser.add_option("--presubmit",
361 dest="presubmit", action="store_true", default=False,
362 help="run tests as part of a Gestures library presubmit")
Dennis Kempin93a71412014-01-10 13:39:37 -0800363
Dennis Kempinc2b59862013-02-20 14:02:25 -0800364 (options, args) = parser.parse_args()
Andrew de los Reyes8c5585b2013-05-20 15:32:05 -0700365 options.download = False # For compatibility with mtedit
Andrew de los Reyes0489c662013-06-04 12:47:50 -0700366 options.screenshot = False # For compatibility with mtedit
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700367
Dennis Kempin07e90e72014-04-15 13:54:39 -0700368 if options.add_platform:
369 AddPlatform(options.add_platform)
370 return
371
Dennis Kempinc2b59862013-02-20 14:02:25 -0800372 if len(args) == 0:
373 test_name = "all"
374 elif len(args) == 1:
375 test_name = args[0]
376 else:
377 parser.print_help()
Harry Cutts91c0d252020-04-28 17:10:02 -0700378 sys.exit(1)
Dennis Kempinc2b59862013-02-20 14:02:25 -0800379
Dennis Kempind97cd722014-01-31 13:32:07 -0800380 level = logging.INFO if options.verbose else logging.WARNING
381 logging.basicConfig(level=level)
382
Dennis Kempinc2b59862013-02-20 14:02:25 -0800383 if options.create:
Dennis Kempinc2b59862013-02-20 14:02:25 -0800384 # obtain trimmed log data
385 original_log = Log(options.create, options)
386 if options.noedit:
387 log = original_log
Dennis Kempin12968302012-08-09 15:37:09 -0700388 else:
Dennis Kempinaad2bbb2013-06-18 13:48:35 -0700389 editor = MTEdit()
Andrew de los Reyes408678b2015-01-09 14:21:55 -0800390 platform = options.platform or test_name.split(os.sep)[0]
Andrew de los Reyes8cc4b0a2014-10-24 12:34:58 -0700391 log = editor.Edit(original_log, force_platform=platform)
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700392
Dennis Kempinc2b59862013-02-20 14:02:25 -0800393 # pass to touchtests
Dennis Kempin3b1fca72014-01-09 11:54:59 -0800394 Add(test_name, log, options.gdb)
Dennis Kempinc2b59862013-02-20 14:02:25 -0800395
396 elif options.view:
397 view = options.view
398 if view == "g":
399 view = "gestures"
400 elif view == "gl":
401 view = "gestures-log"
402 elif view == "el":
403 view = "evdev-log"
404 elif view == "al":
405 view = "activity-log"
406 elif view == "a":
407 view = "activity"
Dennis Kempin3b1fca72014-01-09 11:54:59 -0800408 Get(test_name, view)
Dennis Kempin462c8752013-04-04 16:01:54 -0700409 elif options.gdb:
410 GDB(test_name)
Andrew de los Reyes8063b662014-07-11 14:58:30 -0700411 elif options.collect_ip:
412 generator = TestCollector(options.collect_ip, os.environ["TESTS_DIR"])
413 generator.GenerateAll(test_name, options.overwrite)
Dennis Kempin93a71412014-01-10 13:39:37 -0800414 elif options.robot:
415 generator = RobotTestGenerator(options.robot, not options.nocalib,
416 options.slow, options.manual_fingertips, os.environ["TESTS_DIR"])
417 generator.GenerateAll(test_name, options.overwrite)
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700418 elif options.presubmit:
419 if options.ref is None:
420 print("Error: --ref must be specified with --presubmit.")
421 sys.exit(1)
422
423 PresubmitRun(options.ref, options.autotest)
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700424 else:
Harry Cutts4f5a88c2020-04-28 16:13:00 -0700425 ManualRun(test_name, options.out, options.ref, options.autotest,
426 options.compact_results)
Dennis Kempin1c7ffab2013-02-28 11:43:45 -0800427
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700428
Dennis Kempin22c7c4d2012-07-26 13:04:24 -0700429if __name__ == "__main__":
430 Main()