From fb6cb5f2364257d420460b794aebbcfed7262353 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Fri, 23 Sep 2016 16:34:13 +0100 Subject: [PATCH] add statuses filter to GET /service/{}/job can now pass in a query string `?statuses=x,y,z` to filter jobs based on `Job.job_status`. Not passing in a status or passing in an empty string is equivalent to selecting every filter type at once. --- app/dao/jobs_dao.py | 6 +++++- app/job/rest.py | 10 ++++++---- app/models.py | 9 ++++++++- tests/app/job/test_rest.py | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/app/dao/jobs_dao.py b/app/dao/jobs_dao.py index 8e7d7b3c2..2074d6ab6 100644 --- a/app/dao/jobs_dao.py +++ b/app/dao/jobs_dao.py @@ -27,10 +27,14 @@ def dao_get_job_by_service_id_and_job_id(service_id, job_id): return Job.query.filter_by(service_id=service_id, id=job_id).one() -def dao_get_jobs_by_service_id(service_id, limit_days=None, page=1, page_size=50): +def dao_get_jobs_by_service_id(service_id, limit_days=None, page=1, page_size=50, statuses=''): query_filter = [Job.service_id == service_id] if limit_days is not None: query_filter.append(cast(Job.created_at, sql_date) >= days_ago(limit_days)) + if statuses != ['']: + query_filter.append( + Job.job_status.in_(statuses) + ) return Job.query \ .filter(*query_filter) \ .order_by(desc(Job.created_at)) \ diff --git a/app/job/rest.py b/app/job/rest.py index ced973dba..3a8a60219 100644 --- a/app/job/rest.py +++ b/app/job/rest.py @@ -102,8 +102,10 @@ def get_jobs_by_service(service_id): else: limit_days = None + statuses = [x.strip() for x in request.args.get('statuses', '').split(',')] + page = int(request.args.get('page', 1)) - return jsonify(**get_paginated_jobs(service_id, limit_days, page)) + return jsonify(**get_paginated_jobs(service_id, limit_days, statuses, page)) @job.route('', methods=['POST']) @@ -140,14 +142,14 @@ def create_job(service_id): return jsonify(data=job_json), 201 -def get_paginated_jobs(service_id, limit_days, page): +def get_paginated_jobs(service_id, limit_days, statuses, page): pagination = dao_get_jobs_by_service_id( service_id, limit_days=limit_days, page=page, - page_size=current_app.config['PAGE_SIZE'] + page_size=current_app.config['PAGE_SIZE'], + statuses=statuses ) - data = job_schema.dump(pagination.items, many=True).data for job_data in data: statistics = dao_get_notification_outcomes_for_job(service_id, job_data['id']) diff --git a/app/models.py b/app/models.py index 91294c15d..0a6457667 100644 --- a/app/models.py +++ b/app/models.py @@ -304,7 +304,14 @@ JOB_STATUS_FINISHED = 'finished' JOB_STATUS_SENDING_LIMITS_EXCEEDED = 'sending limits exceeded' JOB_STATUS_SCHEDULED = 'scheduled' JOB_STATUS_CANCELLED = 'cancelled' - +JOB_STATUS_TYPES = [ + JOB_STATUS_PENDING, + JOB_STATUS_IN_PROGRESS, + JOB_STATUS_FINISHED, + JOB_STATUS_SENDING_LIMITS_EXCEEDED, + JOB_STATUS_SCHEDULED, + JOB_STATUS_CANCELLED +] class JobStatus(db.Model): __tablename__ = 'job_status' diff --git a/tests/app/job/test_rest.py b/tests/app/job/test_rest.py index f4dc01392..20d6a4248 100644 --- a/tests/app/job/test_rest.py +++ b/tests/app/job/test_rest.py @@ -14,7 +14,7 @@ from tests.app.conftest import ( sample_notification as create_notification ) from app.dao.templates_dao import dao_update_template -from app.models import NOTIFICATION_STATUS_TYPES +from app.models import NOTIFICATION_STATUS_TYPES, JOB_STATUS_TYPES, JOB_STATUS_PENDING def test_get_job_with_invalid_service_id_returns404(notify_api, sample_api_key, sample_service): @@ -655,6 +655,42 @@ def test_get_jobs_accepts_page_parameter( assert set(resp_json['links'].keys()) == {'prev', 'next', 'last'} +@pytest.mark.parametrize('statuses_filter, expected_statuses', [ + ('', JOB_STATUS_TYPES), + ('pending', [JOB_STATUS_PENDING]), + ('pending, in progress, finished, sending limits exceeded, scheduled, cancelled', JOB_STATUS_TYPES), + # bad statuses are accepted, just return no data + ('foo', []) +]) +def test_get_jobs_can_filter_on_statuses( + notify_db, + notify_db_session, + client, + sample_service, + statuses_filter, + expected_statuses +): + create_job(notify_db, notify_db_session, job_status='pending') + create_job(notify_db, notify_db_session, job_status='in progress') + create_job(notify_db, notify_db_session, job_status='finished') + create_job(notify_db, notify_db_session, job_status='sending limits exceeded') + create_job(notify_db, notify_db_session, job_status='scheduled') + create_job(notify_db, notify_db_session, job_status='cancelled') + + path = '/service/{}/job'.format(sample_service.id) + response = client.get( + path, + headers=[create_authorization_header()], + query_string={'statuses': statuses_filter} + ) + + assert response.status_code == 200 + resp_json = json.loads(response.get_data(as_text=True)) + from pprint import pprint + pprint(resp_json) + assert {x['job_status'] for x in resp_json['data']} == set(expected_statuses) + + def create_10_jobs(db, session, service, template): with freeze_time('2015-01-01T00:00:00') as the_time: for _ in range(10):