class TestDocumentQueries(TestCase): """Tests for /query api for Document instance filtering.""" def setUp(self): super(TestDocumentQueries, self).setUp() self.api = Api() @ddt.data(all_models.Document.FILE, all_models.Document.REFERENCE_URL) def test_filter_document_by_type(self, kind): """Test filter documents by document type.""" data = { all_models.Document.FILE: factories.DocumentFileFactory().id, all_models.Document.REFERENCE_URL: factories.DocumentReferenceUrlFactory().id, } query_request_data = [{ u'fields': [], u'filters': { u'expression': { u'left': u'kind', u'op': {u'name': u'='}, u'right': kind, } }, u'limit': [0, 5], u'object_name': u'Document', u'permissions': u'read', u'type': u'values', }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Document"]["count"]) self.assertEqual(data[kind], resp.json[0]["Document"]["values"][0]["id"])
class TestDocumentQueries(TestCase): """Tests for /query api for Document instance filtering.""" def setUp(self): super(TestDocumentQueries, self).setUp() self.api = Api() @ddt.data(all_models.Document.ATTACHMENT, all_models.Document.URL) def test_filter_document_by_type(self, document_type): """Test filter documents by document type.""" data = { all_models.Document.ATTACHMENT: factories.EvidenceFactory().id, all_models.Document.URL: factories.UrlFactory().id, } query_request_data = [{ u'fields': [], u'filters': { u'expression': { u'left': u'document_type', u'op': { u'name': u'=' }, u'right': document_type, } }, u'limit': [0, 5], u'object_name': u'Document', u'permissions': u'read', u'type': u'values', }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Document"]["count"]) self.assertEqual(data[document_type], resp.json[0]["Document"]["values"][0]["id"])
class TestCommentQueries(TestCase): """Tests for /query api for Comment instance ordering.""" def setUp(self): super(TestCommentQueries, self).setUp() self.api = Api() def test_comment_ordering(self): """Check ordering for comment""" with factories.single_commit(): cgot = wf_factories.CycleTaskGroupObjectTaskFactory() comment1 = factories.CommentFactory( description="comment 1", created_at=datetime.datetime(2017, 1, 1, 7, 31, 32) ) comment2 = factories.CommentFactory( description="comment 2", created_at=datetime.datetime(2017, 1, 1, 7, 31, 42) ) factories.RelationshipFactory(source=comment1, destination=cgot) factories.RelationshipFactory(source=comment2, destination=cgot) query_request_data = [ { u"object_name": u"Comment", u"filters": { u"expression": { u"object_name": u"CycleTaskGroupObjectTask", u"op": { u"name": u"relevant" }, u"ids": [cgot.id] } }, u"order_by": [{ u"name": u"created_at", u"desc": True }] } ] resp = self.api.send_request( self.api.client.post, data=query_request_data, api_link="/query" ) self.assertEqual(2, resp.json[0]["Comment"]["count"]) self.assertEqual( "comment 2", resp.json[0]["Comment"]["values"][0]["description"] ) self.assertEqual( "comment 1", resp.json[0]["Comment"]["values"][1]["description"] )
class TestProgramQueries(TestCase): """Tests for /query api for Program child parent operators.""" def setUp(self): super(TestProgramQueries, self).setUp() self.api = Api() @ddt.data("child", "parent") def test_mega_operators(self, operator): """Test {0} operator""" with factories.single_commit(): program_a = factories.ProgramFactory() program_c = factories.ProgramFactory() program_b = factories.ProgramFactory() factories.RelationshipFactory(source=program_b, destination=program_a) factories.RelationshipFactory(source=program_c, destination=program_b) program_b_id = program_b.id if operator == "child": query_id = program_c.id elif operator == "parent": query_id = program_a.id query_request_data = [ { u"object_name": u"Program", u"filters": { u"expression": { u"object_name": u"Program", u"op": { u"name": operator }, u"ids": [query_id] } }, u"order_by": [{ u"name": u"created_at", u"desc": True }] } ] resp = self.api.send_request( self.api.client.post, data=query_request_data, api_link="/query" ) self.assertEqual(1, resp.json[0]["Program"]["count"]) self.assertEqual( program_b_id, resp.json[0]["Program"]["values"][0]["id"] )
class TestProgramQueries(TestCase): """Tests for /query api for Program child parent operators.""" def setUp(self): super(TestProgramQueries, self).setUp() self.api = Api() @ddt.data("child", "parent") def test_mega_operators(self, operator): """Test {0} operator""" with factories.single_commit(): program_a = factories.ProgramFactory() program_c = factories.ProgramFactory() program_b = factories.ProgramFactory() factories.RelationshipFactory(source=program_b, destination=program_a) factories.RelationshipFactory(source=program_c, destination=program_b) program_b_id = program_b.id if operator == "child": query_id = program_c.id elif operator == "parent": query_id = program_a.id query_request_data = [{ u"object_name": u"Program", u"filters": { u"expression": { u"object_name": u"Program", u"op": { u"name": operator }, u"ids": [query_id] } }, u"order_by": [{ u"name": u"created_at", u"desc": True }] }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Program"]["count"]) self.assertEqual(program_b_id, resp.json[0]["Program"]["values"][0]["id"])
class TestCommentQueries(TestCase): """Tests for /query api for Comment instance ordering.""" def setUp(self): super(TestCommentQueries, self).setUp() self.api = Api() def test_comment_ordering(self): """Check ordering for comment""" with factories.single_commit(): cgot = wf_factories.CycleTaskGroupObjectTaskFactory() comment1 = factories.CommentFactory(description="comment 1", created_at=datetime.datetime( 2017, 1, 1, 7, 31, 32)) comment2 = factories.CommentFactory(description="comment 2", created_at=datetime.datetime( 2017, 1, 1, 7, 31, 42)) factories.RelationshipFactory(source=comment1, destination=cgot) factories.RelationshipFactory(source=comment2, destination=cgot) query_request_data = [{ u"object_name": u"Comment", u"filters": { u"expression": { u"object_name": u"CycleTaskGroupObjectTask", u"op": { u"name": u"relevant" }, u"ids": [cgot.id] } }, u"order_by": [{ u"name": u"created_at", u"desc": True }] }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(2, resp.json[0]["Comment"]["count"]) self.assertEqual("comment 2", resp.json[0]["Comment"]["values"][0]["description"]) self.assertEqual("comment 1", resp.json[0]["Comment"]["values"][1]["description"])
class TestFilterByAuditor(TestCase): """ Test for filter by Auditor. """ def setUp(self): super(TestFilterByAuditor, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, self.auditor = self.generator.generate_person(user_role="Creator") auditor_role = all_models.Role.query.filter_by(name="Auditor").first() with factories.single_commit(): self.audit = factories.AuditFactory(status="In Progress") self.audit_id = self.audit.id audit_context = factories.ContextFactory() self.audit.context = audit_context rbac_factories.UserRoleFactory( context=audit_context, role=auditor_role, person=self.auditor) self.api.set_user(self.auditor) def test_query_audits_by_auditor(self): """test get audit as query get""" objects = self.api.get_query(all_models.Audit, "") self.assertEqual(1, len(objects.json["audits_collection"]["audits"])) audit_dict = objects.json["audits_collection"]["audits"][0] self.assertEqual(self.audit_id, audit_dict["id"]) def test_filter_audits_by_auditor(self): """Test query on audit Global Search. This query is the fact query that frontend is sending in global search. """ query_request_data = [ { u'fields': [], u'filters': { u'expression': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Planned' }, u'op': {u'name': u'OR'}, u'right': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'In Progress' }, u'op': {u'name': u'OR'}, u'right': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Manager Review' }, u'op': {u'name': u'OR'}, u'right': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Ready for External Review', }, u'op': {u'name': u'OR'}, u'right': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Completed', } }, }, }, }, u'keys': [u'status'], u'order_by': { u'compare': None, u'keys': [], u'order': u'', } }, u'limit': [0, 5], u'object_name': u'Audit', u'permissions': u'read', u'type': u'values', }, { u'filters': { u'expression': { u'ids': [u'150'], u'object_name': u'undefined', u'op': {u'name': u'relevant'} }, u'keys': [], u'order_by': {u'compare': None, u'keys': [], u'order': u''} }, u'object_name': u'Audit', u'type': u'ids', }, ] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Audit"]["count"]) self.assertEqual(self.audit_id, resp.json[0]["Audit"]["values"][0]["id"])
class TestWorkflowsApiPost(TestCase): def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() self.generator = wf_generator.WorkflowsGenerator() def tearDown(self): pass def test_send_invalid_data(self): data = self.get_workflow_dict() del data["workflow"]["title"] del data["workflow"]["context"] response = self.api.post(all_models.Workflow, data) self.assert400(response) # TODO: check why response.json["message"] is empty def test_create_one_time_workflows(self): data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflow(self): """Test create valid weekly wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 7 data["workflow"]["unit"] = "day" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflow(self): """Test create valid annual wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) @ddt.data("wrong value", 0, -4) def test_create_wrong_repeat_every_workflow(self, value): # noqa pylint: disable=invalid-name """Test case for invalid repeat_every value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = value data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_wrong_unit_workflow(self): """Test case for invalid unit value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "wrong value" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_task_group(self): wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) # TODO: Api should be able to handle invalid data @unittest.skip("Not implemented.") def test_create_task_group_invalid_workflow_data(self): # noqa pylint: disable=invalid-name data = self.get_task_group_dict({"id": -1, "context": {"id": -1}}) response = self.api.post(all_models.TaskGroup, data) self.assert400(response) @staticmethod def get_workflow_dict(): data = { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "unit": None, "repeat_every": None, "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "owners": None, "context": None, } } return data @staticmethod def get_task_group_dict(workflow): data = { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": 1, "href": "/api/people/1", "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } return data @ddt.data({}, {"repeat_every": 5, "unit": "month"}) def test_repeat_multiplier_field(self, data): """Check repeat_multiplier is set to 0 after wf creation. """ with factories.single_commit(): workflow = wf_factories.WorkflowFactory(**data) workflow_id = workflow.id self.assertEqual( 0, all_models.Workflow.query.get(workflow_id).repeat_multiplier ) # TODO: Unskip in the patch 2 @unittest.skip("Will be activated in patch 2") def test_change_to_one_time_wf(self): """Check repeat_every and unit can be set to Null only together.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None, "unit": None}) self.assert200(resp) @ddt.data({"repeat_every": 5}, {"unit": "month"}) def test_change_repeat_every(self, data): """Check repeat_every or unit can not be changed once set.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory() resp = self.api.put(workflow, data) self.assert400(resp) def test_not_change_to_one_time_wf(self): """Check repeat_every or unit can't be set to Null separately. This test will be useful in the 2nd patch, where we allow to change WF setup """ with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None}) self.assert400(resp) resp = self.api.put(workflow, {"unit": None}) self.assert400(resp) @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request( self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_change_verification_flag_positive(self, flag): # noqa pylint: disable=invalid-name """is_verification_needed flag is changeable for DRAFT workflow.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) self.assertEqual(workflow.status, all_models.Workflow.DRAFT) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert200(resp) self.assertEqual( all_models.Workflow.query.get(workflow_id).is_verification_needed, not flag) @ddt.data(True, False) def test_change_verification_flag_negative(self, flag): # noqa pylint: disable=invalid-name with freezegun.freeze_time("2017-08-10"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=flag, repeat_every=1) wf_factories.TaskGroupTaskFactory( task_group=wf_factories.TaskGroupFactory( context=factories.ContextFactory(), workflow=workflow ), # Two cycles should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) workflow_id = workflow.id self.assertEqual(workflow.status, all_models.Workflow.DRAFT) self.generator.activate_workflow(workflow) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.status, all_models.Workflow.ACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) # End all current cycles for cycle in workflow.cycles: self.generator.modify_object(cycle, {'is_current': False}) workflow = all_models.Workflow.query.filter( all_models.Workflow.id == workflow_id).first() self.assertEqual(workflow.status, all_models.Workflow.INACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else True, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestWorkflowsApiPost(TestCase): """Test class for ggrc workflow api post action.""" def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() self.generator = wf_generator.WorkflowsGenerator() self.wf_admin_id = all_models.Person.query.first().id with factories.single_commit(): self.people_ids = [factories.PersonFactory().id for _ in xrange(6)] def tearDown(self): pass def _delete_and_check_related_acl(self, related_model, exp_acl_count, is_deleted): """Delete related model and check remaining ACL count. Args: related_model: related model class exp_acl_count: expected related ACL count after delete operation is_deleted: is related object already deleted """ if is_deleted: related_count = related_model.query.count() self.assertEqual(related_count, 0) else: related = related_model.query.one() response = self.api.delete(related) self.assert200(response) related_acl_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == related_model.__name__).count() self.assertEqual(related_acl_count, 0) bg_task_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == "BackgroundTask").count() all_acl_count = all_models.AccessControlList.query.count() self.assertEqual(all_acl_count - bg_task_count, exp_acl_count) def test_acl_on_object_deletion(self): """Test related ACL records removed on related object delete""" self._create_propagation_acl_test_data() acl_count = all_models.AccessControlList.query.count() self.assertNotEqual(acl_count, 0) admin = all_models.Person.query.get(1) self.api.set_user(admin) related_models = ( (all_models.TaskGroup, 16, False), (all_models.TaskGroupTask, 16, True), (all_models.Cycle, 2, False), (all_models.CycleTaskGroup, 2, True), (all_models.CycleTaskGroupObjectTask, 2, True), ) for related_model, acl_count, is_deleted in related_models: self._delete_and_check_related_acl(related_model, acl_count, is_deleted) def test_acl_on_workflow_delete(self): """Test related ACL records removed on Workflow delete""" self._create_propagation_acl_test_data() acl_count = all_models.AccessControlList.query.count() self.assertNotEqual(acl_count, 0) admin = all_models.Person.query.get(1) self.api.set_user(admin) workflow = all_models.Workflow.query.one() response = self.api.delete(workflow) self.assert200(response) acl_count = all_models.AccessControlList.query.count() bg_acl_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == "BackgroundTask").count() self.assertEqual(acl_count, bg_acl_count) def test_acl_for_new_related_object(self): """Test Workflow ACL propagation for new related objects.""" data = self.get_workflow_dict() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } data["workflow"]["access_control_list"] = acl_helper.get_acl_list( acl_map) data["workflow"]["unit"] = "week" data["workflow"]["repeat_every"] = 1 response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[2] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[2]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) task_group = all_models.TaskGroup.eager_query().one() data = self.get_task_dict(task_group) data["task_group_task"]["start_date"] = "2018-01-04" data["task_group_task"]["end_date"] = "2018-01-05" response = self.api.post(all_models.TaskGroupTask, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() with freezegun.freeze_time("2018-01-05"): # Generate 1 cycle self.generator.activate_workflow(workflow) cycle_task = all_models.CycleTaskGroupObjectTask.query.one() with factories.single_commit(): comment = factories.CommentFactory() factories.RelationshipFactory(source=comment, destination=cycle_task) self._check_propagated_acl(2, has_comment=True) @ddt.data('Admin', 'Workflow Member') def test_tg_assignee(self, role_name): """Test TaskGroup assignee already has {0} role.""" data = self.get_workflow_dict() init_acl = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES[role_name], } data['workflow']['access_control_list'] = acl_helper.get_acl_list( init_acl) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[1] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[1]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() task_group = all_models.TaskGroup.query.one() ac_people = all_models.AccessControlPerson.query.filter( all_models.AccessControlPerson.person_id == task_group.contact_id, ).all() self.assertEqual(len(ac_people), 1) actual = {(acp.ac_list.object_type, acp.ac_list.object_id) for acp in ac_people} self.assertIn((workflow.type, workflow.id), actual) self.assertNotIn((task_group.type, task_group.id), actual) def test_task_group_assignee_gets_workflow_member(self): # noqa pylint: disable=invalid-name """Test TaskGroup assignee gets WorkflowMember role.""" data = self.get_workflow_dict() init_acl = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } data['workflow']['access_control_list'] = acl_helper.get_acl_list( init_acl) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[2] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[2]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() wf_members = [ acp.person.id for acp in workflow.acr_name_acl_map["Workflow Member"].access_control_people ] self.assertIn(self.people_ids[2], wf_members) def _create_propagation_acl_test_data(self): # noqa pylint: disable=invalid-name """Create objects for Workflow ACL propagation test.""" with freezegun.freeze_time("2017-08-9"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( title='wf1', unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=True, repeat_every=1) wf_factories.TaskGroupTaskFactory( title='tgt1', task_group=wf_factories.TaskGroupFactory( title='tg1', context=factories.ContextFactory(), workflow=workflow), # One cycle should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) self.generator.activate_workflow(workflow) workflow = all_models.Workflow.query.one() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], self.people_ids[2]: WF_ROLES['Workflow Member'], } put_params = { 'access_control_list': acl_helper.get_acl_list(acl_map) } response = self.api.put(workflow, put_params) self.assert200(response) def _check_propagated_acl(self, roles_count, has_comment=False): """ Check Workflow propagated ACL records. Args: roles_count: roles' count created in test has_comment: indicator that related objects contain comments """ related_objects = [ (all_models.TaskGroup.query.one().id, all_models.TaskGroup.__name__), (all_models.TaskGroupTask.query.one().id, all_models.TaskGroupTask.__name__), (all_models.Cycle.query.one().id, all_models.Cycle.__name__), (all_models.CycleTaskGroup.query.one().id, all_models.CycleTaskGroup.__name__), (all_models.CycleTaskGroupObjectTask.query.one().id, all_models.CycleTaskGroupObjectTask.__name__), ] if has_comment: related_objects.append((all_models.Comment.query.one().id, all_models.Comment.__name__), ) # *2 is for relationships related_count = roles_count * len(related_objects) * 2 # additional acl count for Relationship and Comment propagation of # Task Assignees/Task Secondary Assignees access control roles if has_comment: related_count += roles_count * 2 all_acls = all_models.AccessControlList.query.filter( all_models.AccessControlList.parent_id_nn != 0).count() self.assertEqual(all_acls, related_count) def test_assign_workflow_acl(self): """Test propagation Workflow ACL roles on Workflow's update ACL records.""" self._create_propagation_acl_test_data() self._check_propagated_acl(2) def test_unassign_workflow_acl(self): """Test propagation Workflow ACL roles on person unassigned.""" self._create_propagation_acl_test_data() with freezegun.freeze_time("2017-08-9"): workflow = all_models.Workflow.query.one() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } put_params = { 'access_control_list': acl_helper.get_acl_list(acl_map) } response = self.api.put(workflow, put_params) self.assert200(response) self._check_propagated_acl(2) def test_post_workflow_with_acl(self): """Test PUT workflow with ACL.""" data = self.get_workflow_dict() exp_res = { self.wf_admin_id: WF_ROLES['Admin'], self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], self.people_ids[2]: WF_ROLES['Workflow Member'], self.people_ids[3]: WF_ROLES['Workflow Member'] } data['workflow']['access_control_list'] = acl_helper.get_acl_list( exp_res) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.eager_query().one() act_res = { person.id: acl.ac_role_id for person, acl in workflow.access_control_list } self.assertDictEqual(exp_res, act_res) def test_update_workflow_acl_people(self): """Test PUT workflow with updated ACL.""" data = self.get_workflow_dict() init_map = { self.wf_admin_id: WF_ROLES['Admin'], self.people_ids[0]: WF_ROLES['Workflow Member'], } data['workflow']['access_control_list'] = acl_helper.get_acl_list( init_map) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) exp_res = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Admin'], self.people_ids[2]: WF_ROLES['Workflow Member'], self.people_ids[3]: WF_ROLES['Workflow Member'], self.people_ids[4]: WF_ROLES['Workflow Member'] } workflow = all_models.Workflow.eager_query().one() put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)} response = self.api.put(workflow, put_params) self.assert200(response) workflow = all_models.Workflow.eager_query().one() act_res = { person.id: acl.ac_role_id for person, acl in workflow.access_control_list } self.assertDictEqual(exp_res, act_res) def test_send_invalid_data(self): """Test send invalid data on Workflow post.""" data = self.get_workflow_dict() del data["workflow"]["title"] response = self.api.post(all_models.Workflow, data) self.assert400(response) def test_create_one_time_workflows(self): """Test simple create one time Workflow over api.""" data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflow(self): """Test create valid weekly wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 7 data["workflow"]["unit"] = "day" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflow(self): """Test create valid annual wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) @ddt.data("wrong value", 0, -4) def test_create_wrong_repeat_every_workflow(self, value): # noqa pylint: disable=invalid-name """Test case for invalid repeat_every value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = value data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_wrong_unit_workflow(self): """Test case for invalid unit value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "wrong value" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_task_group(self): """Test create task group over api.""" wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) def test_incorrect_wf_id_on_tg_post(self): """Tests incorrect id in tg post payload. Tests that 400 is raised on tg post if id in payload has incorrect type.""" wf_data = self.get_workflow_dict() wf_response = self.api.post(all_models.Workflow, wf_data) data = { "workflow": { "id": { "id": wf_response.json["workflow"]["id"] }, "type": "Workflow" } } tg_response = self.api.post(all_models.TaskGroup, data) self.assertEqual(tg_response.status_code, 400) self.assertEqual(tg_response.json["message"], ("Either type or id are specified " "incorrectly in the request payload.")) @staticmethod def get_workflow_dict(): return { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "unit": None, "repeat_every": None, "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "context": None, } } def get_task_group_dict(self, workflow): return { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": self.wf_admin_id, "href": "/api/people/{}".format(self.wf_admin_id), "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } def get_task_dict(self, task_group): return { "task_group_task": { "start_date": "2017-12-25", "end_date": "2017-12-31", "custom_attributes": {}, "contact": { "id": self.wf_admin_id, "href": "/api/people/{}".format(self.wf_admin_id), "type": "Person" }, "task_group": { "id": task_group.id, "href": "/api/task_groups/{}".format(task_group.id), "type": "TaskGroup" }, "context": { "id": task_group.context_id, "href": "/api/contexts/{}".format(task_group.context_id), "type": "Context" }, "title": "Create_task", "task_type": "text", "description": "" } } @ddt.data({}, {"repeat_every": 5, "unit": "month"}) def test_repeat_multiplier_field(self, data): """Check repeat_multiplier is set to 0 after wf creation.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(**data) workflow_id = workflow.id self.assertEqual( 0, all_models.Workflow.query.get(workflow_id).repeat_multiplier) # TODO: Unskip in the patch 2 @unittest.skip("Will be activated in patch 2") def test_change_to_one_time_wf(self): """Check repeat_every and unit can be set to Null only together.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None, "unit": None}) self.assert200(resp) @ddt.data({"repeat_every": 5}, {"unit": "month"}) def test_change_repeat_every(self, data): """Check repeat_every or unit can not be changed once set.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory() resp = self.api.put(workflow, data) self.assert400(resp) def test_not_change_to_one_time_wf(self): """Check repeat_every or unit can't be set to Null separately. This test will be useful in the 2nd patch, where we allow to change WF setup """ with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None}) self.assert400(resp) resp = self.api.put(workflow, {"unit": None}) self.assert400(resp) @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "title": factories.random_str(prefix='cycle - '), "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request(self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_verification_flag_positive(self, flag): # noqa pylint: disable=invalid-name """is_verification_needed flag is changeable for DRAFT workflow.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) self.assertEqual(workflow.status, all_models.Workflow.DRAFT) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert200(resp) self.assertEqual( all_models.Workflow.query.get(workflow_id).is_verification_needed, not flag) @ddt.data(True, False) def test_verification_flag_negative(self, flag): """Test immutable verification flag on active workflows.""" with freezegun.freeze_time("2017-08-10"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=flag, repeat_every=1) wf_factories.TaskGroupTaskFactory( task_group=wf_factories.TaskGroupFactory( context=factories.ContextFactory(), workflow=workflow), # Two cycles should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) workflow_id = workflow.id self.assertEqual(workflow.status, all_models.Workflow.DRAFT) self.generator.activate_workflow(workflow) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.status, all_models.Workflow.ACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) # End all current cycles for cycle in workflow.cycles: self.generator.modify_object(cycle, {'is_current': False}) workflow = all_models.Workflow.query.filter( all_models.Workflow.id == workflow_id).first() self.assertEqual(workflow.status, all_models.Workflow.INACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else False, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestWorkflowsApiPost(TestCase): """Test class for ggrc workflow api post action.""" def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() self.generator = wf_generator.WorkflowsGenerator() def tearDown(self): pass def test_send_invalid_data(self): """Test send invalid data on Workflow post.""" data = self.get_workflow_dict() del data["workflow"]["title"] del data["workflow"]["context"] response = self.api.post(all_models.Workflow, data) self.assert400(response) # TODO: check why response.json["message"] is empty def test_create_one_time_workflows(self): """Test simple create one time Workflow over api.""" data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflow(self): """Test create valid weekly wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 7 data["workflow"]["unit"] = "day" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflow(self): """Test create valid annual wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) @ddt.data("wrong value", 0, -4) def test_create_wrong_repeat_every_workflow(self, value): # noqa pylint: disable=invalid-name """Test case for invalid repeat_every value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = value data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_wrong_unit_workflow(self): """Test case for invalid unit value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "wrong value" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_task_group(self): """Test create task group over api.""" wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) # TODO: Api should be able to handle invalid data @unittest.skip("Not implemented.") def test_create_task_group_invalid_workflow_data(self): # noqa pylint: disable=invalid-name """Test create task group with invalid data.""" data = self.get_task_group_dict({"id": -1, "context": {"id": -1}}) response = self.api.post(all_models.TaskGroup, data) self.assert400(response) @staticmethod def get_workflow_dict(): return { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "unit": None, "repeat_every": None, "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "owners": None, "context": None, } } @staticmethod def get_task_group_dict(workflow): return { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": 1, "href": "/api/people/1", "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } @ddt.data({}, {"repeat_every": 5, "unit": "month"}) def test_repeat_multiplier_field(self, data): """Check repeat_multiplier is set to 0 after wf creation.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(**data) workflow_id = workflow.id self.assertEqual( 0, all_models.Workflow.query.get(workflow_id).repeat_multiplier) # TODO: Unskip in the patch 2 @unittest.skip("Will be activated in patch 2") def test_change_to_one_time_wf(self): """Check repeat_every and unit can be set to Null only together.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None, "unit": None}) self.assert200(resp) @ddt.data({"repeat_every": 5}, {"unit": "month"}) def test_change_repeat_every(self, data): """Check repeat_every or unit can not be changed once set.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory() resp = self.api.put(workflow, data) self.assert400(resp) def test_not_change_to_one_time_wf(self): """Check repeat_every or unit can't be set to Null separately. This test will be useful in the 2nd patch, where we allow to change WF setup """ with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None}) self.assert400(resp) resp = self.api.put(workflow, {"unit": None}) self.assert400(resp) @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request(self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_change_verification_flag_positive(self, flag): # noqa pylint: disable=invalid-name """is_verification_needed flag is changeable for DRAFT workflow.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) self.assertEqual(workflow.status, all_models.Workflow.DRAFT) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert200(resp) self.assertEqual( all_models.Workflow.query.get(workflow_id).is_verification_needed, not flag) @ddt.data(True, False) def test_change_verification_flag_negative(self, flag): # noqa pylint: disable=invalid-name with freezegun.freeze_time("2017-08-10"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=flag, repeat_every=1) wf_factories.TaskGroupTaskFactory( task_group=wf_factories.TaskGroupFactory( context=factories.ContextFactory(), workflow=workflow), # Two cycles should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) workflow_id = workflow.id self.assertEqual(workflow.status, all_models.Workflow.DRAFT) self.generator.activate_workflow(workflow) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.status, all_models.Workflow.ACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) # End all current cycles for cycle in workflow.cycles: self.generator.modify_object(cycle, {'is_current': False}) workflow = all_models.Workflow.query.filter( all_models.Workflow.id == workflow_id).first() self.assertEqual(workflow.status, all_models.Workflow.INACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else True, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestWorkflowsApiPost(TestCase): """Test class for ggrc workflow api post action.""" def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() self.generator = wf_generator.WorkflowsGenerator() with factories.single_commit(): self.people_ids = [factories.PersonFactory().id for _ in xrange(6)] def tearDown(self): pass def _delete_and_check_related_acl(self, related_model, exp_acl_count, is_deleted): """Delete related model and check remaining ACL count. Args: related_model: related model class exp_acl_count: expected related ACL count after delete operation is_deleted: is related object already deleted """ if is_deleted: related_count = related_model.query.count() self.assertEqual(related_count, 0) else: related = related_model.query.one() response = self.api.delete(related) self.assert200(response) related_acl_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == related_model.__name__).count() self.assertEqual(related_acl_count, 0) all_acl_count = all_models.AccessControlList.query.count() self.assertEqual(all_acl_count, exp_acl_count) def test_related_acl_removed_on_related_obj_delete(self): # noqa pylint: disable=invalid-name """Test related ACL records removed on related object delete""" self._create_propagation_acl_test_data() acl_count = all_models.AccessControlList.query.count() self.assertNotEqual(acl_count, 0) admin = all_models.Person.query.get(1) self.api.set_user(admin) related_models = ( (all_models.CycleTaskEntry, 18, False), (all_models.TaskGroup, 12, False), (all_models.TaskGroupTask, 12, True), (all_models.Cycle, 3, False), (all_models.CycleTaskGroup, 3, True), (all_models.CycleTaskGroupObjectTask, 3, True), ) for related_model, acl_count, is_deleted in related_models: self._delete_and_check_related_acl(related_model, acl_count, is_deleted) def test_related_acl_removed_on_workflow_delete(self): # noqa pylint: disable=invalid-name """Test related ACL records removed on Workflow delete""" self._create_propagation_acl_test_data() acl_count = all_models.AccessControlList.query.count() self.assertNotEqual(acl_count, 0) admin = all_models.Person.query.get(1) self.api.set_user(admin) workflow = all_models.Workflow.query.one() response = self.api.delete(workflow) self.assert200(response) acl_count = all_models.AccessControlList.query.count() self.assertEqual(acl_count, 0) def test_propagate_acl_for_new_related_object(self): # noqa pylint: disable=invalid-name """Test Workflow ACL propagation for new related objects.""" data = self.get_workflow_dict() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } data["workflow"]["access_control_list"] = acl_helper.get_acl_list( acl_map) data["workflow"]["unit"] = "week" data["workflow"]["repeat_every"] = 1 response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[2] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[2]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) task_group = all_models.TaskGroup.eager_query().one() data = self.get_task_dict(task_group) data["task_group_task"]["start_date"] = "2018-01-04" data["task_group_task"]["end_date"] = "2018-01-05" response = self.api.post(all_models.TaskGroupTask, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() with freezegun.freeze_time("2018-01-05"): # Generate 1 cycle self.generator.activate_workflow(workflow) cycle_task = all_models.CycleTaskGroupObjectTask.query.one() cycle = all_models.Cycle.query.one() data = self.get_comment_dict(cycle_task, cycle) response = self.api.post(all_models.CycleTaskEntry, data) self.assertEqual(response.status_code, 201) self._check_propagated_acl(3) @ddt.data('Admin', 'Workflow Member') def test_task_group_assignee_has_workflow_role(self, role_name): # noqa pylint: disable=invalid-name """Test TaskGroup assignee already has Workflow role.""" data = self.get_workflow_dict() init_acl = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES[role_name], } data['workflow']['access_control_list'] = acl_helper.get_acl_list( init_acl) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[1] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[1]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() task_group = all_models.TaskGroup.query.one() actual_acl = all_models.AccessControlList.eager_query().filter( all_models.AccessControlList.person_id == task_group.contact_id, ).all() self.assertEqual(len(actual_acl), 2) expected = { role_name: (workflow.type, workflow.id), "{} Mapped".format(role_name): (task_group.type, task_group.id) } actual = { acl.ac_role.name: (acl.object_type, acl.object_id) for acl in actual_acl } self.assertDictEqual(expected, actual) def test_task_group_assignee_gets_workflow_member(self): # noqa pylint: disable=invalid-name """Test TaskGroup assignee gets WorkflowMember role.""" data = self.get_workflow_dict() init_acl = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } data['workflow']['access_control_list'] = acl_helper.get_acl_list( init_acl) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[2] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[2]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() task_group = all_models.TaskGroup.query.one() parent_acl = all_models.AccessControlList.eager_query().filter( all_models.AccessControlList.person_id == task_group.contact_id, all_models.AccessControlList.object_type == workflow.type, all_models.AccessControlList.object_id == workflow.id).one() tg_acl = all_models.AccessControlList.eager_query().filter( all_models.AccessControlList.person_id == task_group.contact_id, all_models.AccessControlList.object_type == task_group.type, all_models.AccessControlList.object_id == task_group.id).one() self.assertEqual(parent_acl.ac_role.name, "Workflow Member") self.assertEqual(tg_acl.parent_id, parent_acl.id) self.assertEqual(tg_acl.ac_role.name, "Workflow Member Mapped") def _create_propagation_acl_test_data(self): # noqa pylint: disable=invalid-name """Create objects for Workflow ACL propagation test.""" with freezegun.freeze_time("2017-08-9"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( title='wf1', unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=True, repeat_every=1) wf_factories.TaskGroupTaskFactory( title='tgt1', task_group=wf_factories.TaskGroupFactory( title='tg1', context=factories.ContextFactory(), workflow=workflow), # One cycle should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) self.generator.activate_workflow(workflow) cycle = all_models.Cycle.query.one() cycle_task = all_models.CycleTaskGroupObjectTask.query.one() wf_factories.CycleTaskEntryFactory( cycle=cycle, cycle_task_group_object_task=cycle_task, description="Cycle task comment", ) workflow = all_models.Workflow.query.one() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], self.people_ids[2]: WF_ROLES['Workflow Member'], } put_params = { 'access_control_list': acl_helper.get_acl_list(acl_map) } response = self.api.put(workflow, put_params) self.assert200(response) def _check_propagated_acl(self, roles_count): """Check Workflow propagated ACL records. Args: roles_count: roles' count created in test """ related_objects = ((all_models.TaskGroup.query.one().id, all_models.TaskGroup.__name__), (all_models.TaskGroupTask.query.one().id, all_models.TaskGroupTask.__name__), (all_models.Cycle.query.one().id, all_models.Cycle.__name__), (all_models.CycleTaskGroup.query.one().id, all_models.CycleTaskGroup.__name__), (all_models.CycleTaskGroupObjectTask.query.one().id, all_models.CycleTaskGroupObjectTask.__name__), (all_models.CycleTaskEntry.query.one().id, all_models.CycleTaskEntry.__name__)) related_count = len(related_objects) all_acl = [ acl for acl in all_models.AccessControlList.eager_query().all() ] self.assertEqual(len(all_acl), roles_count + roles_count * related_count) workflow = all_models.Workflow.query.one() parent_acl, related_acl = [], [] for acl in all_acl: if (not acl.parent_id and acl.object_id == workflow.id and acl.object_type == workflow.type): parent_acl.append(acl) else: related_acl.append(acl) result = defaultdict(set) for p_acl in parent_acl: for r_acl in related_acl: if (r_acl.ac_role.name == '{} Mapped'.format( p_acl.ac_role.name) and r_acl.parent_id == p_acl.id and r_acl.person_id == p_acl.person_id): result[p_acl.id].add((r_acl.object_id, r_acl.object_type)) self.assertEqual(roles_count, len(result)) for related_pairs in result.values(): self.assertEqual(related_count, len(related_pairs)) self.assertItemsEqual(related_objects, related_pairs) def test_assign_workflow_acl_people_and_propagate(self): # noqa pylint: disable=invalid-name """Test propagation Workflow ACL roles on Workflow's update ACL records.""" self._create_propagation_acl_test_data() self._check_propagated_acl(3) def test_unassign_workflow_acl_people_and_propagate(self): # noqa pylint: disable=invalid-name """Test propagation Workflow ACL roles on person unassigned.""" self._create_propagation_acl_test_data() with freezegun.freeze_time("2017-08-9"): workflow = all_models.Workflow.query.one() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } put_params = { 'access_control_list': acl_helper.get_acl_list(acl_map) } response = self.api.put(workflow, put_params) self.assert200(response) self._check_propagated_acl(2) def test_post_workflow_with_acl_people(self): # noqa pylint: disable=invalid-name """Test PUT workflow with ACL.""" data = self.get_workflow_dict() exp_res = { 1: WF_ROLES['Admin'], self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], self.people_ids[2]: WF_ROLES['Workflow Member'], self.people_ids[3]: WF_ROLES['Workflow Member'] } data['workflow']['access_control_list'] = acl_helper.get_acl_list( exp_res) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.eager_query().one() act_res = { acl.person_id: acl.ac_role_id for acl in workflow.access_control_list } self.assertDictEqual(exp_res, act_res) def test_update_workflow_acl_people(self): """Test PUT workflow with updated ACL.""" data = self.get_workflow_dict() init_map = { 1: WF_ROLES['Admin'], self.people_ids[0]: WF_ROLES['Workflow Member'], } data['workflow']['access_control_list'] = acl_helper.get_acl_list( init_map) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) exp_res = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Admin'], self.people_ids[2]: WF_ROLES['Workflow Member'], self.people_ids[3]: WF_ROLES['Workflow Member'], self.people_ids[4]: WF_ROLES['Workflow Member'] } workflow = all_models.Workflow.eager_query().one() put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)} response = self.api.put(workflow, put_params) self.assert200(response) workflow = all_models.Workflow.eager_query().one() act_res = { acl.person_id: acl.ac_role_id for acl in workflow.access_control_list } self.assertDictEqual(exp_res, act_res) def test_send_invalid_data(self): """Test send invalid data on Workflow post.""" data = self.get_workflow_dict() del data["workflow"]["title"] del data["workflow"]["context"] response = self.api.post(all_models.Workflow, data) self.assert400(response) # TODO: check why response.json["message"] is empty def test_create_one_time_workflows(self): """Test simple create one time Workflow over api.""" data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflow(self): """Test create valid weekly wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 7 data["workflow"]["unit"] = "day" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflow(self): """Test create valid annual wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) @ddt.data("wrong value", 0, -4) def test_create_wrong_repeat_every_workflow(self, value): # noqa pylint: disable=invalid-name """Test case for invalid repeat_every value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = value data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_wrong_unit_workflow(self): """Test case for invalid unit value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "wrong value" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_task_group(self): """Test create task group over api.""" wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) # TODO: Api should be able to handle invalid data @unittest.skip("Not implemented.") def test_create_task_group_invalid_workflow_data(self): # noqa pylint: disable=invalid-name """Test create task group with invalid data.""" data = self.get_task_group_dict({"id": -1, "context": {"id": -1}}) response = self.api.post(all_models.TaskGroup, data) self.assert400(response) @staticmethod def get_workflow_dict(): return { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "unit": None, "repeat_every": None, "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "context": None, } } @staticmethod def get_task_group_dict(workflow): return { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": 1, "href": "/api/people/1", "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } @staticmethod def get_task_dict(task_group): return { "task_group_task": { "start_date": "2017-12-25", "end_date": "2017-12-31", "custom_attributes": {}, "contact": { "id": 1, "href": "/api/people/1", "type": "Person" }, "task_group": { "id": task_group.id, "href": "/api/task_groups/{}".format(task_group.id), "type": "TaskGroup" }, "context": { "id": task_group.context_id, "href": "/api/contexts/{}".format(task_group.context_id), "type": "Context" }, "title": "Create_task", "task_type": "text", "description": "" } } @staticmethod def get_comment_dict(cycle_task, cycle): return { "cycle_task_entry": { "custom_attributes": {}, "cycle_task_group_object_task": { "id": cycle_task.id, "href": "/api/cycle_task_group_object_tasks/{}".format( cycle_task.id), "type": "CycleTaskGroupObjectTask" }, "cycle": { "id": cycle.id, "href": "/api/cycles/{}".format(cycle.id), "type": "Cycle" }, "context": { "id": cycle.context_id, "href": "/api/contexts/{}".format(cycle.context_id), "type": "Context" }, "is_declining_review": "", "description": "CT comment" } } @ddt.data({}, {"repeat_every": 5, "unit": "month"}) def test_repeat_multiplier_field(self, data): """Check repeat_multiplier is set to 0 after wf creation.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(**data) workflow_id = workflow.id self.assertEqual( 0, all_models.Workflow.query.get(workflow_id).repeat_multiplier) # TODO: Unskip in the patch 2 @unittest.skip("Will be activated in patch 2") def test_change_to_one_time_wf(self): """Check repeat_every and unit can be set to Null only together.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None, "unit": None}) self.assert200(resp) @ddt.data({"repeat_every": 5}, {"unit": "month"}) def test_change_repeat_every(self, data): """Check repeat_every or unit can not be changed once set.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory() resp = self.api.put(workflow, data) self.assert400(resp) def test_not_change_to_one_time_wf(self): """Check repeat_every or unit can't be set to Null separately. This test will be useful in the 2nd patch, where we allow to change WF setup """ with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None}) self.assert400(resp) resp = self.api.put(workflow, {"unit": None}) self.assert400(resp) @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request(self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_change_verification_flag_positive(self, flag): # noqa pylint: disable=invalid-name """is_verification_needed flag is changeable for DRAFT workflow.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) self.assertEqual(workflow.status, all_models.Workflow.DRAFT) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert200(resp) self.assertEqual( all_models.Workflow.query.get(workflow_id).is_verification_needed, not flag) @ddt.data(True, False) def test_change_verification_flag_negative(self, flag): # noqa pylint: disable=invalid-name with freezegun.freeze_time("2017-08-10"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=flag, repeat_every=1) wf_factories.TaskGroupTaskFactory( task_group=wf_factories.TaskGroupFactory( context=factories.ContextFactory(), workflow=workflow), # Two cycles should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) workflow_id = workflow.id self.assertEqual(workflow.status, all_models.Workflow.DRAFT) self.generator.activate_workflow(workflow) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.status, all_models.Workflow.ACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) # End all current cycles for cycle in workflow.cycles: self.generator.modify_object(cycle, {'is_current': False}) workflow = all_models.Workflow.query.filter( all_models.Workflow.id == workflow_id).first() self.assertEqual(workflow.status, all_models.Workflow.INACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else True, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestAuditDeprecated(TestCase): """Test for correct working field last_deprecated_date """ def setUp(self): super(TestAuditDeprecated, self).setUp() self.api = Api() def test_redefine_status(self): """Test create audit and change status to Deprecated""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, { "status": "Deprecated" }) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id ).one() self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_keep_date_unchanged(self): """Test set status audit to Deprecated, and then set status to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(audit, { "status": "Planned" }) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id ).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_repeat_deprecated_state(self): """Test set status audit to Deprecated, then to Planned, then to Deprecated and then to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(audit, { "status": "Planned" }) with freeze_time("2017-02-25"): self.api.modify_object(audit, { "status": "Deprecated" }) with freeze_time("2017-02-26"): self.api.modify_object(audit, { "status": "Planned" }) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id ).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 2, 25)) def test_filter_by_deprecated_date(self): """Test filter audits by last deprecated date""" amount_of_audits = 5 list_of_ids = [] with factories.single_commit(): with freeze_time("2017-01-25"): for _ in range(amount_of_audits): list_of_ids.append( factories.AuditFactory(status="Deprecated").id ) query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01-25", }, }, 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"]) def test_sort_by_deprecated_date(self): """Test sorting results of filter audits by deprecated date""" dict_of_dates = {} date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"] with factories.single_commit(): for date in date_list: with freeze_time(date): dict_of_dates[factories.AuditFactory(status="Deprecated").id] = date sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1)) sorted_list_ids = [item[0] for item in sorted_dict] query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01", }, }, "order_by": [{"name": "last_deprecated_date"}], 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])
class TestValidation(TestCase): """Test validation query.""" def setUp(self): """Log in before performing queries.""" # we don't call super as TestCase.setUp clears the DB # super(BaseQueryAPITestCase, self).setUp() self.client.get("/login") self.api = Api() def assert_validation(self, query_data): self.assert400(self.api.send_request(self.api.client.post, data=query_data, api_link="/query")) OPERATIONS = ["=", "!=", "~", "!=", ">", "<", ">=", "<="] @ddt.data(*OPERATIONS) def test_only_left_validations(self, operation): self.assert_validation([{ "object_name": "Snapshot", "filters": { "expression": { "left": "title", "op": {"name": operation}, } } }]) @ddt.data(*OPERATIONS) def test_only_right_validations(self, operation): self.assert_validation([{ "object_name": "Snapshot", "filters": { "expression": { "right": "value", "op": {"name": operation}, } } }]) @ddt.data({}, {"name": "x"}) def test_invalid_operations(self, operation_dict): self.assert_validation([{ "object_name": "Snapshot", "filters": { "expression": { "right": "value", "op": operation_dict } } }]) NO_OPERATION_DATA = [{ "object_name": "Snapshot", "filters": {"expression": {"right": "value", "left": "title"}} }] NO_OBJECT_NAME_DATA = [{ "filters": { "expression": { "left": "title", "op": {"name": "="} } } }] @ddt.data( [{}], NO_OPERATION_DATA, NO_OBJECT_NAME_DATA, ) def test_validation(self, query_data): self.assert_validation(query_data)
class TestPersonResource(TestCase, WithQueryApi): """Tests for special people api endpoints.""" def setUp(self): super(TestPersonResource, self).setUp() self.client.get("/login") self.api = Api() self.generator = WorkflowsGenerator() @staticmethod def _create_users_names_rbac(users): """Create name and Creator role for users, created vid PersonFactory""" if not users: return roles = {r.name: r for r in all_models.Role.query.all()} for user in users: user.name = user.email.split("@")[0] rbac_factories.UserRoleFactory(role=roles["Creator"], person=user) def assert_profile_get_successful(self, response, expected_datetime): """Verify assertions for successful GET profile method""" self.assert200(response) response_datetime = date_parser.parse( response.json["last_seen_whats_new"]) self.assertEqual(expected_datetime, response_datetime) @freeze_time("2018-05-20 12:23:17") def test_profile_get_successful(self): """Test person_profile GET method successfully achieves correct data""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) response = self.api.client.get("/api/people/{}/profile".format( user.id)) self.assert_profile_get_successful(response, default_date()) def test_profile_get_no_profile(self): """Test person_profile GET method achieves data with missing profile""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) profiles_table = PersonProfile.__table__ db_request = profiles_table.delete().where( profiles_table.c.person_id == user.id) db.engine.execute(db_request) with freeze_time("2018-05-28 23:30:10"): response = self.api.client.get("/api/people/{}/profile".format( user.id)) self.assert_profile_get_successful(response, default_date()) def test_profile_get_failed(self): """Test person_profiles GET method fails Now only logged user can request his profile """ with factories.single_commit(): valid_user = factories.PersonFactory() self._create_users_names_rbac([valid_user]) response = self.client.get("/api/people/{}/profile".format( valid_user.id)) # logged with default user during setUp self.assert403(response) response = self.api.client.get("/api/people/{}/profile".format( valid_user.id)) # not authorized user self.assert403(response) @ddt.data("Creator", "Reader", "Editor", "Administrator") def test_profile_post_empty_body(self, role_name): """Test person_profile POST method with empty body - {}.""" role = all_models.Role.query.filter( all_models.Role.name == role_name).one() with factories.single_commit(): user = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role, person=user) self.api.set_user(person=user) response = self.api.send_request( self.api.client.post, data={}, api_link="/api/people/{}/profile".format(user.id)) self.assert405(response) def test_profile_post_unauthorized(self): """Test person_profile POST method with empty body - No Access.""" with factories.single_commit(): user = factories.PersonFactory() response = self.api.send_request( self.api.client.post, data={}, api_link="/api/people/{}/profile".format(user.id)) # not authorized user self.assert405(response) def assert_profile_put_successful(self, response, correct_response, user, expected): """Verify assertions for successful PUT profile method""" self.assert200(response) self.assertEqual(response.json, correct_response) profile = PersonProfile.query.filter_by(person_id=user.id).first() self.assertEqual(profile.last_seen_whats_new, date_parser.parse(expected)) @ddt.data(["2018-05-20 16:38:17", "2018-05-20 16:38:17"], ["2018-07-05T14:11:31Z", "2018-07-05T14:11:31"]) @ddt.unpack def test_profile_put_successful(self, new_date, expected_date): """Test person_profile PUT method for setting data and correct response""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) data = {"last_seen_whats_new": new_date} correct_response = {"Person": {"id": user.id, "profile": data}} response = self.api.client.put("/api/people/{}/profile".format( user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) self.assert_profile_put_successful(response, correct_response, user, expected_date) def test_profile_put_no_profile(self): """Test person_profile PUT method for setting data for missing profile""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) new_date = "2018-05-20 22:05:17" data = {"last_seen_whats_new": new_date} correct_response = {"Person": {"id": user.id, "profile": data}} profiles_table = PersonProfile.__table__ db_request = profiles_table.delete().where( profiles_table.c.person_id == user.id) db.engine.execute(db_request) response = self.api.client.put("/api/people/{}/profile".format( user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) self.assert_profile_put_successful(response, correct_response, user, new_date) def test_profile_put_unauthorized(self): """Test person_profiles PUT method fails for unauthorized user""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) new_date = "2018-05-20 22:05:17" data = {"last_seen_whats_new": new_date} response = self.client.put("/api/people/{}/profile".format(user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) # logged with default user during setUp self.assert403(response) response = self.api.client.put("/api/people/{}/profile".format( user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) # not authorized user self.assert403(response) @ddt.data({"last_seen_whats_new": "NOT A 123 DAT456A"}, { "other_key": "2018-05-20 22:05:17", "one_more_key": 42 }) def test_profile_put_corrupted_data(self, data): """Test person_profiles PUT method fails via incorrect request data If request doesn't have "last_seen_whats_new" key or date is incorrect, response is code 400 "Bad Request" """ with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) response = self.api.client.put("/api/people/{}/profile".format( user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) # missed key in request self.assert400(response) def test_task_count_empty(self): """Test query count without any workflows and tasks.""" user = all_models.Person.query.first() response = self.client.get("/api/people/{}/task_count".format(user.id)) self.assertEqual(response.json, { "open_task_count": 0, "has_overdue": False }) @ddt.data( (True, [ ("task 1", "Finished", 3, True, 3), ("task 1", "Verified", 2, True, 3), ("task 2", "Declined", 2, True, 3), ("task 2", "Verified", 1, False, 3), ("task 2", "Finished", 2, True, 3), ("task 3", "Verified", 1, True, 3), ("task 2", "Verified", 0, False, 3), ]), (False, [ ("task 1", "Finished", 2, True, 3), ("task 2", "In Progress", 2, True, 3), ("task 2", "Finished", 1, False, 3), ("task 3", "Finished", 0, False, 3), ]), ) @ddt.unpack def test_task_count(self, is_verification_needed, transitions): """Test person task counts. This tests checks for correct task counts - with inactive workflows and - with overdue tasks - without overdue tasks - with finished overdue tasks The four checks are done in a single test due to complex differences between tests that make ddt cumbersome and the single test also improves integration test performance due to slow workflow setup stage. """ # pylint: disable=too-many-locals user = all_models.Person.query.first() dummy_user = factories.PersonFactory() user_id = user.id role_id = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Task Assignees", all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id secondary_role_id = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Task Secondary Assignees", all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id one_time_workflow = { "title": "Person resource test workflow", "notify_on_change": True, "description": "some test workflow", "owners": [create_stub(user)], "is_verification_needed": is_verification_needed, "task_groups": [{ "title": "one time task group", "contact": create_stub(user), "task_group_tasks": [ { "title": "task 1", "description": "some task", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id), acl_helper.get_acl_json(secondary_role_id, user.id) ], "start_date": date(2017, 5, 5), "end_date": date(2017, 8, 15), }, { "title": "task 2", "description": "some task 3", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id), acl_helper.get_acl_json(secondary_role_id, user.id), acl_helper.get_acl_json(secondary_role_id, dummy_user.id) ], "start_date": date(2017, 5, 5), "end_date": date(2017, 9, 16), }, { "title": "task 3", "description": "some task 4", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id), acl_helper.get_acl_json(role_id, dummy_user.id) ], "start_date": date(2017, 6, 5), "end_date": date(2017, 10, 16), }, { "title": "dummy task 4", # task should not counted "description": "some task 4", "access_control_list": [acl_helper.get_acl_json(role_id, dummy_user.id)], "start_date": date(2017, 6, 5), "end_date": date(2017, 11, 17), }, { "title": "dummy task 5", # task should not counted "description": "some task 4", "access_control_list": [acl_helper.get_acl_json(role_id, dummy_user.id)], "start_date": date(2017, 6, 5), "end_date": date(2017, 11, 18), } ], "task_group_objects": [] }] } inactive_workflow = { "title": "Activated workflow with archived cycles", "notify_on_change": True, "description": "Extra test workflow", "owners": [create_stub(user)], "task_groups": [{ "title": "Extra task group", "contact": create_stub(user), "task_group_tasks": [{ "title": "not counted existing task", "description": "", "access_control_list": [acl_helper.get_acl_json(role_id, user.id)], "start_date": date(2017, 5, 5), "end_date": date(2017, 8, 15), }], "task_group_objects": [] }] } with freeze_time("2017-10-16 05:09:10"): self.client.get("/login") # Activate normal one time workflow _, workflow = self.generator.generate_workflow(one_time_workflow) _, cycle = self.generator.generate_cycle(workflow) tasks = {t.title: t for t in cycle.cycle_task_group_object_tasks} _, workflow = self.generator.activate_workflow(workflow) # Activate and close the inactive workflow _, workflow = self.generator.generate_workflow(inactive_workflow) _, cycle = self.generator.generate_cycle(workflow) _, workflow = self.generator.activate_workflow(workflow) self.generator.modify_object(cycle, data={"is_current": False}) with freeze_time("2017-7-16 07:09:10"): self.client.get("/login") response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 3, "has_overdue": False }) with freeze_time("2017-10-16 08:09:10"): # same day as task 3 end date self.client.get("/login") response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 3, "has_overdue": True }) for task, status, count, overdue, my_work_count in transitions: self.generator.modify_object(tasks[task], data={"status": status}) task_count_response = \ self.client.get("/api/people/{}/task_count".format(user_id)) my_work_count_response = \ self.client.get("/api/people/{}/my_work_count".format(user_id)) self.assertEqual(task_count_response.json, { "open_task_count": count, "has_overdue": overdue }) self.assertEqual( my_work_count_response.json["CycleTaskGroupObjectTask"], my_work_count) def test_task_count_multiple_wfs(self): """Test task count with both verified and non verified workflows. This checks task counts with 4 tasks 2017, 8, 15 - verification needed 2017, 11, 18 - verification needed 2017, 8, 15 - No verification needed 2017, 11, 18 - No verification needed """ user = all_models.Person.query.first() user_id = user.id role_id = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Task Assignees", all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id workflow_template = { "title": "verified workflow", "owners": [create_stub(user)], "is_verification_needed": True, "task_groups": [{ "title": "one time task group", "contact": create_stub(user), "task_group_tasks": [{ "title": "task 1", "description": "some task", "access_control_list": [acl_helper.get_acl_json(role_id, user.id)], "start_date": date(2017, 5, 5), "end_date": date(2017, 8, 15), }, { "title": "dummy task 5", "description": "some task 4", "access_control_list": [acl_helper.get_acl_json(role_id, user.id)], "start_date": date(2017, 6, 5), "end_date": date(2017, 11, 18), }], "task_group_objects": [] }] } with freeze_time("2017-10-16 05:09:10"): self.client.get("/login") verified_workflow = workflow_template.copy() verified_workflow["is_verification_needed"] = True _, workflow = self.generator.generate_workflow(verified_workflow) _, cycle = self.generator.generate_cycle(workflow) verified_tasks = { task.title: task for task in cycle.cycle_task_group_object_tasks } _, workflow = self.generator.activate_workflow(workflow) non_verified_workflow = workflow_template.copy() non_verified_workflow["is_verification_needed"] = False _, workflow = self.generator.generate_workflow( non_verified_workflow) _, cycle = self.generator.generate_cycle(workflow) non_verified_tasks = { task.title: task for task in cycle.cycle_task_group_object_tasks } _, workflow = self.generator.activate_workflow(workflow) with freeze_time("2017-7-16 07:09:10"): self.client.get("/login") response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 4, "has_overdue": False }) with freeze_time("2017-10-16 08:09:10"): self.client.get("/login") response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 4, "has_overdue": True }) # transition 1, task that needs verification goes to finished state. This # transition should not change anything self.generator.modify_object(verified_tasks["task 1"], data={"status": "Finished"}) response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 4, "has_overdue": True }) # transition 2, task that needs verification goes to verified state. This # transition should reduce task count. self.generator.modify_object(verified_tasks["task 1"], data={"status": "Verified"}) response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 3, "has_overdue": True }) # transition 3, task that does not need verification goes into Finished # state. This transition should reduce task count and remove all overdue # tasks self.generator.modify_object(non_verified_tasks["task 1"], data={"status": "Finished"}) response = self.client.get( "/api/people/{}/task_count".format(user_id)) self.assertEqual(response.json, { "open_task_count": 2, "has_overdue": False }) @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200), ("Administrator", 200)) @ddt.unpack def test_person_editing(self, role_name, status): """{0} should receive {1} status code on edit Person.""" role = all_models.Role.query.filter( all_models.Role.name == role_name).one() with factories.single_commit(): client_user = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role, person=client_user) self.api.set_user(client_user) self.client.get("/login") base_email = "*****@*****.**" person = factories.PersonFactory(email=base_email) person_id = person.id new_email = "new_{}".format(base_email) resp = self.api.put(person, {"email": new_email}) self.assertEqual(status, resp.status_code) person = all_models.Person.query.get(person_id) if status == 200: self.assertEqual(new_email, person.email) else: self.assertEqual(base_email, person.email)
class TestWorkflowsApiPost(TestCase): """Test class for ggrc workflow api post action.""" def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() self.generator = wf_generator.WorkflowsGenerator() self.wf_admin_id = all_models.Person.query.first().id with factories.single_commit(): self.people_ids = [factories.PersonFactory().id for _ in xrange(6)] def tearDown(self): pass def _delete_and_check_related_acl(self, related_model, exp_acl_count, is_deleted): """Delete related model and check remaining ACL count. Args: related_model: related model class exp_acl_count: expected related ACL count after delete operation is_deleted: is related object already deleted """ if is_deleted: related_count = related_model.query.count() self.assertEqual(related_count, 0) else: related = related_model.query.one() response = self.api.delete(related) self.assert200(response) related_acl_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == related_model.__name__ ).count() self.assertEqual(related_acl_count, 0) bg_task_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == "BackgroundTask" ).count() all_acl_count = all_models.AccessControlList.query.count() self.assertEqual(all_acl_count - bg_task_count, exp_acl_count) def test_acl_on_object_deletion(self): """Test related ACL records removed on related object delete""" self._create_propagation_acl_test_data() acl_count = all_models.AccessControlList.query.count() self.assertNotEqual(acl_count, 0) admin = all_models.Person.query.get(1) self.api.set_user(admin) related_models = ( (all_models.CycleTaskEntry, 18, False), (all_models.TaskGroup, 12, False), (all_models.TaskGroupTask, 12, True), (all_models.Cycle, 3, False), (all_models.CycleTaskGroup, 3, True), (all_models.CycleTaskGroupObjectTask, 3, True), ) for related_model, acl_count, is_deleted in related_models: self._delete_and_check_related_acl(related_model, acl_count, is_deleted) def test_acl_on_workflow_delete(self): """Test related ACL records removed on Workflow delete""" self._create_propagation_acl_test_data() acl_count = all_models.AccessControlList.query.count() self.assertNotEqual(acl_count, 0) admin = all_models.Person.query.get(1) self.api.set_user(admin) workflow = all_models.Workflow.query.one() response = self.api.delete(workflow) self.assert200(response) acl_count = all_models.AccessControlList.query.count() bg_acl_count = all_models.AccessControlList.query.filter( all_models.AccessControlList.object_type == "BackgroundTask" ).count() self.assertEqual(acl_count, bg_acl_count) def test_acl_for_new_related_object(self): """Test Workflow ACL propagation for new related objects.""" data = self.get_workflow_dict() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } data["workflow"]["access_control_list"] = acl_helper.get_acl_list(acl_map) data["workflow"]["unit"] = "week" data["workflow"]["repeat_every"] = 1 response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[2] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[2]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) task_group = all_models.TaskGroup.eager_query().one() data = self.get_task_dict(task_group) data["task_group_task"]["start_date"] = "2018-01-04" data["task_group_task"]["end_date"] = "2018-01-05" response = self.api.post(all_models.TaskGroupTask, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() with freezegun.freeze_time("2018-01-05"): # Generate 1 cycle self.generator.activate_workflow(workflow) cycle_task = all_models.CycleTaskGroupObjectTask.query.one() cycle = all_models.Cycle.query.one() data = self.get_comment_dict(cycle_task, cycle) response = self.api.post(all_models.CycleTaskEntry, data) self.assertEqual(response.status_code, 201) self._check_propagated_acl(3) @ddt.data('Admin', 'Workflow Member') def test_tg_assignee(self, role_name): """Test TaskGroup assignee already has {0} role.""" data = self.get_workflow_dict() init_acl = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES[role_name], } data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_acl) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[1] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[1]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() task_group = all_models.TaskGroup.query.one() actual_acl = all_models.AccessControlList.eager_query().filter( all_models.AccessControlList.person_id == task_group.contact_id, ).all() self.assertEqual(len(actual_acl), 2) expected = { role_name: (workflow.type, workflow.id), "{} Mapped".format(role_name): (task_group.type, task_group.id) } actual = { acl.ac_role.name: (acl.object_type, acl.object_id) for acl in actual_acl } self.assertDictEqual(expected, actual) def test_task_group_assignee_gets_workflow_member(self): # noqa pylint: disable=invalid-name """Test TaskGroup assignee gets WorkflowMember role.""" data = self.get_workflow_dict() init_acl = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_acl) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) data = self.get_task_group_dict(response.json["workflow"]) data["task_group"]["contact"]["id"] = self.people_ids[2] data["task_group"]["contact"]["href"] = "/api/people/{}".format( self.people_ids[2]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.query.one() task_group = all_models.TaskGroup.query.one() parent_acl = all_models.AccessControlList.eager_query().filter( all_models.AccessControlList.person_id == task_group.contact_id, all_models.AccessControlList.object_type == workflow.type, all_models.AccessControlList.object_id == workflow.id ).one() tg_acl = all_models.AccessControlList.eager_query().filter( all_models.AccessControlList.person_id == task_group.contact_id, all_models.AccessControlList.object_type == task_group.type, all_models.AccessControlList.object_id == task_group.id ).one() self.assertEqual(parent_acl.ac_role.name, "Workflow Member") self.assertEqual(tg_acl.parent_id, parent_acl.id) self.assertEqual(tg_acl.ac_role.name, "Workflow Member Mapped") def _create_propagation_acl_test_data(self): # noqa pylint: disable=invalid-name """Create objects for Workflow ACL propagation test.""" with freezegun.freeze_time("2017-08-9"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( title='wf1', unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=True, repeat_every=1) wf_factories.TaskGroupTaskFactory( title='tgt1', task_group=wf_factories.TaskGroupFactory( title='tg1', context=factories.ContextFactory(), workflow=workflow ), # One cycle should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7) ) self.generator.activate_workflow(workflow) cycle = all_models.Cycle.query.one() cycle_task = all_models.CycleTaskGroupObjectTask.query.one() wf_factories.CycleTaskEntryFactory( cycle=cycle, cycle_task_group_object_task=cycle_task, description="Cycle task comment", ) workflow = all_models.Workflow.query.one() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], self.people_ids[2]: WF_ROLES['Workflow Member'], } put_params = {'access_control_list': acl_helper.get_acl_list(acl_map)} response = self.api.put(workflow, put_params) self.assert200(response) def _check_propagated_acl(self, roles_count): """Check Workflow propagated ACL records. Args: roles_count: roles' count created in test """ related_objects = ( (all_models.TaskGroup.query.one().id, all_models.TaskGroup.__name__), (all_models.TaskGroupTask.query.one().id, all_models.TaskGroupTask.__name__), (all_models.Cycle.query.one().id, all_models.Cycle.__name__), (all_models.CycleTaskGroup.query.one().id, all_models.CycleTaskGroup.__name__), (all_models.CycleTaskGroupObjectTask.query.one().id, all_models.CycleTaskGroupObjectTask.__name__), (all_models.CycleTaskEntry.query.one().id, all_models.CycleTaskEntry.__name__) ) related_count = len(related_objects) bd_tasks_count = all_models.BackgroundTask.query.count() all_acl = [acl for acl in all_models.AccessControlList.eager_query().all()] self.assertEqual( len(all_acl), bd_tasks_count + roles_count + roles_count * related_count ) workflow = all_models.Workflow.query.one() parent_acl, related_acl = [], [] for acl in all_acl: if (not acl.parent_id and acl.object_id == workflow.id and acl.object_type == workflow.type): parent_acl.append(acl) else: related_acl.append(acl) result = defaultdict(set) for p_acl in parent_acl: for r_acl in related_acl: if (r_acl.ac_role.name == '{} Mapped'.format(p_acl.ac_role.name) and r_acl.parent_id == p_acl.id and r_acl.person_id == p_acl.person_id): result[p_acl.id].add((r_acl.object_id, r_acl.object_type)) self.assertEqual(roles_count, len(result)) def test_assign_workflow_acl(self): """Test propagation Workflow ACL roles on Workflow's update ACL records.""" self._create_propagation_acl_test_data() self._check_propagated_acl(3) def test_unassign_workflow_acl(self): """Test propagation Workflow ACL roles on person unassigned.""" self._create_propagation_acl_test_data() with freezegun.freeze_time("2017-08-9"): workflow = all_models.Workflow.query.one() acl_map = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], } put_params = {'access_control_list': acl_helper.get_acl_list(acl_map)} response = self.api.put(workflow, put_params) self.assert200(response) self._check_propagated_acl(2) def test_post_workflow_with_acl(self): """Test PUT workflow with ACL.""" data = self.get_workflow_dict() exp_res = { self.wf_admin_id: WF_ROLES['Admin'], self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Workflow Member'], self.people_ids[2]: WF_ROLES['Workflow Member'], self.people_ids[3]: WF_ROLES['Workflow Member'] } data['workflow']['access_control_list'] = acl_helper.get_acl_list(exp_res) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) workflow = all_models.Workflow.eager_query().one() act_res = {acl.person_id: acl.ac_role_id for acl in workflow.access_control_list} self.assertDictEqual(exp_res, act_res) def test_update_workflow_acl_people(self): """Test PUT workflow with updated ACL.""" data = self.get_workflow_dict() init_map = { self.wf_admin_id: WF_ROLES['Admin'], self.people_ids[0]: WF_ROLES['Workflow Member'], } data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_map) response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) exp_res = { self.people_ids[0]: WF_ROLES['Admin'], self.people_ids[1]: WF_ROLES['Admin'], self.people_ids[2]: WF_ROLES['Workflow Member'], self.people_ids[3]: WF_ROLES['Workflow Member'], self.people_ids[4]: WF_ROLES['Workflow Member'] } workflow = all_models.Workflow.eager_query().one() put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)} response = self.api.put(workflow, put_params) self.assert200(response) workflow = all_models.Workflow.eager_query().one() act_res = {acl.person_id: acl.ac_role_id for acl in workflow.access_control_list} self.assertDictEqual(exp_res, act_res) def test_send_invalid_data(self): """Test send invalid data on Workflow post.""" data = self.get_workflow_dict() del data["workflow"]["title"] del data["workflow"]["context"] response = self.api.post(all_models.Workflow, data) self.assert400(response) # TODO: check why response.json["message"] is empty def test_create_one_time_workflows(self): """Test simple create one time Workflow over api.""" data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflow(self): """Test create valid weekly wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 7 data["workflow"]["unit"] = "day" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflow(self): """Test create valid annual wf""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) @ddt.data("wrong value", 0, -4) def test_create_wrong_repeat_every_workflow(self, value): # noqa pylint: disable=invalid-name """Test case for invalid repeat_every value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = value data["workflow"]["unit"] = "month" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_wrong_unit_workflow(self): """Test case for invalid unit value""" data = self.get_workflow_dict() data["workflow"]["repeat_every"] = 12 data["workflow"]["unit"] = "wrong value" data["workflow"]["title"] = "Wrong wf" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 400) def test_create_task_group(self): """Test create task group over api.""" wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) @staticmethod def get_workflow_dict(): return { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "unit": None, "repeat_every": None, "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "context": None, } } def get_task_group_dict(self, workflow): return { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": self.wf_admin_id, "href": "/api/people/{}".format(self.wf_admin_id), "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } def get_task_dict(self, task_group): return { "task_group_task": { "start_date": "2017-12-25", "end_date": "2017-12-31", "custom_attributes": {}, "contact": { "id": self.wf_admin_id, "href": "/api/people/{}".format(self.wf_admin_id), "type": "Person" }, "task_group": { "id": task_group.id, "href": "/api/task_groups/{}".format(task_group.id), "type": "TaskGroup" }, "context": { "id": task_group.context_id, "href": "/api/contexts/{}".format(task_group.context_id), "type": "Context" }, "title": "Create_task", "task_type": "text", "description": "" } } @staticmethod def get_comment_dict(cycle_task, cycle): return { "cycle_task_entry": { "custom_attributes": {}, "cycle_task_group_object_task": { "id": cycle_task.id, "href": "/api/cycle_task_group_object_tasks/{}".format( cycle_task.id), "type": "CycleTaskGroupObjectTask" }, "cycle": { "id": cycle.id, "href": "/api/cycles/{}".format(cycle.id), "type": "Cycle" }, "context": { "id": cycle.context_id, "href": "/api/contexts/{}".format(cycle.context_id), "type": "Context" }, "is_declining_review": "", "description": "CT comment" } } @ddt.data({}, {"repeat_every": 5, "unit": "month"}) def test_repeat_multiplier_field(self, data): """Check repeat_multiplier is set to 0 after wf creation.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(**data) workflow_id = workflow.id self.assertEqual( 0, all_models.Workflow.query.get(workflow_id).repeat_multiplier) # TODO: Unskip in the patch 2 @unittest.skip("Will be activated in patch 2") def test_change_to_one_time_wf(self): """Check repeat_every and unit can be set to Null only together.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None, "unit": None}) self.assert200(resp) @ddt.data({"repeat_every": 5}, {"unit": "month"}) def test_change_repeat_every(self, data): """Check repeat_every or unit can not be changed once set.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory() resp = self.api.put(workflow, data) self.assert400(resp) def test_not_change_to_one_time_wf(self): """Check repeat_every or unit can't be set to Null separately. This test will be useful in the 2nd patch, where we allow to change WF setup """ with factories.single_commit(): workflow = wf_factories.WorkflowFactory(repeat_every=12, unit="day") resp = self.api.put(workflow, {"repeat_every": None}) self.assert400(resp) resp = self.api.put(workflow, {"unit": None}) self.assert400(resp) @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request( self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_verification_flag_positive(self, flag): # noqa pylint: disable=invalid-name """is_verification_needed flag is changeable for DRAFT workflow.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) self.assertEqual(workflow.status, all_models.Workflow.DRAFT) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert200(resp) self.assertEqual( all_models.Workflow.query.get(workflow_id).is_verification_needed, not flag) @ddt.data(True, False) def test_verification_flag_negative(self, flag): """Test immutable verification flag on active workflows.""" with freezegun.freeze_time("2017-08-10"): with factories.single_commit(): workflow = wf_factories.WorkflowFactory( unit=all_models.Workflow.WEEK_UNIT, is_verification_needed=flag, repeat_every=1) wf_factories.TaskGroupTaskFactory( task_group=wf_factories.TaskGroupFactory( context=factories.ContextFactory(), workflow=workflow ), # Two cycles should be created start_date=datetime.date(2017, 8, 3), end_date=datetime.date(2017, 8, 7)) workflow_id = workflow.id self.assertEqual(workflow.status, all_models.Workflow.DRAFT) self.generator.activate_workflow(workflow) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.status, all_models.Workflow.ACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) # End all current cycles for cycle in workflow.cycles: self.generator.modify_object(cycle, {'is_current': False}) workflow = all_models.Workflow.query.filter( all_models.Workflow.id == workflow_id).first() self.assertEqual(workflow.status, all_models.Workflow.INACTIVE) resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) workflow = all_models.Workflow.query.get(workflow_id) self.assertEqual(workflow.is_verification_needed, flag) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else True, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestCycleTaskDeprecated(TestCase): """Test for correct working field last_deprecated_date.""" def setUp(self): super(TestCycleTaskDeprecated, self).setUp() self.api = Api() def test_redefine_status(self): """Test cycle task create and change status to Deprecated.""" cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")() with freeze_time("2017-01-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.id == cycle_task.id ).one() self.assertEquals(cycle_task_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_keep_date_unchanged(self): """Test set status to Deprecated, and then set status to Finished.""" cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")() with freeze_time("2017-01-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(cycle_task, { "status": "Finished" }) cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.id == cycle_task.id ).one() self.assertEquals(cycle_task_result.status, "Finished") self.assertEquals(cycle_task_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_repeat_deprecated_state(self): """Test updating of last deprecated date by multiply changing of status.""" cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")() with freeze_time("2017-01-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(cycle_task, { "status": "Finished" }) with freeze_time("2017-02-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) with freeze_time("2017-02-26"): self.api.modify_object(cycle_task, { "status": "Finished" }) cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.id == cycle_task.id ).one() self.assertEquals(cycle_task_result.status, "Finished") self.assertEquals(cycle_task_result.last_deprecated_date, datetime.date(2017, 2, 25)) def test_filter_by_deprecated_date(self): """Test filter cycle task by last deprecated date.""" amount_of_cycle_tasks = 5 list_of_ids = [] cycle_task_factory = factories.get_model_factory( "CycleTaskGroupObjectTask") with factories.single_commit(): with freeze_time("2017-01-25"): for _ in range(amount_of_cycle_tasks): list_of_ids.append( cycle_task_factory(status="Deprecated").id ) query_request_data = [{ "object_name": "CycleTaskGroupObjectTask", 'filters': { 'expression': { 'left': 'task Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01-25", }, }, 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(list_of_ids, result.json[0]["CycleTaskGroupObjectTask"]["ids"]) def test_sort_by_deprecated_date(self): """Test sorting results of filter cycle tasks by deprecated date.""" dict_of_dates = {} date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"] cycle_task_factory = factories.get_model_factory( "CycleTaskGroupObjectTask") with factories.single_commit(): for date in date_list: with freeze_time(date): dict_of_dates[cycle_task_factory(status="Deprecated").id] = date sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1)) sorted_list_ids = [item[0] for item in sorted_dict] query_request_data = [{ "object_name": "CycleTaskGroupObjectTask", 'filters': { 'expression': { 'left': 'task Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01", }, }, "order_by": [{"name": "last_deprecated_date"}], 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(sorted_list_ids, result.json[0]["CycleTaskGroupObjectTask"]["ids"])
class TestWorkflowsApiPost(TestCase): def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() def tearDown(self): pass def test_send_invalid_data(self): data = self.get_workflow_dict() del data["workflow"]["title"] del data["workflow"]["context"] response = self.api.post(all_models.Workflow, data) self.assert400(response) # TODO: check why response.json["message"] is empty def test_create_one_time_workflows(self): data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "weekly" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_monthly_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "monthly" data["workflow"]["title"] = "Monthly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_quarterly_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "quarterly" data["workflow"]["title"] = "Quarterly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "annually" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_task_group(self): wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) # TODO: Api should be able to handle invalid data @unittest.skip("Not implemented.") def test_create_task_group_invalid_workflow_data(self): data = self.get_task_group_dict({"id": -1, "context": {"id": -1}}) response = self.api.post(all_models.TaskGroup, data) self.assert400(response) @staticmethod def get_workflow_dict(): data = { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "frequency": "one_time", "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "owners": None, "context": None, } } return data @staticmethod def get_task_group_dict(workflow): data = { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": 1, "href": "/api/people/1", "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } return data @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request(self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_change_verification_flag(self, flag): """Check is_verification_needed flag isn't changeable.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory( is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else True, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestGGRC2857(TestCase, WithQueryApi): def setUp(self): self.client.get("/login") self.api = Api() program_creator_id = 1; # acl = [acl_helper.get_acl_json(ac_roles["Program Managers"], program_creator_id)] """ Create Program """ response = self.api.post(all_models.Program, { "program": { "title": "Program GGRC-2857", "context": None, "access_control_list": [] #acl }, }) self.program_id = response.json.get("program").get("id") # print('Program id : %s' % self.program_id) """ Create Audit """ response = self.api.post(all_models.Audit, { "audit": { "title": "Program GGRC-2857 audit", 'program': {'id': self.program_id, "type": "Program"}, "status": "Planned", "context": None, "modified_by_id": program_creator_id, "access_control_list": [] } }) self.audit_id = response.json.get("audit").get("id") context = response.json.get("audit").get("context") # print('Audit id : %s' % self.audit_id) """ Create Assessment """ response = self.api.post(all_models.Assessment, { "assessment": { "title": "Assessment GGRC-2857", "context": context, "recipients": "Assignees,Creators,Verifiers", "audit": { "id": self.audit_id, "href": "/api/audits/" + str(self.audit_id), "type": "Audit" }, "access_control_list": [], }, }) self.assessment_id = response.json.get("assessment").get("id") # print('Assessment id : %s' % self.assessment_id) """ Create Regulation """ response = self.api.post(all_models.Regulation, { "regulation":{ "title":"Regulation GGRC-2857", "recipients":"Admin,Primary Contacts,Secondary Contacts", "status":"Draft", "context": None, "kind":"Regulation", "access_control_list":[], }, }) self.regulation_id = response.json.get("regulation").get("id") regulation_slug = response.json.get("regulation").get("slug") # print('Regulation id : %s' % self.regulation_id) """ Map Regulation to Audit """ response = self.api.post(all_models.Relationship, { "relationship":{ "source":{ "id":self.audit_id, "href":"/api/audits/"+ str(self.audit_id), "type":"Audit"}, "destination":{ "id":self.regulation_id, "href":"/api/regulations/" + str(self.regulation_id), "type":"Regulation", }, "context": None, }, }) self.relationship_id = response.json.get("relationship").get("id") # print('Relationship id : %s' % self.relationship_id) """ Export Assessment """ data = [{ "object_name": "Assessment", "filters": { "expression": {}, }, "fields": "all", }] response = self.export_csv(data) """ Change Assessment """ imp = (response.data.replace(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", ",,,,,,,,,,,,,,,,,,,,,,,,"+regulation_slug+",,,,,,,",1)).encode('ascii','ignore') self._file = StringIO(imp) def tearDown(self): asmnt = all_models.Assessment.query.get(self.assessment_id) self.api.delete(asmnt) regul = all_models.Regulation.query.get(self.regulation_id) self.api.delete(regul) prog = all_models.Program.query.get(self.program_id) self.api.delete(prog) return @patch("ggrc.gdrive.file_actions.get_gdrive_file", new=read_imported_file) def test_GGRC2857(self): """ Import/Check Assessment """ data = {"file": (self._file, "test.csv")} response = self.send_import_request(data) self.assertEqual(response[0]["updated"], 1, msg="Only 1 assessment should be updated") """ Check Assessment """ self.snap_types = ["Standard", "Regulation", "Section", "Objective", "Control", "Product", "System", "Process", "AccessGroup", "Clause", "Contract", "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk", "Threat", "Vendor",] self.rel_types = ["Audit", "Evidence", "Issue",] query_data = [] relevant = {"object_name": "Assessment", "op": {"name": "relevant"}, "ids": [self.assessment_id]} for snap_type in self.snap_types: child = self.make_filter_expression(expression=["child_type","=", snap_type]) filters = {"expression": self.make_filter_expression(expression=[child, "AND", relevant])} query_data.append(self._make_query_dict_base("Snapshot", type_="count", filters=filters)) filters = {"expression": relevant} for rel_type in self.rel_types: query_data.append(self._make_query_dict_base(rel_type, type_="count", filters=filters)) response = self.api.send_request( self.api.client.post, data=query_data, api_link="/query" ) self.assertEqual(response.json[1]["Snapshot"]["count"], 1, msg="Only 1 regulation should be relevant to our assessment") """ Check Regulation/Audit """ query_data = [] relevant = {"object_name": "Assessment", "op": {"name": "relevant"}, "ids": [self.assessment_id]} child = self.make_filter_expression(expression=["child_type","=", "Regulation"]) filters = {"expression": self.make_filter_expression(expression=[child, "AND", relevant])} query_data.append({ "object_name": "Snapshot", "filters": filters, "limit": [0, 1], "fields": ["child_id", "child_type", "context", "email", "id", "is_latest_revision", "name", "revision", "revisions", "selfLink", "slug", "status", "title", "type", "viewLink", "workflow_state", "archived", "program", "DEFAULT_PEOPLE_LABELS", "object_people", "user_roles"], }) filters = {"expression": relevant} query_data.append({ "object_name": "Audit", "filters": filters, "limit": [0, 1], "fields": ["child_id", "child_type", "context", "email", "id", "is_latest_revision", "name", "revision", "revisions", "selfLink", "slug", "status", "title", "type", "viewLink", "workflow_state", "archived", "program", "DEFAULT_PEOPLE_LABELS", "object_people", "user_roles"], }) relevant = {"object_name": "Audit", "op": {"name": "relevant"}, "ids": [self.audit_id]} for snap_type in self.snap_types: child = self.make_filter_expression(expression=["child_type","=", snap_type]) filters = {"expression": self.make_filter_expression(expression=[child, "AND", relevant])} query_data.append(self._make_query_dict_base("Snapshot", type_="ids", filters=filters)) filters = {"expression": relevant} query_data.append({ "object_name": "Issue", "filters": filters, "type": "ids", }) response = self.api.send_request( self.api.client.post, data=query_data, api_link="/query" ) self.assertEqual(response.json[0]["Snapshot"]["values"][0]["id"], self.relationship_id, msg="Relashionship Id doesn't match with created") self.assertEqual(response.json[1]["Audit"]["values"][0]["id"], self.audit_id, msg="Audit Id doesn't match with created") return
class TestBulkIssuesSync(TestCase): """Base class for bulk issuetracker synchronization tests.""" def setUp(self): """Set up for test methods.""" super(TestBulkIssuesSync, self).setUp() self.api = Api() self.gen = generator.ObjectGenerator() self.role_people = { "Audit Captains": factories.PersonFactory(email="*****@*****.**"), "Creators": factories.PersonFactory(email="*****@*****.**"), "Assignees": factories.PersonFactory(email="*****@*****.**"), "Verifiers": factories.PersonFactory(email="*****@*****.**"), } self.issue_id = "42" def setup_assessments(self, asmnt_count, issue_id=None, enabled=True): """Create Audit with couple of Assessments and linked IssueTrackerIssues. Args: asmnt_count: Count of Assessments in Audit. Returns: Tuple with Audit id and list of Assessment ids. """ with factories.single_commit(): audit = factories.AuditFactory() audit.add_person_with_role_name( self.role_people["Audit Captains"], "Audit Captains", ) factories.IssueTrackerIssueFactory( enabled=enabled, issue_tracked_obj=audit, issue_id=issue_id, issue_type=constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'], component_id=12345, hotlist_id=12345, issue_priority="P2", issue_severity="S2", ) assessment_ids = [] for _ in range(asmnt_count): asmnt = factories.AssessmentFactory(audit=audit) factories.RelationshipFactory(source=audit, destination=asmnt) for role_name in ["Creators", "Assignees", "Verifiers"]: asmnt.add_person_with_role_name( self.role_people[role_name], role_name, ) factories.IssueTrackerIssueFactory( enabled=enabled, issue_tracked_obj=asmnt, issue_id=issue_id, title=None, ) assessment_ids.append(asmnt.id) return audit.id, assessment_ids @staticmethod def setup_issues(issue_count, issue_id=None, enabled=True): """Create issues with enabled integration.""" with factories.single_commit(): issue_ids = [] for _ in range(issue_count): issue = factories.IssueFactory() factories.IssueTrackerIssueFactory( enabled=enabled, issue_tracked_obj=issue, issue_id=issue_id, title=None, ) issue_ids.append(issue.id) return issue_ids def issuetracker_sync_mock(self, sync_func_name): """IssueTracker sync method mock.""" return mock.patch.object(sync_utils, sync_func_name, return_value={"issueId": self.issue_id}) def generate_children_issues_for(self, parent_type, parent_id, child_type): """Generate IssueTracker issue for objects with provided type and ids. Args: obj_type: Type of objects. Now only 'Assessment' supported. obj_ids: List with ids of objects. Returns: Response with result of issues generation. """ with self.issuetracker_sync_mock("create_issue"): return self.api.send_request(self.api.client.post, api_link="/generate_children_issues", data={ "parent": { "type": parent_type, "id": parent_id }, "child_type": child_type, }) def generate_issues_for(self, object_info): """Generate IssueTracker issues for provided objects.""" with self.issuetracker_sync_mock("create_issue"): return self.api.send_request( self.api.client.post, api_link="/generate_issues", data={ "objects": [{ "type": type_, "id": id_, "hotlist_ids": hotlist_id, "component_id": component_id, } for type_, id_, hotlist_id, component_id in object_info], }) def update_issues_for(self, object_info): """Update IssueTracker issues for provided objects.""" with self.issuetracker_sync_mock("update_issue"): return self.api.send_request( self.api.client.post, api_link="/update_issues", data={ "objects": [{ "type": type_, "id": id_, "hotlist_ids": hotlist_id, "component_id": component_id, } for type_, id_, hotlist_id, component_id in object_info], }) def assert_obj_issues(self, issuetracker_info, assignee=None): """Check correctness of created IssueTracker issues.""" for type_, id_, hotlist_id, component_id in issuetracker_info: obj = inflector.get_model(type_).query.get(id_) issue = obj.issuetracker_issue self.assertEqual(issue.enabled, 1) self.assertEqual(issue.title, obj.title) self.assertEqual(issue.component_id, component_id) self.assertEqual(issue.hotlist_id, hotlist_id) self.assertEqual( issue.issue_type, constants.DEFAULT_ISSUETRACKER_VALUES['issue_type']) self.assertEqual(issue.issue_priority, "P2") self.assertEqual(issue.issue_severity, "S2") self.assertEqual(issue.assignee, assignee) self.assertEqual(issue.cc_list, "") self.assertEqual(issue.issue_id, self.issue_id) self.assertEqual(issue.issue_url, "http://issue/{}".format(self.issue_id)) def assert_children_asmnt_issues(self, asmnt_ids): """Check if Assessments IssueTracker issues inherit data from Audit.""" assessments = all_models.Assessment.query.filter( all_models.Assessment.id.in_(asmnt_ids)) for asmnt in assessments: issue = asmnt.issuetracker_issue parent_issue = asmnt.audit.issuetracker_issue self.assertEqual(issue.enabled, 1) self.assertEqual(issue.title, asmnt.title) self.assertEqual(issue.component_id, parent_issue.component_id) self.assertEqual(issue.hotlist_id, parent_issue.hotlist_id) self.assertEqual(issue.issue_type, parent_issue.issue_type) self.assertEqual(issue.issue_priority, parent_issue.issue_priority) self.assertEqual(issue.issue_severity, parent_issue.issue_severity) self.assertEqual(issue.assignee, "*****@*****.**") self.assertEqual(issue.cc_list, "") self.assertEqual(issue.issue_id, self.issue_id) self.assertEqual(issue.issue_url, "http://issue/{}".format(self.issue_id)) def assert_not_updated(self, object_type, object_ids): """Check if IssueTracker issues have empty fields. Args: object_type: Type of objects which issues should be checked. object_ids: List with ids for objects which issues should be checked. Raise: AssertionError if relevant Issues have non-empty base fields. """ issues = all_models.IssuetrackerIssue.query.filter( all_models.IssuetrackerIssue.object_type == object_type, all_models.IssuetrackerIssue.object_id.in_(object_ids), ) for issue in issues: self.assertEqual(issue.issue_id, None) self.assertEqual(issue.assignee, None) self.assertEqual(issue.cc_list, "") self.assertEqual(issue.title, None)
class TestValidation(TestCase): """Test validation query.""" def setUp(self): """Log in before performing queries.""" # we don't call super as TestCase.setUp clears the DB # super(BaseQueryAPITestCase, self).setUp() self.client.get("/login") self.api = Api() def assert_validation(self, query_data): self.assert400( self.api.send_request(self.api.client.post, data=query_data, api_link="/query")) OPERATIONS = ["=", "!=", "~", "!=", ">", "<", ">=", "<="] @ddt.data(*OPERATIONS) def test_only_left_validations(self, operation): self.assert_validation([{ "object_name": "Snapshot", "filters": { "expression": { "left": "title", "op": { "name": operation }, } } }]) @ddt.data(*OPERATIONS) def test_only_right_validations(self, operation): self.assert_validation([{ "object_name": "Snapshot", "filters": { "expression": { "right": "value", "op": { "name": operation }, } } }]) @ddt.data({}, {"name": "x"}) def test_invalid_operations(self, operation_dict): self.assert_validation([{ "object_name": "Snapshot", "filters": { "expression": { "right": "value", "op": operation_dict } } }]) NO_OPERATION_DATA = [{ "object_name": "Snapshot", "filters": { "expression": { "right": "value", "left": "title" } } }] NO_OBJECT_NAME_DATA = [{ "filters": { "expression": { "left": "title", "op": { "name": "=" } } } }] @ddt.data( [{}], NO_OPERATION_DATA, NO_OBJECT_NAME_DATA, ) def test_validation(self, query_data): self.assert_validation(query_data)
class TestAuditDeprecated(TestCase): """Test for correct working field last_deprecated_date """ def setUp(self): super(TestAuditDeprecated, self).setUp() self.api = Api() def test_redefine_status(self): """Test create audit and change status to Deprecated""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, {"status": "Deprecated"}) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id).one() self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_keep_date_unchanged(self): """Test set status audit to Deprecated, and then set status to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, {"status": "Deprecated"}) with freeze_time("2017-01-26"): self.api.modify_object(audit, {"status": "Planned"}) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_repeat_deprecated_state(self): """Test set status audit to Deprecated, then to Planned, then to Deprecated and then to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, {"status": "Deprecated"}) with freeze_time("2017-01-26"): self.api.modify_object(audit, {"status": "Planned"}) with freeze_time("2017-02-25"): self.api.modify_object(audit, {"status": "Deprecated"}) with freeze_time("2017-02-26"): self.api.modify_object(audit, {"status": "Planned"}) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 2, 25)) def test_filter_by_deprecated_date(self): """Test filter audits by last deprecated date""" amount_of_audits = 5 list_of_ids = [] with factories.single_commit(): with freeze_time("2017-01-25"): for _ in range(amount_of_audits): list_of_ids.append( factories.AuditFactory(status="Deprecated").id) query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': { 'name': '=' }, 'right': "2017-01-25", }, }, 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"]) def test_sort_by_deprecated_date(self): """Test sorting results of filter audits by deprecated date""" dict_of_dates = {} date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"] with factories.single_commit(): for date in date_list: with freeze_time(date): dict_of_dates[factories.AuditFactory( status="Deprecated").id] = date sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1)) sorted_list_ids = [item[0] for item in sorted_dict] query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': { 'name': '=' }, 'right': "2017-01", }, }, "order_by": [{ "name": "last_deprecated_date" }], 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])
class TestWithLastAssessmentDate(TestCase, WithQueryApi): """Integration test suite for WithLastComment functionality.""" def setUp(self): super(TestWithLastAssessmentDate, self).setUp() self.client.get("/login") self.api = Api() self.gen = generator.ObjectGenerator() self.asmnt_comments = defaultdict(dict) with factories.single_commit(): for _ in range(3): asmnt = factories.AssessmentFactory() for _ in range(3): comment = factories.CommentFactory( description=factories.random_str() ) self.asmnt_comments[asmnt.id][comment.id] = comment.description factories.RelationshipFactory(source=asmnt, destination=comment) query = all_models.Revision.query.filter_by(resource_type="Comment") revision_ids = [revision.id for revision in query] self.api.send_request( self.api.client.post, api_link="/admin/compute_attributes", data={"revision_ids": revision_ids} ) def test_last_comment_value(self): """Test assessment has proper value in last_comment field""" assessments = all_models.Assessment.query self.assertEqual(assessments.count(), len(self.asmnt_comments)) for asmnt in assessments: last_comment_id = max(self.asmnt_comments[asmnt.id]) self.assertEqual( asmnt.last_comment_id, last_comment_id ) self.assertEqual( asmnt.last_comment, self.asmnt_comments[asmnt.id][last_comment_id] ) def test_last_comment_filter(self): """Test filtration by last comment.""" asmnt = all_models.Assessment.query.first() result = self._get_first_result_set( self._make_query_dict( "Assessment", expression=("Last Comment", "=", asmnt.last_comment), type_="ids", ), "Assessment", ) self.assertEqual(result["count"], 1) self.assertEqual(result["ids"], [asmnt.id]) def test_last_comment_order(self): """Test sorting by last comment.""" result = self._get_first_result_set( self._make_query_dict( "Assessment", order_by=[{"name": "Last Comment"}], type_="ids" ), "Assessment", "ids", ) asmnts = all_models.Assessment.query sorted_asmnts = sorted(asmnts, key=lambda k: k.last_comment) self.assertEqual(result, [i.id for i in sorted_asmnts]) def test_export_last_comment(self): """Test export Last Assessment Date.""" search_request = [{ "object_name": "Assessment", "filters": { "expression": {}, }, "fields": "all", }] query = self.export_parsed_csv(search_request)["Assessment"] exported_comments = [asmnt["Last Comment"] for asmnt in query] db_comments = [a.last_comment for a in all_models.Assessment.query] self.assertEqual(exported_comments, db_comments) def test_import_last_comment(self): """Test Last Assessment Date field read only on import.""" audit = factories.AuditFactory() response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", "Asmnt-code"), ("Audit", audit.slug), ("Assignees", "*****@*****.**"), ("Creators", "*****@*****.**"), ("Title", "Test title"), ("Last Comment", "some comment"), ])) self._check_csv_response(response, {}) asmnts = all_models.Assessment.query.filter( all_models.Assessment.slug == "Asmnt-code" ).all() self.assertEqual(len(asmnts), 1) self.assertEqual(asmnts[0].last_comment, None) def test_ca_create_on_import(self): """Test creating last_comment CA when comments imported""" audit = factories.AuditFactory() response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", "Asmnt-code"), ("Audit", audit.slug), ("Assignees", "*****@*****.**"), ("Creators", "*****@*****.**"), ("Title", "Test title"), ("Comments", "new comment1;;new comment2;;new comment3"), ])) tasks = self.taskqueue_stub.get_filtered_tasks() deferred.run(tasks[0].payload) self._check_csv_response(response, {}) asmnt = all_models.Assessment.query.filter_by(slug="Asmnt-code").first() self.assertEqual(asmnt.last_comment, "new comment3") def test_ca_update_on_import(self): """Test updating of last_comment CA when comments imported""" asmnt_id = self.asmnt_comments.keys()[0] asmnt_slug = all_models.Assessment.query.get(asmnt_id).slug response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", asmnt_slug), ("Comments", "new comment1;;new comment2;;new comment3"), ])) tasks = self.taskqueue_stub.get_filtered_tasks() deferred.run(tasks[0].payload) self._check_csv_response(response, {}) asmnt = all_models.Assessment.query.filter_by(slug=asmnt_slug).first() self.assertEqual(asmnt.last_comment, "new comment3") @staticmethod def get_model_fulltext(model_name, property, ids): """Get fulltext records for model.""" # pylint: disable=redefined-builtin return db.session.query(mysql.MysqlRecordProperty).filter( mysql.MysqlRecordProperty.type == model_name, mysql.MysqlRecordProperty.property == property, mysql.MysqlRecordProperty.key.in_(ids), ) def test_ca_cleanup_on_obj_delete(self): """Test cleaning of fulltext and attributes tables on obj delete""" asmnt_id = self.asmnt_comments.keys()[0] asmnt = all_models.Assessment.query.get(asmnt_id) last_comment_records = self.get_model_fulltext( "Assessment", "last_comment", [asmnt_id] ) self.assertEqual(last_comment_records.count(), 1) last_comment_attrs = self.get_model_ca("Assessment", [asmnt_id]) self.assertEqual(last_comment_attrs.count(), 1) response = self.api.delete(asmnt) self.assert200(response) last_comment_records = self.get_model_fulltext( "Assessment", "last_comment", [asmnt_id] ) self.assertEqual(last_comment_records.count(), 0) last_comment_attrs = self.get_model_ca("Assessment", [asmnt_id]) self.assertEqual(last_comment_attrs.count(), 0) # Check that other records weren't affected last_comment_records = self.get_model_fulltext( "Assessment", "last_comment", self.asmnt_comments.keys() ) self.assertEqual(last_comment_records.count(), 2) last_comment_attrs = self.get_model_ca( "Assessment", self.asmnt_comments.keys() ) self.assertEqual(last_comment_attrs.count(), 2)
class TestPersonResource(TestCase, WithQueryApi): """Tests for special people api endpoints.""" def setUp(self): super(TestPersonResource, self).setUp() self.client.get("/login") self.api = Api() self.generator = WorkflowsGenerator() @staticmethod def _create_users_names_rbac(users): """Create name and Creator role for users, created vid PersonFactory""" if not users: return roles = {r.name: r for r in all_models.Role.query.all()} for user in users: user.name = user.email.split("@")[0] rbac_factories.UserRoleFactory(role=roles["Creator"], person=user) def assert_profile_get_successful(self, response, expected_datetime): """Verify assertions for successful GET profile method""" self.assert200(response) response_datetime = date_parser.parse(response.json["last_seen_whats_new"]) self.assertEqual(expected_datetime, response_datetime) @freeze_time("2018-05-20 12:23:17") def test_profile_get_successful(self): """Test person_profile GET method successfully achieves correct data""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) response = self.api.client.get("/api/people/{}/profile".format(user.id)) self.assert_profile_get_successful(response, default_date()) def test_profile_get_no_profile(self): """Test person_profile GET method achieves data with missing profile""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) profiles_table = PersonProfile.__table__ db_request = profiles_table.delete().where( profiles_table.c.person_id == user.id) db.engine.execute(db_request) with freeze_time("2018-05-28 23:30:10"): response = self.api.client.get("/api/people/{}/profile".format(user.id)) self.assert_profile_get_successful(response, default_date()) def test_profile_get_failed(self): """Test person_profiles GET method fails Now only logged user can request his profile """ with factories.single_commit(): valid_user = factories.PersonFactory() self._create_users_names_rbac([valid_user]) response = self.client.get( "/api/people/{}/profile".format(valid_user.id)) # logged with default user during setUp self.assert403(response) response = self.api.client.get( "/api/people/{}/profile".format(valid_user.id)) # not authorized user self.assert403(response) @ddt.data("Creator", "Reader", "Editor", "Administrator") def test_profile_post_empty_body(self, role_name): """Test person_profile POST method with empty body - {}.""" role = all_models.Role.query.filter( all_models.Role.name == role_name ).one() with factories.single_commit(): user = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role, person=user) self.api.set_user(person=user) response = self.api.send_request( self.api.client.post, data={}, api_link="/api/people/{}/profile".format(user.id)) self.assert405(response) def test_profile_post_unauthorized(self): """Test person_profile POST method with empty body - No Access.""" with factories.single_commit(): user = factories.PersonFactory() response = self.api.send_request( self.api.client.post, data={}, api_link="/api/people/{}/profile".format(user.id)) # not authorized user self.assert405(response) def assert_profile_put_successful(self, response, correct_response, user, expected): """Verify assertions for successful PUT profile method""" self.assert200(response) self.assertEqual(response.json, correct_response) profile = PersonProfile.query.filter_by(person_id=user.id).first() self.assertEqual(profile.last_seen_whats_new, date_parser.parse(expected)) @ddt.data( ["2018-05-20 16:38:17", "2018-05-20 16:38:17"], ["2018-07-05T14:11:31Z", "2018-07-05T14:11:31"]) @ddt.unpack def test_profile_put_successful(self, new_date, expected_date): """Test person_profile PUT method for setting data and correct response""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) data = {"last_seen_whats_new": new_date} correct_response = {"Person": {"id": user.id, "profile": data}} response = self.api.client.put("/api/people/{}/profile".format(user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) self.assert_profile_put_successful(response, correct_response, user, expected_date) def test_profile_put_no_profile(self): """Test person_profile PUT method for setting data for missing profile""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) new_date = "2018-05-20 22:05:17" data = {"last_seen_whats_new": new_date} correct_response = {"Person": {"id": user.id, "profile": data}} profiles_table = PersonProfile.__table__ db_request = profiles_table.delete().where( profiles_table.c.person_id == user.id) db.engine.execute(db_request) response = self.api.client.put("/api/people/{}/profile".format(user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) self.assert_profile_put_successful(response, correct_response, user, new_date) def test_profile_put_unauthorized(self): """Test person_profiles PUT method fails for unauthorized user""" with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) new_date = "2018-05-20 22:05:17" data = {"last_seen_whats_new": new_date} response = self.client.put("/api/people/{}/profile".format(user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) # logged with default user during setUp self.assert403(response) response = self.api.client.put("/api/people/{}/profile".format(user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) # not authorized user self.assert403(response) @ddt.data({"last_seen_whats_new": "NOT A 123 DAT456A"}, {"other_key": "2018-05-20 22:05:17", "one_more_key": 42}) def test_profile_put_corrupted_data(self, data): """Test person_profiles PUT method fails via incorrect request data If request doesn't have "last_seen_whats_new" key or date is incorrect, response is code 400 "Bad Request" """ with factories.single_commit(): user = factories.PersonFactory() self._create_users_names_rbac([user]) self.api.set_user(person=user) response = self.api.client.put("/api/people/{}/profile".format(user.id), content_type='application/json', data=json.dumps(data), headers=[('X-Requested-By', 'Tests')]) # missed key in request self.assert400(response) def test_task_count_empty(self): """Test query count without any workflows and tasks.""" user = all_models.Person.query.first() response = self.client.get("/api/people/{}/task_count".format(user.id)) self.assertEqual( response.json, {"open_task_count": 0, "has_overdue": False} ) @ddt.data( (True, [ ("task 1", "Finished", 3, True, 3), ("task 1", "Verified", 2, True, 3), ("task 2", "Declined", 2, True, 3), ("task 2", "Verified", 1, False, 3), ("task 2", "Finished", 2, True, 3), ("task 3", "Verified", 1, True, 3), ("task 2", "Verified", 0, False, 3), ]), (False, [ ("task 1", "Finished", 2, True, 3), ("task 2", "In Progress", 2, True, 3), ("task 2", "Finished", 1, False, 3), ("task 3", "Finished", 0, False, 3), ]), ) @ddt.unpack def test_task_count(self, is_verification_needed, transitions): """Test person task counts. This tests checks for correct task counts - with inactive workflows and - with overdue tasks - without overdue tasks - with finished overdue tasks The four checks are done in a single test due to complex differences between tests that make ddt cumbersome and the single test also improves integration test performance due to slow workflow setup stage. """ # pylint: disable=too-many-locals user = all_models.Person.query.first() dummy_user = factories.PersonFactory() user_id = user.id role_id = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Task Assignees", all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id secondary_role_id = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Task Secondary Assignees", all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id one_time_workflow = { "title": "Person resource test workflow", "notify_on_change": True, "description": "some test workflow", "owners": [create_stub(user)], "is_verification_needed": is_verification_needed, "task_groups": [{ "title": "one time task group", "contact": create_stub(user), "task_group_tasks": [{ "title": "task 1", "description": "some task", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id), acl_helper.get_acl_json(secondary_role_id, user.id) ], "start_date": date(2017, 5, 5), "end_date": date(2017, 8, 15), }, { "title": "task 2", "description": "some task 3", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id), acl_helper.get_acl_json(secondary_role_id, user.id), acl_helper.get_acl_json(secondary_role_id, dummy_user.id) ], "start_date": date(2017, 5, 5), "end_date": date(2017, 9, 16), }, { "title": "task 3", "description": "some task 4", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id), acl_helper.get_acl_json(role_id, dummy_user.id) ], "start_date": date(2017, 6, 5), "end_date": date(2017, 10, 16), }, { "title": "dummy task 4", # task should not counted "description": "some task 4", "access_control_list": [ acl_helper.get_acl_json(role_id, dummy_user.id)], "start_date": date(2017, 6, 5), "end_date": date(2017, 11, 17), }, { "title": "dummy task 5", # task should not counted "description": "some task 4", "access_control_list": [ acl_helper.get_acl_json(role_id, dummy_user.id)], "start_date": date(2017, 6, 5), "end_date": date(2017, 11, 18), }], "task_group_objects": [] }] } inactive_workflow = { "title": "Activated workflow with archived cycles", "notify_on_change": True, "description": "Extra test workflow", "owners": [create_stub(user)], "task_groups": [{ "title": "Extra task group", "contact": create_stub(user), "task_group_tasks": [{ "title": "not counted existing task", "description": "", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id)], "start_date": date(2017, 5, 5), "end_date": date(2017, 8, 15), }], "task_group_objects": [] }] } with freeze_time("2017-10-16 05:09:10"): self.client.get("/login") # Activate normal one time workflow _, workflow = self.generator.generate_workflow(one_time_workflow) _, cycle = self.generator.generate_cycle(workflow) tasks = {t.title: t for t in cycle.cycle_task_group_object_tasks} _, workflow = self.generator.activate_workflow(workflow) # Activate and close the inactive workflow _, workflow = self.generator.generate_workflow(inactive_workflow) _, cycle = self.generator.generate_cycle(workflow) _, workflow = self.generator.activate_workflow(workflow) self.generator.modify_object(cycle, data={"is_current": False}) with freeze_time("2017-7-16 07:09:10"): self.client.get("/login") response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 3, "has_overdue": False} ) with freeze_time("2017-10-16 08:09:10"): # same day as task 3 end date self.client.get("/login") response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 3, "has_overdue": True} ) for task, status, count, overdue, my_work_count in transitions: self.generator.modify_object(tasks[task], data={"status": status}) task_count_response = \ self.client.get("/api/people/{}/task_count".format(user_id)) my_work_count_response = \ self.client.get("/api/people/{}/my_work_count".format(user_id)) self.assertEqual( task_count_response.json, {"open_task_count": count, "has_overdue": overdue} ) self.assertEqual( my_work_count_response.json["CycleTaskGroupObjectTask"], my_work_count ) def test_task_count_multiple_wfs(self): """Test task count with both verified and non verified workflows. This checks task counts with 4 tasks 2017, 8, 15 - verification needed 2017, 11, 18 - verification needed 2017, 8, 15 - No verification needed 2017, 11, 18 - No verification needed """ user = all_models.Person.query.first() user_id = user.id role_id = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Task Assignees", all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id workflow_template = { "title": "verified workflow", "owners": [create_stub(user)], "is_verification_needed": True, "task_groups": [{ "title": "one time task group", "contact": create_stub(user), "task_group_tasks": [{ "title": "task 1", "description": "some task", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id)], "start_date": date(2017, 5, 5), "end_date": date(2017, 8, 15), }, { "title": "dummy task 5", "description": "some task 4", "access_control_list": [ acl_helper.get_acl_json(role_id, user.id)], "start_date": date(2017, 6, 5), "end_date": date(2017, 11, 18), }], "task_group_objects": [] }] } with freeze_time("2017-10-16 05:09:10"): self.client.get("/login") verified_workflow = workflow_template.copy() verified_workflow["is_verification_needed"] = True _, workflow = self.generator.generate_workflow(verified_workflow) _, cycle = self.generator.generate_cycle(workflow) verified_tasks = { task.title: task for task in cycle.cycle_task_group_object_tasks } _, workflow = self.generator.activate_workflow(workflow) non_verified_workflow = workflow_template.copy() non_verified_workflow["is_verification_needed"] = False _, workflow = self.generator.generate_workflow(non_verified_workflow) _, cycle = self.generator.generate_cycle(workflow) non_verified_tasks = { task.title: task for task in cycle.cycle_task_group_object_tasks } _, workflow = self.generator.activate_workflow(workflow) with freeze_time("2017-7-16 07:09:10"): self.client.get("/login") response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 4, "has_overdue": False} ) with freeze_time("2017-10-16 08:09:10"): self.client.get("/login") response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 4, "has_overdue": True} ) # transition 1, task that needs verification goes to finished state. This # transition should not change anything self.generator.modify_object( verified_tasks["task 1"], data={"status": "Finished"} ) response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 4, "has_overdue": True} ) # transition 2, task that needs verification goes to verified state. This # transition should reduce task count. self.generator.modify_object( verified_tasks["task 1"], data={"status": "Verified"} ) response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 3, "has_overdue": True} ) # transition 3, task that does not need verification goes into Finished # state. This transition should reduce task count and remove all overdue # tasks self.generator.modify_object( non_verified_tasks["task 1"], data={"status": "Finished"} ) response = self.client.get("/api/people/{}/task_count".format(user_id)) self.assertEqual( response.json, {"open_task_count": 2, "has_overdue": False} ) @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200), ("Administrator", 200)) @ddt.unpack def test_person_editing(self, role_name, status): """{0} should receive {1} status code on edit Person.""" role = all_models.Role.query.filter( all_models.Role.name == role_name ).one() with factories.single_commit(): client_user = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role, person=client_user) self.api.set_user(client_user) self.client.get("/login") base_email = "*****@*****.**" person = factories.PersonFactory(email=base_email) person_id = person.id new_email = "new_{}".format(base_email) resp = self.api.put(person, {"email": new_email}) self.assertEqual(status, resp.status_code) person = all_models.Person.query.get(person_id) if status == 200: self.assertEqual(new_email, person.email) else: self.assertEqual(base_email, person.email)
class TestEvidenceQueries(TestCase): """Tests for /query api for Evidence instance filtering.""" # pylint: disable=invalid-name def setUp(self): super(TestEvidenceQueries, self).setUp() self.api = Api() def test_filter_evidence_by_type_url(self): """Test filter evidences by evidence type URL.""" evidence_gdrive = factories.EvidenceFactory( title='Simple title', kind=all_models.Evidence.URL, link='sample.site' ) evidence_url_id = evidence_gdrive.id query_request_data = [{ u'filters': { u'expression': { u'left': u'type', u'op': {u'name': u'='}, u'right': all_models.Evidence.URL } }, u'object_name': u'Evidence', u'type': u'values' }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Evidence"]["count"]) self.assertEqual(evidence_url_id, resp.json[0]["Evidence"]["values"][0]["id"]) def test_filter_evidence_by_type_gdrive(self): """Test filter evidences by evidence type GDRIVE.""" evidence_gdrive = factories.EvidenceFactory( title='Simple title', source_gdrive_id='gdrive_id', link='sample.site', kind=all_models.Evidence.FILE ) evidence_gdrive_id = evidence_gdrive.id query_request_data = [{ u'filters': { u'expression': { u'left': u'type', u'op': {u'name': u'='}, u'right': all_models.Evidence.FILE } }, u'object_name': u'Evidence', u'type': u'values' }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Evidence"]["count"]) self.assertEqual(evidence_gdrive_id, resp.json[0]["Evidence"]["values"][0]["id"])
class TestEvidenceQueries(TestCase): """Tests for /query api for Evidence instance filtering.""" # pylint: disable=invalid-name def setUp(self): super(TestEvidenceQueries, self).setUp() self.api = Api() def test_filter_evidence_by_type_url(self): """Test filter evidences by evidence type URL.""" evidence_gdrive = factories.EvidenceFactory( title='Simple title', kind=all_models.Evidence.URL, link='sample.site') evidence_url_id = evidence_gdrive.id query_request_data = [{ u'filters': { u'expression': { u'left': u'type', u'op': { u'name': u'=' }, u'right': all_models.Evidence.URL } }, u'object_name': u'Evidence', u'type': u'values' }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Evidence"]["count"]) self.assertEqual(evidence_url_id, resp.json[0]["Evidence"]["values"][0]["id"]) def test_filter_evidence_by_type_gdrive(self): """Test filter evidences by evidence type GDRIVE.""" evidence_gdrive = factories.EvidenceFactory( title='Simple title', source_gdrive_id='gdrive_id', link='sample.site', kind=all_models.Evidence.FILE) evidence_gdrive_id = evidence_gdrive.id query_request_data = [{ u'filters': { u'expression': { u'left': u'type', u'op': { u'name': u'=' }, u'right': all_models.Evidence.FILE } }, u'object_name': u'Evidence', u'type': u'values' }] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Evidence"]["count"]) self.assertEqual(evidence_gdrive_id, resp.json[0]["Evidence"]["values"][0]["id"])
class TestFilterByAuditor(TestCase): """ Test for filter by Auditor. """ def setUp(self): super(TestFilterByAuditor, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, self.auditor = self.generator.generate_person(user_role="Creator") auditor_role = all_models.AccessControlRole.query.filter_by( name="Auditors").one() with factories.single_commit(): self.audit = factories.AuditFactory(status="In Progress") self.audit_id = self.audit.id audit_context = factories.ContextFactory() self.audit.context = audit_context factories.AccessControlListFactory( ac_role=auditor_role, object=self.audit, person=self.auditor ) self.api.set_user(self.auditor) def test_query_audits_by_auditor(self): """test get audit as query get""" objects = self.api.get_query(all_models.Audit, "") self.assertEqual(1, len(objects.json["audits_collection"]["audits"])) audit_dict = objects.json["audits_collection"]["audits"][0] self.assertEqual(self.audit_id, audit_dict["id"]) def test_filter_audits_by_auditor(self): """Test query on audit Global Search. This query is the fact query that frontend is sending in global search. """ query_request_data = [ { u'fields': [], u'filters': { u'expression': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Planned' }, u'op': {u'name': u'OR'}, u'right': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'In Progress' }, u'op': {u'name': u'OR'}, u'right': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Manager Review' }, u'op': {u'name': u'OR'}, u'right': { u'left': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Ready for External Review', }, u'op': {u'name': u'OR'}, u'right': { u'left': u'status', u'op': {u'name': u'='}, u'right': u'Completed', } }, }, }, }, u'keys': [u'status'], u'order_by': { u'compare': None, u'keys': [], u'order': u'', } }, u'limit': [0, 5], u'object_name': u'Audit', u'permissions': u'read', u'type': u'values', }, { u'filters': { u'expression': { u'ids': [u'150'], u'object_name': u'undefined', u'op': {u'name': u'relevant'} }, u'keys': [], u'order_by': {u'compare': None, u'keys': [], u'order': u''} }, u'object_name': u'Audit', u'type': u'ids', }, ] resp = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertEqual(1, resp.json[0]["Audit"]["count"]) self.assertEqual(self.audit_id, resp.json[0]["Audit"]["values"][0]["id"])
class TestWithLastCommentCycleTask(TestCase, WithQueryApi): """ Integration test suite for WithLastComment functionality for Cycle Tasks. """ def setUp(self): super(TestWithLastCommentCycleTask, self).setUp() self.client.get("/login") self.api = Api() def compute_attributes(self): """Method for computed_attributes job""" query = all_models.Revision.query.filter_by(resource_type="Comment") revision_ids = [revision.id for revision in query] self.api.send_request( self.api.client.post, api_link="/admin/compute_attributes", data={"revision_ids": revision_ids} ) @staticmethod def get_model_fulltext(model_name, property, ids): """Get fulltext records for model.""" # pylint: disable=redefined-builtin return db.session.query(mysql.MysqlRecordProperty).filter( mysql.MysqlRecordProperty.type == model_name, mysql.MysqlRecordProperty.property == property, mysql.MysqlRecordProperty.key.in_(ids), ) def test_last_comment_value(self): """Test proper value in last_comment field""" with factories.single_commit(): c_task = wf_factories.CycleTaskGroupObjectTaskFactory() c_task_id = c_task.id comment_1 = factories.CommentFactory(description=factories.random_str()) comment_2 = factories.CommentFactory(description=factories.random_str()) comment_2_id = comment_2.id factories.RelationshipFactory(source=c_task, destination=comment_1) factories.RelationshipFactory(source=c_task, destination=comment_2) self.compute_attributes() comment_2 = all_models.Comment.query.get(comment_2_id) c_task = all_models.CycleTaskGroupObjectTask.query.get(c_task_id) self.assertEqual(c_task.last_comment, comment_2.description) def test_last_comment_filter(self): """Test filtration by last comment.""" with factories.single_commit(): for _ in range(2): c_task = wf_factories.CycleTaskGroupObjectTaskFactory() comment = factories.CommentFactory( description=factories.random_str() ) factories.RelationshipFactory(source=c_task, destination=comment) self.compute_attributes() c_task = all_models.CycleTaskGroupObjectTask.query.first() result = self._get_first_result_set( self._make_query_dict( "CycleTaskGroupObjectTask", expression=("Last Comment", "=", c_task.last_comment), type_="ids", ), "CycleTaskGroupObjectTask", ) self.assertEqual(result["count"], 1) self.assertEqual(result["ids"], [c_task.id]) def test_ca_cleanup_on_obj_delete(self): """Test cleaning of fulltext and attributes tables on obj delete""" with factories.single_commit(): for _ in range(2): c_task = wf_factories.CycleTaskGroupObjectTaskFactory() comment = factories.CommentFactory( description=factories.random_str() ) factories.RelationshipFactory(source=c_task, destination=comment) self.compute_attributes() c_task = all_models.CycleTaskGroupObjectTask.query.first() last_comment_records = self.get_model_fulltext( "CycleTaskGroupObjectTask", "last_comment", [c_task.id] ) last_comment_attrs = self.get_model_ca( "CycleTaskGroupObjectTask", [c_task.id] ) self.assertEqual(last_comment_records.count(), 1) self.assertEqual(last_comment_attrs.count(), 1) response = self.api.delete(c_task) self.assert200(response) last_comment_records = self.get_model_fulltext( "CycleTaskGroupObjectTask", "last_comment", [c_task.id] ) last_comment_attrs = self.get_model_ca( "CycleTaskGroupObjectTask", [c_task.id] ) self.assertEqual(last_comment_attrs.count(), 0) self.assertEqual(last_comment_records.count(), 0) # Check that other records weren't affected task_ids = [task.id for task in all_models.CycleTaskGroupObjectTask.query.all()] last_comment_records = self.get_model_fulltext( "CycleTaskGroupObjectTask", "last_comment", task_ids ) last_comment_attrs = self.get_model_ca( "CycleTaskGroupObjectTask", task_ids, ) self.assertEqual(last_comment_records.count(), 1) self.assertEqual(last_comment_attrs.count(), 1)
class TestWorkflowsApiPost(TestCase): def setUp(self): super(TestWorkflowsApiPost, self).setUp() self.api = Api() def tearDown(self): pass def test_send_invalid_data(self): data = self.get_workflow_dict() del data["workflow"]["title"] del data["workflow"]["context"] response = self.api.post(all_models.Workflow, data) self.assert400(response) # TODO: check why response.json["message"] is empty def test_create_one_time_workflows(self): data = self.get_workflow_dict() response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_weekly_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "weekly" data["workflow"]["title"] = "Weekly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_monthly_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "monthly" data["workflow"]["title"] = "Monthly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_quarterly_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "quarterly" data["workflow"]["title"] = "Quarterly" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_annually_workflows(self): data = self.get_workflow_dict() data["workflow"]["frequency"] = "annually" data["workflow"]["title"] = "Annually" response = self.api.post(all_models.Workflow, data) self.assertEqual(response.status_code, 201) def test_create_task_group(self): wf_data = self.get_workflow_dict() wf_data["workflow"]["title"] = "Create_task_group" wf_response = self.api.post(all_models.Workflow, wf_data) data = self.get_task_group_dict(wf_response.json["workflow"]) response = self.api.post(all_models.TaskGroup, data) self.assertEqual(response.status_code, 201) # TODO: Api should be able to handle invalid data @unittest.skip("Not implemented.") def test_create_task_group_invalid_workflow_data(self): data = self.get_task_group_dict({"id": -1, "context": {"id": -1}}) response = self.api.post(all_models.TaskGroup, data) self.assert400(response) @staticmethod def get_workflow_dict(): data = { "workflow": { "custom_attribute_definitions": [], "custom_attributes": {}, "title": "One_time", "description": "", "frequency": "one_time", "notify_on_change": False, "task_group_title": "Task Group 1", "notify_custom_message": "", "is_verification_needed": True, "owners": None, "context": None, } } return data @staticmethod def get_task_group_dict(workflow): data = { "task_group": { "custom_attribute_definitions": [], "custom_attributes": {}, "_transient": {}, "contact": { "id": 1, "href": "/api/people/1", "type": "Person" }, "workflow": { "id": workflow["id"], "href": "/api/workflows/%d" % workflow["id"], "type": "Workflow" }, "context": { "id": workflow["context"]["id"], "href": "/api/contexts/%d" % workflow["context"]["id"], "type": "Context" }, "modal_title": "Create Task Group", "title": "Create_task_group", "description": "", } } return data @ddt.data(True, False) def test_autogen_verification_flag(self, flag): """Check is_verification_needed flag for activate WF action.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) group = wf_factories.TaskGroupFactory(workflow=workflow) wf_factories.TaskGroupTaskFactory(task_group=group) data = [{ "cycle": { "autogenerate": True, "isOverdue": False, "workflow": { "id": workflow.id, "type": "Workflow", }, "context": { "id": workflow.context_id, "type": "Context", }, } }] resp = self.api.send_request( self.api.client.post, api_link="/api/cycles", data=data) cycle_id = resp.json[0][1]["cycle"]["id"] self.assertEqual( flag, all_models.Cycle.query.get(cycle_id).is_verification_needed) @ddt.data(True, False) def test_change_verification_flag(self, flag): """Check is_verification_needed flag isn't changeable.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": not flag}) self.assert400(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False) def test_not_change_vf_flag(self, flag): """Check is_verification_needed not change on update.""" with factories.single_commit(): workflow = wf_factories.WorkflowFactory(is_verification_needed=flag) workflow_id = workflow.id resp = self.api.put(workflow, {"is_verification_needed": flag}) self.assert200(resp) self.assertEqual( flag, all_models.Workflow.query.get(workflow_id).is_verification_needed) @ddt.data(True, False, None) def test_create_vf_flag(self, flag): """Check is_verification_needed flag setup on create.""" data = self.get_workflow_dict() if flag is None: data['workflow'].pop('is_verification_needed', None) else: data['workflow']['is_verification_needed'] = flag resp = self.api.post(all_models.Workflow, data) self.assertEqual(201, resp.status_code) workflow_id = resp.json['workflow']['id'] self.assertEqual( flag if flag is not None else True, all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestBulkIssuesSync(TestCase): """Base class for bulk issuetracker synchronization tests.""" def setUp(self): """Set up for test methods.""" super(TestBulkIssuesSync, self).setUp() self.api = Api() self.gen = generator.ObjectGenerator() self.role_people = { "Audit Captains": factories.PersonFactory(email="*****@*****.**"), "Creators": factories.PersonFactory(email="*****@*****.**"), "Assignees": factories.PersonFactory(email="*****@*****.**"), "Verifiers": factories.PersonFactory(email="*****@*****.**"), } self.issue_id = "42" def setup_assessments(self, asmnt_count, issue_id=None, enabled=True): """Create Audit with couple of Assessments and linked IssueTrackerIssues. Args: asmnt_count: Count of Assessments in Audit. Returns: Tuple with Audit id and list of Assessment ids. """ with factories.single_commit(): audit = factories.AuditFactory() audit.add_person_with_role_name( self.role_people["Audit Captains"], "Audit Captains", ) factories.IssueTrackerIssueFactory( enabled=enabled, issue_tracked_obj=audit, issue_id=issue_id, issue_type=constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'], component_id=12345, hotlist_id=12345, issue_priority="P2", issue_severity="S2", ) assessment_ids = [] for _ in range(asmnt_count): asmnt = factories.AssessmentFactory(audit=audit) factories.RelationshipFactory(source=audit, destination=asmnt) for role_name in ["Creators", "Assignees", "Verifiers"]: asmnt.add_person_with_role_name( self.role_people[role_name], role_name, ) factories.IssueTrackerIssueFactory( enabled=enabled, issue_tracked_obj=asmnt, issue_id=issue_id, title=None, ) assessment_ids.append(asmnt.id) return audit.id, assessment_ids @staticmethod def setup_issues(issue_count, issue_id=None, enabled=True): """Create issues with enabled integration.""" with factories.single_commit(): issue_ids = [] for _ in range(issue_count): issue = factories.IssueFactory() factories.IssueTrackerIssueFactory( enabled=enabled, issue_tracked_obj=issue, issue_id=issue_id, title=None, ) issue_ids.append(issue.id) return issue_ids def issuetracker_sync_mock(self, sync_func_name): """IssueTracker sync method mock.""" return mock.patch.object( sync_utils, sync_func_name, return_value={"issueId": self.issue_id} ) def generate_children_issues_for(self, parent_type, parent_id, child_type): """Generate IssueTracker issue for objects with provided type and ids. Args: obj_type: Type of objects. Now only 'Assessment' supported. obj_ids: List with ids of objects. Returns: Response with result of issues generation. """ with self.issuetracker_sync_mock("create_issue"): return self.api.send_request( self.api.client.post, api_link="/generate_children_issues", data={ "parent": {"type": parent_type, "id": parent_id}, "child_type": child_type, } ) def generate_issues_for(self, object_info): """Generate IssueTracker issues for provided objects.""" with self.issuetracker_sync_mock("create_issue"): return self.api.send_request( self.api.client.post, api_link="/generate_issues", data={ "objects": [{ "type": type_, "id": id_, "hotlist_ids": hotlist_id, "component_id": component_id, } for type_, id_, hotlist_id, component_id in object_info], } ) def update_issues_for(self, object_info): """Update IssueTracker issues for provided objects.""" with self.issuetracker_sync_mock("update_issue"): return self.api.send_request( self.api.client.post, api_link="/update_issues", data={ "objects": [{ "type": type_, "id": id_, "hotlist_ids": hotlist_id, "component_id": component_id, } for type_, id_, hotlist_id, component_id in object_info], } ) def assert_obj_issues(self, issuetracker_info, assignee=None): """Check correctness of created IssueTracker issues.""" for type_, id_, hotlist_id, component_id in issuetracker_info: obj = inflector.get_model(type_).query.get(id_) issue = obj.issuetracker_issue self.assertEqual(issue.enabled, 1) self.assertEqual(issue.title, obj.title) self.assertEqual(issue.component_id, component_id) self.assertEqual(issue.hotlist_id, hotlist_id) self.assertEqual( issue.issue_type, constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'] ) self.assertEqual(issue.issue_priority, "P2") self.assertEqual(issue.issue_severity, "S2") self.assertEqual(issue.assignee, assignee) self.assertEqual(issue.cc_list, "") self.assertEqual(issue.issue_id, self.issue_id) self.assertEqual( issue.issue_url, "http://issue/{}".format(self.issue_id) ) def assert_children_asmnt_issues(self, asmnt_ids): """Check if Assessments IssueTracker issues inherit data from Audit.""" assessments = all_models.Assessment.query.filter( all_models.Assessment.id.in_(asmnt_ids) ) for asmnt in assessments: issue = asmnt.issuetracker_issue parent_issue = asmnt.audit.issuetracker_issue self.assertEqual(issue.enabled, 1) self.assertEqual(issue.title, asmnt.title) self.assertEqual(issue.component_id, parent_issue.component_id) self.assertEqual(issue.hotlist_id, parent_issue.hotlist_id) self.assertEqual(issue.issue_type, parent_issue.issue_type) self.assertEqual(issue.issue_priority, parent_issue.issue_priority) self.assertEqual(issue.issue_severity, parent_issue.issue_severity) self.assertEqual(issue.assignee, "*****@*****.**") self.assertEqual(issue.cc_list, "") self.assertEqual(issue.issue_id, self.issue_id) self.assertEqual( issue.issue_url, "http://issue/{}".format(self.issue_id) ) def assert_not_updated(self, object_type, object_ids): """Check if IssueTracker issues have empty fields. Args: object_type: Type of objects which issues should be checked. object_ids: List with ids for objects which issues should be checked. Raise: AssertionError if relevant Issues have non-empty base fields. """ issues = all_models.IssuetrackerIssue.query.filter( all_models.IssuetrackerIssue.object_type == object_type, all_models.IssuetrackerIssue.object_id.in_(object_ids), ) for issue in issues: self.assertEqual(issue.issue_id, None) self.assertEqual(issue.assignee, None) self.assertEqual(issue.cc_list, "") self.assertEqual(issue.title, None)