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