""" M2M Config validation.""" import json import logging import os from dataclasses import dataclass from typing import Any from m2mconfig.schemas import RegistryEntry logger = logging.getLogger(__name__) @dataclass class ValidationErrorInfo: entry_index: int entry: dict[str, Any] error_msg: str class M2MValidationError(ValueError): """M2M error type.""" pass class DuplicateRegistryEntry(ValueError): """M2M duplicate entry error type.""" pass def validate_config(m2m_json_path: str) -> list[RegistryEntry]: """Validate the m2m.json file contents.""" if not os.path.isfile(m2m_json_path): raise M2MValidationError(f"Invalid file path: {m2m_json_path}") try: with open(m2m_json_path) as fp: m2m_config = json.load(fp) logger.info( "Successfully loaded M2M Config with %s entries.", len(m2m_config) ) except Exception as ex: raise M2MValidationError( f"Failed to load file: {os.path.realpath(m2m_json_path)}" ) from ex if len(m2m_config) == 0: raise M2MValidationError("M2M config should have more than 0 entries.") m2m_registry_list = [] failed_entries = [] entry_names = set() m2m_identity_uuid_set = set() for i, entry in enumerate(m2m_config): try: registry_entry = RegistryEntry.model_validate(entry) if registry_entry.name in entry_names: raise DuplicateRegistryEntry( f"Duplicate RegistryEntry.name: '{registry_entry.name}'" ) m2m_identity_uuid = registry_entry.client_metadata.m2m_identity_uuid if m2m_identity_uuid in m2m_identity_uuid_set: raise DuplicateRegistryEntry( f"Duplicate RegistryEntry.client_metadata.m2m_identity_uuid: '{m2m_identity_uuid}'" ) entry_names.add(registry_entry.name) m2m_identity_uuid_set.add(m2m_identity_uuid) m2m_registry_list.append(registry_entry) except Exception as ex: failed_entries.append( ValidationErrorInfo(entry_index=i, entry=entry, error_msg=str(ex)) ) else: logger.info("VALID_REGISTRY_ENTRY: '%s'", registry_entry.name) assert_failed_entries(failed_entries) return m2m_registry_list def assert_failed_entries(failed_entries: list[ValidationErrorInfo]) -> None: """Log failed entries and raise an exception if failed_entries is not empty.""" for error_info in failed_entries: logger.error( "INVALID_REGISTRY_ENTRY: entry_index='%s', entry='%s', error_msg:'%s'\n", error_info.entry_index, json.dumps(error_info.entry), error_info.error_msg, ) if len(failed_entries): raise M2MValidationError("Found invalid entries. See log for details.")