Exemplo n.º 1
0
class ProgressLog(flask_restful.Resource):
    """Base class for a progress log resource.

    Attributes:
        client: datastore Client object used to communicate with Datastore.
        run_database: SystemRunDatabase object for querying and storing
            system runs using the client.
        log_database: ProgressLogDatabase object for querying and storing
            progress logs using the client.
        attempt_database: ImportAttemptDatabase object for querying and storing
            import attempts using the client.
    """
    parser = reqparse.RequestParser()
    required_fields = [(_LOG.level, ), (_LOG.message, )]
    optional_fields = [(_LOG.time_logged, ), (_LOG.run_id, ),
                       (_LOG.attempt_id, )]
    utils.add_fields(parser, required_fields, required=True)
    utils.add_fields(parser, optional_fields, required=False)

    def __init__(self, client=None, message_manager=None):
        """Constructs a ProgressLog.

        Args:
            client: datastore Client object used to communicate with Datastore.
            message_manager: LogMessageManager object used to store and retreive
                log messages.
        """
        if not client:
            client = utils.create_datastore_client()
        self.client = client
        self.run_database = system_run_database.SystemRunDatabase(self.client)
        self.log_database = progress_log_database.ProgressLogDatabase(
            self.client, message_manager)
        self.attempt_database = import_attempt_database.ImportAttemptDatabase(
            self.client)
Exemplo n.º 2
0
class ImportAttempt(base_resource.BaseResource):
    """Base class for an import attempt resource.

    Attributes:
        client: datastore Client object used to communicate with Datastore
        database: ImportAttemptDatabase object for querying and storing
            import attempts using the client
    """
    parser = reqparse.RequestParser()
    # The parser looks for these fields in the request body.
    # The Content-Type of the request must be application/json.
    optional_fields = ((_MODEL.attempt_id, str), (_MODEL.run_id,
                                                  str), (_MODEL.import_name,),
                       (_MODEL.absolute_import_name,), (_MODEL.provenance_url,),
                       (_MODEL.provenance_description,), (_MODEL.status,),
                       (_MODEL.time_created,), (_MODEL.time_completed,),
                       (_MODEL.logs, str, 'append'), (_MODEL.import_inputs,
                                                      dict, 'append'))
    utils.add_fields(parser, optional_fields, required=False)

    def __init__(self, client=None):
        """Constructs an ImportAttempt."""
        if not client:
            client = utils.create_datastore_client()
        self.client = client
        self.database = import_attempt_database.ImportAttemptDatabase(
            self.client)
Exemplo n.º 3
0
    def test_combined(self):
        """Tests that add_fields correctly adds both required and
        optional fields to a parser."""
        parser = reqparse.RequestParser()
        required_fields = [('pr_number', int)]
        optional_fields = [('logs', dict, 'append')]
        utils.add_fields(parser, required_fields, required=True)
        utils.add_fields(parser, optional_fields, required=False)

        log_1 = {'level': 'info', 'message': 'ahhhhh'}
        log_2 = {'level': 'error', 'message': 'noooo'}
        with_pr_and_logs = {'pr_number': 1, 'logs': [log_1, log_2]}

        with main.FLASK_APP.test_request_context(json=with_pr_and_logs):
            args = parser.parse_args()
            self.assertEqual(with_pr_and_logs, args)
Exemplo n.º 4
0
    def test_required_fields(self):
        """Tests that add_fields correctly adds required fields
        to the parser."""
        parser = reqparse.RequestParser()
        required_fields = [('pr_number', int)]
        utils.add_fields(parser, required_fields, required=True)

        with_pr = {'pr_number': 1, 'import_name': 'name'}
        with main.FLASK_APP.test_request_context(json=with_pr):
            args = parser.parse_args()
            self.assertEqual({'pr_number': 1}, args)

        without_pr = {'import_name': 'name'}
        with main.FLASK_APP.test_request_context(json=without_pr):
            with self.assertRaises(Exception) as context:
                parser.parse_args()
                self.assertEqual(400, context.exception.code)
Exemplo n.º 5
0
    def test_optional_fields(self):
        """Tests that add_fields correctly adds optional fields
        to the parser."""
        parser = reqparse.RequestParser()
        optional_fields = [('attempt_id', str), ('import_name', str, 'store')]
        utils.add_fields(parser, optional_fields, required=False)

        with main.FLASK_APP.test_request_context(json={'pr_number': 1}):
            args = parser.parse_args()
            self.assertEqual({}, args)

        only_attempt_id = {'attempt_id': "0"}
        with main.FLASK_APP.test_request_context(json=only_attempt_id):
            args = parser.parse_args()
            self.assertEqual(only_attempt_id, args)

        both = {'attempt_id': '0', 'import_name': 'name'}
        with main.FLASK_APP.test_request_context(json=both):
            args = parser.parse_args()
            self.assertEqual(both, args)
