Example #1
0
 def setUp(self):
     super(TestZ3950Analyst, self).setUp()
     self.ctx = ContextFixtures()
     self.z3950_analyst = Z3950Analyst()
     self.result_repo = ResultRepository(db)
     self.task_repo = TaskRepository(db)
     self.data = {
         'user_id': [1],
         'control_number': ['123'],
         'reference': ['abc'],
         'foo': ['bar'],
         'comments': ['Some comment']
     }
Example #2
0
def setup_repositories():
    """Setup repositories."""
    from pybossa.repositories import UserRepository
    from pybossa.repositories import ProjectRepository
    from pybossa.repositories import BlogRepository
    from pybossa.repositories import TaskRepository
    from pybossa.repositories import AuditlogRepository
    from pybossa.repositories import WebhookRepository
    from pybossa.repositories import ResultRepository
    from pybossa.repositories import UserScoreRepository
    global user_repo
    global project_repo
    global blog_repo
    global task_repo
    global auditlog_repo
    global webhook_repo
    global result_repo
    global user_score_repo
    user_repo = UserRepository(db)
    project_repo = ProjectRepository(db)
    blog_repo = BlogRepository(db)
    task_repo = TaskRepository(db)
    auditlog_repo = AuditlogRepository(db)
    webhook_repo = WebhookRepository(db)
    result_repo = ResultRepository(db)
    user_score_repo = UserScoreRepository(db)
Example #3
0
def setup_repositories(app):
    """Setup repositories."""
    from pybossa.repositories import UserRepository
    from pybossa.repositories import ProjectRepository
    from pybossa.repositories import ProjectStatsRepository
    from pybossa.repositories import AnnouncementRepository
    from pybossa.repositories import BlogRepository
    from pybossa.repositories import TaskRepository
    from pybossa.repositories import AuditlogRepository
    from pybossa.repositories import WebhookRepository
    from pybossa.repositories import ResultRepository
    from pybossa.repositories import HelpingMaterialRepository
    global user_repo
    global project_repo
    global project_stats_repo
    global announcement_repo
    global blog_repo
    global task_repo
    global auditlog_repo
    global webhook_repo
    global result_repo
    global helping_repo
    language = app.config.get('FULLTEXTSEARCH_LANGUAGE')
    user_repo = UserRepository(db)
    project_repo = ProjectRepository(db)
    project_stats_repo = ProjectStatsRepository(db)
    announcement_repo = AnnouncementRepository(db)
    blog_repo = BlogRepository(db)
    task_repo = TaskRepository(db, language)
    auditlog_repo = AuditlogRepository(db)
    webhook_repo = WebhookRepository(db)
    result_repo = ResultRepository(db)
    helping_repo = HelpingMaterialRepository(db)
Example #4
0
    def test_delete_also_removes_dependant_resources(self):
        """Test delete removes project tasks and taskruns too"""
        from factories import TaskFactory, TaskRunFactory, BlogpostFactory
        from pybossa.repositories import TaskRepository, BlogRepository

        project = ProjectFactory.create()
        task = TaskFactory.create(project=project)
        taskrun = TaskRunFactory.create(task=task)
        blogpost = BlogpostFactory.create(project=project)

        self.project_repo.delete(project)
        deleted_task = TaskRepository(db).get_task(task.id)
        deleted_taskrun = TaskRepository(db).get_task_run(taskrun.id)
        deleted_blogpost = BlogRepository(db).get(blogpost.id)

        assert deleted_task is None, deleted_task
        assert deleted_taskrun is None, deleted_taskrun
Example #5
0
 def setUp(self):
     super(TestBaseAnalyst, self).setUp()
     BaseAnalyst.__abstractmethods__ = frozenset()
     self.ctx = ContextFixtures()
     self.base_analyst = BaseAnalyst()
     self.project_repo = ProjectRepository(db)
     self.result_repo = ResultRepository(db)
     self.task_repo = TaskRepository(db)
     assert_dict_equal.__self__.maxDiff = None
     assert_equal.__self__.maxDiff = None
Example #6
0
    def test_api_app_access_with_secure_app_access_enabled(self):
        """Test API and APP access with SECURE_APP_ACCESS enabled"""

        project = ProjectFactory.create()
        task = TaskFactory.create(project=project,
                                  n_answers=2,
                                  state='ongoing')
        task_repo = TaskRepository(db)

        admin = UserFactory.create()
        with patch.dict(self.flask_app.config, {'SECURE_APP_ACCESS': True}):
            url = '/api/completedtask?project_id=1&api_key=api-key1'
            res = self.app.get(url)
            assert res.status_code == 401, res.data
            url = '/api/completedtask?project_id=1'
            headers = {'Authorization': 'api-key1'}
            res = self.app.get(url, headers=headers)
            data = json.loads(res.data)
            # no completedtask yet, should return zero
            assert len(data) == 0, data

            #  task is completed
            task_runs = TaskRunFactory.create_batch(2, task=task)
            task.state = 'completed'
            task_repo.update(task)
            url = '/api/completedtask?project_id=1'
            res = self.app.get(url, headers=headers)
            data = json.loads(res.data)

            # correct result
            assert data[0]['project_id'] == 1, data
            assert data[0]['state'] == u'completed', data

            # test api with incorrect api_key
            url = '/api/completedtask?project_id=1&api_key=BAD-api-key'
            res = self.app.get(url)
            err_msg = 'Status code should be 401'
            assert res.status_code == 401, err_msg

            url = "/project/%s?api_key=api-key1" % project.short_name
            res = self.app.get(url, follow_redirects=True, headers=headers)
            err_msg = 'app access should not be allowed with SECURE_APP_ACCESS enabled'
            assert "Sign in" in res.data, err_msg
Example #7
0
    def test_api_app_access_with_secure_app_access_disabled(self):
        """Test API and APP access with SECURE_APP_ACCESS disabled"""

        project = ProjectFactory.create()
        task = TaskFactory.create(project=project,
                                  n_answers=2,
                                  state='ongoing')
        task_repo = TaskRepository(db)

        with patch.dict(self.flask_app.config, {'SECURE_APP_ACCESS': False}):
            # Test no completedtask yet
            url = '/api/completedtask?project_id=1&api_key=api-key1'
            res = self.app.get(url)
            data = json.loads(res.data)
            assert len(data) == 0, data

            #  test task is completed
            task_runs = TaskRunFactory.create_batch(2, task=task)
            task.state = 'completed'
            task_repo.update(task)
            url = '/api/completedtask?project_id=1&api_key=api-key1'
            res = self.app.get(url)
            data = json.loads(res.data)

            # correct result
            assert data[0]['project_id'] == 1, data
            assert data[0]['state'] == u'completed', data

            # test api with incorrect api_key
            url = '/api/completedtask?project_id=1&api_key=bad-api-key'
            res = self.app.get(url)
            err_msg = 'Status code should be 401'
            assert res.status_code == 401, err_msg

            url = "/project/%s?api_key=api-key1" % project.short_name
            res = self.app.get(url, follow_redirects=True)
            err_msg = 'app access should be allowed with SECURE_APP_ACCESS disabled'
            assert not "Sign in" in res.data, err_msg
            assert "Statistics" in res.data
            assert 'id="percent-completed"' in res.data
            assert "<div>100%</div>" in res.data
Example #8
0
def setup_repositories():
    from pybossa.repositories import UserRepository
    from pybossa.repositories import ProjectRepository
    from pybossa.repositories import BlogRepository
    from pybossa.repositories import TaskRepository
    from pybossa.repositories import AuditlogRepository
    global user_repo
    global project_repo
    global blog_repo
    global task_repo
    global auditlog_repo
    user_repo = UserRepository(db)
    project_repo = ProjectRepository(db)
    blog_repo = BlogRepository(db)
    task_repo = TaskRepository(db)
    auditlog_repo = AuditlogRepository(db)
Example #9
0
def setup_repositories(app):
    """Setup repositories."""
    from pybossa.repositories import UserRepository
    from pybossa.repositories import ProjectRepository
    from pybossa.repositories import ProjectStatsRepository
    from pybossa.repositories import AnnouncementRepository
    from pybossa.repositories import BlogRepository
    from pybossa.repositories import TaskRepository
    from pybossa.repositories import AuditlogRepository
    from pybossa.repositories import WebhookRepository
    from pybossa.repositories import ResultRepository
    from pybossa.repositories import HelpingMaterialRepository
    from pybossa.repositories import PerformanceStatsRepository
    global user_repo
    global project_repo
    global project_stats_repo
    global announcement_repo
    global blog_repo
    global task_repo
    global auditlog_repo
    global webhook_repo
    global result_repo
    global helping_repo
    global performance_stats_repo
    language = app.config.get('FULLTEXTSEARCH_LANGUAGE')
    rdancy_upd_exp = app.config.get('REDUNDANCY_UPDATE_EXPIRATION', 30)
    user_repo = UserRepository(db)
    project_repo = ProjectRepository(db)
    project_stats_repo = ProjectStatsRepository(db)
    announcement_repo = AnnouncementRepository(db)
    blog_repo = BlogRepository(db)
    task_repo = TaskRepository(db, language, rdancy_upd_exp)
    auditlog_repo = AuditlogRepository(db)
    webhook_repo = WebhookRepository(db)
    result_repo = ResultRepository(db)
    helping_repo = HelpingMaterialRepository(db)
    performance_stats_repo = PerformanceStatsRepository(db)
