示例#1
0
    def get_node_resource_adapter_config(self, node: Node) \
            -> Dict[str, Any]:
        """
        Deserialize resource adapter configuration to key/value pairs

        """

        #
        # Default settings dict is blank
        #
        config: Dict[str, str] = {}

        #
        # Load settings from class settings definitions if any of them
        # have default values
        #
        config.update(self._load_config_from_class())

        #
        # Load settings from default profile in database, if it exists
        #
        config.update(self._load_config_from_database())

        #
        # Load node specific settings
        #
        override_config: Dict[str, Any] = {}
        if node.instance and \
                node.instance.resource_adapter_configuration and \
                node.instance.resource_adapter_configuration.name != 'Default':
            for c in node.instance.resource_adapter_configuration.configuration:
                override_config[c.key] = c.value

        config.update(override_config)

        #
        # Dump the config with transformed values. Don't bother validating
        # here, as we will consider the node already exists in it's current
        # state
        #
        try:
            validator = ConfigurationValidator(self.settings)
            validator.load(config)
            processed_config: Dict[str, Any] = validator.dump()
        except ValidationError as ex:
            raise ConfigurationError(str(ex))

        #
        # Perform any required additional processing on the config
        #
        self.process_config(processed_config)

        return processed_config
def test_partial_validation():
    s = {
        'integer': settings.IntegerSetting(required=True),
        'string': settings.StringSetting()
    }
    p = ConfigurationValidator(s)

    #
    # Assert that missing fields do not raise a validation error for
    # partial validation
    #
    p.validate(full=False)

    #
    # Assert that partial validation does validate field values
    #
    p['integer'] = 'abc'
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    assert 'integer' in err.errors.keys()

    #
    # Assert that partial validation does validate field names
    #
    p['xyz'] = 'abc'
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    assert 'xyz' in err.errors.keys()
def test_validate_requires():
    s = {
        'integer': settings.IntegerSetting(requires=['string']),
        'string': settings.StringSetting(),
        'bool': settings.BooleanSetting(requires=['sub_requirement']),
        'sub_requirement': settings.StringSetting(),
    }
    p = ConfigurationValidator(s)

    #
    # Assert requires validation error raised
    #
    p['integer'] = '1'
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    #
    # Should not raise a validation error, because requires flag is
    # set on integer only
    #
    assert 'string' not in err.errors.keys()
    #
    # Should raise a validation error, because it has a requires setting
    #
    assert str(err.errors['integer']) == 'Requires string'

    #
    # Assert no validation errors
    #
    p['string'] = 'integer satisfied'
    p.validate()

    #
    # Should be no validation error if bool is falsy
    #
    p['bool'] = 'False'
    p.validate()

    #
    # Should have a validation error when truthy
    #
    p['bool'] = 'True'
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    assert str(err.errors['bool']) == 'Requires sub_requirement'
def test_defaults():
    s = {
        'integer': settings.IntegerSetting(default='3'),
        'string': settings.StringSetting(default='abc')
    }
    p = ConfigurationValidator(s)

    #
    # Assert default values are set
    #
    assert p['integer'] == '3'
    assert p['string'] == 'abc'
    def validate_config(
        self,
        profile: str = DEFAULT_CONFIGURATION_PROFILE_NAME
    ) -> ConfigurationValidator:
        """
        Validates the configuration profile.

        :param str profile: the name of the configuration profile to validate

        :return ConfigurationValidator: the validator, loaded with the
                                        validated data

        :raises ValidationError:

        """
        validator = ConfigurationValidator(self.settings)

        #
        # Load settings from class settings definitions if any of them
        # have default values
        #
        validator.load(self._load_config_from_class())

        #
        # Load settings from default profile in database, if it exists
        #
        validator.load(self._load_config_from_database())

        #
        # Load settings from a specific profile, if one was specified
        #
        if profile and profile != DEFAULT_CONFIGURATION_PROFILE_NAME:
            validator.load(self._load_config_from_database(profile))

        #
        # Validate the settings
        #
        validator.validate()

        return validator
def test_validate_mutually_exclusive():
    s = {
        'integer': settings.IntegerSetting(mutually_exclusive=['string']),
        'string': settings.StringSetting()
    }
    p = ConfigurationValidator(s)

    #
    # Assert no validation errors raised
    #
    p['integer'] = '1'
    p.validate()

    #
    # Assert mutually exclusive validation error raised
    #
    p['string'] = 'abc'
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    #
    # Should not raise a validation error, because mutually exclusive flag is
    # set on integer only
    #
    assert 'string' not in err.errors.keys()
    #
    # Should raise a validation error, because it has mutually exclusive
    # setting
    #
    assert str(err.errors['integer']) == 'Mutually exclusive with string'
def test_required():
    s = {
        'integer': settings.IntegerSetting(required=True),
        'string': settings.StringSetting()
    }
    p = ConfigurationValidator(s)

    #
    # Assert that a required value, if not provided, throws an validation
    # error
    #
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    #
    # Should not raise a validation error, because it is not marked as
    # required
    #
    assert 'string' not in err.errors.keys()
    #
    # Should raise a validation error, because it is required
    #
    assert str(err.errors['integer']) == 'Setting is required'

    #
    # Assert that if the value is in fact provided, no errors are raised
    #
    p['integer'] = '5'
    p.validate()
def test_validate_requires():
    s = {
        'integer': settings.IntegerSetting(requires=['string']),
        'string': settings.StringSetting()
    }
    p = ConfigurationValidator(s)

    #
    # Assert requires validation error raised
    #
    p['integer'] = '1'
    with pytest.raises(ValidationError) as err_info:
        p.validate()
    err: ValidationError = err_info.value
    #
    # Should not raise a validation error, because requires flag is
    # set on integer only
    #
    assert 'string' not in err.errors.keys()
    #
    # Should raise a validation error, because it has a requires setting
    #
    assert str(err.errors['integer']) == 'Requires string'

    #
    # Assert no validation errors
    #
    p['string'] = 'abc'
    p.validate()
def test_dump():
    s = {
        'bool': settings.BooleanSetting(),
        'list_bool': settings.BooleanSetting(list=True),
        'integer': settings.IntegerSetting(),
        'list_integer': settings.IntegerSetting(list=True),
        'string': settings.StringSetting(),
        'list_string': settings.StringSetting(list=True),
        'file': settings.FileSetting(must_exist=False)
    }
    p = ConfigurationValidator(s)

    #
    # Test data loading
    #
    data_to_load = {
        'bool': 'True',
        'list_bool': 'True, false',
        'integer': '3',
        'list_integer': '4, 5',
        'string': 'abc',
        'list_string': 'wz, yz',
        'file': 'file.txt'
    }
    p.load(data_to_load)

    #
    # Perform full validation
    #
    p.validate(full=True)

    #
    # Assert that dumped data is properly transformed
    #
    expected_data = {
        'bool': True,
        'list_bool': [True, False],
        'integer': 3,
        'list_integer': [4, 5],
        'string': 'abc',
        'list_string': ['wz', 'yz'],
        'file': 'file.txt'
    }
    assert p.dump() == expected_data