Exemplo n.º 6
0
class SystemRun(flask_restful.Resource):
    """Base class for a system run resource.

    Attributes:
        client: datastore Client object used to communicate with Datastore
        database: SystemRunDatabase object for querying and storing
            system runs using the client
    """
    parser = reqparse.RequestParser()
    optional_fields = ((_MODEL.run_id, str), (_MODEL.repo_name,),
                       (_MODEL.branch_name,), (_MODEL.pr_number, int),
                       (_MODEL.commit_sha,), (_MODEL.time_created,),
                       (_MODEL.time_completed,), (_MODEL.import_attempts, str,
                                                  'append'),
                       (_MODEL.logs, str, 'append'), (_MODEL.status,))
    utils.add_fields(parser, optional_fields, required=False)

    def __init__(self, client=None):
        """Constructs a SystemRun."""
        if not client:
            client = utils.create_datastore_client()
        self.client = client
        self.database = system_run_database.SystemRunDatabase(self.client)
Exemplo n.º 7
0
    def test_dict(self):
        """Tests parsing dicts."""
        parser = reqparse.RequestParser()
        utils.add_fields(parser, [('field', dict, 'append')], required=True)

        body = {'field': [{'abc': '1'}, {'def': '2', 'ghi': '3'}, {}]}
        with main.FLASK_APP.test_request_context(json=body):
            self.assertEqual(body, parser.parse_args())

        # Empty list throws exception if field required
        parser = reqparse.RequestParser()
        utils.add_fields(parser, [('field', dict, 'append')], required=True)
        body = {'field': []}
        with self.assertRaises(exceptions.BadRequest):
            with main.FLASK_APP.test_request_context(json=body):
                parser.parse_args()

        # Empty list accepted if field not required
        parser = reqparse.RequestParser()
        utils.add_fields(parser, [('field', dict, 'append')], required=False)
        body = {'field': []}
        with main.FLASK_APP.test_request_context(json=body):
            self.assertEqual({}, parser.parse_args())
Exemplo n.º 8
0
class SystemRunList(system_run.SystemRun):
    """API for querying a list of system runs based on some criteria and
    for creating new system runs.

    See SystemRun.
    """
    _parser = system_run.SystemRun.parser.copy()
    utils.add_fields(_parser, (('limit', int), ('order', str, 'append')),
                     required=False)

    def get(self):
        """Retrieves a list of system runs that pass the filter defined by
        the key-value mappings in the request body.

        The filter can only contain fields defined by SystemRun.

        This endpoint accepts two url arguments: limit and order.
        limit is an integer that specifies the maximum number of system runs
        returned and order is a list of field names to order the returned
        system runs by. Prepend "-" to a field name to sort it in
        descending order. The list can be specified by repeated keys. E.g.,
        ?order=status&order=-time_created.

        Returns:
            A list of system runs each as a datastore Entity object
            if successful. Otherwise, (error message, error code), where
            the error message is a string and the error code is an int.
        """
        args = None
        try:
            args = SystemRunList._parser.parse_args(strict=True)
        except exceptions.BadRequest as exc:
            return exc.description, exc.code
        order = args.pop('order', ())
        limit = args.pop('limit', None)
        for field in args:
            if field not in system_run_model.FIELDS:
                return (f'Field {field} is not a valid field for a system run',
                        http.HTTPStatus.BAD_REQUEST)
        return self.database.filter(args, order=order, limit=limit)

    def post(self):
        """Creates a new system run with the fields provided in the
        request body.

        Returns:
            The created system run as a datastore Entity object with
            run_id set. Otherwise, (error message, error code), where
            the error message is a string and the error code is an int.
        """
        args = system_run.SystemRunByID.parser.parse_args()
        valid, err, code = validation.is_system_run_valid(args)
        if not valid:
            return err, code

        # Only the API can modify these fields
        args.pop('run_id', None)
        args.pop('import_attempts', None)
        args.pop('logs', None)
        system_run.set_system_run_default_values(args)

        with self.client.transaction():
            run = self.database.get(make_new=True)
            run.update(args)
            return self.database.save(run)