def test_init_validation(self): """Tests the validation done in __init__""" # Try minimal acceptable configuration BatchDefinitionV6(do_validate=True) # Invalid version definition = {'version': 'BAD'} self.assertRaises(InvalidDefinition, BatchDefinitionV6, definition, True) # Missing root_batch_id definition = {'version': '6', 'previous_batch': {'all_jobs': True}} self.assertRaises(InvalidDefinition, BatchDefinitionV6, definition, True) # Valid previous batch definition definition = { 'version': '6', 'previous_batch': { 'root_batch_id': 1234, 'forced_nodes': { 'all': False, 'nodes': ['job_a', 'job_b'] } } } BatchDefinitionV6(definition=definition, do_validate=True)
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_definition(self): """Returns the definition for this batch :returns: The definition for this batch :rtype: :class:`batch.definition.definition.BatchDefinition` """ return BatchDefinitionV6(definition=self.definition, do_validate=False).get_definition()
def _post_v6(self, request): """The v6 version for validating a new batch :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ recipe_type_id = rest_util.parse_int(request, 'recipe_type_id') definition_dict = rest_util.parse_dict(request, 'definition') configuration_dict = rest_util.parse_dict(request, 'configuration', required=False) # Make sure the recipe type exists try: recipe_type = RecipeType.objects.get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise BadParameter('Unknown recipe type: %d' % recipe_type_id) try: definition = BatchDefinitionV6(definition=definition_dict, do_validate=True).get_definition() configuration = BatchConfigurationV6( configuration=configuration_dict, do_validate=True).get_configuration() except InvalidDefinition as ex: raise BadParameter(unicode(ex)) except InvalidConfiguration as ex: raise BadParameter(unicode(ex)) # Validate the batch validation = Batch.objects.validate_batch_v6( recipe_type, definition, configuration=configuration) batch = validation.batch recipe_type_serializer = RecipeTypeBaseSerializerV6(batch.recipe_type) resp_dict = { 'is_valid': validation.is_valid, 'errors': [e.to_dict() for e in validation.errors], 'warnings': [w.to_dict() for w in validation.warnings], 'recipes_estimated': definition.estimated_recipes, 'recipe_type': recipe_type_serializer.data } if batch.superseded_batch: recipe_type_rev_serializer = RecipeTypeRevisionBaseSerializerV6( batch.superseded_batch.recipe_type_rev) prev_batch_dict = { 'recipe_type_rev': recipe_type_rev_serializer.data } resp_dict['prev_batch'] = prev_batch_dict if definition.prev_batch_diff: diff_v6 = convert_recipe_diff_to_v6_json( definition.prev_batch_diff) diff_dict = rest_util.strip_schema_version(diff_v6.get_dict()) prev_batch_dict['diff'] = diff_dict return Response(resp_dict)
def _create_v6(self, request): """The v6 version for creating batches :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) recipe_type_id = rest_util.parse_int(request, 'recipe_type_id') definition_dict = rest_util.parse_dict(request, 'definition') configuration_dict = rest_util.parse_dict(request, 'configuration', required=False) # Make sure the recipe type exists try: recipe_type = RecipeType.objects.get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise BadParameter('Unknown recipe type: %d' % recipe_type_id) # Validate and create the batch try: definition = BatchDefinitionV6(definition=definition_dict, do_validate=True).get_definition() configuration = BatchConfigurationV6( configuration=configuration_dict, do_validate=True).get_configuration() with transaction.atomic(): event = TriggerEvent.objects.create_trigger_event( 'USER', None, {'user': '******'}, now()) batch = Batch.objects.create_batch_v6( title, description, recipe_type, event, definition, configuration=configuration) CommandMessageManager().send_messages( [create_batch_recipes_message(batch.id)]) except InvalidDefinition as ex: raise BadParameter(unicode(ex)) except InvalidConfiguration as ex: raise BadParameter(unicode(ex)) # Fetch the full batch with details batch = Batch.objects.get_details_v6(batch.id) url = reverse('batch_details_view', args=[batch.id], request=request) serializer = BatchDetailsSerializerV6(batch) return Response(serializer.data, status=status.HTTP_201_CREATED, headers={'Location': url})
def test_create_from_json(self): """Tests creating a BatchDefinition from a JSON""" # Valid previous batch definition definition = { 'version': '6', 'previous_batch': { 'root_batch_id': 1234, 'job_names': ['job_a', 'job_b'], 'all_jobs': True } } json = BatchDefinitionV6(definition=definition, do_validate=True) self.assertIsNotNone(json.get_definition())
def create_batch(title=None, description=None, recipe_type=None, definition=None, configuration=None, is_creation_done=False, recipes_total=None): """Creates a batch model for unit testing :returns: The batch model :rtype: :class:`batch.models.Batch` """ if not recipe_type: recipe_type = recipe_test_utils.create_recipe_type_v6() if not definition: definition = BatchDefinition() # Create a previous batch so we can create a valid definition # TODO: this can be replaced by a DataSet once they are implemented prev_batch = Batch() prev_batch.recipe_type = recipe_type prev_batch.recipe_type_rev = RecipeTypeRevision.objects.get_revision(recipe_type.name, recipe_type.revision_num) prev_batch.event = TriggerEvent.objects.create_trigger_event('USER', None, {'user': '******'}, now()) prev_batch.is_creation_done = True prev_batch.recipes_total = 10 prev_batch.save() prev_batch.root_batch_id = prev_batch.id prev_batch.save() definition.root_batch_id = prev_batch.root_batch_id if not isinstance(definition, BatchDefinition): definition = BatchDefinitionV6(definition).get_definition() if not configuration: configuration = BatchConfiguration() if not title: global BATCH_TITLE_COUNTER title = 'Test Batch Title %i' % BATCH_TITLE_COUNTER BATCH_TITLE_COUNTER += 1 if not description: global BATCH_DESCRIPTION_COUNTER description = 'Test Batch Description %i' % BATCH_DESCRIPTION_COUNTER BATCH_DESCRIPTION_COUNTER += 1 event = TriggerEvent.objects.create_trigger_event('USER', None, {'user': '******'}, now()) batch = Batch.objects.create_batch_v6(title, description, recipe_type, event, definition, configuration) if is_creation_done: batch.is_creation_done = True if recipes_total is not None: batch.recipes_total = recipes_total batch.save() return batch
def test_validate(self): """Tests calling BatchDefinition.validate()""" recipe_type_1 = recipe_test_utils.create_recipe_type() recipe_type_2 = recipe_test_utils.create_recipe_type() bad_recipe_type_prev_batch = batch_test_utils.create_batch( recipe_type=recipe_type_1) still_creating_prev_batch = batch_test_utils.create_batch( recipe_type=recipe_type_2) prev_batch = batch_test_utils.create_batch(recipe_type=recipe_type_2, is_creation_done=True, recipes_total=10) batch = batch_test_utils.create_batch(recipe_type=recipe_type_2) # No recipes would be created json_dict = {'version': '6'} json = BatchDefinitionV6(definition=json_dict) definition = json.get_definition() batch.superseded_batch = None self.assertRaises(InvalidDefinition, definition.validate, batch) # Mismatched recipe types json_dict = { 'version': '6', 'previous_batch': { 'root_batch_id': bad_recipe_type_prev_batch.root_batch_id } } json = BatchDefinitionV6(definition=json_dict) definition = json.get_definition() batch.superseded_batch = bad_recipe_type_prev_batch self.assertRaises(InvalidDefinition, definition.validate, batch) # Previous batch not done creating recipes json_dict = { 'version': '6', 'previous_batch': { 'root_batch_id': still_creating_prev_batch.root_batch_id } } json = BatchDefinitionV6(definition=json_dict) definition = json.get_definition() batch.superseded_batch = still_creating_prev_batch self.assertRaises(InvalidDefinition, definition.validate, batch) # Previous batch cannot be reprocessed json_dict = { 'version': '6', 'previous_batch': { 'root_batch_id': prev_batch.root_batch_id } } json = BatchDefinitionV6(definition=json_dict) definition = json.get_definition() batch.superseded_batch = prev_batch with patch('batch.definition.definition.RecipeDiff') as mock_delta: instance = mock_delta.return_value instance.can_be_reprocessed = False self.assertRaises(InvalidDefinition, definition.validate, batch) # Valid definition with previous batch json_dict = { 'version': '6', 'previous_batch': { 'root_batch_id': prev_batch.root_batch_id } } json = BatchDefinitionV6(definition=json_dict) definition = json.get_definition() batch.superseded_batch = prev_batch definition.validate(batch)