def test_convert_definition_to_v6(self): """Tests calling convert_definition_to_v6()""" # Try definition with nothing set definition = BatchDefinition() json = convert_definition_to_v6(definition) BatchDefinitionV6(definition=json.get_dict(), do_validate=True) # Revalidate # Try definition with previous batch ID set definition = BatchDefinition() definition.root_batch_id = 1234 json = convert_definition_to_v6(definition) BatchDefinitionV6(definition=json.get_dict(), do_validate=True) # Revalidate self.assertEqual(json.get_definition().root_batch_id, definition.root_batch_id)
def get_v6_definition_json(self): """Returns the batch definition in v6 of the JSON schema :returns: The batch definition in v6 of the JSON schema :rtype: dict """ # Handle batches with old (pre-v6) definitions if 'version' in self.definition and self.definition['version'] == '1.0': return {} return rest_utils.strip_schema_version(convert_definition_to_v6(self.get_definition()).get_dict())
def validate_batch_v6(self, recipe_type, definition, configuration=None): """Validates the given recipe type, definition, and configuration for creating a new batch :param recipe_type: The type of recipes that will be created for this batch :type recipe_type: :class:`recipe.models.RecipeType` :param definition: The definition for running the batch :type definition: :class:`batch.definition.definition.BatchDefinition` :param configuration: The batch configuration :type configuration: :class:`batch.configuration.configuration.BatchConfiguration` :returns: The batch validation :rtype: :class:`batch.models.BatchValidation` """ is_valid = True errors = [] warnings = [] try: batch = Batch() batch.recipe_type = recipe_type batch.recipe_type_rev = RecipeTypeRevision.objects.get_revision( recipe_type.name, recipe_type.revision_num) batch.definition = convert_definition_to_v6(definition).get_dict() batch.configuration = convert_configuration_to_v6( configuration).get_dict() if definition.root_batch_id is not None: # Find latest batch with the root ID try: superseded_batch = Batch.objects.get_batch_from_root( definition.root_batch_id) except Batch.DoesNotExist: raise InvalidDefinition( 'PREV_BATCH_NOT_FOUND', 'No batch with that root ID exists') batch.root_batch_id = superseded_batch.root_batch_id batch.superseded_batch = superseded_batch warnings.extend(definition.validate(batch)) warnings.extend(configuration.validate(batch)) except ValidationException as ex: is_valid = False errors.append(ex.error) batch.recipes_estimated = definition.estimated_recipes return BatchValidation(is_valid, errors, warnings, batch)
def create_batch_v6(self, title, description, recipe_type, event, definition, configuration=None): """Creates a new batch that will contain a collection of recipes to process. The definition and configuration will be stored in version 6 of their respective schemas. This method will only create the batch, not its recipes. To create the batch's recipes, a CreateBatchRecipes message needs to be sent to the messaging backend. :param title: The human-readable name of the batch :type title: string :param description: A human-readable description of the batch :type description: string :param recipe_type: The type of recipes that will be created for this batch :type recipe_type: :class:`recipe.models.RecipeType` :param event: The event that created this batch :type event: :class:`trigger.models.TriggerEvent` :param definition: The definition for running the batch :type definition: :class:`batch.definition.definition.BatchDefinition` :param configuration: The batch configuration :type configuration: :class:`batch.configuration.configuration.BatchConfiguration` :returns: The newly created batch :rtype: :class:`batch.models.Batch` :raises :class:`batch.configuration.exceptions.InvalidConfiguration`: If the configuration is invalid :raises :class:`batch.definition.exceptions.InvalidDefinition`: If the definition is invalid """ batch = Batch() batch.title = title batch.description = description batch.recipe_type = recipe_type batch.recipe_type_rev = RecipeTypeRevision.objects.get_revision( recipe_type.name, recipe_type.revision_num) batch.event = event batch.definition = convert_definition_to_v6(definition).get_dict() batch.configuration = convert_configuration_to_v6( configuration).get_dict() with transaction.atomic(): if definition.root_batch_id is not None: # Find latest batch with the root ID and supersede it try: superseded_batch = Batch.objects.get_locked_batch_from_root( definition.root_batch_id) except Batch.DoesNotExist: raise InvalidDefinition( 'PREV_BATCH_NOT_FOUND', 'No batch with that root ID exists') batch.root_batch_id = superseded_batch.root_batch_id batch.superseded_batch = superseded_batch self.supersede_batch(superseded_batch.id, now()) definition.validate(batch) configuration.validate(batch) batch.recipes_estimated = definition.estimated_recipes batch.save() if batch.root_batch_id is None: # Batches with no superseded batch are their own root batch.root_batch_id = batch.id Batch.objects.filter(id=batch.id).update( root_batch_id=batch.id) # Create models for batch metrics batch_metrics_models = [] for job_name in recipe_type.get_definition().get_topological_order( ): batch_metrics_model = BatchMetrics() batch_metrics_model.batch_id = batch.id batch_metrics_model.job_name = job_name batch_metrics_models.append(batch_metrics_model) BatchMetrics.objects.bulk_create(batch_metrics_models) return batch