diff --git a/pybossa/redis_lock.py b/pybossa/redis_lock.py index 3a7f27fc31..9b4003e9f9 100644 --- a/pybossa/redis_lock.py +++ b/pybossa/redis_lock.py @@ -233,7 +233,7 @@ def get_task_category_lock(self, project_id, user_id=None, category=None, exclud def acquire_reserve_task_lock(self, project_id, task_id, user_id, category): - if not(project_id or user_id or task_id or category): + if not(project_id and user_id and task_id and category): raise BadRequest('Missing required parameters') # check task category reserved by user diff --git a/pybossa/sched.py b/pybossa/sched.py index 1758067de4..ce219318a2 100644 --- a/pybossa/sched.py +++ b/pybossa/sched.py @@ -252,12 +252,6 @@ def get_candidate_task_ids(project_id, user_id=None, user_ip=None, data = query.limit(limit).offset(offset).all() return _handle_tuples(data) -def task_contains_category(task_id, category): - task = task_repo.get_task(task_id) - if not (task and category): - return False - return all([field in task.info for field in category]) - def locked_scheduler(query_factory): @wraps(query_factory) diff --git a/test/test_reserve_task_category.py b/test/test_reserve_task_category.py index 633bb402d6..a3db26889d 100644 --- a/test/test_reserve_task_category.py +++ b/test/test_reserve_task_category.py @@ -26,9 +26,14 @@ reserve_task_sql_filters, get_reserve_task_category_info, acquire_reserve_task_lock, - release_reserve_task_lock_by_keys + release_reserve_task_lock_by_keys, + release_reserve_task_lock_by_id, + get_reserve_task_key ) import time +from nose.tools import assert_raises +from werkzeug.exceptions import BadRequest + class TestReserveTaskCategory(sched.Helper): @@ -157,3 +162,125 @@ def test_acquire_and_release_reserve_task_lock(self): release_reserve_task_lock_by_keys([expected_reserve_task_key], timeout, expiry=expiry) time.sleep(expiry) assert expected_reserve_task_key not in sentinel.master.keys(), "reserve task key should not exist in redis cache" + + + @with_context + def test_reserve_task_category_lock_raises_exceptions(self): + # missing project_id raises exception + with assert_raises(BadRequest): + get_reserve_task_category_info(["x", "y"], None, 1, 1) + + # missing user id and passing exclude user raises exception + with assert_raises(BadRequest): + get_reserve_task_category_info(["x", "y"], 1, 1, user_id=None, exclude_user=True) + + _, category_keys = get_reserve_task_category_info(["x", "y"], 1, 1, 1) + assert not category_keys, "reserve task category keys should not be present" + + user = UserFactory.create() + project = ProjectFactory.create( + owner=user, + info=dict( + sched="task_queue_scheduler", + reserve_tasks=dict( + category=["field_1", "field_2"] + ) + ) + ) + task = TaskFactory.create_batch( + 1, project=project, n_answers=1, + info=dict(field_1="abc", field_2=123) + )[0] + with assert_raises(BadRequest): + acquire_reserve_task_lock(project.id, task.id, None, 1) + + + @with_context + def test_reserve_task_category_lock_exclude_user(self): + # with exclude_user = True, exclude user category key for user id = `` + reserve_task_config = ["field_1", "field_2"] + user = UserFactory.create() + project = ProjectFactory.create( + owner=user, + info=dict( + sched="task_queue_scheduler", + reserve_tasks=dict( + category=reserve_task_config + ) + ) + ) + tasks = TaskFactory.create_batch( + 2, project=project, n_answers=1, + info=dict(field_1="abc", field_2=123) + ) + + non_excluded_user_id = 2 + acquire_reserve_task_lock(project.id, tasks[0].id, user.id, 1) + acquire_reserve_task_lock(project.id, tasks[1].id, non_excluded_user_id, 1) + expected_category_keys = [ + "reserve_task:project:{}:category:field_1:abc:field_2:123:user:{}:task:{}".format( + project.id, non_excluded_user_id, tasks[1].id + )] + _, category_keys = get_reserve_task_category_info(reserve_task_config, 1, 1, user.id, exclude_user=True) + assert category_keys == expected_category_keys, "reserve task category keys should exclude user {} reserve category key".format(user.id) + # cleanup; release reserve task lock + expiry = 1 + release_reserve_task_lock_by_id(project.id, tasks[0].id, user.id, 1, expiry=expiry) + release_reserve_task_lock_by_id(project.id, tasks[1].id, non_excluded_user_id, 1, expiry=expiry) + + + @with_context + def test_release_reserve_task_lock_by_id(self): + timeout = 100 + category_fields = ["field_1", "field_2"] + user = UserFactory.create() + # project w/o reserve_tasks configured don't acquire lock + project = ProjectFactory.create( + owner=user, + info=dict( + sched="task_queue_scheduler", + reserve_tasks=dict( + category=category_fields + ) + ) + ) + task = TaskFactory.create_batch( + 1, project=project, n_answers=1, + info=dict(field_1="abc", field_2=123) + )[0] + acquire_reserve_task_lock(project.id, task.id, user.id, timeout) + category_key = ":".join(["{}:{}".format(field, task.info[field]) for field in category_fields]) + expected_reserve_task_key = "reserve_task:project:{}:category:{}:user:{}:task:{}".format( + project.id, category_key, user.id, task.id + ) + assert expected_reserve_task_key in sentinel.master.keys(), "reserve task key must exist in redis cache" + + # release reserve task lock + expiry = 1 + release_reserve_task_lock_by_id(project.id, task.id, user.id, timeout, expiry=expiry) + time.sleep(expiry) + assert expected_reserve_task_key not in sentinel.master.keys(), "reserve task key should not exist in redis cache" + + + @with_context + def test_get_reserve_task_key(self): + category_fields = ["field_1", "field_2"] + task_info = dict(field_1="abc", field_2=123) + expected_key = ":".join(["{}:{}".format(field, task_info[field]) for field in sorted(category_fields)]) + user = UserFactory.create() + # project w/o reserve_tasks configured don't acquire lock + project = ProjectFactory.create( + owner=user, + info=dict( + sched="task_queue_scheduler", + reserve_tasks=dict( + category=category_fields + ) + ) + ) + task = TaskFactory.create_batch( + 1, project=project, n_answers=1, + info=task_info + )[0] + reserve_key = get_reserve_task_key(task.id) + assert reserve_key == expected_key, "reserve key expected to be {}".format(expected_key) \ No newline at end of file