class TestTaskRepositorySaveDeleteUpdate(Test): def setUp(self): super(TestTaskRepositorySaveDeleteUpdate, self).setUp() self.task_repo = TaskRepository(db) def test_save_saves_tasks(self): """Test save persists Task instances""" task = TaskFactory.build() assert self.task_repo.get_task(task.id) is None self.task_repo.save(task) assert self.task_repo.get_task(task.id) == task, "Task not saved" def test_save_saves_taskruns(self): """Test save persists TaskRun instances""" taskrun = TaskRunFactory.build() assert self.task_repo.get_task_run(taskrun.id) is None self.task_repo.save(taskrun) assert self.task_repo.get_task_run( taskrun.id) == taskrun, "TaskRun not saved" def test_save_fails_if_integrity_error(self): """Test save raises a DBIntegrityError if the instance to be saved lacks a required value""" task = TaskFactory.build(project_id=None, project=None) assert_raises(DBIntegrityError, self.task_repo.save, task) def test_save_only_saves_tasks_and_taskruns(self): """Test save raises a WrongObjectError when an object which is neither a Task nor a Taskrun instance is saved""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.save, bad_object) def test_update_task(self): """Test update persists the changes made to Task instances""" task = TaskFactory.create(state='ongoing') task.state = 'done' self.task_repo.update(task) updated_task = self.task_repo.get_task(task.id) assert updated_task.state == 'done', updated_task def test_update_taskrun(self): """Test update persists the changes made to TaskRun instances""" taskrun = TaskRunFactory.create(info='info') taskrun.info = 'updated info!' self.task_repo.update(taskrun) updated_taskrun = self.task_repo.get_task_run(taskrun.id) assert updated_taskrun.info == 'updated info!', updated_taskrun def test_update_fails_if_integrity_error(self): """Test update raises a DBIntegrityError if the instance to be updated lacks a required value""" task = TaskFactory.create() task.project_id = None assert_raises(DBIntegrityError, self.task_repo.update, task) def test_update_only_updates_tasks_and_taskruns(self): """Test update raises a WrongObjectError when an object which is neither a Task nor a TaskRun instance is updated""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.update, bad_object) def test_delete_task(self): """Test delete removes the Task instance""" task = TaskFactory.create() self.task_repo.delete(task) deleted = self.task_repo.get_task(task.id) assert deleted is None, deleted def test_delete_task_deletes_dependent_taskruns(self): """Test delete removes the dependent TaskRun instances""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) self.task_repo.delete(task) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_taskrun(self): """Test delete removes the TaskRun instance""" taskrun = TaskRunFactory.create() self.task_repo.delete(taskrun) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_only_deletes_tasks(self): """Test delete raises a WrongObjectError if is requested to delete other than a task""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.delete, bad_object) def test_delete_all_deletes_many_tasks(self): """Test delete_all deletes many tasks at once""" tasks = TaskFactory.create_batch(2) self.task_repo.delete_all(tasks) for task in tasks: assert self.task_repo.get_task(task.id) is None, task def test_delete_all_deletes_dependent(self): """Test delete_all deletes dependent taskruns too""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) self.task_repo.delete_all([task]) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_all_deletes_many_taskruns(self): """Test delete_all deletes many taskruns at once""" taskruns = TaskRunFactory.create_batch(2) self.task_repo.delete_all(taskruns) for taskrun in taskruns: assert self.task_repo.get_task_run(taskrun.id) is None, taskrun def test_delete_all_raises_error_if_no_task(self): """Test delete_all raises a WrongObjectError if is requested to delete any other object than a task""" bad_objects = [dict(), 'string'] assert_raises(WrongObjectError, self.task_repo.delete_all, bad_objects) def test_update_tasks_redundancy_changes_all_project_tasks_redundancy( self): """Test update_tasks_redundancy updates the n_answers value for every task in the project""" project = ProjectFactory.create() TaskFactory.create_batch(2, project=project, n_answers=1) self.task_repo.update_tasks_redundancy(project, 2) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.n_answers == 2, task.n_answers def test_update_tasks_redundancy_updates_state_when_incrementing(self): """Test update_tasks_redundancy changes 'completed' tasks to 'ongoing' if n_answers is incremented enough""" project = ProjectFactory.create() tasks = TaskFactory.create_batch(2, project=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 3) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.state == 'ongoing', task.state def test_update_tasks_redundancy_updates_state_when_decrementing(self): """Test update_tasks_redundancy changes 'ongoing' tasks to 'completed' if n_answers is decremented enough""" project = ProjectFactory.create() tasks = TaskFactory.create_batch(2, project=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) TaskRunFactory.create(task=tasks[1]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 1) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.state == 'completed', task.state
class TestTaskRepositoryForTaskQueries(Test): def setUp(self): super(TestTaskRepositoryForTaskQueries, self).setUp() self.task_repo = TaskRepository(db) def test_orderby(self): """Test orderby.""" project = ProjectFactory.create() task1 = TaskFactory.create(fav_user_ids=[1], project=project) task2 = TaskFactory.create(fav_user_ids=None, project=project) task3 = TaskFactory.create(fav_user_ids=[1, 2, 3], project=project) task = self.task_repo.filter_tasks_by(orderby='id', desc=True, project_id=project.id, limit=1)[0] assert task == task3, (task, task3) task = self.task_repo.filter_tasks_by(orderby='id', desc=False, project_id=project.id, limit=1)[0] assert task == task1, (task, task1) task = self.task_repo.filter_tasks_by(orderby='created', desc=True, project_id=project.id)[0] assert task == task3, (task.id, task3.id) task = self.task_repo.filter_tasks_by(orderby='created', desc=False, project_id=project.id)[0] assert task == task1, (task.created, task1.created) task = self.task_repo.filter_tasks_by(orderby='fav_user_ids', desc=True, project_id=project.id)[0][0] assert task == task3, (task.id, task3.id) task = self.task_repo.filter_tasks_by(orderby='fav_user_ids', desc=False, project_id=project.id)[0][0] assert task == task2, (task.fav_user_ids, task2.fav_user_ids) def test_handle_info_json_plain_text(self): """Test handle info in JSON as plain text works.""" TaskFactory.create(info='answer') res = self.task_repo.filter_tasks_by(info='answer') assert len(res) == 1 assert res[0].info == 'answer', res[0] def test_handle_info_json(self): """Test handle info in JSON works.""" TaskFactory.create(info={'foo': 'bar'}) info = 'foo::bar' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] def test_handle_info_json_fulltextsearch(self): """Test handle info fulltextsearch in JSON works.""" text = 'bar word agent something' TaskFactory.create(info={'foo': text}) info = 'foo::agent' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1 assert res[0][0].info['foo'] == text, res[0] res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0, len(res) def test_handle_info_json_multiple_keys(self): """Test handle info in JSON with multiple keys works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) info = 'foo::bar|bar::foo' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['bar'] == 'foo', res[0] def test_handle_info_json_multiple_keys_fulltextsearch(self): """Test handle info in JSON with multiple keys works.""" text = "two three four five" TaskFactory.create(info={'foo': 'bar', 'extra': text}) info = 'foo::bar|extra::four' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1, len(res) assert res[0][0].info['foo'] == 'bar', res[0] assert res[0][0].info['extra'] == text, res[0] res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0, len(res) def test_handle_info_json_multiple_keys_and_fulltextsearch(self): """Test handle info in JSON with multiple keys and AND operator works.""" text = "agent myself you bar" TaskFactory.create(info={'foo': 'bar', 'bar': text}) info = 'foo::bar|bar::you&agent' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1, len(res) assert res[0][0].info['foo'] == 'bar', res[0] assert res[0][0].info['bar'] == text, res[0] def test_handle_info_json_multiple_keys_404(self): """Test handle info in JSON with multiple keys not found works.""" TaskFactory.create(info={'foo': 'bar', 'daniel': 'foo'}) info = 'foo::bar|bar::foo' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0 def test_handle_info_json_multiple_keys_404_with_one_pipe(self): """Test handle info in JSON with multiple keys not found works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) info = 'foo::bar|' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['bar'] == 'foo', res[0] def test_handle_info_json_multiple_keys_404_fulltextsearch(self): """Test handle info in JSON with full text search with multiple keys not found works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) info = 'foo::bar|' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1 assert res[0][0].info['foo'] == 'bar', res[0] assert res[0][0].info['bar'] == 'foo', res[0] def test_handle_info_json_wrong_data(self): """Test handle info in JSON with wrong data works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) infos = ['|', '||', '|::', ':|', '::|', '|:', 'foo|', 'foo|'] for info in infos: res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0 for info in infos: res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 0 def test_get_task_return_none_if_no_task(self): """Test get_task method returns None if there is no task with the specified id""" task = self.task_repo.get_task(200) assert task is None, task def test_get_task_returns_task(self): """Test get_task method returns a task if exists""" task = TaskFactory.create() retrieved_task = self.task_repo.get_task(task.id) assert task == retrieved_task, retrieved_task def test_get_task_by(self): """Test get_task_by returns a task with the specified attribute""" task = TaskFactory.create(state='done') retrieved_task = self.task_repo.get_task_by(state=task.state) assert task == retrieved_task, retrieved_task def test_get_task_by_returns_none_if_no_task(self): """Test get_task_by returns None if no task matches the query""" TaskFactory.create(state='done') task = self.task_repo.get_task_by(state='ongoing') assert task is None, task def test_filter_tasks_by_no_matches(self): """Test filter_tasks_by returns an empty list if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) retrieved_tasks = self.task_repo.filter_tasks_by(state='ongoing') assert isinstance(retrieved_tasks, list) assert len(retrieved_tasks) == 0, retrieved_tasks def test_filter_tasks_by_one_condition(self): """Test filter_tasks_by returns a list of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') retrieved_tasks = self.task_repo.filter_tasks_by(state='done') assert len(retrieved_tasks) == 3, retrieved_tasks assert should_be_missing not in retrieved_tasks, retrieved_tasks def test_filter_tasks_by_multiple_conditions(self): """Test filter_tasks_by supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) retrieved_tasks = self.task_repo.filter_tasks_by(state='done', n_answers=99) assert len(retrieved_tasks) == 1, retrieved_tasks assert task in retrieved_tasks, retrieved_tasks def test_filter_tasks_support_yield_option(self): """Test that filter_tasks_by with the yielded=True option returns the results as a generator""" tasks = TaskFactory.create_batch(2, state='done') yielded_tasks = self.task_repo.filter_tasks_by(state='done', yielded=True) import types assert isinstance(yielded_tasks.__iter__(), types.GeneratorType) for task in yielded_tasks: assert task in tasks def test_filter_tasks_limit_offset(self): """Test that filter_tasks_by supports limit and offset options""" TaskFactory.create_batch(4) all_tasks = self.task_repo.filter_tasks_by() first_two = self.task_repo.filter_tasks_by(limit=2) last_two = self.task_repo.filter_tasks_by(limit=2, offset=2) assert len(first_two) == 2, first_two assert len(last_two) == 2, last_two assert first_two == all_tasks[:2] assert last_two == all_tasks[2:] def test_count_tasks_with_no_matches(self): """Test count_tasks_with returns 0 if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) count = self.task_repo.count_tasks_with(state='ongoing') assert count == 0, count def test_count_tasks_with_one_condition(self): """Test count_tasks_with returns the number of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') count = self.task_repo.count_tasks_with(state='done') assert count == 3, count def test_count_tasks_with_multiple_conditions(self): """Test count_tasks_with supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) count = self.task_repo.count_tasks_with(state='done', n_answers=99) assert count == 1, count
class TestTaskRepositoryForTaskQueries(Test): def setUp(self): super(TestTaskRepositoryForTaskQueries, self).setUp() self.task_repo = TaskRepository(db) def test_get_task_return_none_if_no_task(self): """Test get_task method returns None if there is no task with the specified id""" task = self.task_repo.get_task(200) assert task is None, task def test_get_task_returns_task(self): """Test get_task method returns a task if exists""" task = TaskFactory.create() retrieved_task = self.task_repo.get_task(task.id) assert task == retrieved_task, retrieved_task def test_get_task_by(self): """Test get_task_by returns a task with the specified attribute""" task = TaskFactory.create(state='done') retrieved_task = self.task_repo.get_task_by(state=task.state) assert task == retrieved_task, retrieved_task def test_get_task_by_returns_none_if_no_task(self): """Test get_task_by returns None if no task matches the query""" TaskFactory.create(state='done') task = self.task_repo.get_task_by(state='ongoing') assert task is None, task def test_filter_tasks_by_no_matches(self): """Test filter_tasks_by returns an empty list if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) retrieved_tasks = self.task_repo.filter_tasks_by(state='ongoing') assert isinstance(retrieved_tasks, list) assert len(retrieved_tasks) == 0, retrieved_tasks def test_filter_tasks_by_one_condition(self): """Test filter_tasks_by returns a list of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') retrieved_tasks = self.task_repo.filter_tasks_by(state='done') assert len(retrieved_tasks) == 3, retrieved_tasks assert should_be_missing not in retrieved_tasks, retrieved_tasks def test_filter_tasks_by_multiple_conditions(self): """Test filter_tasks_by supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) retrieved_tasks = self.task_repo.filter_tasks_by(state='done', n_answers=99) assert len(retrieved_tasks) == 1, retrieved_tasks assert task in retrieved_tasks, retrieved_tasks def test_filter_tasks_support_yield_option(self): """Test that filter_tasks_by with the yielded=True option returns the results as a generator""" tasks = TaskFactory.create_batch(2, state='done') yielded_tasks = self.task_repo.filter_tasks_by(state='done', yielded=True) import types assert isinstance(yielded_tasks.__iter__(), types.GeneratorType) for task in yielded_tasks: assert task in tasks def test_filter_tasks_limit_offset(self): """Test that filter_tasks_by supports limit and offset options""" TaskFactory.create_batch(4) all_tasks = self.task_repo.filter_tasks_by() first_two = self.task_repo.filter_tasks_by(limit=2) last_two = self.task_repo.filter_tasks_by(limit=2, offset=2) assert len(first_two) == 2, first_two assert len(last_two) == 2, last_two assert first_two == all_tasks[:2] assert last_two == all_tasks[2:] def test_count_tasks_with_no_matches(self): """Test count_tasks_with returns 0 if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) count = self.task_repo.count_tasks_with(state='ongoing') assert count == 0, count def test_count_tasks_with_one_condition(self): """Test count_tasks_with returns the number of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') count = self.task_repo.count_tasks_with(state='done') assert count == 3, count def test_count_tasks_with_multiple_conditions(self): """Test count_tasks_with supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) count = self.task_repo.count_tasks_with(state='done', n_answers=99) assert count == 1, count
class TestTaskRepositorySaveDeleteUpdate(Test): def setUp(self): super(TestTaskRepositorySaveDeleteUpdate, self).setUp() self.task_repo = TaskRepository(db) def test_save_saves_tasks(self): """Test save persists Task instances""" task = TaskFactory.build() assert self.task_repo.get_task(task.id) is None self.task_repo.save(task) assert self.task_repo.get_task(task.id) == task, "Task not saved" def test_save_saves_taskruns(self): """Test save persists TaskRun instances""" taskrun = TaskRunFactory.build() assert self.task_repo.get_task_run(taskrun.id) is None self.task_repo.save(taskrun) assert self.task_repo.get_task_run(taskrun.id) == taskrun, "TaskRun not saved" def test_save_fails_if_integrity_error(self): """Test save raises a DBIntegrityError if the instance to be saved lacks a required value""" task = TaskFactory.build(project_id=None, project=None) assert_raises(DBIntegrityError, self.task_repo.save, task) def test_save_only_saves_tasks_and_taskruns(self): """Test save raises a WrongObjectError when an object which is neither a Task nor a Taskrun instance is saved""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.save, bad_object) def test_update_task(self): """Test update persists the changes made to Task instances""" task = TaskFactory.create(state='ongoing') task.state = 'done' self.task_repo.update(task) updated_task = self.task_repo.get_task(task.id) assert updated_task.state == 'done', updated_task def test_update_taskrun(self): """Test update persists the changes made to TaskRun instances""" taskrun = TaskRunFactory.create(info='info') taskrun.info = 'updated info!' self.task_repo.update(taskrun) updated_taskrun = self.task_repo.get_task_run(taskrun.id) assert updated_taskrun.info == 'updated info!', updated_taskrun def test_update_fails_if_integrity_error(self): """Test update raises a DBIntegrityError if the instance to be updated lacks a required value""" task = TaskFactory.create() task.project_id = None assert_raises(DBIntegrityError, self.task_repo.update, task) def test_update_only_updates_tasks_and_taskruns(self): """Test update raises a WrongObjectError when an object which is neither a Task nor a TaskRun instance is updated""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.update, bad_object) def test_delete_task(self): """Test delete removes the Task instance""" task = TaskFactory.create() self.task_repo.delete(task) deleted = self.task_repo.get_task(task.id) assert deleted is None, deleted def test_delete_task_deletes_dependent_taskruns(self): """Test delete removes the dependent TaskRun instances""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) self.task_repo.delete(task) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_taskrun(self): """Test delete removes the TaskRun instance""" taskrun = TaskRunFactory.create() self.task_repo.delete(taskrun) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_only_deletes_tasks(self): """Test delete raises a WrongObjectError if is requested to delete other than a task""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.delete, bad_object) def test_delete_valid_from_project_deletes_many_tasks(self): """Test delete_valid_from_project deletes many tasks at once""" tasks = TaskFactory.create_batch(2) project = project_repo.get(tasks[0].project_id) self.task_repo.delete_valid_from_project(project) tasks = self.task_repo.filter_tasks_by(project_id=project.id) assert len(tasks) == 0, len(tasks) def test_delete_valid_from_project_deletes_dependent(self): """Test delete_valid_from_project deletes dependent taskruns too""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) task_run_id = taskrun.id project = project_repo.get(task.project_id) self.task_repo.delete_valid_from_project(project) deleted = self.task_repo.get_task_run(id=task_run_id) assert deleted is None, deleted def test_delete_valid_from_project_deletes_dependent_without_result(self): """Test delete_valid_from_project deletes dependent taskruns without result""" task = TaskFactory.create(n_answers=1) project = project_repo.get(task.project_id) taskrun = TaskRunFactory.create(task=task) task2 = TaskFactory.create(project=project) TaskRunFactory.create(task=task2) self.task_repo.delete_valid_from_project(project) non_deleted = self.task_repo.filter_tasks_by(project_id=project.id) err_msg = "There should be one task, as it belongs to a result" assert len(non_deleted) == 1, err_msg assert non_deleted[0].id == task.id, err_msg non_deleted = self.task_repo.filter_task_runs_by(project_id=project.id) err_msg = "There should be one task_run, as it belongs to a result" assert len(non_deleted) == 1, err_msg assert non_deleted[0].id == taskrun.id, err_msg def test_delete_taskruns_from_project_deletes_taskruns(self): task = TaskFactory.create() project = project_repo.get(task.project_id) taskrun = TaskRunFactory.create(task=task) self.task_repo.delete_taskruns_from_project(project) taskruns = self.task_repo.filter_task_runs_by(project_id=project.id) assert taskruns == [], taskruns def test_update_tasks_redundancy_changes_all_project_tasks_redundancy(self): """Test update_tasks_redundancy updates the n_answers value for every task in the project""" project = ProjectFactory.create() TaskFactory.create_batch(2, project=project, n_answers=1) self.task_repo.update_tasks_redundancy(project, 2) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.n_answers == 2, task.n_answers def test_update_tasks_redundancy_updates_state_when_incrementing(self): """Test update_tasks_redundancy changes 'completed' tasks to 'ongoing' if n_answers is incremented enough""" project = ProjectFactory.create() tasks = TaskFactory.create_batch(2, project=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 3) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.state == 'ongoing', task.state def test_update_tasks_redundancy_updates_state_when_decrementing(self): """Test update_tasks_redundancy changes 'ongoing' tasks to 'completed' if n_answers is decremented enough""" project = ProjectFactory.create() tasks = TaskFactory.create_batch(2, project=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) TaskRunFactory.create(task=tasks[1]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 1) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.state == 'completed', task.state
class TestTaskRepositoryForTaskQueries(Test): def setUp(self): super(TestTaskRepositoryForTaskQueries, self).setUp() self.task_repo = TaskRepository(db) def test_handle_info_json_plain_text(self): """Test handle info in JSON as plain text works.""" TaskFactory.create(info='answer') res = self.task_repo.filter_tasks_by(info='answer') assert len(res) == 1 assert res[0].info == 'answer', res[0] def test_handle_info_json(self): """Test handle info in JSON works.""" TaskFactory.create(info={'foo': 'bar'}) info = 'foo::bar' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] def test_handle_info_json_fulltextsearch(self): """Test handle info fulltextsearch in JSON works.""" text = 'bar word agent something' TaskFactory.create(info={'foo': text}) info = 'foo::agent' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1 assert res[0].info['foo'] == text, res[0] res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0, len(res) def test_handle_info_json_multiple_keys(self): """Test handle info in JSON with multiple keys works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) info = 'foo::bar|bar::foo' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['bar'] == 'foo', res[0] def test_handle_info_json_multiple_keys_fulltextsearch(self): """Test handle info in JSON with multiple keys works.""" text = "two three four five" TaskFactory.create(info={'foo': 'bar', 'extra': text}) info = 'foo::bar|extra::four' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1, len(res) assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['extra'] == text, res[0] res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0, len(res) def test_handle_info_json_multiple_keys_and_fulltextsearch(self): """Test handle info in JSON with multiple keys and AND operator works.""" text = "agent myself you bar" TaskFactory.create(info={'foo': 'bar', 'bar': text}) info = 'foo::bar|bar::you&agent' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1, len(res) assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['bar'] == text, res[0] def test_handle_info_json_multiple_keys_404(self): """Test handle info in JSON with multiple keys not found works.""" TaskFactory.create(info={'foo': 'bar', 'daniel': 'foo'}) info = 'foo::bar|bar::foo' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0 def test_handle_info_json_multiple_keys_404_with_one_pipe(self): """Test handle info in JSON with multiple keys not found works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) info = 'foo::bar|' res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['bar'] == 'foo', res[0] def test_handle_info_json_multiple_keys_404_fulltextsearch(self): """Test handle info in JSON with full text search with multiple keys not found works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) info = 'foo::bar|' res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 1 assert res[0].info['foo'] == 'bar', res[0] assert res[0].info['bar'] == 'foo', res[0] def test_handle_info_json_wrong_data(self): """Test handle info in JSON with wrong data works.""" TaskFactory.create(info={'foo': 'bar', 'bar': 'foo'}) infos = ['|', '||', '|::', ':|', '::|', '|:', 'foo|', 'foo|'] for info in infos: res = self.task_repo.filter_tasks_by(info=info) assert len(res) == 0 for info in infos: res = self.task_repo.filter_tasks_by(info=info, fulltextsearch='1') assert len(res) == 0 def test_get_task_return_none_if_no_task(self): """Test get_task method returns None if there is no task with the specified id""" task = self.task_repo.get_task(200) assert task is None, task def test_get_task_returns_task(self): """Test get_task method returns a task if exists""" task = TaskFactory.create() retrieved_task = self.task_repo.get_task(task.id) assert task == retrieved_task, retrieved_task def test_get_task_by(self): """Test get_task_by returns a task with the specified attribute""" task = TaskFactory.create(state='done') retrieved_task = self.task_repo.get_task_by(state=task.state) assert task == retrieved_task, retrieved_task def test_get_task_by_returns_none_if_no_task(self): """Test get_task_by returns None if no task matches the query""" TaskFactory.create(state='done') task = self.task_repo.get_task_by(state='ongoing') assert task is None, task def test_filter_tasks_by_no_matches(self): """Test filter_tasks_by returns an empty list if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) retrieved_tasks = self.task_repo.filter_tasks_by(state='ongoing') assert isinstance(retrieved_tasks, list) assert len(retrieved_tasks) == 0, retrieved_tasks def test_filter_tasks_by_one_condition(self): """Test filter_tasks_by returns a list of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') retrieved_tasks = self.task_repo.filter_tasks_by(state='done') assert len(retrieved_tasks) == 3, retrieved_tasks assert should_be_missing not in retrieved_tasks, retrieved_tasks def test_filter_tasks_by_multiple_conditions(self): """Test filter_tasks_by supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) retrieved_tasks = self.task_repo.filter_tasks_by(state='done', n_answers=99) assert len(retrieved_tasks) == 1, retrieved_tasks assert task in retrieved_tasks, retrieved_tasks def test_filter_tasks_support_yield_option(self): """Test that filter_tasks_by with the yielded=True option returns the results as a generator""" tasks = TaskFactory.create_batch(2, state='done') yielded_tasks = self.task_repo.filter_tasks_by(state='done', yielded=True) import types assert isinstance(yielded_tasks.__iter__(), types.GeneratorType) for task in yielded_tasks: assert task in tasks def test_filter_tasks_limit_offset(self): """Test that filter_tasks_by supports limit and offset options""" TaskFactory.create_batch(4) all_tasks = self.task_repo.filter_tasks_by() first_two = self.task_repo.filter_tasks_by(limit=2) last_two = self.task_repo.filter_tasks_by(limit=2, offset=2) assert len(first_two) == 2, first_two assert len(last_two) == 2, last_two assert first_two == all_tasks[:2] assert last_two == all_tasks[2:] def test_count_tasks_with_no_matches(self): """Test count_tasks_with returns 0 if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) count = self.task_repo.count_tasks_with(state='ongoing') assert count == 0, count def test_count_tasks_with_one_condition(self): """Test count_tasks_with returns the number of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') count = self.task_repo.count_tasks_with(state='done') assert count == 3, count def test_count_tasks_with_multiple_conditions(self): """Test count_tasks_with supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) count = self.task_repo.count_tasks_with(state='done', n_answers=99) assert count == 1, count
class TestTaskRepositorySaveDeleteUpdate(Test): def setUp(self): super(TestTaskRepositorySaveDeleteUpdate, self).setUp() self.task_repo = TaskRepository(db) @with_context def test_save_saves_tasks(self): """Test save persists Task instances""" task = TaskFactory.build() assert self.task_repo.get_task(task.id) is None self.task_repo.save(task) assert self.task_repo.get_task(task.id) == task, "Task not saved" @with_context def test_save_saves_taskruns(self): """Test save persists TaskRun instances""" taskrun = TaskRunFactory.build() assert self.task_repo.get_task_run(taskrun.id) is None self.task_repo.save(taskrun) assert self.task_repo.get_task_run(taskrun.id) == taskrun, "TaskRun not saved" @with_context def test_save_fails_if_integrity_error(self): """Test save raises a DBIntegrityError if the instance to be saved lacks a required value""" task = TaskFactory.build(project_id=None, project=None) assert_raises(DBIntegrityError, self.task_repo.save, task) @with_context def test_save_only_saves_tasks_and_taskruns(self): """Test save raises a WrongObjectError when an object which is neither a Task nor a Taskrun instance is saved""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.save, bad_object) @with_context def test_update_task(self): """Test update persists the changes made to Task instances""" task = TaskFactory.create(state='ongoing') task.state = 'done' self.task_repo.update(task) updated_task = self.task_repo.get_task(task.id) assert updated_task.state == 'done', updated_task @with_context def test_update_taskrun(self): """Test update persists the changes made to TaskRun instances""" taskrun = TaskRunFactory.create(info='info') taskrun.info = 'updated info!' self.task_repo.update(taskrun) updated_taskrun = self.task_repo.get_task_run(taskrun.id) assert updated_taskrun.info == 'updated info!', updated_taskrun @with_context def test_update_fails_if_integrity_error(self): """Test update raises a DBIntegrityError if the instance to be updated lacks a required value""" task = TaskFactory.create() task.project_id = None assert_raises(DBIntegrityError, self.task_repo.update, task) @with_context def test_update_only_updates_tasks_and_taskruns(self): """Test update raises a WrongObjectError when an object which is neither a Task nor a TaskRun instance is updated""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.update, bad_object) @with_context def test_delete_task(self): """Test delete removes the Task instance""" task = TaskFactory.create() self.task_repo.delete(task) deleted = self.task_repo.get_task(task.id) assert deleted is None, deleted @with_context def test_delete_task_deletes_dependent_taskruns(self): """Test delete removes the dependent TaskRun instances""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) self.task_repo.delete(task) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted @with_context def test_delete_taskrun(self): """Test delete removes the TaskRun instance""" taskrun = TaskRunFactory.create() self.task_repo.delete(taskrun) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted @with_context def test_delete_only_deletes_tasks(self): """Test delete raises a WrongObjectError if is requested to delete other than a task""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.delete, bad_object) @with_context def test_delete_valid_from_project_deletes_many_tasks(self): """Test delete_valid_from_project deletes many tasks at once""" tasks = TaskFactory.create_batch(2) project = project_repo.get(tasks[0].project_id) self.task_repo.delete_valid_from_project(project) tasks = self.task_repo.filter_tasks_by(project_id=project.id) assert len(tasks) == 0, len(tasks) @with_context def test_delete_valid_from_project_deletes_dependent(self): """Test delete_valid_from_project deletes dependent taskruns too""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) task_run_id = taskrun.id project = project_repo.get(task.project_id) self.task_repo.delete_valid_from_project(project) deleted = self.task_repo.get_task_run(id=task_run_id) assert deleted is None, deleted @with_context def test_delete_valid_from_project_deletes_dependent_without_result(self): """Test delete_valid_from_project deletes dependent taskruns without result""" task = TaskFactory.create(n_answers=1) project = project_repo.get(task.project_id) taskrun = TaskRunFactory.create(task=task) task2 = TaskFactory.create(project=project) TaskRunFactory.create(task=task2) self.task_repo.delete_valid_from_project(project) non_deleted = self.task_repo.filter_tasks_by(project_id=project.id) err_msg = "There should be one task, as it belongs to a result" assert len(non_deleted) == 1, err_msg assert non_deleted[0].id == task.id, err_msg non_deleted = self.task_repo.filter_task_runs_by(project_id=project.id) err_msg = "There should be one task_run, as it belongs to a result" assert len(non_deleted) == 1, err_msg assert non_deleted[0].id == taskrun.id, err_msg @with_context def test_delete_taskruns_from_project_deletes_taskruns(self): task = TaskFactory.create() project = project_repo.get(task.project_id) taskrun = TaskRunFactory.create(task=task) self.task_repo.delete_taskruns_from_project(project) taskruns = self.task_repo.filter_task_runs_by(project_id=project.id) assert taskruns == [], taskruns @with_context def test_update_tasks_redundancy_changes_all_project_tasks_redundancy(self): """Test update_tasks_redundancy updates the n_answers value for every task in the project""" project = ProjectFactory.create() TaskFactory.create_batch(2, project=project, n_answers=1) self.task_repo.update_tasks_redundancy(project, 2) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.n_answers == 2, task.n_answers @with_context def test_update_tasks_redundancy_updates_state_when_incrementing(self): """Test update_tasks_redundancy changes 'completed' tasks to 'ongoing' if n_answers is incremented enough""" project = ProjectFactory.create() tasks = TaskFactory.create_batch(2, project=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 3) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.state == 'ongoing', task.state @with_context def test_update_tasks_redundancy_updates_state_when_decrementing(self): """Test update_tasks_redundancy changes 'ongoing' tasks to 'completed' if n_answers is decremented enough""" project = ProjectFactory.create() tasks = TaskFactory.create_batch(2, project=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) TaskRunFactory.create(task=tasks[1]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 1) tasks = self.task_repo.filter_tasks_by(project_id=project.id) for task in tasks: assert task.state == 'completed', task.state
class TestTaskRepositoryForTaskQueries(Test): def setUp(self): super(TestTaskRepositoryForTaskQueries, self).setUp() self.task_repo = TaskRepository(db) def test_get_task_return_none_if_no_task(self): """Test get_task method returns None if there is no task with the specified id""" task = self.task_repo.get_task(200) assert task is None, task def test_get_task_returns_task(self): """Test get_task method returns a task if exists""" task = TaskFactory.create() retrieved_task = self.task_repo.get_task(task.id) assert task == retrieved_task, retrieved_task def test_get_task_by(self): """Test get_task_by returns a task with the specified attribute""" task = TaskFactory.create(state='done') retrieved_task = self.task_repo.get_task_by(state=task.state) assert task == retrieved_task, retrieved_task def test_get_task_by_returns_none_if_no_task(self): """Test get_task_by returns None if no task matches the query""" TaskFactory.create(state='done') task = self.task_repo.get_task_by(state='ongoing') assert task is None, task def test_filter_tasks_by_no_matches(self): """Test filter_tasks_by returns an empty list if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) retrieved_tasks = self.task_repo.filter_tasks_by(state='ongoing') assert isinstance(retrieved_tasks, list) assert len(retrieved_tasks) == 0, retrieved_tasks def test_filter_tasks_by_one_condition(self): """Test filter_tasks_by returns a list of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') retrieved_tasks = self.task_repo.filter_tasks_by(state='done') assert len(retrieved_tasks) == 3, retrieved_tasks assert should_be_missing not in retrieved_tasks, retrieved_tasks def test_filter_tasks_by_multiple_conditions(self): """Test filter_tasks_by supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) retrieved_tasks = self.task_repo.filter_tasks_by(state='done', n_answers=99) assert len(retrieved_tasks) == 1, retrieved_tasks assert task in retrieved_tasks, retrieved_tasks def test_filter_tasks_support_yield_option(self): """Test that filter_tasks_by with the yielded=True option returns the results as a generator""" tasks = TaskFactory.create_batch(2, state='done') yielded_tasks = self.task_repo.filter_tasks_by(state='done', yielded=True) import types assert isinstance(yielded_tasks.__iter__(), types.GeneratorType) for task in yielded_tasks: assert task in tasks def test_filter_tasks_limit_offset(self): """Test that filter_tasks_by supports limit and offset options""" TaskFactory.create_batch(4) all_tasks = self.task_repo.filter_tasks_by() first_two = self.task_repo.filter_tasks_by(limit=2) last_two = self.task_repo.filter_tasks_by(limit=2, offset=2) assert len(first_two) == 2, first_two assert len(last_two) == 2, last_two assert first_two == all_tasks[:2] assert last_two == all_tasks[2:] def test_count_tasks_with_no_matches(self): """Test count_tasks_with returns 0 if no tasks match the query""" TaskFactory.create(state='done', n_answers=17) count = self.task_repo.count_tasks_with(state='ongoing') assert count == 0, count def test_count_tasks_with_one_condition(self): """Test count_tasks_with returns the number of tasks that meet the filtering condition""" TaskFactory.create_batch(3, state='done') should_be_missing = TaskFactory.create(state='ongoing') count = self.task_repo.count_tasks_with(state='done') assert count == 3, count def test_count_tasks_with_multiple_conditions(self): """Test count_tasks_with supports multiple-condition queries""" TaskFactory.create(state='done', n_answers=17) task = TaskFactory.create(state='done', n_answers=99) count = self.task_repo.count_tasks_with(state='done', n_answers=99) assert count == 1, count
class TestTaskRepositorySaveDeleteUpdate(Test): def setUp(self): super(TestTaskRepositorySaveDeleteUpdate, self).setUp() self.task_repo = TaskRepository(db) def test_save_saves_tasks(self): """Test save persists Task instances""" task = TaskFactory.build() assert self.task_repo.get_task(task.id) is None self.task_repo.save(task) assert self.task_repo.get_task(task.id) == task, "Task not saved" def test_save_saves_taskruns(self): """Test save persists TaskRun instances""" taskrun = TaskRunFactory.build() assert self.task_repo.get_task_run(taskrun.id) is None self.task_repo.save(taskrun) assert self.task_repo.get_task_run(taskrun.id) == taskrun, "TaskRun not saved" def test_save_fails_if_integrity_error(self): """Test save raises a DBIntegrityError if the instance to be saved lacks a required value""" task = TaskFactory.build(app_id=None, app=None) assert_raises(DBIntegrityError, self.task_repo.save, task) def test_save_only_saves_tasks_and_taskruns(self): """Test save raises a WrongObjectError when an object which is neither a Task nor a Taskrun instance is saved""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.save, bad_object) def test_update_task(self): """Test update persists the changes made to Task instances""" task = TaskFactory.create(state='ongoing') task.state = 'done' self.task_repo.update(task) updated_task = self.task_repo.get_task(task.id) assert updated_task.state == 'done', updated_task def test_update_taskrun(self): """Test update persists the changes made to TaskRun instances""" taskrun = TaskRunFactory.create(info='info') taskrun.info = 'updated info!' self.task_repo.update(taskrun) updated_taskrun = self.task_repo.get_task_run(taskrun.id) assert updated_taskrun.info == 'updated info!', updated_taskrun def test_update_fails_if_integrity_error(self): """Test update raises a DBIntegrityError if the instance to be updated lacks a required value""" task = TaskFactory.create() task.app_id = None assert_raises(DBIntegrityError, self.task_repo.update, task) def test_update_only_updates_tasks_and_taskruns(self): """Test update raises a WrongObjectError when an object which is neither a Task nor a TaskRun instance is updated""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.update, bad_object) def test_delete_task(self): """Test delete removes the Task instance""" task = TaskFactory.create() self.task_repo.delete(task) deleted = self.task_repo.get_task(task.id) assert deleted is None, deleted def test_delete_task_deletes_dependent_taskruns(self): """Test delete removes the dependent TaskRun instances""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) self.task_repo.delete(task) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_taskrun(self): """Test delete removes the TaskRun instance""" taskrun = TaskRunFactory.create() self.task_repo.delete(taskrun) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_only_deletes_tasks(self): """Test delete raises a WrongObjectError if is requested to delete other than a task""" bad_object = dict() assert_raises(WrongObjectError, self.task_repo.delete, bad_object) def test_delete_all_deletes_many_tasks(self): """Test delete_all deletes many tasks at once""" tasks = TaskFactory.create_batch(2) self.task_repo.delete_all(tasks) for task in tasks: assert self.task_repo.get_task(task.id) is None, task def test_delete_all_deletes_dependent(self): """Test delete_all deletes dependent taskruns too""" task = TaskFactory.create() taskrun = TaskRunFactory.create(task=task) self.task_repo.delete_all([task]) deleted = self.task_repo.get_task_run(taskrun.id) assert deleted is None, deleted def test_delete_all_deletes_many_taskruns(self): """Test delete_all deletes many taskruns at once""" taskruns = TaskRunFactory.create_batch(2) self.task_repo.delete_all(taskruns) for taskrun in taskruns: assert self.task_repo.get_task_run(taskrun.id) is None, taskrun def test_delete_all_raises_error_if_no_task(self): """Test delete_all raises a WrongObjectError if is requested to delete any other object than a task""" bad_objects = [dict(), 'string'] assert_raises(WrongObjectError, self.task_repo.delete_all, bad_objects) def test_update_tasks_redundancy_changes_all_project_tasks_redundancy(self): """Test update_tasks_redundancy updates the n_answers value for every task in the project""" project = AppFactory.create() TaskFactory.create_batch(2, app=project, n_answers=1) self.task_repo.update_tasks_redundancy(project, 2) tasks = self.task_repo.filter_tasks_by(app_id=project.id) for task in tasks: assert task.n_answers == 2, task.n_answers def test_update_tasks_redundancy_updates_state_when_incrementing(self): """Test update_tasks_redundancy changes 'completed' tasks to 'ongoing' if n_answers is incremented enough""" project = AppFactory.create() tasks = TaskFactory.create_batch(2, app=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 3) tasks = self.task_repo.filter_tasks_by(app_id=project.id) for task in tasks: assert task.state == 'ongoing', task.state def test_update_tasks_redundancy_updates_state_when_decrementing(self): """Test update_tasks_redundancy changes 'ongoing' tasks to 'completed' if n_answers is decremented enough""" project = AppFactory.create() tasks = TaskFactory.create_batch(2, app=project, n_answers=2) TaskRunFactory.create_batch(2, task=tasks[0]) TaskRunFactory.create(task=tasks[1]) tasks[0].state = 'completed' self.task_repo.update(tasks[0]) assert tasks[0].state == 'completed', tasks[0].state assert tasks[1].state == 'ongoing', tasks[1].state self.task_repo.update_tasks_redundancy(project, 1) tasks = self.task_repo.filter_tasks_by(app_id=project.id) for task in tasks: assert task.state == 'completed', task.state