diff options
Diffstat (limited to 'testing/mozharness/scripts/does_it_crash.py')
-rwxr-xr-x | testing/mozharness/scripts/does_it_crash.py | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/testing/mozharness/scripts/does_it_crash.py b/testing/mozharness/scripts/does_it_crash.py new file mode 100755 index 0000000000..0c54b63131 --- /dev/null +++ b/testing/mozharness/scripts/does_it_crash.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** END LICENSE BLOCK ***** +""" does_it_crash.py + + Runs a thing to see if it crashes within a set period. +""" +import os +import sys + +import requests + +sys.path.insert(1, os.path.dirname(sys.path[0])) + +import mozinstall +from mozharness.base.script import BaseScript +from mozprocess import ProcessHandler + + +class DoesItCrash(BaseScript): + config_options = [ + [ + [ + "--thing-url", + ], + { + "action": "store", + "dest": "thing_url", + "type": str, + "help": "An URL that points to a package containing the thing to run", + }, + ], + [ + [ + "--thing-to-run", + ], + { + "action": "store", + "dest": "thing_to_run", + "type": str, + "help": "The thing to run. If --thing-url is a package, this should be " + "its location relative to the root of the package.", + }, + ], + [ + [ + "--thing-arg", + ], + { + "action": "append", + "dest": "thing_args", + "type": str, + "default": [], + "help": "Args for the thing. May be passed multiple times", + }, + ], + [ + [ + "--run-for", + ], + { + "action": "store", + "dest": "run_for", + "default": 30, + "type": int, + "help": "How long to run the thing for, in seconds", + }, + ], + ] + + def __init__(self): + super(DoesItCrash, self).__init__( + all_actions=[ + "download", + "run-thing", + ], + default_actions=[ + "download", + "run-thing", + ], + config_options=self.config_options, + ) + + def downloadFile(self, url, file_name): + req = requests.get(url, stream=True, timeout=30) + file_path = os.path.join(os.getcwd(), file_name) + + with open(file_path, "wb") as f: + for chunk in req.iter_content(chunk_size=1024): + if not chunk: + continue + f.write(chunk) + f.flush() + return file_path + + def download(self): + url = self.config["thing_url"] + fn = "thing." + url.split(".")[-1] + self.downloadFile(url=url, file_name=fn) + if mozinstall.is_installer(fn): + self.install_dir = mozinstall.install(fn, "thing") + else: + self.install_dir = "" + + def run_thing(self): + thing = os.path.abspath( + os.path.join(self.install_dir, self.config["thing_to_run"]) + ) + # thing_args is a LockedTuple, which mozprocess doesn't like + args = list(self.config["thing_args"]) + timeout = self.config["run_for"] + + self.log(f"Running {thing} with args {args}") + p = ProcessHandler( + thing, + args=args, + shell=False, + storeOutput=True, + kill_on_timeout=True, + stream=False, + ) + p.run(timeout) + # Wait for the timeout + a grace period (to make sure we don't interrupt + # process tear down). + # Without this, this script could potentially hang + p.wait(timeout + 10) + if not p.timedOut: + # It crashed, oh no! + self.critical( + f"TEST-UNEXPECTED-FAIL: {thing} did not run for {timeout} seconds" + ) + self.critical("Output was:") + for l in p.output: + self.critical(l) + self.fatal("fail") + else: + self.info(f"PASS: {thing} ran successfully for {timeout} seconds") + + +# __main__ {{{1 +if __name__ == "__main__": + crashit = DoesItCrash() + crashit.run_and_exit() |