Skip to content

Commit

Permalink
Perform final status report in Session.close()
Browse files Browse the repository at this point in the history
This helps avoid missing iteration data if a run is aborted.
  • Loading branch information
tysmith committed Nov 8, 2022
1 parent 453c329 commit 65e06c9
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 76 deletions.
18 changes: 18 additions & 0 deletions grizzly/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@

from pytest import fixture

from .adapter import Adapter
from .target import Target


@fixture
def session_setup(mocker):
mocker.patch("grizzly.main.FuzzManagerReporter", autospec=True)
mocker.patch("grizzly.main.Sapphire", autospec_set=True)
adapter_cls = mocker.Mock(spec_set=Adapter)
adapter_cls.return_value.RELAUNCH = Adapter.RELAUNCH
adapter_cls.return_value.TIME_LIMIT = Adapter.TIME_LIMIT
target_cls = mocker.Mock(spec_set=Target)
mocker.patch("grizzly.main.load_plugin", side_effect=(adapter_cls, target_cls))
session_cls = mocker.patch("grizzly.main.Session", autospec_set=True)
session_obj = session_cls.return_value.__enter__.return_value
session_obj.status.results.total = 0
yield adapter_cls.return_value, session_cls, session_obj, target_cls


@fixture
def patch_collector(mocker):
Expand Down
42 changes: 20 additions & 22 deletions grizzly/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def main(args):
LOG.info("Running with Valgrind. This will be SLOW!")

adapter = None
session = None
complete_with_results = False
target = None
try:
LOG.debug("initializing Adapter %r", args.adapter)
Expand Down Expand Up @@ -102,7 +102,7 @@ def main(args):
with Sapphire(auto_close=1, timeout=timeout) as server:
target.reverse(server.port, server.port)
LOG.debug("initializing the Session")
session = Session(
with Session(
adapter,
reporter,
server,
Expand All @@ -112,22 +112,23 @@ def main(args):
relaunch=relaunch,
report_limit=args.limit_reports,
report_size=args.collect,
)
if args.log_level == DEBUG or args.verbose:
display_mode = Session.DISPLAY_VERBOSE
else:
display_mode = Session.DISPLAY_NORMAL
session.run(
args.ignore,
time_limit,
input_path=str(args.input),
iteration_limit=args.limit,
no_harness=args.no_harness,
result_limit=1 if args.smoke_test else 0,
runtime_limit=args.runtime,
display_mode=display_mode,
launch_attempts=args.launch_attempts,
)
) as session:
if args.log_level == DEBUG or args.verbose:
display_mode = Session.DISPLAY_VERBOSE
else:
display_mode = Session.DISPLAY_NORMAL
session.run(
args.ignore,
time_limit,
input_path=str(args.input),
iteration_limit=args.limit,
no_harness=args.no_harness,
result_limit=1 if args.smoke_test else 0,
runtime_limit=args.runtime,
display_mode=display_mode,
launch_attempts=args.launch_attempts,
)
complete_with_results = session.status.results.total > 0

except KeyboardInterrupt:
LOG.info("Ctrl+C detected.")
Expand All @@ -140,9 +141,6 @@ def main(args):

finally:
LOG.info("Shutting down...")
if session is not None:
LOG.debug("calling session.close()")
session.close()
if target is not None:
LOG.debug("calling target.cleanup()")
target.cleanup()
Expand All @@ -151,6 +149,6 @@ def main(args):
adapter.cleanup()
LOG.info("Done.")

if session and session.status.results.total > 0:
if complete_with_results:
return Exit.ERROR
return Exit.SUCCESS
6 changes: 3 additions & 3 deletions grizzly/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ def __exit__(self, *exc):
self.close()

def close(self):
if self.status is not None:
# perform final status report
self.status.report(force=True)
if self.iomanager is not None:
self.iomanager.cleanup()

Expand Down Expand Up @@ -304,6 +307,3 @@ def run(
LOG.warning(
"Large browser logs: %dMBs", (self.status.log_size / 0x100000)
)

# perform final status report
self.status.report(force=True)
77 changes: 26 additions & 51 deletions grizzly/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@
"""test Grizzly main"""
from pytest import mark

from sapphire import Sapphire

from .adapter import Adapter
from .args import GrizzlyArgs
from .common.utils import Exit
from .main import main
from .target import Target, TargetLaunchError


class FakeAdapter(Adapter):
def generate(self, testcase, server_map):
pass
from .target import TargetLaunchError


@mark.parametrize(
Expand Down Expand Up @@ -47,33 +39,29 @@ def generate(self, testcase, server_map):
(0, ["--verbose"]),
],
)
def test_main_01(mocker, adpt_relaunch, extra_args):
def test_main_01(mocker, session_setup, adpt_relaunch, extra_args):
"""test main()"""
mocker.patch("grizzly.main.FuzzManagerReporter", autospec=True)
mocker.patch(
"grizzly.args.scan_plugins",
autospec=True,
side_effect=(["targ"], ["adpt"]),
)
fake_target = mocker.Mock(spec_set=Target)
FakeAdapter.RELAUNCH = adpt_relaunch
mocker.patch("grizzly.main.load_plugin", side_effect=(FakeAdapter, fake_target))
fake_session = mocker.patch("grizzly.main.Session", autospec_set=True)
fake_session.return_value.server = mocker.Mock(spec_set=Sapphire)
adapter, session_cls, session_obj, target_cls = session_setup
adapter.RELAUNCH = adpt_relaunch