Example #10
0
 def setUp(self):
     super(TestTaskRepositoryForTaskQueries, self).setUp()
     self.task_repo = TaskRepository(db)
Example #11
0
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
Example #12
0
class TestTaskRepositoryForTaskrunQueries(Test):

    def setUp(self):
        super(TestTaskRepositoryForTaskrunQueries, self).setUp()
        self.task_repo = TaskRepository(db)


    def test_get_task_run_return_none_if_no_task_run(self):
        """Test get_task_run method returns None if there is no taskrun with the
        specified id"""

        taskrun = self.task_repo.get_task_run(200)

        assert taskrun is None, taskrun


    def test_get_task_run_returns_task_run(self):
        """Test get_task_run method returns a taskrun if exists"""

        taskrun = TaskRunFactory.create()

        retrieved_taskrun = self.task_repo.get_task_run(taskrun.id)

        assert taskrun == retrieved_taskrun, retrieved_taskrun


    def test_get_task_run_by(self):
        """Test get_task_run_by returns a taskrun with the specified attribute"""

        taskrun = TaskRunFactory.create(info='info')

        retrieved_taskrun = self.task_repo.get_task_run_by(info=taskrun.info)

        assert taskrun == retrieved_taskrun, retrieved_taskrun

    def test_get_task_run_by_info_json(self):
        """Test get_task_run_by with JSON returns a
        taskrun with the specified attribute"""

        data = {'foo': 'bar'}
        taskrun = TaskRunFactory.create(info=data)

        info = 'foo::bar'
        retrieved_taskrun = self.task_repo.get_task_run_by(info=info)

        assert taskrun == retrieved_taskrun, retrieved_taskrun

    def test_get_task_run_by_info_json_fulltext(self):
        """Test get_task_run_by with JSON and fulltext returns a
        taskrun with the specified attribute"""

        data = {'foo': 'bar'}
        taskrun = TaskRunFactory.create(info=data)

        info = 'foo::bar'
        retrieved_taskrun = self.task_repo.get_task_run_by(info=info,
                                                           fulltextsearch='1')

        assert taskrun == retrieved_taskrun, retrieved_taskrun



    def test_get_task_run_by_returns_none_if_no_task_run(self):
        """Test get_task_run_by returns None if no taskrun matches the query"""

        TaskRunFactory.create(info='info')

        taskrun = self.task_repo.get_task_run_by(info='other info')

        assert taskrun is None, taskrun


    def test_filter_task_runs_by_no_matches(self):
        """Test filter_task_runs_by returns an empty list if no taskruns match
        the query"""

        TaskRunFactory.create(info='info')

        retrieved_taskruns = self.task_repo.filter_task_runs_by(info='other')

        assert isinstance(retrieved_taskruns, list)
        assert len(retrieved_taskruns) == 0, retrieved_taskruns


    def test_filter_task_runs_by_one_condition(self):
        """Test filter_task_runs_by returns a list of taskruns that meet the
        filtering condition"""

        TaskRunFactory.create_batch(3, info='info')
        should_be_missing = TaskFactory.create(info='other info')

        retrieved_taskruns = self.task_repo.filter_task_runs_by(info='info')

        assert len(retrieved_taskruns) == 3, retrieved_taskruns
        assert should_be_missing not in retrieved_taskruns, retrieved_taskruns


    def test_filter_task_runs_by_multiple_conditions(self):
        """Test filter_task_runs_by supports multiple-condition queries"""

        TaskRunFactory.create(info='info', user_ip='8.8.8.8')
        taskrun = TaskRunFactory.create(info='info', user_ip='1.1.1.1')

        retrieved_taskruns = self.task_repo.filter_task_runs_by(info='info',
                                                                user_ip='1.1.1.1')

        assert len(retrieved_taskruns) == 1, retrieved_taskruns
        assert taskrun in retrieved_taskruns, retrieved_taskruns


    def test_filter_task_runs_by_multiple_conditions_fulltext(self):
        """Test filter_task_runs_by supports multiple-condition
        fulltext queries"""

        text = 'you agent something word'
        data = {'foo': 'bar', 'bar': text}
        TaskRunFactory.create(info=data, user_ip='8.8.8.8')
        taskrun = TaskRunFactory.create(info=data, user_ip='1.1.1.1')

        info = 'foo::bar|bar::agent'
        retrieved_taskruns = self.task_repo.filter_task_runs_by(info=info,
                                                                user_ip='1.1.1.1',
                                                                fulltextsearch='1')

        assert len(retrieved_taskruns) == 1, retrieved_taskruns
        assert taskrun in retrieved_taskruns, retrieved_taskruns

        retrieved_taskruns = self.task_repo.filter_task_runs_by(info=info,
                                                                user_ip='1.1.1.1')
        assert len(retrieved_taskruns) == 0, retrieved_taskruns

    def test_filter_task_runs_support_yield_option(self):
        """Test that filter_task_runs_by with the yielded=True option returns
        the results as a generator"""

        task_runs = TaskRunFactory.create_batch(2, info='info')

        yielded_task_runs = self.task_repo.filter_task_runs_by(info='info',
                                                               yielded=True)

        import types
        assert isinstance(yielded_task_runs.__iter__(), types.GeneratorType)
        for taskrun in yielded_task_runs:
            assert taskrun in task_runs


    def test_filter_tasks_runs_limit_offset(self):
        """Test that filter_tasks_by supports limit and offset options"""

        TaskRunFactory.create_batch(4)
        all_task_runs = self.task_repo.filter_task_runs_by()

        first_two = self.task_repo.filter_task_runs_by(limit=2)
        last_two = self.task_repo.filter_task_runs_by(limit=2, offset=2)

        assert len(first_two) == 2, first_two
        assert len(last_two) == 2, last_two
        assert first_two == all_task_runs[:2]
        assert last_two == all_task_runs[2:]


    def test_count_task_runs_with_no_matches(self):
        """Test count_task_runs_with returns 0 if no taskruns match the query"""

        TaskRunFactory.create(info='info')

        count = self.task_repo.count_task_runs_with(info='other info')

        assert count == 0, count


    def test_count_task_runs_with_one_condition(self):
        """Test count_task_runs_with returns the number of taskruns that meet the
        filtering condition"""

        TaskRunFactory.create_batch(3, info='info')
        should_be_missing = TaskRunFactory.create(info='other info')

        count = self.task_repo.count_task_runs_with(info='info')

        assert count == 3, count


    def test_count_task_runs_with_multiple_conditions(self):
        """Test count_task_runs_with supports multiple-condition queries"""

        TaskRunFactory.create(info='info', user_ip='8.8.8.8')
        taskrun = TaskRunFactory.create(info='info', user_ip='1.1.1.1')

        count = self.task_repo.count_task_runs_with(info='info',
                                                    user_ip='1.1.1.1')

        assert count == 1, count
 def setUp(self):
     super(TestUserRepository, self).setUp()
     self.user_repo = UserRepository(db)
     self.task_repo = TaskRepository(db)
