示例#1
0
def check(config_dir, secrets=False):
    """Perform a check by mocking hass load functions."""
    logging.getLogger("homeassistant.loader").setLevel(logging.CRITICAL)
    res: Dict[str, Any] = {
        "yaml_files": OrderedDict(),  # yaml_files loaded
        "secrets": OrderedDict(),  # secret cache and secrets loaded
        "except": OrderedDict(),  # exceptions raised (with config)
        #'components' is a HomeAssistantConfig  # noqa: E265
        "secret_cache": None,
    }

    # pylint: disable=possibly-unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config file names."""
        res["yaml_files"][filename] = True
        return MOCKS["load"][1](filename)

    # pylint: disable=possibly-unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS["secrets"][1](ldr, node)
        except HomeAssistantError:
            val = None
        res["secrets"][node.value] = val
        return val

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        if not secrets and key == "secrets":
            continue
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()[f"mock_{key.replace('*', '')}"]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()

    if secrets:
        # Ensure !secrets point to the patched function
        yaml_loader.yaml.SafeLoader.add_constructor("!secret",
                                                    yaml_loader.secret_yaml)

    try:
        hass = core.HomeAssistant()
        hass.config.config_dir = config_dir

        res["components"] = hass.loop.run_until_complete(
            async_check_ha_config_file(hass))
        res["secret_cache"] = OrderedDict(yaml_loader.__SECRET_CACHE)
        for err in res["components"].errors:
            domain = err.domain or ERROR_STR
            res["except"].setdefault(domain, []).append(err.message)
            if err.config:
                res["except"].setdefault(domain, []).append(err.config)

    except Exception as err:  # pylint: disable=broad-except
        _LOGGER.exception("BURB")
        print(color("red", "Fatal error while loading config:"), str(err))
        res["except"].setdefault(ERROR_STR, []).append(str(err))
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        if secrets:
            # Ensure !secrets point to the original function
            yaml_loader.yaml.SafeLoader.add_constructor(
                "!secret", yaml_loader.secret_yaml)
        bootstrap.clear_secret_cache()

    return res
示例#2
0
def check(config_path):
    """Perform a check by mocking hass load functions."""
    res = {
        'yaml_files': OrderedDict(),  # yaml_files loaded
        'secrets': OrderedDict(),  # secret cache and secrets loaded
        'except': OrderedDict(),  # exceptions raised (with config)
        'components': OrderedDict(),  # successful components
        'secret_cache': OrderedDict(),
    }

    # pylint: disable=unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config files."""
        res['yaml_files'][filename] = True
        return MOCKS['load'][1](filename)

    # pylint: disable=unused-variable
    def mock_get(comp_name):
        """Mock hass.loader.get_component to replace setup & setup_platform."""
        def mock_setup(*kwargs):
            """Mock setup, only record the component name & config."""
            assert comp_name not in res['components'], \
                "Components should contain a list of platforms"
            res['components'][comp_name] = kwargs[1].get(comp_name)
            return True
        module = MOCKS['get'][1](comp_name)

        if module is None:
            # Ensure list
            res['except'][ERROR_STR] = res['except'].get(ERROR_STR, [])
            res['except'][ERROR_STR].append('{} not found: {}'.format(
                'Platform' if '.' in comp_name else 'Component', comp_name))
            return None

        # Test if platform/component and overwrite setup
        if '.' in comp_name:
            module.setup_platform = mock_setup

            if hasattr(module, 'async_setup_platform'):
                del module.async_setup_platform
        else:
            module.setup = mock_setup

            if hasattr(module, 'async_setup'):
                del module.async_setup

        return module

    # pylint: disable=unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS['secrets'][1](ldr, node)
        except HomeAssistantError:
            val = None
        res['secrets'][node.value] = val
        return val

    def mock_except(ex, domain, config,  # pylint: disable=unused-variable
                    hass=None):
        """Mock bootstrap.log_exception."""
        MOCKS['except'][1](ex, domain, config, hass)
        res['except'][domain] = config.get(domain, config)

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()['mock_' + key.replace('*', '')]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()
    # Ensure !secrets point to the patched function
    yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)

    try:
        bootstrap.from_config_file(config_path, skip_pip=True)
        res['secret_cache'] = dict(yaml.__SECRET_CACHE)
    except Exception as err:  # pylint: disable=broad-except
        print(color('red', 'Fatal error while loading config:'), str(err))
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        # Ensure !secrets point to the original function
        yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
        bootstrap.clear_secret_cache()

    return res
示例#3
0
def check(config_dir, secrets=False):
    """Perform a check by mocking hass load functions."""
    logging.getLogger('homeassistant.loader').setLevel(logging.CRITICAL)
    res = {
        'yaml_files': OrderedDict(),  # yaml_files loaded
        'secrets': OrderedDict(),  # secret cache and secrets loaded
        'except': OrderedDict(),  # exceptions raised (with config)
        'components': None,  # successful components
        'secret_cache': None,
    }

    # pylint: disable=possibly-unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config file names."""
        res['yaml_files'][filename] = True
        return MOCKS['load'][1](filename)

    # pylint: disable=possibly-unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS['secrets'][1](ldr, node)
        except HomeAssistantError:
            val = None
        res['secrets'][node.value] = val
        return val

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        if not secrets and key == 'secrets':
            continue
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()['mock_' + key.replace('*', '')]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()

    if secrets:
        # Ensure !secrets point to the patched function
        yaml.yaml.SafeLoader.add_constructor('!secret', yaml.secret_yaml)

    try:
        hass = core.HomeAssistant()
        hass.config.config_dir = config_dir

        res['components'] = check_ha_config_file(hass)
        res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE)

        for err in res['components'].errors:
            domain = err.domain or ERROR_STR
            res['except'].setdefault(domain, []).append(err.message)
            if err.config:
                res['except'].setdefault(domain, []).append(err.config)

    except Exception as err:  # pylint: disable=broad-except
        _LOGGER.exception("BURB")
        print(color('red', 'Fatal error while loading config:'), str(err))
        res['except'].setdefault(ERROR_STR, []).append(str(err))
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        if secrets:
            # Ensure !secrets point to the original function
            yaml.yaml.SafeLoader.add_constructor('!secret', yaml.secret_yaml)
        bootstrap.clear_secret_cache()

    return res
示例#4
0
def check(config_path):
    """Perform a check by mocking hass load functions."""
    res = {
        'yaml_files': OrderedDict(),  # yaml_files loaded
        'secrets': OrderedDict(),  # secret cache and secrets loaded
        'except': OrderedDict(),  # exceptions raised (with config)
        'components': OrderedDict(),  # successful components
        'secret_cache': OrderedDict(),
    }

    # pylint: disable=unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config files."""
        res['yaml_files'][filename] = True
        return MOCKS['load'][1](filename)

    # pylint: disable=unused-variable
    def mock_get(comp_name):
        """Mock hass.loader.get_component to replace setup & setup_platform."""
        def mock_setup(*kwargs):
            """Mock setup, only record the component name & config."""
            assert comp_name not in res['components'], \
                "Components should contain a list of platforms"
            res['components'][comp_name] = kwargs[1].get(comp_name)
            return True

        module = MOCKS['get'][1](comp_name)

        if module is None:
            # Ensure list
            msg = '{} not found: {}'.format(
                'Platform' if '.' in comp_name else 'Component', comp_name)
            res['except'].setdefault(ERROR_STR, []).append(msg)
            return None

        # Test if platform/component and overwrite setup
        if '.' in comp_name:
            module.setup_platform = mock_setup

            if hasattr(module, 'async_setup_platform'):
                del module.async_setup_platform
        else:
            module.setup = mock_setup

            if hasattr(module, 'async_setup'):
                del module.async_setup

        return module

    # pylint: disable=unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS['secrets'][1](ldr, node)
        except HomeAssistantError:
            val = None
        res['secrets'][node.value] = val
        return val

    def mock_except(
            ex,
            domain,
            config,  # pylint: disable=unused-variable
            hass=None):
        """Mock config.log_exception."""
        MOCKS['except'][1](ex, domain, config, hass)
        res['except'][domain] = config.get(domain, config)

    def mock_package_error(  # pylint: disable=unused-variable
            package, component, config, message):
        """Mock config_util._log_pkg_error."""
        MOCKS['package_error'][1](package, component, config, message)

        pkg_key = 'homeassistant.packages.{}'.format(package)
        res['except'][pkg_key] = config.get('homeassistant', {}) \
            .get('packages', {}).get(package)

    def mock_logger_exception(msg, *params):
        """Log logger.exceptions."""
        res['except'].setdefault(ERROR_STR, []).append(msg % params)
        MOCKS['logger_exception'][1](msg, *params)

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()['mock_' + key.replace('*', '')]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()
    # Ensure !secrets point to the patched function
    yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)

    try:
        with patch('homeassistant.util.logging.AsyncHandler._process'):
            bootstrap.from_config_file(config_path, skip_pip=True)
        res['secret_cache'] = dict(yaml.__SECRET_CACHE)
    except Exception as err:  # pylint: disable=broad-except
        print(color('red', 'Fatal error while loading config:'), str(err))
        res['except'].setdefault(ERROR_STR, []).append(err)
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        # Ensure !secrets point to the original function
        yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
        bootstrap.clear_secret_cache()

    return res
示例#5
0
def check(config_dir, secrets=False):
    """Perform a check by mocking hass load functions."""
    logging.getLogger('homeassistant.loader').setLevel(logging.CRITICAL)
    res = {
        'yaml_files': OrderedDict(),  # yaml_files loaded
        'secrets': OrderedDict(),  # secret cache and secrets loaded
        'except': OrderedDict(),  # exceptions raised (with config)
        'components': None,  # successful components
        'secret_cache': None,
    }

    # pylint: disable=unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config file names."""
        res['yaml_files'][filename] = True
        return MOCKS['load'][1](filename)

    # pylint: disable=unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS['secrets'][1](ldr, node)
        except HomeAssistantError:
            val = None
        res['secrets'][node.value] = val
        return val

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        if not secrets and key == 'secrets':
            continue
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()['mock_' + key.replace('*', '')]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()

    if secrets:
        # Ensure !secrets point to the patched function
        yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)

    try:

        class HassConfig():
            """Hass object with config."""
            def __init__(self, conf_dir):
                """Init the config_dir."""
                self.config = core.Config()
                self.config.config_dir = conf_dir

        loader.prepare(HassConfig(config_dir))

        res['components'] = check_ha_config_file(config_dir)

        res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE)

        for err in res['components'].errors:
            domain = err.domain or ERROR_STR
            res['except'].setdefault(domain, []).append(err.message)
            if err.config:
                res['except'].setdefault(domain, []).append(err.config)

    except Exception as err:  # pylint: disable=broad-except
        print(color('red', 'Fatal error while loading config:'), str(err))
        res['except'].setdefault(ERROR_STR, []).append(str(err))
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        if secrets:
            # Ensure !secrets point to the original function
            yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
        bootstrap.clear_secret_cache()

    return res