# use __file__ as "binary" since it is not used
cmd = [__file__, "adpt", "--platform", "targ"] + extra_args
args = GrizzlyArgs().parse_args(cmd)
fake_session.return_value.status.results.total = 1 if args.smoke_test else 0
session_obj.status.results.total = 1 if args.smoke_test else 0

assert main(args) == (Exit.ERROR if args.smoke_test else Exit.SUCCESS)
assert fake_session.mock_calls[0][-1]["coverage"] == args.coverage
assert session_cls.mock_calls[0][-1]["coverage"] == args.coverage
if adpt_relaunch:
assert fake_session.mock_calls[0][-1]["relaunch"] == adpt_relaunch
assert session_cls.mock_calls[0][-1]["relaunch"] == adpt_relaunch
else:
assert fake_session.mock_calls[0][-1]["relaunch"] == args.relaunch
assert fake_session.return_value.run.call_count == 1
assert fake_target.return_value.cleanup.call_count == 1
assert session_cls.mock_calls[0][-1]["relaunch"] == args.relaunch
assert session_obj.run.call_count == 1
assert target_cls.return_value.cleanup.call_count == 1


@mark.parametrize(
Expand All @@ -85,24 +73,17 @@ def test_main_01(mocker, adpt_relaunch, extra_args):
(Exit.LAUNCH_FAILURE, TargetLaunchError),
],
)
def test_main_02(mocker, exit_code, to_raise):
def test_main_02(mocker, session_setup, exit_code, to_raise):
"""test main() - exit codes"""
mocker.patch("grizzly.main.FailedLaunchReporter", autospec=True)
mocker.patch("grizzly.main.FuzzManagerReporter", autospec=True)
fake_target = mocker.Mock(spec_set=Target)
mocker.patch("grizzly.main.load_plugin", side_effect=(FakeAdapter, fake_target))
fake_session = mocker.patch("grizzly.main.Session", autospec=True)
fake_session.return_value.status.results.total = 0
_, _, session_obj, target_cls = session_setup
if to_raise == TargetLaunchError:
fake_session.return_value.run.side_effect = TargetLaunchError(
"test", mocker.Mock()
)
session_obj.run.side_effect = TargetLaunchError("test", mocker.Mock())
else:
fake_session.return_value.run.side_effect = to_raise()

session_obj.run.side_effect = to_raise()
args = mocker.MagicMock(adapter="fake", time_limit=1, timeout=1)
assert main(args) == exit_code
assert fake_target.return_value.cleanup.call_count == 1
assert target_cls.return_value.cleanup.call_count == 1


@mark.parametrize(
Expand All @@ -120,22 +101,18 @@ def test_main_02(mocker, exit_code, to_raise):
(None, 1),
],
)
def test_main_03(mocker, test_limit, timeout):
def test_main_03(mocker, session_setup, test_limit, timeout):
"""test main() - time-limit and timeout"""
mocker.patch("grizzly.main.FuzzManagerReporter", autospec=True)
mocker.patch(
"grizzly.main.load_plugin",
side_effect=(FakeAdapter, mocker.Mock(spec_set=Target)),
)
fake_session = mocker.patch("grizzly.main.Session", autospec=True)
fake_session.return_value.status.results.total = 0
# no_harness=False for code coverage
args = mocker.MagicMock(
adapter="fake",
no_harness=False,
time_limit=test_limit,
timeout=timeout,
)
assert main(args) == Exit.SUCCESS
target_cls = session_setup[3]
assert target_cls.return_value.cleanup.call_count == 1


@mark.parametrize(
Expand All @@ -151,13 +128,10 @@ def test_main_03(mocker, test_limit, timeout):
(False, False, True),
],
) # pylint: disable=invalid-name
def test_main_04(mocker, pernosco, rr, valgrind): # pylint: disable=invalid-name
def test_main_04(
mocker, session_setup, pernosco, rr, valgrind
): # pylint: disable=invalid-name
"""test enabling debuggers"""
mocker.patch("grizzly.main.FuzzManagerReporter", autospec=True)
fake_target = mocker.Mock(spec_set=Target)
mocker.patch("grizzly.main.load_plugin", side_effect=(FakeAdapter, fake_target))
fake_session = mocker.patch("grizzly.main.Session", autospec=True)
fake_session.return_value.status.results.total = 0
# maximum one debugger allowed at a time
assert sum((pernosco, rr, valgrind)) < 2, "test broken!"
args = mocker.MagicMock(
Expand All @@ -169,6 +143,7 @@ def test_main_04(mocker, pernosco, rr, valgrind): # pylint: disable=invalid-nam
valgrind=valgrind,
)
assert main(args) == Exit.SUCCESS
assert fake_target.call_args[-1]["pernosco"] == pernosco
assert fake_target.call_args[-1]["rr"] == rr
assert fake_target.call_args[-1]["valgrind"] == valgrind
target_cls = session_setup[3]
assert target_cls.call_args[-1]["pernosco"] == pernosco
assert target_cls.call_args[-1]["rr"] == rr
assert target_cls.call_args[-1]["valgrind"] == valgrind

0 comments on commit 65e06c9

Please sign in to comment.