From 20bc9d065414f8cb7abf04132da449c6e0ef24b4 Mon Sep 17 00:00:00 2001 From: Tyson Smith Date: Mon, 27 Nov 2023 11:39:43 -0800 Subject: [PATCH] Set TEST_INFO in a single location --- grizzly/common/fuzzmanager.py | 3 +- grizzly/common/storage.py | 17 ++++---- grizzly/common/test_fuzzmanager.py | 5 ++- grizzly/common/test_storage.py | 56 +++++++++++++-------------- grizzly/reduce/strategies/beautify.py | 4 +- 5 files changed, 43 insertions(+), 42 deletions(-) diff --git a/grizzly/common/fuzzmanager.py b/grizzly/common/fuzzmanager.py index 761b60dd..23c8dfa8 100644 --- a/grizzly/common/fuzzmanager.py +++ b/grizzly/common/fuzzmanager.py @@ -15,6 +15,7 @@ from FTB.Signatures.CrashInfo import CrashInfo from .reporter import Quality +from .storage import TEST_INFO from .utils import grz_tmp FM_CONFIG = Path.home() / ".fuzzmanagerconf" @@ -334,7 +335,7 @@ def testcases(self, subset=None): # - 'foo-0' (most recent) # see FuzzManagerReporter for more info self._contents = sorted( - (x.parent for x in self._storage.rglob("test_info.json")), + (x.parent for x in self._storage.rglob(TEST_INFO)), reverse=True, ) diff --git a/grizzly/common/storage.py b/grizzly/common/storage.py index 254cb796..b53e992c 100644 --- a/grizzly/common/storage.py +++ b/grizzly/common/storage.py @@ -20,6 +20,7 @@ LOG = getLogger(__name__) +TEST_INFO = "test_info.json" class TestCaseLoadFailure(Exception): @@ -288,7 +289,7 @@ def dump(self, dst_path, include_details=False): Args: dst_path (str): Path to directory to output data. - include_details (bool): Output "test_info.json" file. + include_details (bool): Output test info file. Returns: None @@ -325,7 +326,7 @@ def dump(self, dst_path, include_details=False): info["assets"] = self.assets info["assets_path"] = "_assets_" copytree(self.assets_path, dst_path / info["assets_path"]) - with (dst_path / "test_info.json").open("w") as out_fp: + with (dst_path / TEST_INFO).open("w") as out_fp: json.dump(info, out_fp, indent=2, sort_keys=True) @staticmethod @@ -423,7 +424,7 @@ def load(cls, path, entry_point=None, catalog=False): if ( not entry.is_dir() and test.assets_path not in entry.parents - and entry.name != "test_info.json" + and entry.name != TEST_INFO ): test.add_from_file( entry, file_name=entry.relative_to(test.root).as_posix() @@ -438,7 +439,7 @@ def load_meta(cls, path, entry_point=None): """Process and sanitize TestCase meta data. Args: - path (Path): Directory containing test_info.json file. + path (Path): Directory containing test info file. entry_point (): See TestCase.load(). Returns: @@ -490,20 +491,20 @@ def read_info(path): """Attempt to load test info. Args: - path (Path): Directory containing test_info.json. + path (Path): Directory containing test info file. Yields: dict: Test info. """ try: - with (path / "test_info.json").open("r") as in_fp: + with (path / TEST_INFO).open("r") as in_fp: info = json.load(in_fp) except FileNotFoundError: info = None except ValueError: - raise TestCaseLoadFailure("Invalid 'test_info.json'") from None + raise TestCaseLoadFailure(f"Invalid '{TEST_INFO}'") from None if info is not None and not isinstance(info.get("target"), str): - raise TestCaseLoadFailure("Invalid 'target' entry in 'test_info.json'") + raise TestCaseLoadFailure(f"Invalid 'target' entry in '{TEST_INFO}'") return info or {} @property diff --git a/grizzly/common/test_fuzzmanager.py b/grizzly/common/test_fuzzmanager.py index 0c6dacfe..42a1cb76 100644 --- a/grizzly/common/test_fuzzmanager.py +++ b/grizzly/common/test_fuzzmanager.py @@ -10,6 +10,7 @@ from pytest import mark, raises from .fuzzmanager import Bucket, CrashEntry, load_fm_data +from .storage import TEST_INFO def test_bucket_1(mocker): @@ -178,8 +179,8 @@ def test_crash_3(mocker, tmp_path): for i in (1, 3, 2, 0): test = tmp_path / f"test-{i}" test.mkdir() - (test / "test_info.json").touch() - zip_fp.write(test / "test_info.json", arcname=f"test-{i}/test_info.json") + (test / TEST_INFO).touch() + zip_fp.write(test / TEST_INFO, arcname=f"test-{i}/{TEST_INFO}") with CrashEntry(234) as crash: assert crash.testcase == "test.zip" # pre-load data dict so I can re-patch get coll.return_value.get.return_value = mocker.Mock( diff --git a/grizzly/common/test_storage.py b/grizzly/common/test_storage.py index 768e6e3a..1bff54b8 100644 --- a/grizzly/common/test_storage.py +++ b/grizzly/common/test_storage.py @@ -8,7 +8,7 @@ from pytest import mark, raises from ..target import AssetManager -from .storage import TestCase, TestCaseLoadFailure, TestFileExists +from .storage import TEST_INFO, TestCase, TestCaseLoadFailure, TestFileExists def test_testcase_01(tmp_path): @@ -38,7 +38,7 @@ def test_testcase_01(tmp_path): tcase.dump(tmp_path) assert not any(tmp_path.iterdir()) tcase.dump(tmp_path, include_details=True) - assert (tmp_path / "test_info.json").is_file() + assert (tmp_path / TEST_INFO).is_file() tcase.cleanup() assert not tcase.root.is_dir() @@ -142,20 +142,18 @@ def test_testcase_06(): def test_testcase_07(tmp_path): """test TestCase.read_info()""" - # missing test_info.json + # missing test info file assert not TestCase.read_info(tmp_path) - # invalid test_info.json - (tmp_path / "test_info.json").write_text("X") - with raises(TestCaseLoadFailure, match="Invalid 'test_info.json'"): + # invalid test info file + (tmp_path / TEST_INFO).write_text("X") + with raises(TestCaseLoadFailure, match=f"Invalid '{TEST_INFO}'"): TestCase.read_info(tmp_path) - # test_info.json missing 'target' entry - (tmp_path / "test_info.json").write_text("{}") - with raises( - TestCaseLoadFailure, match="Invalid 'target' entry in 'test_info.json'" - ): + # test info file missing 'target' entry + (tmp_path / TEST_INFO).write_text("{}") + with raises(TestCaseLoadFailure, match=f"Invalid 'target' entry in '{TEST_INFO}'"): TestCase.read_info(tmp_path) # success - (tmp_path / "test_info.json").write_text('{"target": "foo"}') + (tmp_path / TEST_INFO).write_text('{"target": "foo"}') assert TestCase.read_info(tmp_path) == {"target": "foo"} @@ -165,7 +163,7 @@ def test_testcase_08(tmp_path): with raises(TestCaseLoadFailure, match="Could not determine entry point"): TestCase._find_entry_point(tmp_path) # missing potential entry point - (tmp_path / "test_info.json").touch() + (tmp_path / TEST_INFO).touch() with raises(TestCaseLoadFailure, match="Could not determine entry point"): TestCase._find_entry_point(tmp_path) # success @@ -194,21 +192,21 @@ def test_testcase_09(tmp_path): entry_point, info = TestCase.load_meta(tmp_path / "test_01.html") assert entry_point == tmp_path / "test_01.html" assert not info - # success (test_info.json) - (tmp_path / "test_info.json").write_text('{"target": "test_01.html"}') + # success (with test info file) + (tmp_path / TEST_INFO).write_text('{"target": "test_01.html"}') (tmp_path / "other.html").touch() entry_point, info = TestCase.load_meta(tmp_path) assert entry_point == (tmp_path / "test_01.html") assert info.get("target") == "test_01.html" - # success (test_info.json) override entry point + # success (with test info file) override entry point entry_point, info = TestCase.load_meta( tmp_path, entry_point=(tmp_path / "other.html") ) assert entry_point == tmp_path / "other.html" assert info.get("target") == "other.html" - # invalid test_info.json (will fallback to searching for test) + # invalid test info file (will fallback to searching for test) (tmp_path / "other.html").unlink() - (tmp_path / "test_info.json").write_text("{}") + (tmp_path / TEST_INFO).write_text("{}") entry_point, info = TestCase.load_meta(tmp_path) assert entry_point == (tmp_path / "test_01.html") assert not info @@ -242,7 +240,7 @@ def test_testcase_10(tmp_path): def test_testcase_11(tmp_path): - """test TestCase.load() existing test case with simple test_info.json""" + """test TestCase.load() existing test case with simple test info file""" # build a test case src = tmp_path / "src" with TestCase("test.html", "test-adapter") as test: @@ -259,7 +257,7 @@ def test_testcase_11(tmp_path): @mark.parametrize("catalog", [False, True]) def test_testcase_12(tmp_path, catalog): - """test TestCase.load() existing test case with test_info.json""" + """test TestCase.load() existing test case with test info file""" # build a test case asset_file = tmp_path / "asset.txt" asset_file.touch() @@ -284,7 +282,7 @@ def test_testcase_12(tmp_path, catalog): assert "optional.bin" in loaded.optional assert "nested/a.html" in loaded.optional assert "_assets_/asset.txt" not in loaded.optional - assert "test_info.json" not in loaded.optional + assert TEST_INFO not in loaded.optional else: assert not any(loaded.optional) assert loaded.assets == {"example": "asset.txt"} @@ -297,32 +295,32 @@ def test_testcase_12(tmp_path, catalog): def test_testcase_13(tmp_path): - """test TestCase.load() test_info.json error cases""" - # bad 'assets' entry in test_info.json + """test TestCase.load() test info file error cases""" + # bad 'assets' entry in test info file src_dir = tmp_path / "src" src_dir.mkdir() entry_point = src_dir / "target.html" entry_point.touch() with TestCase("target.html", "test-adapter") as src: src.dump(src_dir, include_details=True) - test_info = loads((src_dir / "test_info.json").read_text()) + test_info = loads((src_dir / TEST_INFO).read_text()) test_info["assets"] = {"bad": 1} - (src_dir / "test_info.json").write_text(dumps(test_info)) + (src_dir / TEST_INFO).write_text(dumps(test_info)) with raises(TestCaseLoadFailure, match="'assets' contains invalid entry"): TestCase.load(src_dir) - # bad 'env' entry in test_info.json + # bad 'env' entry in test info file with TestCase("target.html", "test-adapter") as src: src.dump(src_dir, include_details=True) - test_info = loads((src_dir / "test_info.json").read_text()) + test_info = loads((src_dir / TEST_INFO).read_text()) test_info["env"] = {"bad": 1} - (src_dir / "test_info.json").write_text(dumps(test_info)) + (src_dir / TEST_INFO).write_text(dumps(test_info)) with raises(TestCaseLoadFailure, match="'env' contains invalid entry"): TestCase.load(src_dir) # missing asset data test_info["env"].clear() test_info["assets"] = {"a": "a"} test_info["assets_path"] = "missing" - (src_dir / "test_info.json").write_text(dumps(test_info)) + (src_dir / TEST_INFO).write_text(dumps(test_info)) with TestCase.load(src_dir) as loaded: assert not loaded.assets assert loaded.assets_path is None diff --git a/grizzly/reduce/strategies/beautify.py b/grizzly/reduce/strategies/beautify.py index 1ef592f0..dc7cecda 100644 --- a/grizzly/reduce/strategies/beautify.py +++ b/grizzly/reduce/strategies/beautify.py @@ -27,7 +27,7 @@ except ImportError: # pragma: no cover HAVE_JSBEAUTIFIER = False -from ...common.storage import TestCase +from ...common.storage import TEST_INFO, TestCase from . import Strategy, _contains_dd LOG = getLogger(__name__) @@ -64,7 +64,7 @@ class _BeautifyStrategy(Strategy, ABC): """ all_extensions = None - ignore_files = {"test_info.json", "prefs.js"} + ignore_files = {TEST_INFO, "prefs.js"} import_available = None import_name = None native_extension = None