Example #14
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
Example #15
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 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
Example #17
0
class TestIIIFAnnotationAnalyst(Test):
    def setUp(self):
        super(TestIIIFAnnotationAnalyst, self).setUp()
        self.ctx = ContextFixtures()
        self.result_repo = ResultRepository(db)
        self.task_repo = TaskRepository(db)
        self.iiif_analyst = IIIFAnnotationAnalyst()
        self.comments = ['Some comment']
        self.tags = {
            'foo': [
                dict(x=100, y=100, w=100, h=100),
                dict(x=200, y=200, w=200, h=200)
            ],
            'bar': [dict(x=300, y=300, w=300, h=300)]
        }
        transcription_data = {'foo': ['bar', 'baz'], 'qux': ['quux', 'quuz']}
        self.transcriptions_df = pandas.DataFrame(transcription_data)

        self.comment_annos = []
        for comment in self.comments:
            self.comment_annos.append({
                'motivation': 'commenting',
                'body': {
                    'type': 'TextualBody',
                    'value': comment,
                    'purpose': 'commenting',
                    'format': 'text/plain'
                },
                'target': 'example.com'
            })

        self.tagging_annos = []
        for tag, rect_list in self.tags.items():
            for rect in rect_list:
                self.tagging_annos.append({
                    'motivation': 'tagging',
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect['x'], rect['y'], rect['w'], rect['h'])
                        }
                    }
                })

        self.transcription_annos = []
        for tag, value_list in transcription_data.items():
            for value in value_list:
                self.transcription_annos.append({
                    'motivation':
                    'describing',
                    'body': [{
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    }, {
                        'type': 'TextualBody',
                        'purpose': 'describing',
                        'value': value,
                        'format': 'text/plain'
                    }],
                    'target':
                    'example.com'
                })

        self.data = {
            'user_id': [1, 2, 3],
            'info':
            [self.comment_annos, self.tagging_annos, self.transcription_annos]
        }

    def test_get_comments(self):
        """Test IIIF Annotation comments are returned."""
        task_run_df = pandas.DataFrame(self.data)
        comments = self.iiif_analyst.get_comments(task_run_df)
        expected = [(1, comment) for comment in self.comments]
        assert_equal(comments, expected)

    def test_get_tags(self):
        """Test IIIF Annotation tags are returned."""
        task_run_df = pandas.DataFrame(self.data)
        tags = self.iiif_analyst.get_tags(task_run_df)
        assert_dict_equal(tags, self.tags)

    def test_get_tags_with_body_list(self):
        """Test IIIF Annotation tags are returned when body is a list."""
        self.tagging_annos[0]['body'] = [
            self.tagging_annos[0]['body'], {
                'type': 'TextualBody',
                'purpose': 'classifying',
                'value': 'foo'
            }
        ]
        task_run_df = pandas.DataFrame(self.data)
        tags = self.iiif_analyst.get_tags(task_run_df)
        assert_dict_equal(tags, self.tags)

    def test_get_transcriptions_df(self):
        """Test IIIF Annotation transcriptions are returned."""
        task_run_df = pandas.DataFrame(self.data)
        df = self.iiif_analyst.get_transcriptions_df(task_run_df)
        assert_dict_equal(df.to_dict(), self.transcriptions_df.to_dict())

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_analysis_with_no_transcriptions(self, mock_client):
        """Test IIIF analysis with no transcriptions."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info=[{
                                        'motivation':
                                        'describing',
                                        'body': [{
                                            'purpose': 'describing',
                                            'value': ''
                                        }, {
                                            'purpose': 'tagging',
                                            'value': 'foo'
                                        }]
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_fragment_selector_stripped(self, mock_client):
        """Test IIIF fragment selector is stripped if rule applied."""
        n_answers = 3
        source = 'example.com'
        target = {
            'source': source,
            'selector': {
                'conformsTo': 'http://www.w3.org/TR/media-frags/',
                'type': 'FragmentSelector',
                'value': '?xywh=100,100,100,100'
            }
        }
        rules = dict(remove_fragment_selector=True)
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules=rules,
                                    anno_collection=anno_collection)
        tag = 'foo'
        value = 'bar'
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info=[{
                                        'motivation':
                                        'describing',
                                        'body': [{
                                            'purpose': 'describing',
                                            'value': value
                                        }, {
                                            'purpose': 'tagging',
                                            'value': 'foo'
                                        }]
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'describing',
                'type':
                'Annotation',
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': [{
                    'type': 'TextualBody',
                    'purpose': 'describing',
                    'value': value,
                    'format': 'text/plain'
                }, {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                }],
                'target':
                source
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_comment_annotation_created(self, mock_client):
        """Test IIIF comment annotations are created."""
        n_answers = 1
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    anno_collection=anno_collection)
        user = UserFactory()
        value = 'foo'
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info=[{
                                        'motivation': 'commenting',
                                        'body': {
                                            'value': value
                                        }
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'commenting',
                'type':
                'Annotation',
                'creator': {
                    'id': url_for('api.api_user', oid=user.id),
                    'type': 'Person',
                    'name': user.fullname,
                    'nickname': user.name
                },
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'commenting',
                    'value': value,
                    'format': 'text/plain'
                },
                'target':
                target
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_transcriptions_are_normalised(self, mock_client):
        """Test IIIF transcriptions are normalised according to set rules."""
        n_answers = 1
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        rules = dict(case='title',
                     whitespace='full_stop',
                     trim_punctuation=True)
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules=rules,
                                    anno_collection=anno_collection)
        tag = 'foo'
        values = ['HeLLo!', ' hello ', ' hELLO.']
        for value in values:
            TaskRunFactory.create(task=task,
                                  info=[{
                                      'motivation':
                                      'describing',
                                      'body': [{
                                          'purpose': 'describing',
                                          'value': value
                                      }, {
                                          'purpose': 'tagging',
                                          'value': tag
                                      }]
                                  }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'describing',
                'type':
                'Annotation',
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': [{
                    'type': 'TextualBody',
                    'purpose': 'describing',
                    'value': 'Hello',
                    'format': 'text/plain'
                }, {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                }],
                'target':
                target
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_with_matching_transcriptions(self, mock_client):
        """Test IIIF results with matching transcriptions."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules={},
                                    anno_collection=anno_collection)
        value = 'foo'
        tag = 'bar'
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info=[{
                                        'motivation':
                                        'describing',
                                        'body': [{
                                            'purpose': 'describing',
                                            'value': value
                                        }, {
                                            'purpose': 'tagging',
                                            'value': tag
                                        }]
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'describing',
                'type':
                'Annotation',
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': [{
                    'type': 'TextualBody',
                    'purpose': 'describing',
                    'value': value,
                    'format': 'text/plain'
                }, {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                }],
                'target':
                target
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_increased_when_not_max(self, mock_client):
        """Test IIIF task redundancy is updated when max not reached."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    max_answers=n_answers + 1)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info=[{
                                      'motivation':
                                      'describing',
                                      'body': [{
                                          'purpose': 'describing',
                                          'value': i
                                      }, {
                                          'purpose': 'tagging',
                                          'value': i
                                      }]
                                  }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers + 1)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_when_max(self, mock_client):
        """Test IIIF task redundancy is not updated when max is reached."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target, max_answers=n_answers)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info=[{
                                      'motivation':
                                      'describing',
                                      'body': [{
                                          'purpose': 'describing',
                                          'value': i
                                      }, {
                                          'purpose': 'tagging',
                                          'value': i
                                      }]
                                  }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_for_tags(self, mock_client):
        """Test IIIF task redundancy is not updated for tags."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    max_answers=n_answers + 1)
        for i in range(n_answers):
            TaskRunFactory.create(
                task=task,
                info=[{
                    'motivation': 'tagging',
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': 'foo'
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo': 'http://www.w3.org/TR/media-frags/',
                            'type': 'FragmentSelector',
                            'value': '?xywh={0},{0},{0},{0}'.format(i)
                        }
                    }
                }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_for_comments(self, mock_client):
        """Test IIIF task redundancy is not updated for comments."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    max_answers=n_answers + 1)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info=[{
                                      'motivation': 'commenting',
                                      'body': {
                                          'type': 'TextualBody',
                                          'value': i,
                                          'purpose': 'commenting',
                                          'format': 'text/plain'
                                      }
                                  }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)

        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_when_no_values(self, mock_client):
        """Test IIIF task redundancy is not updated when no values."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    max_answers=n_answers + 1)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info=[{
                                      'motivation':
                                      'describing',
                                      'body': [{
                                          'purpose': 'describing',
                                          'value': ''
                                      }, {
                                          'purpose': 'tagging',
                                          'value': 'foo'
                                      }]
                                  }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_equal_regions_combined(self, mock_client):
        """Test IIIF equal tag regions are combined."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules={},
                                    anno_collection=anno_collection)
        rect = dict(x=400, y=200, w=100, h=150)
        tag = 'foo'
        TaskRunFactory.create_batch(
            n_answers,
            task=task,
            info=[{
                'motivation': 'tagging',
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                },
                'target': {
                    'source': 'example.com',
                    'selector': {
                        'conformsTo':
                        'http://www.w3.org/TR/media-frags/',
                        'type':
                        'FragmentSelector',
                        'value':
                        '?xywh={0},{1},{2},{3}'.format(rect['x'], rect['y'],
                                                       rect['w'], rect['h'])
                    }
                }
            }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'tagging',
                'type':
                'Annotation',
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                },
                'target': {
                    'source': 'example.com',
                    'selector': {
                        'conformsTo':
                        'http://www.w3.org/TR/media-frags/',
                        'type':
                        'FragmentSelector',
                        'value':
                        '?xywh={0},{1},{2},{3}'.format(rect['x'], rect['y'],
                                                       rect['w'], rect['h'])
                    }
                }
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_equal_regions_combined(self, mock_client):
        """Test IIIF equal tag regions are combined."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules={},
                                    anno_collection=anno_collection)
        rect = dict(x=400, y=200, w=100, h=150)
        tag = 'foo'
        TaskRunFactory.create_batch(
            n_answers,
            task=task,
            info=[{
                'motivation': 'tagging',
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                },
                'target': {
                    'source': 'example.com',
                    'selector': {
                        'conformsTo':
                        'http://www.w3.org/TR/media-frags/',
                        'type':
                        'FragmentSelector',
                        'value':
                        '?xywh={0},{1},{2},{3}'.format(rect['x'], rect['y'],
                                                       rect['w'], rect['h'])
                    }
                }
            }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'tagging',
                'type':
                'Annotation',
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                },
                'target': {
                    'source': 'example.com',
                    'selector': {
                        'conformsTo':
                        'http://www.w3.org/TR/media-frags/',
                        'type':
                        'FragmentSelector',
                        'value':
                        '?xywh={0},{1},{2},{3}'.format(rect['x'], rect['y'],
                                                       rect['w'], rect['h'])
                    }
                }
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_similar_regions_combined(self, mock_client):
        """Test IIIF similar tag regions are combined."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules={},
                                    anno_collection=anno_collection)
        rect1 = dict(x=90, y=100, w=110, h=90)
        rect2 = dict(x=100, y=110, w=90, h=100)
        rect3 = dict(x=110, y=90, w=100, h=110)
        rects = [rect1, rect2, rect3]
        tag = 'foo'
        for rect in rects:
            TaskRunFactory.create(
                task=task,
                info=[{
                    'motivation': 'tagging',
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect['x'], rect['y'], rect['w'], rect['h'])
                        }
                    }
                }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'tagging',
                'type':
                'Annotation',
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'tagging',
                    'value': tag
                },
                'target': {
                    'source': 'example.com',
                    'selector': {
                        'conformsTo': 'http://www.w3.org/TR/media-frags/',
                        'type': 'FragmentSelector',
                        'value': '?xywh=90,90,120,110'
                    }
                }
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_different_regions_combined(self, mock_client):
        """Test IIIF different tag regions are not combined."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules={},
                                    anno_collection=anno_collection)
        rect1 = dict(x=10, y=10, w=10, h=10)
        rect2 = dict(x=100, y=100, w=100, h=100)
        rect3 = dict(x=200, y=200, w=200, h=200)
        rects = [rect1, rect2, rect3]
        tag = 'foo'
        for rect in rects:
            TaskRunFactory.create(
                task=task,
                info=[{
                    'motivation': 'tagging',
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect['x'], rect['y'], rect['w'], rect['h'])
                        }
                    }
                }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.call_args_list, [
            call(
                anno_collection, {
                    'motivation':
                    'tagging',
                    'type':
                    'Annotation',
                    'generator':
                    [{
                        "id": flask_app.config.get('GITHUB_REPO'),
                        "type": "Software",
                        "name": "LibCrowds",
                        "homepage": flask_app.config.get('SPA_SERVER_NAME')
                    }, {
                        "id": url_for('api.api_task', oid=task.id),
                        "type": "Software"
                    }],
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect1['x'], rect1['y'], rect1['w'], rect1['h'])
                        }
                    }
                }),
            call(
                anno_collection, {
                    'motivation':
                    'tagging',
                    'type':
                    'Annotation',
                    'generator': [
                        {
                            "id": flask_app.config.get('GITHUB_REPO'),
                            "type": "Software",
                            "name": "LibCrowds",
                            "homepage": flask_app.config.get('SPA_SERVER_NAME')
                        }, {
                            "id": url_for('api.api_task', oid=task.id),
                            "type": "Software"
                        }
                    ],
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect2['x'], rect2['y'], rect2['w'], rect2['h'])
                        }
                    }
                }),
            call(
                anno_collection, {
                    'motivation':
                    'tagging',
                    'type':
                    'Annotation',
                    'generator': [
                        {
                            "id": flask_app.config.get('GITHUB_REPO'),
                            "type": "Software",
                            "name": "LibCrowds",
                            "homepage": flask_app.config.get('SPA_SERVER_NAME')
                        }, {
                            "id": url_for('api.api_task', oid=task.id),
                            "type": "Software"
                        }
                    ],
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect3['x'], rect3['y'], rect3['w'], rect3['h'])
                        }
                    }
                })
        ])

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_old_annotations_deleted(self, mock_client):
        """Test IIIF old Annotations deleted."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        user = UserFactory()
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info=[{
                                        'motivation': 'commenting',
                                        'body': {
                                            'value': 'foo'
                                        }
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_annos = [{'id': 'baz'}, {'id': 'qux'}]
        fake_search = MagicMock()
        fake_search.return_value = fake_annos
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id, analyse_full=True)
        mock_client.delete_batch.assert_called_once_with(fake_annos)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_results_with_annotations_not_analysed(self, mock_client):
        """Test results with Annotations already not analysed by default."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        user = UserFactory()
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info=[{
                                        'motivation': 'commenting',
                                        'body': {
                                            'value': 'foo'
                                        }
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_annos = [{'id': 'baz'}, {'id': 'qux'}]
        fake_search = MagicMock()
        fake_search.return_value = fake_annos
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert_equal(mock_client.delete_batch.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_annotation_collection_iri_added_to_result_info(self, mock_client):
        """Test IIIF result info updated with AnnotationCollection IRI."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'annotations.example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    anno_collection=anno_collection)
        user = UserFactory()
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info=[{
                                        'motivation': 'commenting',
                                        'body': {
                                            'value': 'foo'
                                        }
                                    }])
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert_dict_equal(result.info, {'annotations': anno_collection})

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_task_rejected(self, mock_client):
        """Test IIIF annotation not created when task rejected * n_answers."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'annotations.example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    anno_collection=anno_collection)
        user = UserFactory()
        reason = 'invalid-task'
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info={'reject': reason})
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.iiif_analyst.analyse(result.id)
        assert not mock_client.create_annotation.called
        assert_dict_equal(result.info, {
            'annotations': anno_collection,
            'rejected': reason
        })
Example #18
0
class TestZ3950Analyst(Test):
    def setUp(self):
        super(TestZ3950Analyst, self).setUp()
        self.ctx = ContextFixtures()
        self.z3950_analyst = Z3950Analyst()
        self.result_repo = ResultRepository(db)
        self.task_repo = TaskRepository(db)
        self.data = {
            'user_id': [1],
            'control_number': ['123'],
            'reference': ['abc'],
            'foo': ['bar'],
            'comments': ['Some comment']
        }

    def test_get_comments(self):
        """Test Z3950 comments are returned."""
        task_run_df = pandas.DataFrame(self.data)
        comments = self.z3950_analyst.get_comments(task_run_df)
        expected = [(self.data['user_id'][i], self.data['comments'][i])
                    for i in range(len(self.data['user_id']))]
        assert_equal(comments, expected)

    def test_get_tags(self):
        """Test Z3950 tags are returned."""
        task_run_df = pandas.DataFrame(self.data)
        tags = self.z3950_analyst.get_tags(task_run_df)
        assert_dict_equal(tags, {})

    def test_get_transcriptions_df(self):
        """Test Z3950 transcriptions are returned."""
        task_run_df = pandas.DataFrame(self.data)
        df = self.z3950_analyst.get_transcriptions_df(task_run_df)
        assert_dict_equal(
            df.to_dict(), {
                'control_number': dict(enumerate(self.data['control_number'])),
                'reference': dict(enumerate(self.data['reference']))
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_analysis_with_no_transcriptions(self, mock_client):
        """Test Z3950 analysis with no transcriptions."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'control_number': '',
                                        'reference': '',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_analysis_with_no_transcriptions_and_old_keys(self, mock_client):
        """Test Z3950 analysis with no transcriptions and old keys."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'oclc': '',
                                        'shelfmark': '',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_analysis_with_no_reference(self, mock_client):
        """Test Z3950 analysis with no reference."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'control_number': 'foo',
                                        'reference': '',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_analysis_with_no_control_number(self, mock_client):
        """Test Z3950 analysis with no control number."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'control_number': '',
                                        'reference': 'foo',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_comment_annotation_created(self, mock_client):
        """Test Z3950 comment annotations are created."""
        n_answers = 1
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    anno_collection=anno_collection)
        user = UserFactory()
        value = 'foo'
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info={
                                        'control_number': '',
                                        'reference': '',
                                        'comments': value
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        func = mock_client.create_annotation
        func.assert_called_once_with(
            anno_collection, {
                'motivation':
                'commenting',
                'type':
                'Annotation',
                'creator': {
                    'id': url_for('api.api_user', oid=user.id),
                    'type': 'Person',
                    'name': user.fullname,
                    'nickname': user.name
                },
                'generator':
                [{
                    "id": flask_app.config.get('GITHUB_REPO'),
                    "type": "Software",
                    "name": "LibCrowds",
                    "homepage": flask_app.config.get('SPA_SERVER_NAME')
                }, {
                    "id": url_for('api.api_task', oid=task.id),
                    "type": "Software"
                }],
                'body': {
                    'type': 'TextualBody',
                    'purpose': 'commenting',
                    'value': value,
                    'format': 'text/plain'
                },
                'target':
                target
            })

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_transcriptions_are_normalised(self, mock_client):
        """Test Z3950 transcriptions are normalised according to set rules."""
        n_answers = 1
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        rules = dict(case='title',
                     whitespace='full_stop',
                     trim_punctuation=True)
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules=rules,
                                    anno_collection=anno_collection)
        control_number = 'foo'
        references = ['OR 123  456.', 'Or.123.456. ', 'or 123 456']
        for value in references:
            TaskRunFactory.create(task=task,
                                  info={
                                      'reference': value,
                                      'control_number': control_number,
                                      'comments': ''
                                  })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(
            mock_client.create_annotation.call_args_list, [
                call(
                    anno_collection, {
                        'motivation':
                        'describing',
                        'type':
                        'Annotation',
                        'generator':
                        [{
                            "id": flask_app.config.get('GITHUB_REPO'),
                            "type": "Software",
                            "name": "LibCrowds",
                            "homepage": flask_app.config.get('SPA_SERVER_NAME')
                        }, {
                            "id": url_for('api.api_task', oid=task.id),
                            "type": "Software"
                        }],
                        'body': [{
                            'type': 'TextualBody',
                            'purpose': 'describing',
                            'value': control_number.capitalize(),
                            'format': 'text/plain'
                        }, {
                            'type': 'TextualBody',
                            'purpose': 'tagging',
                            'value': 'control_number'
                        }],
                        'target':
                        target
                    }),
                call(
                    anno_collection, {
                        'motivation':
                        'describing',
                        'type':
                        'Annotation',
                        'generator': [
                            {
                                "id": flask_app.config.get('GITHUB_REPO'),
                                "type": "Software",
                                "name": "LibCrowds",
                                "homepage":
                                flask_app.config.get('SPA_SERVER_NAME')
                            }, {
                                "id": url_for('api.api_task', oid=task.id),
                                "type": "Software"
                            }
                        ],
                        'body': [{
                            'type': 'TextualBody',
                            'purpose': 'describing',
                            'value': 'Or.123.456',
                            'format': 'text/plain'
                        }, {
                            'type': 'TextualBody',
                            'purpose': 'tagging',
                            'value': 'reference'
                        }],
                        'target':
                        target
                    })
            ])

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_with_matching_transcriptions(self, mock_client):
        """Test Z3950 results with matching transcriptions."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'http://eg.com/collection'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    rules={},
                                    anno_collection=anno_collection)
        reference = 'foo'
        control_number = 'bar'
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'reference': reference,
                                        'control_number': control_number,
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        func = mock_client.create_annotation
        assert_equal(
            mock_client.create_annotation.call_args_list, [
                call(
                    anno_collection, {
                        'motivation':
                        'describing',
                        'type':
                        'Annotation',
                        'generator':
                        [{
                            "id": flask_app.config.get('GITHUB_REPO'),
                            "type": "Software",
                            "name": "LibCrowds",
                            "homepage": flask_app.config.get('SPA_SERVER_NAME')
                        }, {
                            "id": url_for('api.api_task', oid=task.id),
                            "type": "Software"
                        }],
                        'body': [{
                            'type': 'TextualBody',
                            'purpose': 'describing',
                            'value': control_number,
                            'format': 'text/plain'
                        }, {
                            'type': 'TextualBody',
                            'purpose': 'tagging',
                            'value': 'control_number'
                        }],
                        'target':
                        target
                    }),
                call(
                    anno_collection, {
                        'motivation':
                        'describing',
                        'type':
                        'Annotation',
                        'generator': [
                            {
                                "id": flask_app.config.get('GITHUB_REPO'),
                                "type": "Software",
                                "name": "LibCrowds",
                                "homepage":
                                flask_app.config.get('SPA_SERVER_NAME')
                            }, {
                                "id": url_for('api.api_task', oid=task.id),
                                "type": "Software"
                            }
                        ],
                        'body': [{
                            'type': 'TextualBody',
                            'purpose': 'describing',
                            'value': reference,
                            'format': 'text/plain'
                        }, {
                            'type': 'TextualBody',
                            'purpose': 'tagging',
                            'value': 'reference'
                        }],
                        'target':
                        target
                    })
            ])

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_increased_when_not_max(self, mock_client):
        """Test Z3950 task redundancy is updated when max not reached."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target, max_answers=4)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info={
                                      'reference': i,
                                      'control_number': i,
                                      'comments': ''
                                  })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers + 1)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_when_max(self, mock_client):
        """Test Z3950 task redundancy is not updated when max is reached."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target, max_answers=3)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info={
                                      'reference': i,
                                      'control_number': i,
                                      'comments': ''
                                  })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.create_annotation.called, False)

        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_for_comments(self, mock_client):
        """Test Z3950 task redundancy is not updated for comments."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    max_answers=n_answers + 1)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info={
                                      'reference': 'foo',
                                      'control_number': 'bar',
                                      'comments': i
                                  })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_redundancy_not_increased_when_no_values(self, mock_client):
        """Test Z3950 task redundancy is not updated when no values."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    max_answers=n_answers + 1)
        for i in range(n_answers):
            TaskRunFactory.create(task=task,
                                  info={
                                      'reference': '',
                                      'control_number': '',
                                      'comments': ''
                                  })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        updated_task = self.task_repo.get_task(task.id)
        assert_equal(updated_task.n_answers, n_answers)
        assert_equal(mock_client.create_annotation.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_old_annotations_deleted(self, mock_client):
        """Test Z3950 old Annotations deleted."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'reference': '',
                                        'control_number': '',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_annos = [{'id': 'baz'}, {'id': 'qux'}]
        fake_search = MagicMock()
        fake_search.return_value = fake_annos
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id, analyse_full=True)
        mock_client.delete_batch.assert_called_once_with(fake_annos)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_results_with_annotations_not_analysed(self, mock_client):
        """Test results with Annotations already not analysed by default."""
        n_answers = 3
        target = 'example.com'
        task = self.ctx.create_task(n_answers, target)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'reference': 'foo',
                                        'control_number': 'bar',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_annos = [{'id': 'baz'}, {'id': 'qux'}]
        fake_search = MagicMock()
        fake_search.return_value = fake_annos
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_equal(mock_client.delete_batch.called, False)

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_annotation_collection_iri_added_to_result_info(self, mock_client):
        """Test Z3950 result info updated with AnnotationCollection IRI."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'annotations.example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    anno_collection=anno_collection)
        TaskRunFactory.create_batch(n_answers,
                                    task=task,
                                    info={
                                        'reference': 'foo',
                                        'control_number': 'bar',
                                        'comments': ''
                                    })
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert_dict_equal(result.info, {'annotations': anno_collection})

    @with_context
    @patch('pybossa_lc.model.base.wa_client')
    def test_task_rejected(self, mock_client):
        """Test Z3950 annotation not created when task rejected * n_answers."""
        n_answers = 3
        target = 'example.com'
        anno_collection = 'annotations.example.com'
        task = self.ctx.create_task(n_answers,
                                    target,
                                    anno_collection=anno_collection)
        user = UserFactory()
        reason = 'invalid-task'
        TaskRunFactory.create_batch(n_answers,
                                    user=user,
                                    task=task,
                                    info={'reject': reason})
        result = self.result_repo.filter_by(project_id=task.project_id)[0]
        fake_search = MagicMock()
        fake_search.return_value = []
        mock_client.search_annotations = fake_search
        self.z3950_analyst.analyse(result.id)
        assert not mock_client.create_annotation.called
        assert_dict_equal(result.info, {
            'annotations': anno_collection,
            'rejected': reason
        })
Example #19
0
    def setUp(self):
        super(TestIIIFAnnotationAnalyst, self).setUp()
        self.ctx = ContextFixtures()
        self.result_repo = ResultRepository(db)
        self.task_repo = TaskRepository(db)
        self.iiif_analyst = IIIFAnnotationAnalyst()
        self.comments = ['Some comment']
        self.tags = {
            'foo': [
                dict(x=100, y=100, w=100, h=100),
                dict(x=200, y=200, w=200, h=200)
            ],
            'bar': [dict(x=300, y=300, w=300, h=300)]
        }
        transcription_data = {'foo': ['bar', 'baz'], 'qux': ['quux', 'quuz']}
        self.transcriptions_df = pandas.DataFrame(transcription_data)

        self.comment_annos = []
        for comment in self.comments:
            self.comment_annos.append({
                'motivation': 'commenting',
                'body': {
                    'type': 'TextualBody',
                    'value': comment,
                    'purpose': 'commenting',
                    'format': 'text/plain'
                },
                'target': 'example.com'
            })

        self.tagging_annos = []
        for tag, rect_list in self.tags.items():
            for rect in rect_list:
                self.tagging_annos.append({
                    'motivation': 'tagging',
                    'body': {
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    },
                    'target': {
                        'source': 'example.com',
                        'selector': {
                            'conformsTo':
                            'http://www.w3.org/TR/media-frags/',
                            'type':
                            'FragmentSelector',
                            'value':
                            '?xywh={0},{1},{2},{3}'.format(
                                rect['x'], rect['y'], rect['w'], rect['h'])
                        }
                    }
                })

        self.transcription_annos = []
        for tag, value_list in transcription_data.items():
            for value in value_list:
                self.transcription_annos.append({
                    'motivation':
                    'describing',
                    'body': [{
                        'type': 'TextualBody',
                        'purpose': 'tagging',
                        'value': tag
                    }, {
                        'type': 'TextualBody',
                        'purpose': 'describing',
                        'value': value,
                        'format': 'text/plain'
                    }],
                    'target':
                    'example.com'
                })

        self.data = {
            'user_id': [1, 2, 3],
            'info':
            [self.comment_annos, self.tagging_annos, self.transcription_annos]
        }
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
Example #21
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_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
Example #22
0
 def setUp(self):
     super(TestTaskRepositorySaveDeleteUpdate, self).setUp()
     self.task_repo = TaskRepository(db)
class TestUserRepository(Test):
    def setUp(self):
        super(TestUserRepository, self).setUp()
        self.user_repo = UserRepository(db)
        self.task_repo = TaskRepository(db)

    @with_context
    def test_get_return_none_if_no_user(self):
        """Test get method returns None if there is no user with the
        specified id"""

        user = self.user_repo.get(200)

        assert user is None, user

    @with_context
    def test_get_returns_user(self):
        """Test get method returns a user if exists"""

        user = UserFactory.create()

        retrieved_user = self.user_repo.get(user.id)

        assert user == retrieved_user, retrieved_user

    @with_context
    def test_get_by_name_return_none_if_no_user(self):
        """Test get_by_name returns None when a user with the specified
        name does not exist"""

        user = self.user_repo.get_by_name('thisuserdoesnotexist')

        assert user is None, user

    @with_context
    def test_get_by_name_returns_the_user(self):
        """Test get_by_name returns a user if exists"""

        user = UserFactory.create()

        retrieved_user = self.user_repo.get_by_name(user.name)

        assert user == retrieved_user, retrieved_user

    @with_context
    def test_get_by(self):
        """Test get_by returns a user with the specified attribute"""

        user = UserFactory.create(name='Jon Snow')

        retrieved_user = self.user_repo.get_by(name=user.name)

        assert user == retrieved_user, retrieved_user

    @with_context
    def test_get_by_returns_none_if_no_user(self):
        """Test get_by returns None if no user matches the query"""

        UserFactory.create(name='Tyrion Lannister')

        user = self.user_repo.get_by(name='no_name')

        assert user is None, user

    @with_context
    def get_all_returns_list_of_all_users(self):
        """Test get_all returns a list of all the existing users"""

        users = UserFactory.create_batch(3)

        retrieved_users = self.user_repo.get_all()

        assert isinstance(retrieved_users, list)
        assert len(retrieved_users) == len(users), retrieved_users
        for user in retrieved_users:
            assert user in users, user

    @with_context
    def test_filter_by_no_matches(self):
        """Test filter_by returns an empty list if no users match the query"""

        UserFactory.create(name='reek', fullname='Theon Greyjoy')

        retrieved_users = self.user_repo.filter_by(name='asha')

        assert isinstance(retrieved_users, list)
        assert len(retrieved_users) == 0, retrieved_users

    @with_context
    def test_filter_by_one_condition(self):
        """Test filter_by returns a list of users that meet the filtering
        condition"""

        UserFactory.create_batch(3, locale='es')
        should_be_missing = UserFactory.create(locale='fr')

        retrieved_users = self.user_repo.filter_by(locale='es')

        assert len(retrieved_users) == 3, retrieved_users
        assert should_be_missing not in retrieved_users, retrieved_users

    @with_context
    def test_filter_by_multiple_conditions(self):
        """Test filter_by supports multiple-condition queries"""

        UserFactory.create_batch(2, locale='es', privacy_mode=True)
        user = UserFactory.create(locale='es', privacy_mode=False)

        retrieved_users = self.user_repo.filter_by(locale='es',
                                                   privacy_mode=False)

        assert len(retrieved_users) == 1, retrieved_users
        assert user in retrieved_users, retrieved_users

    @with_context
    def test_filter_by_limit_offset(self):
        """Test that filter_by supports limit and offset options"""

        UserFactory.create_batch(4)
        all_users = self.user_repo.filter_by()

        first_two = self.user_repo.filter_by(limit=2)
        last_two = self.user_repo.filter_by(limit=2, offset=2)

        assert len(first_two) == 2, first_two
        assert len(last_two) == 2, last_two
        assert first_two == all_users[:2]
        assert last_two == all_users[2:]

    @with_context
    def test_search_by_name_returns_list(self):
        """Test search_by_name returns a list with search results"""

        search = self.user_repo.search_by_name('')

        assert isinstance(search, list), search.__class__

    @with_context
    def test_search_by_name(self):
        """Test search_by_name returns a list with the user if searching by
        either its name or fullname"""

        user = UserFactory.create(name='greenseer', fullname='Jojen Reed')

        search_by_name = self.user_repo.search_by_name('greenseer')
        search_by_fullname = self.user_repo.search_by_name('Jojen Reed')

        assert user in search_by_name, search_by_name
        assert user in search_by_fullname, search_by_fullname

    @with_context
    def test_search_by_name_capital_lower_letters(self):
        """Test search_by_name works the same with capital or lower letters"""

        user_capitals = UserFactory.create(name='JOJEN')
        user_lowers = UserFactory.create(name='meera')

        search_lower = self.user_repo.search_by_name('jojen')
        search_capital = self.user_repo.search_by_name('MEERA')

        assert user_capitals in search_lower, search_lower
        assert user_lowers in search_capital, search_capital

    @with_context
    def test_search_by_name_substrings(self):
        """Test search_by_name works when searching by a substring"""

        user = UserFactory.create(name='Hodor')

        search = self.user_repo.search_by_name('odo')

        assert user in search, search

    @with_context
    def test_search_by_name_empty_string(self):
        """Test search_by_name returns an empty list when searching by '' """

        user = UserFactory.create(name='Brandon')

        search = self.user_repo.search_by_name('')

        assert len(search) == 0, search

    @with_context
    def test_total_users_no_users(self):
        """Test total_users return 0 if there are no users"""

        count = self.user_repo.total_users()

        assert count == 0, count

    @with_context
    def test_total_users_count(self):
        """Test total_users return 1 if there is one user"""

        UserFactory.create()
        count = self.user_repo.total_users()

        assert count == 1, count

    @with_context
    def test_save(self):
        """Test save persist the user"""

        user = UserFactory.build()
        assert self.user_repo.get(user.id) is None

        self.user_repo.save(user)

        assert self.user_repo.get(user.id) == user, "User 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"""

        user = UserFactory.build(name=None)

        assert_raises(DBIntegrityError, self.user_repo.save, user)

    @with_context
    def test_save_only_saves_users(self):
        """Test save raises a WrongObjectError when an object which is not
        a User instance is saved"""

        bad_object = dict()

        assert_raises(WrongObjectError, self.user_repo.save, bad_object)

    @with_context
    def test_update(self):
        """Test update persists the changes made to the user"""

        user = UserFactory.create(locale='en')
        user.locale = 'it'

        self.user_repo.update(user)
        updated_user = self.user_repo.get(user.id)

        assert updated_user.locale == 'it', updated_user

    @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"""

        user = UserFactory.create()
        user.name = None

        assert_raises(DBIntegrityError, self.user_repo.update, user)

    @with_context
    def test_update_only_updates_users(self):
        """Test update raises a WrongObjectError when an object which is not
        a User instance is updated"""

        bad_object = dict()

        assert_raises(WrongObjectError, self.user_repo.update, bad_object)

    @with_context
    def test_get_users_no_args(self):
        """Test get users by id returns empty list
        """
        assert self.user_repo.get_users(None) == []

    @with_context
    def test_get_users(self):

        tyrion = UserFactory.create(name='Tyrion Lannister')
        theon = UserFactory.create(name='reek', fullname='Theon Greyjoy')
        robb = UserFactory.create(fullname='Robb Stark')

        retrieved_users = self.user_repo.get_users([tyrion.id, theon.id])
        assert any(user == tyrion for user in retrieved_users)
        assert any(user == theon for user in retrieved_users)
        assert all(user != robb for user in retrieved_users)

    @with_context
    def test_delete_user(self):
        """Test USER delete works."""
        user = UserFactory.create()
        user_id = user.id
        user = self.user_repo.get_by(id=user_id)
        assert user.id == user_id
        self.user_repo.delete(user)
        user = self.user_repo.get_by(id=user_id)
        assert user is None

    @with_context
    def test_fake_user_id(self):
        """Test remove user ID works and it's replaced by a fake IP."""
        user = UserFactory.create()
        taskruns = TaskRunFactory.create_batch(3, user=user)
        fake_ips = []
        assert taskruns[0].user_id == user.id
        self.user_repo.fake_user_id(user)
        for taskrun in taskruns:
            taskrun = self.task_repo.get_task_run_by(id=taskrun.id)
            assert taskrun.user_id is None
            assert taskrun.user_ip is not None
            fake_ips.append(taskrun.user_ip)
        assert len(set(fake_ips)) == 3

    @with_context
    def test_delete_user_with_task_runs(self):
        """Delete user with task runs works."""
        user = UserFactory.create()
        taskruns = TaskRunFactory.create_batch(3, user=user)
        fake_ips = []
        user_id = user.id
        assert taskruns[0].user_id == user.id
        self.user_repo.delete(user)
        for taskrun in taskruns:
            taskrun = self.task_repo.get_task_run_by(id=taskrun.id)
            assert taskrun.user_id is None
            assert taskrun.user_ip is not None
            fake_ips.append(taskrun.user_ip)
        assert len(set(fake_ips)) == 3
        user = self.user_repo.get_by(id=user_id)
        assert user is None
Example #24
0
class TestTaskRepositoryForTaskrunQueries(Test):
    def setUp(self):
        super(TestTaskRepositoryForTaskrunQueries, self).setUp()
        self.task_repo = TaskRepository(db)

    def test_get_task_run_return_none_if_no_task_run(self):
        """Test get_task_run method returns None if there is no taskrun with the
        specified id"""

        taskrun = self.task_repo.get_task_run(200)

        assert taskrun is None, taskrun

    def test_get_task_run_returns_task_run(self):
        """Test get_task_run method returns a taskrun if exists"""

        taskrun = TaskRunFactory.create()

        retrieved_taskrun = self.task_repo.get_task_run(taskrun.id)

        assert taskrun == retrieved_taskrun, retrieved_taskrun

    def test_get_task_run_by(self):
        """Test get_task_run_by returns a taskrun with the specified attribute"""

        taskrun = TaskRunFactory.create(info='info')

        retrieved_taskrun = self.task_repo.get_task_run_by(info=taskrun.info)

        assert taskrun == retrieved_taskrun, retrieved_taskrun

    def test_get_task_run_by_returns_none_if_no_task_run(self):
        """Test get_task_run_by returns None if no taskrun matches the query"""

        TaskRunFactory.create(info='info')

        taskrun = self.task_repo.get_task_run_by(info='other info')

        assert taskrun is None, taskrun

    def test_filter_task_runs_by_no_matches(self):
        """Test filter_task_runs_by returns an empty list if no taskruns match
        the query"""

        TaskRunFactory.create(info='info')

        retrieved_taskruns = self.task_repo.filter_task_runs_by(info='other')

        assert isinstance(retrieved_taskruns, list)
        assert len(retrieved_taskruns) == 0, retrieved_taskruns

    def test_filter_task_runs_by_one_condition(self):
        """Test filter_task_runs_by returns a list of taskruns that meet the
        filtering condition"""

        TaskRunFactory.create_batch(3, info='info')
        should_be_missing = TaskFactory.create(info='other info')

        retrieved_taskruns = self.task_repo.filter_task_runs_by(info='info')

        assert len(retrieved_taskruns) == 3, retrieved_taskruns
        assert should_be_missing not in retrieved_taskruns, retrieved_taskruns

    def test_filter_task_runs_by_multiple_conditions(self):
        """Test filter_task_runs_by supports multiple-condition queries"""

        TaskRunFactory.create(info='info', user_ip='8.8.8.8')
        taskrun = TaskRunFactory.create(info='info', user_ip='1.1.1.1')

        retrieved_taskruns = self.task_repo.filter_task_runs_by(
            info='info', user_ip='1.1.1.1')

        assert len(retrieved_taskruns) == 1, retrieved_taskruns
        assert taskrun in retrieved_taskruns, retrieved_taskruns

    def test_filter_task_runs_support_yield_option(self):
        """Test that filter_task_runs_by with the yielded=True option returns
        the results as a generator"""

        task_runs = TaskRunFactory.create_batch(2, info='info')

        yielded_task_runs = self.task_repo.filter_task_runs_by(info='info',
                                                               yielded=True)

        import types
        assert isinstance(yielded_task_runs.__iter__(), types.GeneratorType)
        for taskrun in yielded_task_runs:
            assert taskrun in task_runs

    def test_filter_tasks_limit_offset(self):
        """Test that filter_tasks_by supports limit and offset options"""

        TaskRunFactory.create_batch(4)
        all_task_runs = self.task_repo.filter_task_runs_by()

        first_two = self.task_repo.filter_task_runs_by(limit=2)
        last_two = self.task_repo.filter_task_runs_by(limit=2, offset=2)

        assert len(first_two) == 2, first_two
        assert len(last_two) == 2, last_two
        assert first_two == all_task_runs[:2]
        assert last_two == all_task_runs[2:]

    def test_count_task_runs_with_no_matches(self):
        """Test count_task_runs_with returns 0 if no taskruns match the query"""

        TaskRunFactory.create(info='info')

        count = self.task_repo.count_task_runs_with(info='other info')

        assert count == 0, count

    def test_count_task_runs_with_one_condition(self):
        """Test count_task_runs_with returns the number of taskruns that meet the
        filtering condition"""

        TaskRunFactory.create_batch(3, info='info')
        should_be_missing = TaskRunFactory.create(info='other info')

        count = self.task_repo.count_task_runs_with(info='info')

        assert count == 3, count

    def test_count_task_runs_with_multiple_conditions(self):
        """Test count_task_runs_with supports multiple-condition queries"""

        TaskRunFactory.create(info='info', user_ip='8.8.8.8')
        taskrun = TaskRunFactory.create(info='info', user_ip='1.1.1.1')

        count = self.task_repo.count_task_runs_with(info='info',
                                                    user_ip='1.1.1.1')

        assert count == 1, count
Example #25
0
class TestUserRepository(Test):

    def setUp(self):
        super(TestUserRepository, self).setUp()
        self.user_repo = UserRepository(db)
        self.task_repo = TaskRepository(db)


    @with_context
    def test_get_return_none_if_no_user(self):
        """Test get method returns None if there is no user with the
        specified id"""

        user = self.user_repo.get(200)

        assert user is None, user


    @with_context
    def test_get_returns_user(self):
        """Test get method returns a user if exists"""

        user = UserFactory.create()

        retrieved_user = self.user_repo.get(user.id)

        assert user == retrieved_user, retrieved_user


    @with_context
    def test_get_by_name_return_none_if_no_user(self):
        """Test get_by_name returns None when a user with the specified
        name does not exist"""

        user = self.user_repo.get_by_name('thisuserdoesnotexist')

        assert user is None, user


    @with_context
    def test_get_by_name_returns_the_user(self):
        """Test get_by_name returns a user if exists"""

        user = UserFactory.create()

        retrieved_user = self.user_repo.get_by_name(user.name)

        assert user == retrieved_user, retrieved_user


    @with_context
    def test_get_by(self):
        """Test get_by returns a user with the specified attribute"""

        user = UserFactory.create(name='Jon Snow')

        retrieved_user = self.user_repo.get_by(name=user.name)

        assert user == retrieved_user, retrieved_user


    @with_context
    def test_get_by_returns_none_if_no_user(self):
        """Test get_by returns None if no user matches the query"""

        UserFactory.create(name='Tyrion Lannister')

        user = self.user_repo.get_by(name='no_name')

        assert user is None, user


    @with_context
    def get_all_returns_list_of_all_users(self):
        """Test get_all returns a list of all the existing users"""

        users = UserFactory.create_batch(3)

        retrieved_users = self.user_repo.get_all()

        assert isinstance(retrieved_users, list)
        assert len(retrieved_users) == len(users), retrieved_users
        for user in retrieved_users:
            assert user in users, user


    @with_context
    def test_filter_by_no_matches(self):
        """Test filter_by returns an empty list if no users match the query"""

        UserFactory.create(name='reek', fullname='Theon Greyjoy')

        retrieved_users = self.user_repo.filter_by(name='asha')

        assert isinstance(retrieved_users, list)
        assert len(retrieved_users) == 0, retrieved_users


    @with_context
    def test_filter_by_one_condition(self):
        """Test filter_by returns a list of users that meet the filtering
        condition"""

        UserFactory.create_batch(3, locale='es')
        should_be_missing = UserFactory.create(locale='fr')

        retrieved_users = self.user_repo.filter_by(locale='es')

        assert len(retrieved_users) == 3, retrieved_users
        assert should_be_missing not in retrieved_users, retrieved_users


    @with_context
    def test_filter_by_multiple_conditions(self):
        """Test filter_by supports multiple-condition queries"""

        UserFactory.create_batch(2, locale='es', privacy_mode=True)
        user = UserFactory.create(locale='es', privacy_mode=False)

        retrieved_users = self.user_repo.filter_by(locale='es',
                                                   privacy_mode=False)

        assert len(retrieved_users) == 1, retrieved_users
        assert user in retrieved_users, retrieved_users


    @with_context
    def test_filter_by_limit_offset(self):
        """Test that filter_by supports limit and offset options"""

        UserFactory.create_batch(4)
        all_users = self.user_repo.filter_by()

        first_two = self.user_repo.filter_by(limit=2)
        last_two = self.user_repo.filter_by(limit=2, offset=2)

        assert len(first_two) == 2, first_two
        assert len(last_two) == 2, last_two
        assert first_two == all_users[:2]
        assert last_two == all_users[2:]


    @with_context
    def test_search_by_name_returns_list(self):
        """Test search_by_name returns a list with search results"""

        search = self.user_repo.search_by_name('')

        assert isinstance(search, list), search.__class__


    @with_context
    def test_search_by_name(self):
        """Test search_by_name returns a list with the user if searching by
        either its name or fullname"""

        user = UserFactory.create(name='greenseer', fullname='Jojen Reed')

        search_by_name = self.user_repo.search_by_name('greenseer')
        search_by_fullname = self.user_repo.search_by_name('Jojen Reed')

        assert user in search_by_name, search_by_name
        assert user in search_by_fullname, search_by_fullname


    @with_context
    def test_search_by_name_capital_lower_letters(self):
        """Test search_by_name works the same with capital or lower letters"""

        user_capitals = UserFactory.create(name='JOJEN')
        user_lowers = UserFactory.create(name='meera')

        search_lower = self.user_repo.search_by_name('jojen')
        search_capital = self.user_repo.search_by_name('MEERA')

        assert user_capitals in search_lower, search_lower
        assert user_lowers in search_capital, search_capital


    @with_context
    def test_search_by_name_substrings(self):
        """Test search_by_name works when searching by a substring"""

        user = UserFactory.create(name='Hodor')

        search = self.user_repo.search_by_name('odo')

        assert user in search, search


    @with_context
    def test_search_by_name_empty_string(self):
        """Test search_by_name returns an empty list when searching by '' """

        user = UserFactory.create(name='Brandon')

        search = self.user_repo.search_by_name('')

        assert len(search) == 0, search


    @with_context
    def test_total_users_no_users(self):
        """Test total_users return 0 if there are no users"""

        count = self.user_repo.total_users()

        assert count == 0, count


    @with_context
    def test_total_users_count(self):
        """Test total_users return 1 if there is one user"""

        UserFactory.create()
        count = self.user_repo.total_users()

        assert count == 1, count


    @with_context
    def test_save(self):
        """Test save persist the user"""

        user = UserFactory.build()
        assert self.user_repo.get(user.id) is None

        self.user_repo.save(user)

        assert self.user_repo.get(user.id) == user, "User 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"""

        user = UserFactory.build(name=None)

        assert_raises(DBIntegrityError, self.user_repo.save, user)


    @with_context
    def test_save_only_saves_users(self):
        """Test save raises a WrongObjectError when an object which is not
        a User instance is saved"""

        bad_object = dict()

        assert_raises(WrongObjectError, self.user_repo.save, bad_object)


    @with_context
    def test_update(self):
        """Test update persists the changes made to the user"""

        user = UserFactory.create(locale='en')
        user.locale = 'it'

        self.user_repo.update(user)
        updated_user = self.user_repo.get(user.id)

        assert updated_user.locale == 'it', updated_user


    @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"""

        user = UserFactory.create()
        user.name = None

        assert_raises(DBIntegrityError, self.user_repo.update, user)


    @with_context
    def test_update_only_updates_users(self):
        """Test update raises a WrongObjectError when an object which is not
        a User instance is updated"""

        bad_object = dict()

        assert_raises(WrongObjectError, self.user_repo.update, bad_object)


    @with_context
    def test_get_users_no_args(self):
        """Test get users by id returns empty list
        """
        assert self.user_repo.get_users(None) == []


    @with_context
    def test_get_users(self):

        tyrion = UserFactory.create(name='Tyrion Lannister')
        theon = UserFactory.create(name='reek', fullname='Theon Greyjoy')

        retrieved_users = self.user_repo.get_users([tyrion.id, theon.id])
        assert any(user == tyrion for user in retrieved_users)
        assert any(user == theon for user in retrieved_users)

    @with_context
    def test_delete_user(self):
        """Test USER delete works."""
        user = UserFactory.create()
        user_id = user.id
        user = self.user_repo.get_by(id=user_id)
        assert user.id == user_id
        self.user_repo.delete(user)
        user = self.user_repo.get_by(id=user_id)
        assert user is None

    @with_context
    def test_fake_user_id(self):
        """Test remove user ID works and it's replaced by a fake IP."""
        user = UserFactory.create()
        taskruns = TaskRunFactory.create_batch(3, user=user)
        fake_ips = []
        assert taskruns[0].user_id == user.id
        self.user_repo.fake_user_id(user)
        for taskrun in taskruns:
            taskrun = self.task_repo.get_task_run_by(id=taskrun.id)
            assert taskrun.user_id is None
            assert taskrun.user_ip is not None
            fake_ips.append(taskrun.user_ip)
        assert len(set(fake_ips)) == 3

    @with_context
    def test_delete_user_with_task_runs(self):
        """Delete user with task runs works."""
        user = UserFactory.create()
        taskruns = TaskRunFactory.create_batch(3, user=user)
        fake_ips = []
        user_id = user.id
        assert taskruns[0].user_id == user.id
        self.user_repo.delete(user)
        for taskrun in taskruns:
            taskrun = self.task_repo.get_task_run_by(id=taskrun.id)
            assert taskrun.user_id is None
            assert taskrun.user_ip is not None
            fake_ips.append(taskrun.user_ip)
        assert len(set(fake_ips)) == 3
        user = self.user_repo.get_by(id=user_id)
        assert user is None
Example #26
0
 def setUp(self):
     super(TestTaskRepositoryForTaskQueries, self).setUp()
     self.task_repo = TaskRepository(db)
Example #27
0
 def setUp(self):
     super(TestUserRepository, self).setUp()
     self.user_repo = UserRepository(db)
     self.task_repo = TaskRepository(db)
Example #28
0
 def setUp(self):
     super(TestTaskRepositorySaveDeleteUpdate, self).setUp()
     self.task_repo = TaskRepository(db)
Example #29
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
Example #30
0
#
# PYBOSSA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with PYBOSSA.  If not, see <http://www.gnu.org/licenses/>.
from mock import patch, Mock
from pybossa.importers import Importer

from default import Test, with_context
from factories import ProjectFactory, TaskFactory
from pybossa.repositories import TaskRepository
from pybossa.core import db
task_repo = TaskRepository(db)


@patch.object(Importer, '_create_importer_for')
class TestImporterPublicMethods(Test):
    importer = Importer()

    @with_context
    def test_create_tasks_creates_them_correctly(self, importer_factory):
        mock_importer = Mock()
        mock_importer.tasks.return_value = [{
            'info': {
                'question': 'question',
                'url': 'url'
            },
            'n_answers': 20
Example #31
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(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