diff --git a/anta/catalog.py b/anta/catalog.py index ad0670bb8..1ed45c098 100644 --- a/anta/catalog.py +++ b/anta/catalog.py @@ -222,11 +222,20 @@ def parse(filename: str | Path) -> AntaCatalog: message = f"Unable to parse ANTA Test Catalog file '{filename}'" anta_log_exception(e, message, logger) raise + + if data is None: + logger.warning("Catalog file at %s is empty", filename) + return AntaCatalog([], filename=filename) + + if not isinstance(data, dict): + raise ValueError(f"Parsed data in {filename} does not have the correct format, Aborting...") + try: catalog_data = AntaCatalogFile(**data) except ValidationError as e: anta_log_exception(e, f"Test catalog '{filename}' is invalid!", logger) raise + tests: list[AntaTestDefinition] = [] for t in catalog_data.root.values(): tests.extend(t) @@ -244,6 +253,14 @@ def from_dict(data: RawCatalogInput) -> AntaCatalog: data: Python dictionary used to instantiate the AntaCatalog instance """ tests: list[AntaTestDefinition] = [] + + if data is None: + logger.warning("Catalog input data is empty") + return AntaCatalog([]) + + if not isinstance(data, dict): + raise ValueError(f"Wrong input type for catalog data, must be a dict, got {type(data)}") + try: catalog_data = AntaCatalogFile(**data) # type: ignore[arg-type] except ValidationError as e: diff --git a/tests/data/test_catalog_wrong_type.yml b/tests/data/test_catalog_wrong_type.yml new file mode 100644 index 000000000..3f8f04360 --- /dev/null +++ b/tests/data/test_catalog_wrong_type.yml @@ -0,0 +1 @@ +"Not a string" diff --git a/tests/data/test_empty_catalog.yml b/tests/data/test_empty_catalog.yml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/units/test_catalog.py b/tests/units/test_catalog.py index ba486a317..56b279398 100644 --- a/tests/units/test_catalog.py +++ b/tests/units/test_catalog.py @@ -70,6 +70,11 @@ (VerifyL3MTU, {"mtu": 1500, "filters": {"tags": ["demo"]}}), ], }, + { + "name": "test_empty_catalog", + "filename": "test_empty_catalog.yml", + "tests": [], + }, ] CATALOG_PARSE_FAIL_DATA: list[dict[str, Any]] = [ { @@ -102,6 +107,7 @@ "filename": "test_catalog_test_definition_multiple_dicts.yml", "error": "Value error, AntaTestDefinition must be a dictionary with a single entry", }, + {"name": "wrong_type_after_parsing", "filename": "test_catalog_wrong_type.yml", "error": " does not have the correct format, Aborting..."}, ] CATALOG_FROM_DICT_FAIL_DATA: list[dict[str, Any]] = [ { @@ -109,6 +115,11 @@ "filename": "test_catalog_with_undefined_tests.yml", "error": "FakeTest is not defined in Python module ", + }, ] CATALOG_FROM_LIST_FAIL_DATA: list[dict[str, Any]] = [ { @@ -209,9 +220,12 @@ def test_parse_fail(self, catalog_data: dict[str, Any]) -> None: """ Errors when instantiating AntaCatalog from a file """ - with pytest.raises(ValidationError) as exec_info: + with pytest.raises((ValidationError, ValueError)) as exec_info: AntaCatalog.parse(str(DATA_DIR / catalog_data["filename"])) - assert catalog_data["error"] in exec_info.value.errors()[0]["msg"] + if exec_info.type == ValidationError: + assert catalog_data["error"] in exec_info.value.errors()[0]["msg"] + else: + assert catalog_data["error"] in str(exec_info) def test_parse_fail_parsing(self, caplog: pytest.LogCaptureFixture) -> None: """ @@ -241,9 +255,12 @@ def test_from_dict_fail(self, catalog_data: dict[str, Any]) -> None: """ with open(file=str(DATA_DIR / catalog_data["filename"]), mode="r", encoding="UTF-8") as file: data = safe_load(file) - with pytest.raises(ValidationError) as exec_info: + with pytest.raises((ValidationError, ValueError)) as exec_info: AntaCatalog.from_dict(data) - assert catalog_data["error"] in exec_info.value.errors()[0]["msg"] + if exec_info.type == ValidationError: + assert catalog_data["error"] in exec_info.value.errors()[0]["msg"] + else: + assert catalog_data["error"] in str(exec_info) def test_filename(self) -> None: """