From 0badb98cc7ffcdb717a5f7a82c09e25e09671bcb Mon Sep 17 00:00:00 2001 From: Tyson Smith Date: Tue, 18 Apr 2023 14:10:59 -0700 Subject: [PATCH] Update FFPuppet support Support use of Path objects with FFpuppet --- grizzly/args.py | 8 ++--- grizzly/common/report.py | 4 +-- grizzly/common/reporter.py | 4 +-- grizzly/common/test_report.py | 13 +++---- grizzly/common/test_reporter.py | 13 +++---- grizzly/reduce/test_reduce.py | 19 +++++----- grizzly/reduce/test_strategies.py | 7 ++-- grizzly/replay/replay.py | 9 +++-- grizzly/replay/test_main.py | 18 +++++++--- grizzly/replay/test_replay.py | 52 ++++++++++++++------------- grizzly/target/puppet_target.py | 4 +-- grizzly/target/target.py | 3 +- grizzly/target/target_monitor.py | 3 +- grizzly/target/test_puppet_target.py | 36 +++++++++---------- grizzly/target/test_target.py | 6 ++-- grizzly/target/test_target_monitor.py | 6 ++-- grizzly/test_main.py | 6 +++- grizzly/test_session.py | 3 +- setup.cfg | 2 +- 19 files changed, 117 insertions(+), 99 deletions(-) diff --git a/grizzly/args.py b/grizzly/args.py index 860c515f..f3b66b0f 100644 --- a/grizzly/args.py +++ b/grizzly/args.py @@ -4,7 +4,7 @@ from argparse import ArgumentParser, HelpFormatter from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING from os import getenv -from os.path import exists, isfile +from os.path import exists from pathlib import Path from platform import system @@ -53,7 +53,7 @@ def __init__(self): if not targets: self.parser.error("No Platforms (Targets) are installed") - self.parser.add_argument("binary", help="Firefox binary to run") + self.parser.add_argument("binary", type=Path, help="Firefox binary to run") self.parser.add_argument( "--log-level", choices=sorted(self._level_map), @@ -250,8 +250,8 @@ def parse_args(self, argv=None): return args def sanity_check(self, args): - if not isfile(args.binary): - self.parser.error(f"file not found: {args.binary!r}") + if not args.binary.is_file(): + self.parser.error(f"file not found: '{args.binary!s}'") if args.launch_attempts < 1: self.parser.error("--launch-attempts must be >= 1") diff --git a/grizzly/common/report.py b/grizzly/common/report.py index 1b476f2f..75ca84dd 100644 --- a/grizzly/common/report.py +++ b/grizzly/common/report.py @@ -51,12 +51,12 @@ class Report: def __init__(self, log_path, target_binary, is_hang=False, size_limit=MAX_LOG_SIZE): assert isinstance(log_path, Path) - assert isinstance(target_binary, str) + assert isinstance(target_binary, Path) self._crash_info = None self._logs = self._select_logs(log_path) assert self._logs is not None self._signature = None - self._target_binary = Path(target_binary) + self._target_binary = target_binary self.is_hang = is_hang self.path = log_path # tail files in log_path if needed diff --git a/grizzly/common/reporter.py b/grizzly/common/reporter.py index 03724ec2..6cbd01d9 100644 --- a/grizzly/common/reporter.py +++ b/grizzly/common/reporter.py @@ -187,7 +187,7 @@ def sanity_check(bin_file): """Perform FuzzManager sanity check. Args: - bin_file (str): Binary file being tested. + bin_file (Path): Binary file being tested. Returns: None @@ -196,7 +196,7 @@ def sanity_check(bin_file): raise OSError(f"Missing: {FuzzManagerReporter.FM_CONFIG}") if not Path(f"{bin_file}.fuzzmanagerconf").is_file(): raise OSError(f"Missing: {bin_file}.fuzzmanagerconf") - ProgramConfiguration.fromBinary(bin_file) + ProgramConfiguration.fromBinary(str(bin_file)) def add_extra_metadata(self, key, value): """Add extra metadata to be reported with any CrashEntrys reported. diff --git a/grizzly/common/test_report.py b/grizzly/common/test_report.py index a9572a8a..f3020f9b 100644 --- a/grizzly/common/test_report.py +++ b/grizzly/common/test_report.py @@ -3,6 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. """test Grizzly Report""" # pylint: disable=protected-access +from pathlib import Path from FTB.Signatures.CrashInfo import CrashInfo from pytest import mark, raises @@ -23,7 +24,7 @@ def test_report_01(tmp_path): (tmp_path / "not_a_log.txt").touch() (tmp_path / "log_stderr.txt").write_bytes(b"STDERR log") (tmp_path / "log_stdout.txt").write_bytes(b"STDOUT log") - report = Report(tmp_path, "a.bin", size_limit=0) + report = Report(tmp_path, Path("a.bin"), size_limit=0) assert report._target_binary.name == "a.bin" assert report.path == tmp_path assert report._logs.aux is None @@ -43,7 +44,7 @@ def test_report_02(tmp_path): (tmp_path / "log_stderr.txt").write_bytes(b"STDERR log") (tmp_path / "log_stdout.txt").write_bytes(b"STDOUT log") _create_crash_log(tmp_path / "log_asan_blah.txt") - report = Report(tmp_path, "bin") + report = Report(tmp_path, Path("bin")) assert report.path == tmp_path assert report._logs.aux.name == "log_asan_blah.txt" assert report._logs.stderr.name == "log_stderr.txt" @@ -249,7 +250,7 @@ def test_report_10(tmp_path): (tmp_path / "unrelated.txt").write_bytes(b"nothing burger\n" * 200) (tmp_path / "rr-trace").mkdir() size_limit = len("STDERR log\n") - report = Report(tmp_path, "bin", size_limit=size_limit) + report = Report(tmp_path, Path("bin"), size_limit=size_limit) assert report.path == tmp_path assert report._logs.aux is None assert report._logs.stderr.name == "log_stderr.txt" @@ -281,7 +282,7 @@ def test_report_12(tmp_path): (tmp_path / "log_stdout.txt").write_bytes(b"STDOUT log") _create_crash_log(tmp_path / "log_asan_blah.txt") # no binary.fuzzmanagerconf - report = Report(tmp_path, target_binary="fake_bin") + report = Report(tmp_path, Path("bin")) assert report._crash_info is None assert report.crash_info is not None assert report._crash_info is not None @@ -291,7 +292,7 @@ def test_report_12(tmp_path): conf.write(b"platform = x86-64\n") conf.write(b"product = mozilla-central\n") conf.write(b"os = linux\n") - report = Report(tmp_path, target_binary=str(tmp_path / "fake_bin")) + report = Report(tmp_path, Path("bin")) assert report._crash_info is None assert report.crash_info is not None assert report._crash_info is not None @@ -323,7 +324,7 @@ def test_report_13(mocker, tmp_path, sig_cache, has_sig): (tmp_path / "log_stdout.txt").write_bytes(b"STDOUT log") if has_sig: _create_crash_log(tmp_path / "log_asan_blah.txt") - report = Report(tmp_path, "bin") + report = Report(tmp_path, Path("bin")) assert report._signature is None if has_sig: assert report.crash_signature diff --git a/grizzly/common/test_reporter.py b/grizzly/common/test_reporter.py index 6054a011..f2d60092 100644 --- a/grizzly/common/test_reporter.py +++ b/grizzly/common/test_reporter.py @@ -3,6 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. """test Grizzly Reporter""" # pylint: disable=protected-access +from pathlib import Path from FTB.ProgramConfiguration import ProgramConfiguration from pytest import mark, raises @@ -69,7 +70,7 @@ def test_filesystem_reporter_01(tmp_path): report_path = tmp_path / "reports" report_path.mkdir() reporter = FilesystemReporter(report_path) - reporter.submit([], Report(log_path, "fake_bin")) + reporter.submit([], Report(log_path, Path("bin"))) buckets = tuple(report_path.iterdir()) # check major bucket assert len(buckets) == 1 @@ -92,7 +93,7 @@ def test_filesystem_reporter_02(tmp_path, mocker): report_path = tmp_path / "reports" assert not report_path.exists() reporter = FilesystemReporter(report_path) - reporter.submit(tests, Report(log_path, "fake_bin")) + reporter.submit(tests, Report(log_path, Path("bin"))) assert not log_path.exists() assert report_path.exists() assert len(tuple(report_path.iterdir())) == 1 @@ -102,7 +103,7 @@ def test_filesystem_reporter_02(tmp_path, mocker): (log_path / "log_stderr.txt").write_bytes(b"STDERR log") (log_path / "log_stdout.txt").write_bytes(b"STDOUT log") tests = list(mocker.Mock(spec_set=TestCase, timestamp=1) for _ in range(2)) - reporter.submit(tests, Report(log_path, "fake_bin")) + reporter.submit(tests, Report(log_path, Path("bin"))) assert all(x.dump.call_count == 1 for x in tests) assert len(tuple(report_path.iterdir())) == 2 assert len(tuple(report_path.glob("NO_STACK"))) == 1 @@ -117,7 +118,7 @@ def test_filesystem_reporter_03(tmp_path): reporter = FilesystemReporter(tmp_path / "reports") reporter.min_space = 2**50 with raises(RuntimeError, match="Low disk space: "): - reporter.submit([], Report(log_path, "fake_bin")) + reporter.submit([], Report(log_path, Path("bin"))) def test_filesystem_reporter_04(mocker, tmp_path): @@ -208,7 +209,7 @@ def test_fuzzmanager_reporter_02( test_cases.append(fake_test) reporter = FuzzManagerReporter("fake-tool") reporter.force_report = force - reporter.submit(test_cases, Report(log_path, "fake_bin", is_hang=True)) + reporter.submit(test_cases, Report(log_path, Path("bin"), is_hang=True)) assert not log_path.is_dir() assert fake_collector.call_args == ({"tool": "fake-tool"},) if (frequent and not force) or ignored: @@ -262,5 +263,5 @@ def test_failed_launch_reporter_01(mocker, tmp_path): report_path.mkdir() (report_path / "log_stderr.txt").write_bytes(b"STDERR log") (report_path / "log_stdout.txt").write_bytes(b"STDOUT log") - FailedLaunchReporter().submit([], Report(report_path, "fake_bin")) + FailedLaunchReporter().submit([], Report(report_path, Path("bin"))) assert any(gtp.glob("*_logs")) diff --git a/grizzly/reduce/test_reduce.py b/grizzly/reduce/test_reduce.py index beca35d4..704a909e 100644 --- a/grizzly/reduce/test_reduce.py +++ b/grizzly/reduce/test_reduce.py @@ -8,6 +8,7 @@ from functools import partial, wraps from itertools import count from logging import getLogger +from pathlib import Path from pytest import mark, param, raises @@ -29,7 +30,7 @@ ) -def _fake_save_logs_foo(result_logs, meta=False): # pylint: disable=unused-argument +def _fake_save_logs_foo(result_logs): """write fake log data to disk""" (result_logs / "log_stderr.txt").write_text("STDERR log\n") (result_logs / "log_stdout.txt").write_text("STDOUT log\n") @@ -41,7 +42,7 @@ def _fake_save_logs_foo(result_logs, meta=False): # pylint: disable=unused-argu ) -def _fake_save_logs_bar(result_logs, meta=False): # pylint: disable=unused-argument +def _fake_save_logs_bar(result_logs): """write fake log data to disk""" (result_logs / "log_stderr.txt").write_text("STDERR log\n") (result_logs / "log_stdout.txt").write_text("STDOUT log\n") @@ -290,7 +291,7 @@ def replay_run(_tests, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir(exist_ok=True) _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) results.append(ReplayResult(report, [["test.html"]], [], True)) return results @@ -553,7 +554,7 @@ def replay_run(testcases, _time_limit, **kw): _fake_save_logs_foo(log_path) else: _fake_save_logs_bar(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html"]], [], expected)] return [] @@ -623,7 +624,7 @@ def replay_run(_tests, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html"]], [], True)] return [] @@ -694,7 +695,7 @@ def replay_run(_tests, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html"]], [], True)] return [] @@ -766,7 +767,7 @@ def replay_run(testcases, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html"]], [], True)] return [] @@ -829,7 +830,7 @@ def replay_run(testcases, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html"]], [], True)] return [] @@ -966,7 +967,7 @@ def replay_run(_testcases, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html"]], durations, interesting)] replayer.run.side_effect = replay_run diff --git a/grizzly/reduce/test_strategies.py b/grizzly/reduce/test_strategies.py index 2d58a397..df7e1f2b 100644 --- a/grizzly/reduce/test_strategies.py +++ b/grizzly/reduce/test_strategies.py @@ -5,6 +5,7 @@ """Unit tests for `grizzly.reduce.strategies`.""" from collections import namedtuple from logging import getLogger +from pathlib import Path from pytest import mark, raises @@ -163,7 +164,7 @@ def replay_run(testcases, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ ReplayResult(report, [["test.html"]] * len(testcases), [], True) ] @@ -346,7 +347,7 @@ def replay_run(testcases, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, served.pop(0), [], True)] replayer.run.side_effect = replay_run @@ -407,7 +408,7 @@ def replay_run(testcases, _time_limit, **kw): log_path = tmp_path / f"crash{replayer.run.call_count}_logs" log_path.mkdir() _fake_save_logs_foo(log_path) - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) return [ReplayResult(report, [["test.html", "other.html"]], [], True)] return [] diff --git a/grizzly/replay/replay.py b/grizzly/replay/replay.py index 01ea95e7..d196ca25 100644 --- a/grizzly/replay/replay.py +++ b/grizzly/replay/replay.py @@ -48,7 +48,7 @@ def __init__(self, report, served, durations, expected): class ReplayManager: - HARNESS_FILE = str(Path(__file__).parent / ".." / "common" / "harness.html") + HARNESS_FILE = Path(__file__).parent.parent / "common" / "harness.html" __slots__ = ( "ignore", @@ -81,8 +81,7 @@ def __init__( self._relaunch = relaunch self._signature = signature if use_harness: - with open(self.HARNESS_FILE, "rb") as in_fp: - self._harness = in_fp.read() + self._harness = self.HARNESS_FILE.read_bytes() else: # target must relaunch every iteration when not using harness assert relaunch == 1 @@ -401,10 +400,10 @@ def run( # update console to show progress LOG.info("Processing result...") # TODO: use self.target.create_report here - log_path = mkdtemp(prefix="logs_", dir=grz_tmp("logs")) + log_path = Path(mkdtemp(prefix="logs_", dir=grz_tmp("logs"))) self.target.save_logs(log_path) report = Report( - Path(log_path), self.target.binary, is_hang=run_result.timeout + log_path, self.target.binary, is_hang=run_result.timeout ) # check signatures if run_result.timeout: diff --git a/grizzly/replay/test_main.py b/grizzly/replay/test_main.py index 7d1e5e85..9b14b983 100644 --- a/grizzly/replay/test_main.py +++ b/grizzly/replay/test_main.py @@ -4,6 +4,8 @@ """ unit tests for grizzly.replay.main """ +from pathlib import Path + from pytest import mark from sapphire import Served @@ -36,7 +38,9 @@ def test_main_01(mocker, server, tmp_path): server.serve_path.return_value = (Served.ALL, ["test.html"]) # setup Target load_target = mocker.patch("grizzly.replay.replay.load_plugin", autospec=True) - target = mocker.Mock(spec_set=Target, binary="bin", environ={}, launch_timeout=30) + target = mocker.Mock( + spec_set=Target, binary=Path("bin"), environ={}, launch_timeout=30 + ) target.assets = mocker.Mock(spec_set=AssetManager) target.check_result.side_effect = (Result.FOUND, Result.NONE, Result.FOUND) target.filtered_environ.return_value = {"ENV": "123"} @@ -108,7 +112,9 @@ def test_main_02(mocker, server, tmp_path, repro_results): mocker.patch("grizzly.common.runner.sleep", autospec=True) server.serve_path.return_value = (Served.ALL, ["test.html"]) # setup Target - target = mocker.Mock(spec_set=Target, binary="bin", environ={}, launch_timeout=30) + target = mocker.Mock( + spec_set=Target, binary=Path("bin"), environ={}, launch_timeout=30 + ) target.check_result.side_effect = repro_results target.filtered_environ.return_value = {} target.save_logs = _fake_save_logs @@ -263,7 +269,9 @@ def test_main_05(mocker, server, tmp_path): """test ReplayManager.main() loading specified assets""" server.serve_path.return_value = (None, ["test.html"]) # setup Target - target = mocker.NonCallableMock(spec_set=Target, binary="bin", launch_timeout=30) + target = mocker.NonCallableMock( + spec_set=Target, binary=Path("bin"), launch_timeout=30 + ) target.check_result.return_value = Result.FOUND target.filtered_environ.return_value = {} target.monitor.is_healthy.return_value = False @@ -389,7 +397,9 @@ def test_main_07(mocker, server, tmp_path): reporter = mocker.patch("grizzly.replay.replay.FuzzManagerReporter", autospec=True) # setup Target load_target = mocker.patch("grizzly.replay.replay.load_plugin", autospec=True) - target = mocker.Mock(spec_set=Target, binary="bin", environ={}, launch_timeout=30) + target = mocker.Mock( + spec_set=Target, binary=Path("bin"), environ={}, launch_timeout=30 + ) target.assets = mocker.Mock(spec_set=AssetManager) target.check_result.side_effect = (Result.FOUND,) target.save_logs = _fake_save_logs diff --git a/grizzly/replay/test_replay.py b/grizzly/replay/test_replay.py index e51a9113..c5f29c87 100644 --- a/grizzly/replay/test_replay.py +++ b/grizzly/replay/test_replay.py @@ -21,7 +21,7 @@ pytestmark = mark.usefixtures("patch_collector", "tmp_path_grz_tmp") -def _fake_save_logs(result_logs, _meta=False): +def _fake_save_logs(result_logs): """write fake log data to disk""" log_path = Path(result_logs) (log_path / "log_stderr.txt").write_text("STDERR log\n") @@ -56,7 +56,9 @@ def test_replay_01(mocker, server): def test_replay_02(mocker, server): """test ReplayManager.run() - no repro - with repeats""" server.serve_path.return_value = (Served.ALL, ["index.html"]) - target = mocker.Mock(spec_set=Target, closed=False, launch_timeout=30) + target = mocker.Mock( + spec_set=Target, binary=Path("bin"), closed=False, launch_timeout=30 + ) target.check_result.return_value = Result.NONE target.monitor.is_healthy.return_value = False iter_cb = mocker.Mock() @@ -110,14 +112,14 @@ def test_replay_04(mocker, server, good_sig): """test ReplayManager.run() - successful repro""" served = ["index.html"] server.serve_path.return_value = (Served.ALL, served) - target = mocker.Mock(spec_set=Target, binary="C:\\fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.check_result.return_value = Result.FOUND target.monitor.is_healthy.return_value = False if good_sig: target.save_logs = _fake_save_logs else: - def _save_logs(result_logs, _meta=False): + def _save_logs(result_logs): """create uninteresting logs""" log_path = Path(result_logs) (log_path / "log_stderr.txt").write_text("STDERR log\n") @@ -150,7 +152,9 @@ def _save_logs(result_logs, _meta=False): def test_replay_05(mocker, server): """test ReplayManager.run() - error - landing page not requested""" - target = mocker.Mock(spec_set=Target, binary="bin", closed=True, launch_timeout=30) + target = mocker.Mock( + spec_set=Target, binary=Path("bin"), closed=True, launch_timeout=30 + ) tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] # test target unresponsive target.check_result.return_value = Result.NONE @@ -182,7 +186,7 @@ def test_replay_05(mocker, server): def test_replay_06(mocker, server): """test ReplayManager.run() delayed failure - following test landing page not requested""" - target = mocker.Mock(spec_set=Target, binary="bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) type(target).closed = mocker.PropertyMock(side_effect=(True, False, True)) target.check_result.side_effect = (Result.NONE, Result.FOUND) target.monitor.is_healthy.return_value = False @@ -220,7 +224,7 @@ def test_replay_08(mocker, server): """test ReplayManager.run() - early exit""" mocker.patch("grizzly.common.runner.sleep", autospec=True) server.serve_path.return_value = (Served.ALL, ["a.html"]) - target = mocker.Mock(spec_set=Target, binary="path/fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.save_logs = _fake_save_logs tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] # early failure @@ -293,7 +297,7 @@ def test_replay_09(mocker, server): server.serve_path.return_value = (Served.ALL, ["a.html"]) signature = mocker.Mock() signature.matches.side_effect = (True, False, False) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, launch_timeout=30) target.check_result.return_value = Result.FOUND tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] with ReplayManager( @@ -327,7 +331,7 @@ def test_replay_10(mocker, server): server.serve_path.return_value = (Served.ALL, ["a.html"]) sig = mocker.Mock(spec_set=CrashSignature) sig.matches.side_effect = (True, True) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, launch_timeout=30) target.check_result.return_value = Result.FOUND target.monitor.is_healthy.return_value = False tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] @@ -356,7 +360,7 @@ def test_replay_11(mocker, server): fake_report = mocker.patch("grizzly.replay.replay.Report", autospec=True) fake_report.side_effect = (report_1, report_2) server.serve_path.return_value = (Served.ALL, ["a.html"]) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, launch_timeout=30) target.check_result.return_value = Result.FOUND target.monitor.is_healthy.return_value = False tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] @@ -384,7 +388,7 @@ def test_replay_12(mocker, server): fake_report = mocker.patch("grizzly.replay.replay.Report", autospec=True) fake_report.side_effect = (report_1, report_2) server.serve_path.return_value = (Served.ALL, ["a.html"]) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, launch_timeout=30) target.check_result.side_effect = ( Result.NONE, Result.FOUND, @@ -408,7 +412,7 @@ def test_replay_12(mocker, server): def test_replay_13(mocker, server): """test ReplayManager.run() - any crash - startup failure""" server.serve_path.return_value = (Served.NONE, []) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.check_result.return_value = Result.FOUND target.save_logs = _fake_save_logs target.monitor.is_healthy.return_value = False @@ -441,7 +445,7 @@ def test_replay_14(mocker, server): fake_report.side_effect = (report_1, report_2, report_3) fake_report.calc_hash.return_value = "bucket_hash" server.serve_path.return_value = (Served.ALL, ["a.html"]) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, launch_timeout=30) target.check_result.return_value = Result.FOUND target.monitor.is_healthy.return_value = False tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] @@ -468,7 +472,7 @@ def test_replay_15(mocker, server): fake_report = mocker.patch("grizzly.replay.replay.Report", autospec=True) fake_report.side_effect = (report_0,) server.serve_path.side_effect = ((Served.ALL, ["a.html"]), KeyboardInterrupt) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, launch_timeout=30) target.check_result.return_value = Result.FOUND tests = [mocker.MagicMock(spec_set=TestCase, landing_page="a.html")] with ReplayManager( @@ -532,7 +536,7 @@ def test_replay_18(mocker, server): (Served.ALL, ["1.html"]), (Served.ALL, ["2.html"]), ) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.check_result.side_effect = ( Result.NONE, Result.NONE, @@ -636,10 +640,10 @@ def test_replay_21(mocker, tmp_path): # failure fake_load.return_value = () with raises(TestCaseLoadFailure, match="Failed to load TestCases"): - ReplayManager.load_testcases(str(tmp_path)) + ReplayManager.load_testcases(tmp_path) # success fake_load.return_value = [test0, test1] - tests, assets, env_vars = ReplayManager.load_testcases(str(tmp_path)) + tests, assets, env_vars = ReplayManager.load_testcases(tmp_path) assert env_vars assert env_vars["env"] == "var" assert not any(x.env_vars for x in tests) @@ -650,7 +654,7 @@ def test_replay_21(mocker, tmp_path): # success select test0.pop_assets.return_value = mocker.Mock(spec_set=AssetManager) fake_load.return_value = [test0, test1, test2, mocker.MagicMock(spec_set=TestCase)] - tests, assets, _ = ReplayManager.load_testcases(str(tmp_path), subset=[1, 3]) + tests, assets, _ = ReplayManager.load_testcases(tmp_path, subset=[1, 3]) assert len(tests) == 2 assert tests[0].landing_page == "x.html" assert test0.cleanup.call_count == 1 @@ -662,7 +666,7 @@ def test_replay_21(mocker, tmp_path): # select (first and last) with invalid input test0.pop_assets.return_value = None fake_load.return_value = [test0, test1, test2] - tests, _a, _e = ReplayManager.load_testcases(str(tmp_path), subset=[0, 10, -10, -1]) + tests, _a, _e = ReplayManager.load_testcases(tmp_path, subset=[0, 10, -10, -1]) assert len(tests) == 2 assert test0.cleanup.call_count == 0 assert test1.cleanup.call_count == 1 @@ -701,7 +705,7 @@ def test_replay_22( signature.rawSignature = "fakesig" else: signature = None - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.check_result.return_value = Result.FOUND target.handle_hang.return_value = False target.save_logs = _fake_save_logs @@ -778,13 +782,13 @@ def test_replay_24(mocker, server, tmp_path): sig = CrashSignature.fromFile(str(sig_file)) server.serve_path.return_value = (Served.ALL, ["index.html"]) - target = mocker.MagicMock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.MagicMock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.check_result.return_value = Result.FOUND target.monitor.is_healthy.return_value = False call_count = 0 - def _save_logs_variation(result_logs, _meta=False): + def _save_logs_variation(result_logs): """create different stacks each call""" nonlocal call_count call_count += 1 @@ -842,11 +846,11 @@ def test_replay_25(mocker, server, stderr_log, ignored, total, include_stack): assert iters == ignored + total, "test is broken" assert iters == len(include_stack), "test is broken" server.serve_path.return_value = (Served.ALL, ["index.html"]) - target = mocker.Mock(spec_set=Target, binary="fake_bin", launch_timeout=30) + target = mocker.Mock(spec_set=Target, binary=Path("bin"), launch_timeout=30) target.check_result.return_value = Result.FOUND target.monitor.is_healthy.return_value = False - def _save_logs_variation(result_logs, _meta=False): + def _save_logs_variation(result_logs): """create logs""" nonlocal stderr_log nonlocal include_stack diff --git a/grizzly/target/puppet_target.py b/grizzly/target/puppet_target.py index a2b179ae..37c52993 100644 --- a/grizzly/target/puppet_target.py +++ b/grizzly/target/puppet_target.py @@ -130,9 +130,9 @@ def closed(self): return self._puppet.reason is not None def create_report(self, is_hang=False): - logs = mkdtemp(prefix="logs_", dir=grz_tmp("logs")) + logs = Path(mkdtemp(prefix="logs_", dir=grz_tmp("logs"))) self.save_logs(logs) - return Report(Path(logs), self.binary, is_hang=is_hang) + return Report(logs, self.binary, is_hang=is_hang) def filtered_environ(self): # remove context specific entries from environment diff --git a/grizzly/target/target.py b/grizzly/target/target.py index df78ec68..6345e383 100644 --- a/grizzly/target/target.py +++ b/grizzly/target/target.py @@ -5,7 +5,6 @@ from enum import Enum, unique from logging import getLogger from os import environ -from os.path import isfile from threading import Lock from ..common.utils import grz_tmp @@ -62,7 +61,7 @@ def __init__(self, binary, launch_timeout, log_limit, memory_limit, assets=None) assert launch_timeout > 0 assert log_limit >= 0 assert memory_limit >= 0 - assert binary is not None and isfile(binary) + assert binary is not None and binary.is_file() assert assets is None or isinstance(assets, AssetManager) self._assets = assets if assets else AssetManager(base_path=grz_tmp("target")) self._lock = Lock() diff --git a/grizzly/target/target_monitor.py b/grizzly/target/target_monitor.py index 110b52d5..314abe0b 100644 --- a/grizzly/target/target_monitor.py +++ b/grizzly/target/target_monitor.py @@ -32,8 +32,7 @@ def log_data(self, log_id, offset=0): log_file = self.clone_log(log_id, offset=offset) if log_file: try: - with open(log_file, "rb") as log_fp: - data = log_fp.read() + data = log_file.read_bytes() finally: remove(log_file) return data diff --git a/grizzly/target/test_puppet_target.py b/grizzly/target/test_puppet_target.py index 9fdace33..089c05ff 100644 --- a/grizzly/target/test_puppet_target.py +++ b/grizzly/target/test_puppet_target.py @@ -20,7 +20,7 @@ def test_puppet_target_01(mocker, tmp_path): fake_ffp.return_value.log_length.return_value = 562 fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: assert target.assets assert target.closed assert target.launch_timeout == 300 @@ -31,11 +31,11 @@ def test_puppet_target_01(mocker, tmp_path): fake_ffp.return_value.log_length.assert_any_call("stderr") fake_ffp.return_value.log_length.assert_any_call("stdout") assert target.monitor is not None - target.save_logs("fake_dest") + target.save_logs(tmp_path / "fake_dest") assert fake_ffp.return_value.save_logs.call_count == 1 assert fake_ffp.return_value.clean_up.call_count == 1 # with extra args - with PuppetTarget(str(fake_file), 1, 1, 1, rr=True, fake=1) as target: + with PuppetTarget(fake_file, 1, 1, 1, rr=True, fake=1) as target: pass @@ -45,7 +45,7 @@ def test_puppet_target_02(mocker, tmp_path): fake_file = tmp_path / "fake" fake_file.touch() # test providing prefs.js - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: # launch success target.launch("launch_target_page") assert fake_ffp.return_value.launch.call_count == 1 @@ -102,7 +102,7 @@ def test_puppet_target_03(mocker, tmp_path, healthy, reason, ignore, result, clo fake_ffp.return_value.available_logs.return_value = "ffp_worker_log_size" fake_ffp.return_value.is_healthy.return_value = healthy fake_ffp.return_value.reason = reason - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: assert target.check_result(ignore) == result assert fake_ffp.return_value.close.call_count == closes @@ -135,7 +135,7 @@ def test_puppet_target_04(mocker, tmp_path, healthy, usage, os_name, killed, deb fake_file.touch() fake_ffp.return_value.cpu_usage.return_value = usage fake_ffp.return_value.is_healthy.return_value = healthy - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: target._debugger = debugger target.handle_hang() assert fake_ffp.return_value.is_healthy.call_count == 1 @@ -162,7 +162,7 @@ def test_puppet_target_05(mocker, tmp_path): fake_time = mocker.patch("grizzly.target.puppet_target.time", autospec=True) fake_file = tmp_path / "fake" fake_file.touch() - target = PuppetTarget(str(fake_file), 300, 25, 5000) + target = PuppetTarget(fake_file, 300, 25, 5000) fake_kill = mocker.patch("grizzly.target.puppet_target.kill", autospec=True) # not running fake_ffp.return_value.get_pid.return_value = None @@ -264,7 +264,7 @@ def test_puppet_target_06(mocker, tmp_path): fake_ffp.return_value.cpu_usage.return_value = [(999, 30), (998, 20), (997, 10)] fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: assert not target.is_idle(0) assert not target.is_idle(25) assert target.is_idle(50) @@ -275,7 +275,7 @@ def test_puppet_target_07(mocker, tmp_path): fake_ffp = mocker.patch("grizzly.target.puppet_target.FFPuppet", autospec=True) fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: fake_ffp.return_value.is_running.return_value = False fake_ffp.return_value.is_healthy.return_value = False assert target.monitor is not None @@ -299,7 +299,7 @@ def test_puppet_target_08(mocker, tmp_path): fake_file = tmp_path / "fake" fake_file.write_text("1\n2\n") # no prefs file provided - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: assert target.assets.get("prefs") is None target.process_assets() assert isfile(target.assets.get("prefs")) @@ -307,14 +307,14 @@ def test_puppet_target_08(mocker, tmp_path): # prefs file provided with AssetManager(base_path=str(tmp_path)) as assets: assets.add("prefs", str(fake_file)) - with PuppetTarget(str(fake_file), 300, 25, 5000, assets=assets) as target: + with PuppetTarget(fake_file, 300, 25, 5000, assets=assets) as target: target.process_assets() assert isfile(target.assets.get("prefs")) assert target.assets.get("prefs").endswith("fake") # abort tokens file provided with AssetManager(base_path=str(tmp_path)) as assets: assets.add("abort-tokens", str(fake_file)) - with PuppetTarget(str(fake_file), 300, 25, 5000, assets=assets) as target: + with PuppetTarget(fake_file, 300, 25, 5000, assets=assets) as target: # ignore E1101: (pylint 2.9.3 bug?) # Method 'add_abort_token' has no 'call_count' member (no-member) # pylint: disable=no-member @@ -346,7 +346,7 @@ def test_puppet_target_09( fake_file = tmp_path / "fake" fake_file.touch() with PuppetTarget( - str(fake_file), 30, 25, 500, pernosco=pernosco, rr=rr, valgrind=valgrind + fake_file, 30, 25, 500, pernosco=pernosco, rr=rr, valgrind=valgrind ) as _: pass if pernosco: @@ -383,7 +383,7 @@ def test_puppet_target_10(tmp_path, asset, env): if asset: supp_asset.touch() assets.add("lsan-suppressions", str(supp_asset)) - with PuppetTarget(str(fake_file), 300, 25, 5000, assets=assets) as target: + with PuppetTarget(fake_file, 300, 25, 5000, assets=assets) as target: target.environ["TSAN_OPTIONS"] = "a=1" if env: supp_env.touch() @@ -404,7 +404,7 @@ def test_puppet_target_11(tmp_path): """test PuppetTarget.filtered_environ()""" fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: target.environ = { "TRACKED": "1", "ASAN_OPTIONS": "external_symbolizer_path='a':no_remove='b'", @@ -438,7 +438,7 @@ def test_puppet_target_12(tmp_path, base, extra, result): """test PuppetTarget.merge_environment()""" fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: target.environ = base target.merge_environment(extra) assert target.environ == result @@ -459,7 +459,7 @@ def test_puppet_target_13(tmp_path, base, extra, result): """test PuppetTarget.merge_environment() - merge sanitizer options""" fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: target.environ = base target.merge_environment(extra) for opt in target.environ["ASAN_OPTIONS"].split(":"): @@ -471,5 +471,5 @@ def test_puppet_target_14(mocker, tmp_path): mocker.patch("grizzly.target.puppet_target.system", return_value="foo") fake_file = tmp_path / "fake" fake_file.touch() - with PuppetTarget(str(fake_file), 300, 25, 5000) as target: + with PuppetTarget(fake_file, 300, 25, 5000) as target: target.dump_coverage() diff --git a/grizzly/target/test_target.py b/grizzly/target/test_target.py index 66b3c5ee..fae52683 100644 --- a/grizzly/target/test_target.py +++ b/grizzly/target/test_target.py @@ -48,8 +48,8 @@ def test_target_01(tmp_path): """test creating a simple Target""" fake_file = tmp_path / "fake" fake_file.touch() - with SimpleTarget(str(fake_file), 10, 2, 3) as target: - assert target.binary == str(fake_file) + with SimpleTarget(fake_file, 10, 2, 3) as target: + assert target.binary == fake_file assert target.assets org_path = target.assets.path target.assets = AssetManager(base_path=str(tmp_path)) @@ -72,7 +72,7 @@ def test_target_02(mocker, tmp_path): mocker.patch.dict("grizzly.target.target.environ", {"SKIP": "x", "TEST_INC": "1"}) fake_file = tmp_path / "fake" fake_file.touch() - with SimpleTarget(str(fake_file), 321, 2, 3) as target: + with SimpleTarget(fake_file, 321, 2, 3) as target: assert target.environ assert "SKIP" not in target.environ assert target.environ["TEST_INC"] == "1" diff --git a/grizzly/target/test_target_monitor.py b/grizzly/target/test_target_monitor.py index aefd5451..bd78be76 100644 --- a/grizzly/target/test_target_monitor.py +++ b/grizzly/target/test_target_monitor.py @@ -1,8 +1,6 @@ # 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/. -from os.path import isfile - from .target_monitor import TargetMonitor @@ -13,7 +11,7 @@ class _BasicMonitor(TargetMonitor): def clone_log(self, log_id, offset=0): log_file = tmp_path / "test_log.txt" log_file.write_bytes(b"test") - return str(log_file) + return log_file def is_healthy(self): return True @@ -30,7 +28,7 @@ def log_length(self, log_id): mon = _BasicMonitor() test_log = mon.clone_log("test_log", offset=0) - assert isfile(test_log) + assert test_log.is_file() assert mon.is_healthy() assert mon.is_running() assert mon.launches == 1 diff --git a/grizzly/test_main.py b/grizzly/test_main.py index 8233c33d..37021dcc 100644 --- a/grizzly/test_main.py +++ b/grizzly/test_main.py @@ -2,6 +2,8 @@ # 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/. """test Grizzly main""" +from pathlib import Path + from pytest import mark from .args import GrizzlyArgs @@ -81,7 +83,7 @@ def test_main_02(mocker, session_setup, exit_code, to_raise): session_obj.run.side_effect = TargetLaunchError("test", mocker.Mock()) else: session_obj.run.side_effect = to_raise() - args = mocker.MagicMock(adapter="fake", time_limit=1, timeout=1) + args = mocker.MagicMock(adapter="fake", binary=Path("bin"), time_limit=1, timeout=1) assert main(args) == exit_code assert target_cls.return_value.cleanup.call_count == 1 @@ -106,6 +108,7 @@ def test_main_03(mocker, session_setup, test_limit, timeout): # no_harness=False for code coverage args = mocker.MagicMock( adapter="fake", + binary=Path("bin"), no_harness=False, time_limit=test_limit, timeout=timeout, @@ -136,6 +139,7 @@ def test_main_04( assert sum((pernosco, rr, valgrind)) < 2, "test broken!" args = mocker.MagicMock( adapter="fake", + binary=Path("bin"), pernosco=pernosco, rr=rr, time_limit=1, diff --git a/grizzly/test_session.py b/grizzly/test_session.py index b42082ee..d4d46e63 100644 --- a/grizzly/test_session.py +++ b/grizzly/test_session.py @@ -6,6 +6,7 @@ unit tests for grizzly.Session """ from itertools import chain, count, repeat +from pathlib import Path from pytest import mark, raises @@ -222,7 +223,7 @@ def test_session_03(mocker, tmp_path, harness, report_size, relaunch, iters, has log_fp.write("SEGV on unknown address 0x0 (pc 0x0 bp 0x0 sp 0x0 T0)\n") log_fp.write(" #0 0xbad000 in foo /file1.c:123:234\n") log_fp.write(" #1 0x1337dd in bar /file2.c:1806:19\n") - report = Report(log_path, "bin") + report = Report(log_path, Path("bin")) target.create_report.return_value = report with Session( adapter, reporter, server, target, relaunch=relaunch, report_size=report_size diff --git a/setup.cfg b/setup.cfg index 6af6cbcb..66ac26e5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,7 +22,7 @@ include_package_data = True install_requires = cssbeautifier fasteners - ffpuppet >= 0.9.2 + ffpuppet >= 0.10.0 FuzzManager jsbeautifier lithium-reducer >= 0.5.3