Beispiel #1
0
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
Beispiel #3
0
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
Beispiel #6
0
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