From 834801d19bfb803d87dcf6612bcba92176f40ac3 Mon Sep 17 00:00:00 2001 From: Adam Shimali Date: Fri, 15 Jan 2016 15:48:05 +0000 Subject: [PATCH 1/2] Added endpoints for creating job, and getting job/jobs. --- app/__init__.py | 3 ++ app/dao/jobs_dao.py | 4 +- app/job/rest.py | 51 ++++++++++++++++++++ app/models.py | 1 + app/schemas.py | 9 +++- tests/app/job/__init__.py | 0 tests/app/job/test_job_rest.py | 88 ++++++++++++++++++++++++++++++++++ 7 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 app/job/rest.py create mode 100644 tests/app/job/__init__.py create mode 100644 tests/app/job/test_job_rest.py diff --git a/app/__init__.py b/app/__init__.py index edf5291bf4..7607fc95cf 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -30,10 +30,13 @@ def create_app(config_name): from app.user.rest import user as user_blueprint from app.template.rest import template as template_blueprint from app.status.healthcheck import status as status_blueprint + from app.job.rest import job as job_blueprint + application.register_blueprint(service_blueprint, url_prefix='/service') application.register_blueprint(user_blueprint, url_prefix='/user') application.register_blueprint(template_blueprint, url_prefix="/template") application.register_blueprint(status_blueprint, url_prefix='/status') + application.register_blueprint(job_blueprint, url_prefix='/job') return application diff --git a/app/dao/jobs_dao.py b/app/dao/jobs_dao.py index 06e56fb979..65d300522c 100644 --- a/app/dao/jobs_dao.py +++ b/app/dao/jobs_dao.py @@ -7,8 +7,8 @@ def save_job(job): db.session.commit() -def get_job_by_id(id): - return Job.query.get(id) +def get_job_by_id(job_id): + return Job.query.filter_by(id=job_id).one() def get_jobs_by_service(service_id): diff --git a/app/job/rest.py b/app/job/rest.py new file mode 100644 index 0000000000..cab2082c69 --- /dev/null +++ b/app/job/rest.py @@ -0,0 +1,51 @@ +from flask import ( + Blueprint, + jsonify, + request +) + +from sqlalchemy.exc import DataError +from sqlalchemy.orm.exc import NoResultFound + +from app.dao.jobs_dao import ( + save_job, + get_job_by_id, + get_jobs +) + +from app.schemas import ( + job_schema, + jobs_schema +) + +job = Blueprint('job', __name__) + + +@job.route('/', methods=['GET']) +@job.route('/', methods=['GET']) +def get_job(job_id=None): + if job_id: + try: + job = get_job_by_id(job_id) + data, errors = job_schema.dump(job) + return jsonify(data=data) + except DataError: + return jsonify(result="error", message="Invalid job id"), 400 + except NoResultFound: + return jsonify(result="error", message="Job not found"), 404 + else: + jobs = get_jobs() + data, errors = jobs_schema.dump(jobs) + return jsonify(data=data) + + +@job.route('/', methods=['POST']) +def create_job(): + job, errors = job_schema.load(request.get_json()) + if errors: + return jsonify(result="error", message=errors), 400 + try: + save_job(job) + except Exception as e: + return jsonify(result="error", message=str(e)), 500 + return jsonify(data=job_schema.dump(job).data), 201 diff --git a/app/models.py b/app/models.py index 07d03a1df3..8b265143e9 100644 --- a/app/models.py +++ b/app/models.py @@ -108,6 +108,7 @@ class Job(db.Model): service_id = db.Column(db.BigInteger, db.ForeignKey('services.id'), index=True, unique=False) service = db.relationship('Service', backref=db.backref('jobs', lazy='dynamic')) template_id = db.Column(db.BigInteger, db.ForeignKey('templates.id'), index=True, unique=False) + template = db.relationship('Template', backref=db.backref('jobs', lazy='dynamic')) created_at = db.Column( db.DateTime, index=False, diff --git a/app/schemas.py b/app/schemas.py index 3f28b9e34d..f5d9a03494 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -25,7 +25,7 @@ class Meta: class TemplateSchema(ma.ModelSchema): class Meta: model = models.Template - exclude = ("updated_at", "created_at", "service_id") + exclude = ("updated_at", "created_at", "service_id", "jobs") class TokenSchema(ma.ModelSchema): @@ -34,6 +34,11 @@ class Meta: exclude = ["service"] +class JobSchema(ma.ModelSchema): + class Meta: + model = models.Job + + user_schema = UserSchema() users_schema = UserSchema(many=True) service_schema = ServiceSchema() @@ -42,3 +47,5 @@ class Meta: templates_schema = TemplateSchema(many=True) token_schema = TokenSchema() tokens_schema = TokenSchema(many=True) +job_schema = JobSchema() +jobs_schema = JobSchema(many=True) diff --git a/tests/app/job/__init__.py b/tests/app/job/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/app/job/test_job_rest.py b/tests/app/job/test_job_rest.py new file mode 100644 index 0000000000..9e8bf6d64a --- /dev/null +++ b/tests/app/job/test_job_rest.py @@ -0,0 +1,88 @@ +import json +import uuid + +from flask import url_for + +from tests.app.conftest import sample_job as create_job + + +def test_get_jobs(notify_api, notify_db, notify_db_session, sample_template): + + _setup_jobs(notify_db, notify_db_session, sample_template) + + with notify_api.test_request_context(): + with notify_api.test_client() as client: + response = client.get(url_for('job.get_job')) + assert response.status_code == 200 + resp_json = json.loads(response.get_data(as_text=True)) + assert len(resp_json['data']) == 5 + + +def test_get_job_with_invalid_id_returns400(notify_api, notify_db, + notify_db_session, + sample_template): + with notify_api.test_request_context(): + with notify_api.test_client() as client: + response = client.get(url_for('job.get_job', job_id='invalid_id')) + assert response.status_code == 400 + resp_json = json.loads(response.get_data(as_text=True)) + assert resp_json == {'message': 'Invalid job id', + 'result': 'error'} + + +def test_get_job_with_unknown_id_returns404(notify_api, notify_db, + notify_db_session, + sample_template): + random_id = str(uuid.uuid4()) + with notify_api.test_request_context(): + with notify_api.test_client() as client: + response = client.get(url_for('job.get_job', job_id=random_id)) + assert response.status_code == 404 + resp_json = json.loads(response.get_data(as_text=True)) + assert resp_json == {'message': 'Job not found', 'result': + 'error'} + + +def test_get_job_by_id(notify_api, notify_db, notify_db_session, + sample_job): + job_id = str(sample_job.id) + with notify_api.test_request_context(): + with notify_api.test_client() as client: + response = client.get(url_for('job.get_job', job_id=job_id)) + assert response.status_code == 200 + resp_json = json.loads(response.get_data(as_text=True)) + assert resp_json['data']['id'] == job_id + + +def test_post_job(notify_api, notify_db, notify_db_session, sample_template): + job_id = uuid.uuid4() + template_id = sample_template.id + service_id = sample_template.service.id + original_file_name = 'thisisatest.csv' + data = { + 'id': str(job_id), + 'service': service_id, + 'template': template_id, + 'original_file_name': original_file_name + } + headers = [('Content-Type', 'application/json')] + with notify_api.test_request_context(): + with notify_api.test_client() as client: + response = client.post( + url_for('job.create_job'), + data=json.dumps(data), + headers=headers) + assert response.status_code == 201 + + resp_json = json.loads(response.get_data(as_text=True)) + + assert resp_json['data']['id'] == str(job_id) + assert resp_json['data']['service'] == service_id + assert resp_json['data']['template'] == template_id + assert resp_json['data']['original_file_name'] == original_file_name + + +def _setup_jobs(notify_db, notify_db_session, template, number_of_jobs=5): + for i in range(number_of_jobs): + create_job(notify_db, notify_db_session, service=template.service, + template=template) From 99c38314b559345c5a2b337c351447e18b0c99d2 Mon Sep 17 00:00:00 2001 From: Adam Shimali Date: Fri, 15 Jan 2016 16:34:48 +0000 Subject: [PATCH 2/2] Removed trailing slash from job rest base url --- app/job/rest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/job/rest.py b/app/job/rest.py index cab2082c69..26ba4ae9b0 100644 --- a/app/job/rest.py +++ b/app/job/rest.py @@ -22,7 +22,7 @@ @job.route('/', methods=['GET']) -@job.route('/', methods=['GET']) +@job.route('', methods=['GET']) def get_job(job_id=None): if job_id: try: @@ -39,7 +39,7 @@ def get_job(job_id=None): return jsonify(data=data) -@job.route('/', methods=['POST']) +@job.route('', methods=['POST']) def create_job(): job, errors = job_schema.load(request.get_json()) if errors: