def validate_conf(self, name, config, step_addr): """ Use JSONSchema validation to validate the configuration. Validation errors will be reported by raising ConfigError. :param name: The name of the action or modifier. :param config: The actual configuration. :param step_addr: The address of the step in the test configuration. """ utils.schema_validate(config, self.schema, ConfigError, name, step_addr=step_addr)
def test_failure(self, mock_validate): try: utils.schema_validate('inst', 'sch', SchemaException, 'foo', 'bar', spam='one', maps='two') except SchemaException as exc: self.assertEqual(exc.msg, 'Failed to validate "foo/bar/a/[2]/b/[3]/c": ' 'validation failed') self.assertEqual(exc.kwargs, { 'spam': 'one', 'maps': 'two', }) else: self.fail('Failed to raise SchemaException')
def test_success(self, mock_validate): utils.schema_validate('inst', 'sch', SchemaException, 'foo', 'bar', spam='one', maps='two') mock_validate.assert_called_once_with('inst', 'sch')
def parse_step(cls, ctxt, step_addr, step_conf): """ Parse a step dictionary. :param ctxt: The context object. :param step_addr: The address of the step in the test configuration. :param step_conf: The description of the step. This may be a scalar string or a dictionary. :returns: A list of steps. """ # Make sure the step makes sense if isinstance(step_conf, six.string_types): # Convert string to a dict for uniformity of processing step_conf = {step_conf: None} elif not isinstance(step_conf, collections.Mapping): raise ConfigError( 'Unable to parse step configuration: expecting string or ' 'dictionary, not "%s"' % step_conf.__class__.__name__, step_addr, ) # Parse the configuration into the action and modifier classes # and the configuration to apply to each action_item = None mod_items = {} kwargs = {} # extra args for Step.__init__() for key, key_conf in step_conf.items(): # Handle special keys first if key in cls.schemas: # Validate the key utils.schema_validate(key_conf, cls.schemas[key], ConfigError, key, step_addr=step_addr) # Save the value kwargs[key] = key_conf # Is it an action? elif key in entry.points[NAMESPACE_ACTION]: if action_item is not None: raise ConfigError( 'Bad step configuration: action "%s" specified, ' 'but action "%s" already processed' % (key, action_item.name), step_addr, ) action_item = StepItem( entry.points[NAMESPACE_ACTION][key], key, key_conf) # OK, is it a modifier? elif key in entry.points[NAMESPACE_MODIFIER]: mod_class = entry.points[NAMESPACE_MODIFIER][key] # Store it in priority order mod_items.setdefault(mod_class.priority, []) mod_items[mod_class.priority].append(StepItem( mod_class, key, key_conf)) # Couldn't resolve it else: raise ConfigError( 'Bad step configuration: unable to resolve action ' '"%s"' % key, step_addr, ) # Make sure we have an action if action_item is None: raise ConfigError( 'Bad step configuration: no action specified', step_addr, ) # What is the action type? action_type = (Modifier.STEP if action_item.cls.step_action else Modifier.NORMAL) # OK, build our modifiers list and preprocess the action # configuration modifiers = [] for mod_item in utils.iter_prio_dict(mod_items): # Verify that the modifier is compatible with the # action if mod_item.cls.restriction & action_type == 0: raise ConfigError( 'Bad step configuration: modifier "%s" is ' 'incompatible with the action "%s"' % (mod_item.name, action_item.name), step_addr, ) # Initialize the modifier modifier = mod_item.init(ctxt, step_addr) # Add it to the list of modifiers modifiers.append(modifier) # Apply the modifier's configuration processing action_item.conf = modifier.action_conf( ctxt, action_item.cls, action_item.name, action_item.conf, step_addr) # Now we can initialize the action action = action_item.init(ctxt, step_addr) # Create the step step = cls(step_addr, action, modifiers, **kwargs) # If the final_action is a StepAction, invoke it now and # return the list of steps. We do this after creating the # Step object so that we can take advantage of its handling of # modifiers. if action_item.cls.step_action: return step(ctxt) # Not a step action, return the step as a list of one element return [step]