From 72b2bd11158c35f32c79707f1c60b1589c4aaedf Mon Sep 17 00:00:00 2001 From: Tyson Smith Date: Mon, 13 Nov 2023 12:58:11 -0800 Subject: [PATCH] Always create an AssetManager when creating Target Also make references to AssetManager less ambiguous. --- grizzly/common/test_storage.py | 16 ++--- grizzly/main.py | 2 +- grizzly/reduce/core.py | 19 +++--- grizzly/reduce/test_reduce.py | 16 ++--- grizzly/reduce/test_strategies.py | 6 +- grizzly/replay/replay.py | 30 +++++---- grizzly/replay/test_main.py | 77 ++++++++++++++++++++--- grizzly/replay/test_replay.py | 24 +++---- grizzly/session.py | 4 +- grizzly/target/puppet_target.py | 19 +++--- grizzly/target/target.py | 22 +++---- grizzly/target/test_assets.py | 94 ++++++++++++++-------------- grizzly/target/test_puppet_target.py | 45 ++++++------- grizzly/target/test_target.py | 8 +-- grizzly/test_session.py | 69 ++++---------------- 15 files changed, 236 insertions(+), 215 deletions(-) diff --git a/grizzly/common/test_storage.py b/grizzly/common/test_storage.py index 602b5bab..3803789c 100644 --- a/grizzly/common/test_storage.py +++ b/grizzly/common/test_storage.py @@ -218,8 +218,8 @@ def test_testcase_08(tmp_path): (tmp_path / "src" / "nested" / "empty").mkdir() dst_dir = tmp_path / "dst" # build test case - with AssetManager(base_path=tmp_path) as assets: - assets.add("example", asset_file) + with AssetManager(base_path=tmp_path) as asset_mgr: + asset_mgr.add("example", asset_file) with TestCase("target.bin", "test-adapter") as src: src.env_vars["TEST_ENV_VAR"] = "100" src.add_from_file(entry_point) @@ -230,8 +230,8 @@ def test_testcase_08(tmp_path): file_name=str((nested / "x.bin").relative_to(src_dir)), required=False, ) - src.assets = dict(assets.assets) - src.assets_path = assets.path + src.assets = dict(asset_mgr.assets) + src.assets_path = asset_mgr.path src.dump(dst_dir, include_details=True) # test loading test case from test_info.json with TestCase.load_single(dst_dir) as dst: @@ -334,11 +334,11 @@ def test_testcase_14(tmp_path): nested.mkdir() asset_file = tmp_path / "example_asset" asset_file.touch() - with AssetManager(base_path=tmp_path) as assets: - assets.add("example", asset_file) + with AssetManager(base_path=tmp_path) as asset_mgr: + asset_mgr.add("example", asset_file) with TestCase("target.bin", "test-adapter") as src: - src.assets = assets.assets - src.assets_path = assets.path + src.assets = asset_mgr.assets + src.assets_path = asset_mgr.path src.add_from_bytes(b"test", "target.bin") src.dump(nested / "test-1", include_details=True) src.dump(nested / "test-2", include_details=True) diff --git a/grizzly/main.py b/grizzly/main.py index 26dcad26..3c8000a9 100644 --- a/grizzly/main.py +++ b/grizzly/main.py @@ -81,7 +81,7 @@ def main(args): valgrind=args.valgrind, ) # add specified assets - target.assets.add_batch(args.asset) + target.asset_mgr.add_batch(args.asset) target.process_assets() adapter.monitor = target.monitor diff --git a/grizzly/reduce/core.py b/grizzly/reduce/core.py index b355ed7c..1dd3a5ff 100644 --- a/grizzly/reduce/core.py +++ b/grizzly/reduce/core.py @@ -557,12 +557,14 @@ def run(self, repeat=1, launch_attempts=3, min_results=1, post_launch_delay=0): for testcase in self.testcases: testcase.cleanup() # add target assets to test cases - if not self.target.assets.is_empty(): + if not self.target.asset_mgr.is_empty(): for test in reduction: test.assets = dict( - self.target.assets.assets + self.target.asset_mgr.assets + ) + test.assets_path = ( + self.target.asset_mgr.path ) - test.assets_path = self.target.assets.path # add target environment variables if self.target.filtered_environ(): for test in reduction: @@ -783,7 +785,7 @@ def main(cls, args): elif args.valgrind: LOG.info("Running with Valgrind. This will be SLOW!") - assets = None + asset_mgr = None certs = None signature = None signature_desc = None @@ -798,7 +800,7 @@ def main(cls, args): signature_desc = meta["shortDescription"] try: - testcases, assets, env_vars = ReplayManager.load_testcases( + testcases, asset_mgr, env_vars = ReplayManager.load_testcases( args.input, subset=args.test_index ) except TestCaseLoadFailure as exc: @@ -834,7 +836,6 @@ def main(cls, args): args.launch_timeout, args.log_limit, args.memory, - assets=assets, certs=certs, headless=args.headless, pernosco=args.pernosco, @@ -848,7 +849,7 @@ def main(cls, args): env_vars = None # TODO: support overriding existing assets # prioritize specified assets over included - target.assets.add_batch(args.asset) + target.asset_mgr.add_batch(args.asset) target.process_assets() if certs and not target.https(): @@ -919,8 +920,8 @@ def main(cls, args): target.cleanup() for testcase in testcases: testcase.cleanup() - if assets: - assets.cleanup() + if asset_mgr: + asset_mgr.cleanup() if certs is not None: certs.cleanup() LOG.info("Done.") diff --git a/grizzly/reduce/test_reduce.py b/grizzly/reduce/test_reduce.py index 4830f7d8..41f7374b 100644 --- a/grizzly/reduce/test_reduce.py +++ b/grizzly/reduce/test_reduce.py @@ -566,7 +566,7 @@ def replay_run(testcases, _time_limit, **kw): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], @@ -650,7 +650,7 @@ def fake_iter(): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], @@ -722,7 +722,7 @@ def fake_iter(): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], @@ -783,7 +783,7 @@ def replay_run(testcases, _time_limit, **kw): update_coll = mocker.patch("grizzly.common.fuzzmanager.Collector") target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], @@ -855,10 +855,10 @@ def submit(test_cases, report, force=False): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {"test": "abc"} - with AssetManager(base_path=str(tmp_path)) as assets: + with AssetManager(base_path=tmp_path) as asset_mgr: (tmp_path / "example_asset").touch() - assets.add("example", tmp_path / "example_asset", copy=False) - target.assets = assets + asset_mgr.add("example", tmp_path / "example_asset", copy=False) + target.asset_mgr = asset_mgr try: mgr = ReduceManager( [], @@ -979,7 +979,7 @@ def replay_run(_testcases, _time_limit, **kw): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) server = mocker.Mock(spec_set=Sapphire, timeout=iter_input) try: mgr = ReduceManager( diff --git a/grizzly/reduce/test_strategies.py b/grizzly/reduce/test_strategies.py index 82a2f627..96b2bea7 100644 --- a/grizzly/reduce/test_strategies.py +++ b/grizzly/reduce/test_strategies.py @@ -180,7 +180,7 @@ def replay_run(testcases, _time_limit, **kw): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], @@ -361,7 +361,7 @@ def replay_run(testcases, _time_limit, **kw): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], @@ -421,7 +421,7 @@ def replay_run(testcases, _time_limit, **kw): target = mocker.Mock(spec_set=Target) target.filtered_environ.return_value = {} - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) try: mgr = ReduceManager( [], diff --git a/grizzly/replay/replay.py b/grizzly/replay/replay.py index 2585cd22..fafec3f4 100644 --- a/grizzly/replay/replay.py +++ b/grizzly/replay/replay.py @@ -175,11 +175,11 @@ def load_testcases(cls, path, subset=None): if not testcases: raise TestCaseLoadFailure("Failed to load TestCases") # load and remove assets and environment variables from test cases - assets = None + asset_mgr = None env_vars = None for test in testcases: - if assets is None and test.assets and test.assets_path: - assets = AssetManager.load(test.assets, test.root / test.assets_path) + if asset_mgr is None and test.assets and test.assets_path: + asset_mgr = AssetManager.load(test.assets, test.root / test.assets_path) if not env_vars and test.env_vars: env_vars = dict(test.env_vars) test.env_vars.clear() @@ -190,7 +190,7 @@ def load_testcases(cls, path, subset=None): LOG.debug( "loaded TestCase(s): %d, assets: %r, env vars: %r", len(testcases), - assets is not None, + asset_mgr is not None, env_vars is not None, ) if subset: @@ -205,7 +205,7 @@ def load_testcases(cls, path, subset=None): for test in testcases: test.cleanup() testcases = selected - return testcases, assets, env_vars + return testcases, asset_mgr, env_vars @staticmethod def report_to_filesystem(path, results, tests=None): @@ -604,7 +604,7 @@ def main(cls, args): signature = CrashSignature.fromFile(args.sig) if args.sig else None try: - testcases, assets, env_vars = cls.load_testcases( + testcases, asset_mgr, env_vars = cls.load_testcases( args.input, subset=args.test_index ) except TestCaseLoadFailure as exc: @@ -645,7 +645,6 @@ def main(cls, args): args.launch_timeout, args.log_limit, args.memory, - assets=assets, certs=certs, headless=args.headless, pernosco=args.pernosco, @@ -656,8 +655,13 @@ def main(cls, args): LOG.debug("adding environment loaded from test case") target.merge_environment(env_vars) + # use asset manager created from test case content if available + if asset_mgr: + target.asset_mgr = asset_mgr + # target is now responsible for `asset_mgr` + asset_mgr = None # TODO: prioritize specified assets over included - target.assets.add_batch(args.asset) + target.asset_mgr.add_batch(args.asset) target.process_assets() if certs and not target.https(): @@ -699,10 +703,10 @@ def main(cls, args): LOG.info("No results detected") if results and (args.logs or args.fuzzmanager): # add target assets to test cases - if not target.assets.is_empty(): + if not target.asset_mgr.is_empty(): for test in testcases: - test.assets = dict(target.assets.assets) - test.assets_path = target.assets.path + test.assets = dict(target.asset_mgr.assets) + test.assets_path = target.asset_mgr.path # add target environment variables if target.filtered_environ(): for test in testcases: @@ -740,8 +744,8 @@ def main(cls, args): target.cleanup() for testcase in testcases: testcase.cleanup() - if assets: - assets.cleanup() + if asset_mgr: + asset_mgr.cleanup() if certs is not None: certs.cleanup() LOG.info("Done.") diff --git a/grizzly/replay/test_main.py b/grizzly/replay/test_main.py index 1b7474bc..082304bd 100644 --- a/grizzly/replay/test_main.py +++ b/grizzly/replay/test_main.py @@ -41,7 +41,7 @@ def test_main_01(mocker, server, tmp_path): target = mocker.Mock( spec_set=Target, binary=Path("bin"), environ={}, launch_timeout=30 ) - target.assets = mocker.Mock(spec_set=AssetManager) + target.asset_mgr = mocker.Mock(spec_set=AssetManager) target.check_result.side_effect = (Result.FOUND, Result.NONE, Result.FOUND) target.filtered_environ.return_value = {"ENV": "123"} target.save_logs = _fake_save_logs @@ -88,8 +88,8 @@ def test_main_01(mocker, server, tmp_path): assert target.close.call_count == 4 assert target.filtered_environ.call_count == 2 assert target.cleanup.call_count == 1 - assert target.assets.add.call_count == 0 - assert target.assets.is_empty.call_count == 1 + assert target.asset_mgr.add.call_count == 0 + assert target.asset_mgr.is_empty.call_count == 1 assert log_path.is_dir() assert any(log_path.glob("reports/*/log_asan_blah.txt")) assert any(log_path.glob("reports/*/log_stderr.txt")) @@ -342,10 +342,10 @@ def test_main_05(mocker, server, tmp_path): src.add_from_file(entry_point) src.dump(input_path, include_details=True) args.input = input_path - with AssetManager(base_path=str(tmp_path)) as assets: - target.assets = assets + with AssetManager(base_path=tmp_path) as asset_mgr: + target.asset_mgr = asset_mgr assert ReplayManager.main(args) == Exit.SUCCESS - assert "from_cmdline" in target.assets.assets + assert "from_cmdline" in target.asset_mgr.assets assert target.launch.call_count == 1 assert target.check_result.call_count == 1 assert target.filtered_environ.call_count == 1 @@ -424,10 +424,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( + target = mocker.MagicMock( 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 load_target.return_value.return_value = target @@ -467,8 +466,6 @@ def test_main_07(mocker, server, tmp_path): assert load_target.call_count == 1 assert target.close.call_count == 2 assert target.cleanup.call_count == 1 - assert target.assets.add.call_count == 0 - assert target.assets.is_empty.call_count == 1 assert reporter.return_value.submit.call_count == 1 @@ -498,3 +495,63 @@ def test_main_08(mocker, tmp_path, https_supported): mocker.patch("grizzly.replay.replay.ReplayManager.run", return_value=[]) assert ReplayManager.main(args) == Exit.FAILURE assert target.https.call_count == 1 + + +def test_main_09(mocker, server, tmp_path): + """test ReplayManager.main() - load test case assets""" + server.serve_path.return_value = (None, ["test.html"]) + # setup Target + target = mocker.NonCallableMock( + spec_set=Target, binary=Path("bin"), launch_timeout=30 + ) + target.check_result.return_value = Result.NONE + target.monitor.is_healthy.return_value = False + mocker.patch( + "grizzly.replay.replay.load_plugin", + autospec=True, + return_value=mocker.Mock(spec_set=Target, return_value=target), + ) + # setup args + input_path = tmp_path / "input" + input_path.mkdir() + args = mocker.MagicMock( + adapter="fake", + binary=Path("bin"), + fuzzmanager=False, + idle_delay=0, + idle_threshold=0, + input=input_path, + launch_attempts=1, + logs=None, + min_crashes=1, + post_launch_delay=-1, + relaunch=1, + repeat=1, + sig=None, + use_http=False, + test_index=None, + time_limit=1, + timeout=1, + ) + # build a test case + entry_point = input_path / "test.html" + entry_point.touch() + # build test case and asset + asset = tmp_path / "sample_asset" + asset.touch() + with AssetManager(base_path=tmp_path) as asset_mgr: + asset_mgr.add("sample", asset) + with TestCase("test.html", "test-adapter") as src: + src.assets = asset_mgr.assets + src.assets_path = asset_mgr.path + src.add_from_file(entry_point) + src.dump(input_path, include_details=True) + # this will load the previously created test case and asset from the filesystem + try: + assert ReplayManager.main(args) == Exit.FAILURE + assert target.launch.call_count == 1 + assert "sample" in target.asset_mgr.assets + assert target.asset_mgr.path is not None + finally: + if target.asset_mgr: + target.asset_mgr.cleanup() diff --git a/grizzly/replay/test_replay.py b/grizzly/replay/test_replay.py index e44bd496..1a27e023 100644 --- a/grizzly/replay/test_replay.py +++ b/grizzly/replay/test_replay.py @@ -635,26 +635,26 @@ def test_replay_21(tmp_path): data.write_text("test") dst = tmp_path / "dst" # build test case - with AssetManager() as assets: + with AssetManager() as asset_mgr: (tmp_path / "prefs.js").touch() - assets.add("prefs", tmp_path / "prefs.js", copy=False) + asset_mgr.add("prefs", tmp_path / "prefs.js", copy=False) with TestCase(data.name, "foo") as src: src.env_vars = {"foo": "bar"} - src.assets = dict(assets.assets) - src.assets_path = assets.path + src.assets = dict(asset_mgr.assets) + src.assets_path = asset_mgr.path src.add_from_file(data, data.name) src.dump(dst, include_details=True) # load single file - tests, assets, env_vars = ReplayManager.load_testcases(dst / "testcase.html") + tests, asset_mgr, env_vars = ReplayManager.load_testcases(dst / "testcase.html") assert len(tests) == 1 assert not env_vars - assert assets is None + assert asset_mgr is None # load directory - tests, assets, env_vars = ReplayManager.load_testcases(dst) + tests, asset_mgr, env_vars = ReplayManager.load_testcases(dst) assert len(tests) == 1 assert env_vars == {"foo": "bar"} - assert assets - assert "prefs" in assets.assets + assert asset_mgr + assert "prefs" in asset_mgr.assets def test_replay_22(mocker, tmp_path): @@ -678,14 +678,14 @@ def test_replay_22(mocker, tmp_path): ReplayManager.load_testcases(tmp_path) # success fake_load.return_value = [test0, test1] - tests, assets, env_vars = ReplayManager.load_testcases(tmp_path) + tests, asset_mgr, 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) assert len(tests) == 2 assert tests[0].cleanup.call_count == 0 assert tests[1].cleanup.call_count == 0 - assert assets is None + assert asset_mgr is None # success select fake_load.return_value = [ test0, @@ -693,7 +693,7 @@ def test_replay_22(mocker, tmp_path): test2, mocker.MagicMock(spec_set=TestCase, assets={}, assets_path=None, env_vars={}), ] - tests, assets, _ = ReplayManager.load_testcases(tmp_path, subset=[1, 3]) + tests, asset_mgr, _ = ReplayManager.load_testcases(tmp_path, subset=[1, 3]) assert len(tests) == 2 assert tests[0].entry_point == "x.html" assert test0.cleanup.call_count == 1 diff --git a/grizzly/session.py b/grizzly/session.py index 159bc839..23a2d9d6 100644 --- a/grizzly/session.py +++ b/grizzly/session.py @@ -270,8 +270,8 @@ def run( if initial or not self.status.results.is_frequent(bucket_hash): # add target info to test cases for test in self.iomanager.tests: - test.assets = dict(self.target.assets.assets) - test.assets_path = self.target.assets.path + test.assets = dict(self.target.asset_mgr.assets) + test.assets_path = self.target.asset_mgr.path test.env_vars = self.target.filtered_environ() self.reporter.submit(self.iomanager.tests, report, force=initial) else: diff --git a/grizzly/target/puppet_target.py b/grizzly/target/puppet_target.py index 497ead03..dacbc5cf 100644 --- a/grizzly/target/puppet_target.py +++ b/grizzly/target/puppet_target.py @@ -97,7 +97,6 @@ def __init__(self, binary, launch_timeout, log_limit, memory_limit, **kwds): launch_timeout, log_limit, memory_limit, - assets=kwds.pop("assets", None), certs=certs, ) self._https = certs is not None @@ -373,8 +372,8 @@ def merge_environment(self, extra): self.environ = output def process_assets(self): - self._extension = self.assets.get("extension") - self._prefs = self.assets.get("prefs") + self._extension = self.asset_mgr.get("extension") + self._prefs = self.asset_mgr.get("prefs") # generate temporary prefs.js with prefpicker if self._prefs is None: LOG.debug("using prefpicker to generate prefs.js") @@ -382,11 +381,11 @@ def process_assets(self): prefs = Path(tmp_path) / "prefs.js" template = PrefPicker.lookup_template("browser-fuzzing.yml") PrefPicker.load_template(template).create_prefsjs(prefs) - self._prefs = self.assets.add("prefs", prefs, copy=False) - abort_tokens = self.assets.get("abort-tokens") + self._prefs = self.asset_mgr.add("prefs", prefs, copy=False) + abort_tokens = self.asset_mgr.get("abort-tokens") if abort_tokens: LOG.debug("loading 'abort tokens' from %r", abort_tokens) - with (self.assets.path / abort_tokens).open() as in_fp: + with (self.asset_mgr.path / abort_tokens).open() as in_fp: for line in in_fp: line = line.strip() if line: @@ -399,9 +398,11 @@ def process_assets(self): # load existing sanitizer options from environment var_name = f"{sanitizer.upper()}_OPTIONS" opts.load_options(self.environ.get(var_name, "")) - if self.assets.get(asset): + if self.asset_mgr.get(asset): # use suppression file if provided as asset - opts.add("suppressions", f"'{self.assets.get(asset)}'", overwrite=True) + opts.add( + "suppressions", f"'{self.asset_mgr.get(asset)}'", overwrite=True + ) elif opts.get("suppressions"): path = Path(opts.pop("suppressions").strip("\"'")) if path.is_file(): @@ -409,7 +410,7 @@ def process_assets(self): LOG.debug("using %r from environment", asset) opts.add( "suppressions", - f"'{self.assets.add(asset, path)}'", + f"'{self.asset_mgr.add(asset, path)}'", overwrite=True, ) else: diff --git a/grizzly/target/target.py b/grizzly/target/target.py index f09f6f17..f449e972 100644 --- a/grizzly/target/target.py +++ b/grizzly/target/target.py @@ -47,7 +47,7 @@ class Target(metaclass=ABCMeta): TRACKED_ENVVARS = () __slots__ = ( - "_assets", + "_asset_mgr", "_https", "_lock", "_monitor", @@ -65,16 +65,14 @@ def __init__( launch_timeout, log_limit, memory_limit, - assets=None, certs=None, ): assert launch_timeout > 0 assert log_limit >= 0 assert memory_limit >= 0 assert binary is not None and binary.is_file() - assert assets is None or isinstance(assets, AssetManager) assert certs is None or isinstance(certs, CertificateBundle) - self._assets = assets if assets else AssetManager(base_path=grz_tmp("target")) + self._asset_mgr = AssetManager(base_path=grz_tmp("target")) self._https = False self._lock = Lock() self._monitor = None @@ -92,14 +90,14 @@ def __exit__(self, *exc): self.cleanup() @property - def assets(self): - return self._assets + def asset_mgr(self): + return self._asset_mgr - @assets.setter - def assets(self, assets): - self._assets.cleanup() - assert isinstance(assets, AssetManager) - self._assets = assets + @asset_mgr.setter + def asset_mgr(self, asset_mgr): + self._asset_mgr.cleanup() + assert isinstance(asset_mgr, AssetManager) + self._asset_mgr = asset_mgr @abstractmethod def _cleanup(self): @@ -112,7 +110,7 @@ def check_result(self, ignored): def cleanup(self): # call target specific _cleanup first self._cleanup() - self._assets.cleanup() + self._asset_mgr.cleanup() @abstractmethod def close(self, force_close=False): diff --git a/grizzly/target/test_assets.py b/grizzly/target/test_assets.py index dd1f457a..f14af421 100644 --- a/grizzly/target/test_assets.py +++ b/grizzly/target/test_assets.py @@ -11,27 +11,27 @@ def test_asset_manager_01(tmp_path): """test AssetManager()""" - with AssetManager(base_path=tmp_path) as assets: - assert not assets.assets - assert assets.path - assert assets.is_empty() + with AssetManager(base_path=tmp_path) as asset_mgr: + assert not asset_mgr.assets + assert asset_mgr.path + assert asset_mgr.is_empty() # add file (move) example = tmp_path / "example.txt" example.write_text("foo") - asset_location = assets.add("example_file", example, copy=False) - assert assets.assets["example_file"] == "example.txt" - assert assets.path / "example.txt" == asset_location - assert assets.get("example_file") == asset_location - assert len(assets.assets) == 1 - assert not assets.is_empty() + asset_location = asset_mgr.add("example_file", example, copy=False) + assert asset_mgr.assets["example_file"] == "example.txt" + assert asset_mgr.path / "example.txt" == asset_location + assert asset_mgr.get("example_file") == asset_location + assert len(asset_mgr.assets) == 1 + assert not asset_mgr.is_empty() assert not example.is_file() - assert (assets.path / "example.txt").is_file() + assert (asset_mgr.path / "example.txt").is_file() # add existing asset - update asset (copy) example = tmp_path / "example_2.txt" example.write_text("foo") - assets.add("example_file", example) + asset_mgr.add("example_file", example) assert example.is_file() - assert len(assets.assets) == 1 + assert len(asset_mgr.assets) == 1 # add directory example = tmp_path / "example_path" example.mkdir() @@ -39,50 +39,52 @@ def test_asset_manager_01(tmp_path): (example / "a" / "1.txt").write_text("1") (example / "b").mkdir() (example / "b" / "2.txt").write_text("2") - assets.add("example_path", example) + asset_mgr.add("example_path", example) rmtree(example) - assert (assets.path / "example_path/a/1.txt").is_file() - assert (assets.path / "example_path/b/2.txt").is_file() - assert len(assets.assets) == 2 + assert (asset_mgr.path / "example_path/a/1.txt").is_file() + assert (asset_mgr.path / "example_path/b/2.txt").is_file() + assert len(asset_mgr.assets) == 2 # get - assert (assets.path / "example_2.txt").samefile(assets.get("example_file")) - assert (assets.path / "example_path").samefile(assets.get("example_path")) + assert (asset_mgr.path / "example_2.txt").samefile( + asset_mgr.get("example_file") + ) + assert (asset_mgr.path / "example_path").samefile(asset_mgr.get("example_path")) # remove directory - assets.remove("example_path") - assert len(assets.assets) == 1 - assert assets.path.is_dir() - assert not (assets.path / "example_path").is_dir() + asset_mgr.remove("example_path") + assert len(asset_mgr.assets) == 1 + assert asset_mgr.path.is_dir() + assert not (asset_mgr.path / "example_path").is_dir() # remove file - assets.remove("example_file") - assert len(assets.assets) == 0 - assert not any(assets.path.iterdir()) + asset_mgr.remove("example_file") + assert len(asset_mgr.assets) == 0 + assert not any(asset_mgr.path.iterdir()) # cleanup - assets.cleanup() - assert not assets.assets - assert assets.path is None + asset_mgr.cleanup() + assert not asset_mgr.assets + assert asset_mgr.path is None def test_asset_manager_02(tmp_path): """test AssetManager() failures""" - with AssetManager(base_path=str(tmp_path)) as assets: + with AssetManager(base_path=tmp_path) as asset_mgr: # get missing - assert assets.get("missing") is None + assert asset_mgr.get("missing") is None # add missing file with raises(OSError, match="'missing' does not exist"): - assets.add("a", Path("missing")) - assert not assets.assets + asset_mgr.add("a", Path("missing")) + assert not asset_mgr.assets # remove invalid asset - assets.remove("missing") + asset_mgr.remove("missing") # add file example = tmp_path / "example.txt" example.touch() - assets.add("example_file", example, copy=True) + asset_mgr.add("example_file", example, copy=True) # add with asset with name and file collision - assets.add("example_file", example, copy=True) + asset_mgr.add("example_file", example, copy=True) # add with file name collision as different asset with raises(AssetError, match="collide: 'example.txt' already exists"): - assets.add("collide", example) - assert "collide" not in assets.assets + asset_mgr.add("collide", example) + assert "collide" not in asset_mgr.assets def test_asset_manager_03(tmp_path): @@ -91,17 +93,17 @@ def test_asset_manager_03(tmp_path): src.mkdir() (src / "b.txt").touch() - with AssetManager.load({"a": "b.txt"}, src, base_path=str(tmp_path)) as assets: - assert len(assets.assets) == 1 - assert "a" in assets.assets - assert assets.assets["a"] == "b.txt" - assert (assets.path / assets.assets["a"]).is_file() + with AssetManager.load({"a": "b.txt"}, src, base_path=tmp_path) as asset_mgr: + assert len(asset_mgr.assets) == 1 + assert "a" in asset_mgr.assets + assert asset_mgr.assets["a"] == "b.txt" + assert (asset_mgr.path / asset_mgr.assets["a"]).is_file() def test_asset_manager_04(tmp_path): """test AssetManager.add_batch()""" batch = [] - with AssetManager(base_path=str(tmp_path)) as assets: + with AssetManager(base_path=tmp_path) as asset_mgr: # add file example = tmp_path / "example.txt" example.write_text("example") @@ -112,5 +114,5 @@ def test_asset_manager_04(tmp_path): (example / "a").mkdir() (example / "a" / "1.txt").write_text("1") batch.append(["example_path", example]) - assets.add_batch(batch) - assert len(assets.assets) == 2 + asset_mgr.add_batch(batch) + assert len(asset_mgr.assets) == 2 diff --git a/grizzly/target/test_puppet_target.py b/grizzly/target/test_puppet_target.py index 298d4c4b..bc523a93 100644 --- a/grizzly/target/test_puppet_target.py +++ b/grizzly/target/test_puppet_target.py @@ -21,7 +21,7 @@ def test_puppet_target_01(mocker, tmp_path): fake_file = tmp_path / "fake" fake_file.touch() with PuppetTarget(fake_file, 300, 25, 5000) as target: - assert target.assets + assert target.asset_mgr assert target.closed assert target.launch_timeout == 300 assert target.log_limit == 25 @@ -301,28 +301,30 @@ def test_puppet_target_08(mocker, tmp_path): fake_file.write_text("1\n2\n") # no prefs file provided with PuppetTarget(fake_file, 300, 25, 5000) as target: - assert target.assets.get("prefs") is None + assert target.asset_mgr.get("prefs") is None target.process_assets() - assert target.assets.get("prefs").is_file() - assert target.assets.get("prefs").name == "prefs.js" + assert target.asset_mgr.get("prefs").is_file() + assert target.asset_mgr.get("prefs").name == "prefs.js" # prefs file provided - with AssetManager(base_path=str(tmp_path)) as assets: - assets.add("prefs", fake_file) - with PuppetTarget(fake_file, 300, 25, 5000, assets=assets) as target: + with AssetManager(base_path=tmp_path) as asset_mgr: + asset_mgr.add("prefs", fake_file) + with PuppetTarget(fake_file, 300, 25, 5000) as target: + target.asset_mgr = asset_mgr target.process_assets() - assert target.assets.get("prefs").is_file() - assert target.assets.get("prefs").name == "fake" + assert target.asset_mgr.get("prefs").is_file() + assert target.asset_mgr.get("prefs").name == "fake" # abort tokens file provided - with AssetManager(base_path=str(tmp_path)) as assets: - assets.add("abort-tokens", fake_file) - with PuppetTarget(fake_file, 300, 25, 5000, assets=assets) as target: + with AssetManager(base_path=tmp_path) as asset_mgr: + asset_mgr.add("abort-tokens", fake_file) + with PuppetTarget(fake_file, 300, 25, 5000) as target: # ignore E1101: (pylint 2.9.3 bug?) # Method 'add_abort_token' has no 'call_count' member (no-member) # pylint: disable=no-member assert target._puppet.add_abort_token.call_count == 0 + target.asset_mgr = asset_mgr target.process_assets() - assert target.assets.get("abort-tokens").is_file() - assert target.assets.get("abort-tokens").name == "fake" + assert target.asset_mgr.get("abort-tokens").is_file() + assert target.asset_mgr.get("abort-tokens").name == "fake" assert target._puppet.add_abort_token.call_count == 2 @@ -379,31 +381,32 @@ def test_puppet_target_10(tmp_path, asset, env): fake_file.touch() supp_asset = tmp_path / "supp_asset" supp_env = tmp_path / "supp_env" - with AssetManager(base_path=str(tmp_path)) as assets: - assets.add("prefs", fake_file) + with AssetManager(base_path=tmp_path) as asset_mgr: + asset_mgr.add("prefs", fake_file) if asset: supp_asset.touch() - assets.add("lsan-suppressions", supp_asset) - with PuppetTarget(fake_file, 300, 25, 5000, assets=assets) as target: + asset_mgr.add("lsan-suppressions", supp_asset) + with PuppetTarget(fake_file, 300, 25, 5000) as target: target.environ["TSAN_OPTIONS"] = "a=1" if env: supp_env.touch() target.environ["LSAN_OPTIONS"] = f"suppressions='{supp_env}'" else: target.environ["LSAN_OPTIONS"] = "suppressions='missing'" + target.asset_mgr = asset_mgr target.process_assets() if asset: assert ( - f"suppressions='{target.assets.path / supp_asset.name}'" + f"suppressions='{target.asset_mgr.path / supp_asset.name}'" in target.environ["LSAN_OPTIONS"] ) elif env: assert ( - f"suppressions='{target.assets.path / supp_env.name}'" + f"suppressions='{target.asset_mgr.path / supp_env.name}'" in target.environ["LSAN_OPTIONS"] ) else: - assert not assets.get("lsan-suppressions") + assert not asset_mgr.get("lsan-suppressions") def test_puppet_target_11(tmp_path): diff --git a/grizzly/target/test_target.py b/grizzly/target/test_target.py index 3c0be4aa..1b50efb4 100644 --- a/grizzly/target/test_target.py +++ b/grizzly/target/test_target.py @@ -53,10 +53,10 @@ def test_target_01(tmp_path): fake_file.touch() 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)) - assert target.assets.path != org_path + assert target.asset_mgr + org_path = target.asset_mgr.path + target.asset_mgr = AssetManager(base_path=tmp_path) + assert target.asset_mgr.path != org_path assert not target.environ assert not target.filtered_environ() assert not target.is_idle(0) diff --git a/grizzly/test_session.py b/grizzly/test_session.py index 61b653c6..e22f6e65 100644 --- a/grizzly/test_session.py +++ b/grizzly/test_session.py @@ -16,7 +16,7 @@ from .common.reporter import Report, Reporter from .common.runner import RunResult from .session import LogOutputLimiter, Session, SessionError -from .target import AssetManager, Result, Target +from .target import Result, Target pytestmark = mark.usefixtures("patch_collector", "tmp_path_status_db_fuzz") @@ -68,12 +68,7 @@ def test_session_01(mocker, harness, profiling, coverage, relaunch, iters, runti """test Session with typical fuzzer Adapter""" mocker.patch("grizzly.common.status.time", side_effect=count(start=1.0, step=1.0)) server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager), - environ={}, - launch_timeout=30, - ) + target = mocker.Mock(spec_set=Target, environ={}, launch_timeout=30) target.log_size.return_value = 1000 target.monitor.launches = 1 # avoid shutdown delay @@ -138,12 +133,7 @@ def test_session_01(mocker, harness, profiling, coverage, relaunch, iters, runti def test_session_02(mocker, harness, relaunch, remaining): """test Session with playback Adapter""" server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager), - environ={}, - launch_timeout=30, - ) + target = mocker.Mock(spec_set=Target, environ={}, launch_timeout=30) # calculate if the target is 'closed' based on relaunch type(target).closed = mocker.PropertyMock( side_effect=((x % relaunch == 0) for x in range(remaining)) @@ -194,12 +184,7 @@ def test_session_03(mocker, tmp_path, harness, report_size, relaunch, iters, has adapter = SimpleAdapter(harness) reporter = mocker.Mock(spec_set=Reporter) server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager, assets={}), - environ={}, - launch_timeout=30, - ) + target = mocker.MagicMock(spec_set=Target, environ={}, launch_timeout=30) target.monitor.launches = 1 # avoid shutdown delay target.monitor.is_healthy.return_value = False @@ -246,12 +231,7 @@ def generate(self, _testcase, _server_map): server = mocker.Mock(spec_set=Sapphire, port=0x1337) server.serve_path.return_value = (Served.NONE, []) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager), - environ={}, - launch_timeout=30, - ) + target = mocker.Mock(spec_set=Target, environ={}, launch_timeout=30) target.monitor.launches = 1 with Session(FuzzAdapter("fuzz"), None, server, target) as session: with raises(SessionError, match="Test case is missing entry point"): @@ -277,12 +257,7 @@ def test_session_05(mocker, harness, report_size): ) report.crash_info.createShortSignature.return_value = "[@ sig]" server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager, assets={}), - environ={}, - launch_timeout=30, - ) + target = mocker.MagicMock(spec_set=Target, environ={}, launch_timeout=30) target.monitor.launches = 1 type(target).closed = mocker.PropertyMock(side_effect=(True, False)) target.check_result.side_effect = (Result.NONE, Result.FOUND) @@ -323,12 +298,8 @@ def test_session_06(mocker, srv_results, target_result, ignored, results): report.crash_info.createShortSignature.return_value = "[@ sig]" reporter = mocker.Mock(spec_set=Reporter) server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager), - closed=True, - environ={}, - launch_timeout=30, + target = mocker.MagicMock( + spec_set=Target, closed=True, environ={}, launch_timeout=10 ) target.log_size.return_value = 1 target.monitor.launches = 1 @@ -355,9 +326,7 @@ def test_session_07(mocker): adapter = mocker.Mock(spec_set=Adapter, remaining=None) adapter.IGNORE_UNSERVED = False server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, assets=mocker.Mock(spec_set=AssetManager), environ={} - ) + target = mocker.MagicMock(spec_set=Target, environ={}) target.monitor.launches = 1 with Session(adapter, None, server, target) as session: session.run([], 10, iteration_limit=1) @@ -381,11 +350,7 @@ def test_session_08(mocker): report = mocker.Mock(spec_set=Report, major="major123", minor="minor456") reporter = mocker.Mock(spec_set=Reporter) server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager, assets={}), - environ={}, - ) + target = mocker.MagicMock(spec_set=Target, environ={}) target.monitor.launches = 1 target.create_report.return_value = report with Session(adapter, reporter, server, target) as session: @@ -416,12 +381,7 @@ def test_session_09(mocker, harness, report_size, relaunch, iters, report_limit) report = mocker.Mock(spec_set=Report, major="abc", minor="def", crash_hash="123") report.crash_info.createShortSignature.return_value = "[@ sig]" server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager, assets={}), - environ={}, - launch_timeout=30, - ) + target = mocker.MagicMock(spec_set=Target, environ={}, launch_timeout=30) target.monitor.launches = 1 # avoid shutdown delay target.monitor.is_healthy.return_value = False @@ -463,12 +423,7 @@ def test_session_10(mocker, harness, iters, result_limit, results): report = mocker.Mock(spec_set=Report, major="abc", minor="def", crash_hash="123") report.crash_info.createShortSignature.return_value = "[@ sig]" server = mocker.Mock(spec_set=Sapphire, port=0x1337) - target = mocker.Mock( - spec_set=Target, - assets=mocker.Mock(spec_set=AssetManager, assets={}), - environ={}, - launch_timeout=30, - ) + target = mocker.MagicMock(spec_set=Target, environ={}, launch_timeout=30) target.monitor.launches = 1 # avoid shutdown delay target.monitor.is_healthy.return_value = False