class TestReader(TestCase): """Test that some objects cannot be deleted by anyone.""" def setUp(self): super(TestReader, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_objects() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def init_objects(self): """Creates the objects used by all the tests""" self.api.set_user(self.users["admin"]) _, person = self.object_generator.generate_person() self.objects = [person] def test_undeletable_objects(self): """No user shoud be allowed to delete these objects.""" for role, user in self.users.iteritems(): self.api.set_user(user) for obj in self.objects: response = self.api.delete(obj) self.assertEqual(response.status_code, 403, "{} can delete {}".format(role, obj.type))
class TestReader(TestCase): """Test that some objects cannot be deleted by anyone.""" def setUp(self): TestCase.setUp(self) self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_objects() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def init_objects(self): """Creates the objects used by all the tests""" self.api.set_user(self.users["admin"]) _, person = self.object_generator.generate_person() self.objects = [person] def test_undeletable_objects(self): """No user shoud be allowed to delete these objects.""" for role, user in self.users.iteritems(): self.api.set_user(user) for obj in self.objects: response = self.api.delete(obj) self.assertEqual(response.status_code, 403, "{} can delete {}".format(role, obj.type))
class TestFilteringByRequest(TestCase): """Test filter query by request""" def setUp(self): super(TestFilteringByRequest, self).setUp() self.object_generator = ObjectGenerator() self.api = Api() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = ( ("creator", "Creator"), ("admin", "Administrator"), ("john", None), ) self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_no_role_users_filtering(self): """Test 'No Role' users filtering""" self.api.set_user(self.users['admin']) response = self.api.get_query(all_models.Person, "__no_role=true") self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json['people_collection']['people']), 1) self.assertEqual( response.json['people_collection']['people'][0]['name'], 'john' )
class TestFilteringByRequest(TestCase): """Test filter query by request""" def setUp(self): super(TestFilteringByRequest, self).setUp() self.object_generator = ObjectGenerator() self.api = Api() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = ( ("creator", "Creator"), ("admin", "Administrator"), ("john", None), ) self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_no_role_users_filtering(self): """Test 'No Role' users filtering""" self.api.set_user(self.users['admin']) response = self.api.get_query(all_models.Person, "__no_role=true") self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json['people_collection']['people']), 1) self.assertEqual( response.json['people_collection']['people'][0]['name'], 'john')
def set_up_people(self): """Set up people with different roles needed by the tests""" self.people = {} object_generator = ObjectGenerator() for name in ["Creator", "Reader", "Editor"]: _, user = object_generator.generate_person(data={"name": name}, user_role=name) self.people[name] = user
def set_up_people(self): """Set up people with different roles needed by the tests""" self.people = {} object_generator = ObjectGenerator() for name in ["Creator", "Reader", "Editor"]: _, user = object_generator.generate_person( data={"name": name}, user_role=name) self.people[name] = user
class TestPersonProfilePermissions(TestCase): """Test PersonProfile.""" def setUp(self): super(TestPersonProfilePermissions, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """Init user with different roles.""" users = [("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user @ddt.data("reader", "editor", "admin", "creator") def test_permissions(self, name): """Test permissions for user roles.""" user = all_models.Person.query.get(self.users[name].id) profile_id = user.profile.id self.api.set_user(self.users[name]) response = self.api.get(all_models.PersonProfile, profile_id) self.assert200(response) new_date = "2018-05-20 22:05:17" response = self.api.put( user.profile, { "people_profiles": { "id": profile_id, "last_seen_whats_new": new_date, }, }) self.assert200(response) response = self.api.delete(user.profile, profile_id) if name == "admin": self.assert200(response) else: self.assert403(response) res = self.api.get(all_models.PersonProfile, None) api_profiles = res.json["people_profiles_collection"][ "people_profiles"] api_profile_id = api_profiles[0]["id"] if name == "admin": self.assertEqual(len(api_profiles), 4) else: self.assertEqual(len(api_profiles), 1) self.assertEqual(profile_id, api_profile_id)
class TestAccessControlRole(TestCase): """TestAccessControlRole""" def setUp(self): super(TestAccessControlRole, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.people = {} for name in ["Creator", "Reader", "Editor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role=name) self.people[name] = user def _post_role(self): """Helper function for POSTing roles""" name = random_str(prefix="Access Control Role - ") return self.api.post( AccessControlRole, { "access_control_role": { "name": name, "object_type": "Control", "context": None, "read": True }, }) def test_create(self): """Test Access Control Role creation""" response = self._post_role() assert response.status_code == 201, \ "Failed to create a new access control role, response was {}".format( response.status) id_ = response.json['access_control_role']['id'] role = AccessControlRole.query.filter( AccessControlRole.id == id_).first() assert role.read == 1, \ "Read permission not correctly saved {}".format(role.read) assert role.update == 1, \ "Update permission not correctly saved {}".format(role.update) assert role.delete == 1, \ "Update permission not correctly saved {}".format(role.delete) def test_only_admin_can_post(self): """Only admin users should be able to POST access control roles""" for name in ("Creator", "Reader", "Editor"): person = self.people.get(name) self.api.set_user(person) response = self._post_role() assert response.status_code == 403, \ "Non admins should get forbidden error when POSTing role. {}".format( response.status)
class TestPersonProfilePermissions(TestCase): """Test PersonProfile.""" def setUp(self): super(TestPersonProfilePermissions, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """Init user with different roles.""" users = [("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role ) self.users[name] = user @ddt.data("reader", "editor", "admin", "creator") def test_permissions(self, name): """Test permissions for user roles.""" user = all_models.Person.query.get(self.users[name].id) profile = all_models.PersonProfile.query.join( all_models.PersonProfile.person ).filter_by( email=user.email ).one() self.api.set_user(self.users[name]) response = self.api.get(all_models.PersonProfile, profile.id) self.assert200(response) new_date = "2018-05-20 22:05:17" response = self.api.put(profile, { "people_profiles": { "id": profile.id, "last_seen_whats_new": new_date, }, }) self.assert200(response) response = self.api.delete(profile) if name == "admin": self.assert200(response) else: self.assert403(response)
class TestPermissionsOnAssessmentRelatedAssignables(TestCase): """Test check Reader permissions for Assessment related assignables Global Reader once assigned to Assessment as Assessor, should have permissions to read/update/delete URLs(Documents) related to this Assessment """ def setUp(self): super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, self.reader = self.generator.generate_person( user_role="Reader" ) audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) object_person_rel = factories.RelationshipFactory( source=assessment, destination=self.reader ) factories.RelationshipAttrFactory( relationship_id=object_person_rel.id, attr_name="AssigneeType", attr_value="Assessor" ) factories.RelationshipFactory(source=audit, destination=assessment) document = factories.DocumentFactory() document_id = document.id doc_rel = factories.RelationshipFactory(source=assessment, destination=document) doc_rel_id = doc_rel.id self.api.set_user(self.reader) self.document = all_models.Document.query.get(document_id) self.doc_relationship = all_models.Relationship.query.get(doc_rel_id) def test_delete_action(self): """Test permissions for delete action on Document""" resp = self.api.delete(self.document) self.assert200(resp) self.assertFalse(all_models.Document.query.filter( all_models.Document.id == self.document.id).all()) def test_unmap_action(self): """Test permissions for unmap action on Document""" resp = self.api.delete(self.doc_relationship) self.assert200(resp) self.assertFalse(all_models.Relationship.query.filter( all_models.Relationship.id == self.doc_relationship.id).all())
class TestAccessControlRole(TestCase): """TestAccessControlRole""" def setUp(self): super(TestAccessControlRole, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.people = {} for name in ["Creator", "Reader", "Editor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role=name) self.people[name] = user def _post_role(self): """Helper function for POSTing roles""" name = random_str(prefix="Access Control Role - ") return self.api.post(AccessControlRole, { "access_control_role": { "name": name, "object_type": "Control", "context": None, "read": True }, }) def test_create(self): """Test Access Control Role creation""" response = self._post_role() assert response.status_code == 201, \ "Failed to create a new access control role, response was {}".format( response.status) id_ = response.json['access_control_role']['id'] role = AccessControlRole.query.filter(AccessControlRole.id == id_).first() assert role.read == 1, \ "Read permission not correctly saved {}".format(role.read) assert role.update == 1, \ "Update permission not correctly saved {}".format(role.update) assert role.delete == 1, \ "Update permission not correctly saved {}".format(role.delete) def test_only_admin_can_post(self): """Only admin users should be able to POST access control roles""" for name in ("Creator", "Reader", "Editor"): person = self.people.get(name) self.api.set_user(person) response = self._post_role() assert response.status_code == 403, \ "Non admins should get forbidden error when POSTing role. {}".format( response.status)
class TestFilteringByRequest(TestCase): """Test filter query by request""" def setUp(self): super(TestFilteringByRequest, self).setUp() self.object_generator = ObjectGenerator() self.api = Api() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = ( ("creator", "Creator"), ("admin", "Administrator"), ("john", "WorkflowOwner") ) self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user context = ( db.session.query(all_models.Context).filter( all_models.Context.id != 0 ).first() ) user_role = ( db.session.query(all_models.UserRole).join(all_models.Person). filter( and_( all_models.UserRole.person_id == all_models.Person.id, all_models.Person.name == "john" ) ).first() ) user_role.context_id = context.id db.session.commit() db.session.flush() def test_no_role_users_filtering(self): """Test 'No Role' users filtering""" self.api.set_user(self.users['admin']) response = self.api.get_query(all_models.Person, "__no_role=true") self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json['people_collection']['people']), 1) self.assertEqual( response.json['people_collection']['people'][0]['name'], 'john' )
def test_import_evidence_mapped(self, status): """Test notifications for '{}' Assessment if Evidence mapped in import.""" object_generator = ObjectGenerator() _, user = object_generator.generate_person(user_role="Creator") assessment = factories.AssessmentFactory() assessment.add_person_with_role_name(user, "Verifiers") assessment.status = status db.session.commit() response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", assessment.slug), ("Evidence URL", "some url"), ])) self._check_csv_response(response, {}) self.assert_asmnt_notifications()
class TestPermissions(TestCase): """Test permissions for background tasks""" def setUp(self): super(TestPermissions, self).setUp() self.generator = Generator() self.api = api_helper.Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_bg_tasks_access(self): """Only admin can use admin requirement""" from ggrc.models import all_models control_dict = { "control": { "title": "Control title", "context": None, }, } response = self.api.send_request( self.api.client.post, all_models.Control, control_dict, {"X-GGRC-BackgroundTask": "true"}, ) self.assertEqual(response.status_code, 201) for role in ("reader", "creator", "admin"): self.api.set_user(self.users[role]) content = self.api.client.get("/api/background_tasks") self.assert200(content) bg_tasks_content = \ content.json['background_tasks_collection']['background_tasks'] for bg_task_content in bg_tasks_content: self.assertEqual(set(bg_task_content.keys()), {"id", "selfLink", "status", "type"}) self.assertTrue(len(bg_tasks_content) >= 1)
class TestPermissionsOnAssessmentRelatedAssignables(TestCase): """Test check Reader permissions for Assessment related assignables Global Reader once assigned to Assessment as Assessor, should have permissions to read/update/delete URLs(Documents) related to this Assessment """ def setUp(self): super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, self.reader = self.generator.generate_person(user_role="Reader") audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) object_person_rel = factories.RelationshipFactory( source=assessment, destination=self.reader) factories.RelationshipAttrFactory(relationship_id=object_person_rel.id, attr_name="AssigneeType", attr_value="Assessor") factories.RelationshipFactory(source=audit, destination=assessment) document = factories.DocumentFactory() document_id = document.id doc_rel = factories.RelationshipFactory(source=assessment, destination=document) doc_rel_id = doc_rel.id self.api.set_user(self.reader) self.document = all_models.Document.query.get(document_id) self.doc_relationship = all_models.Relationship.query.get(doc_rel_id) def test_delete_action(self): """Test permissions for delete action on Document""" resp = self.api.delete(self.document) self.assert200(resp) self.assertFalse( all_models.Document.query.filter( all_models.Document.id == self.document.id).all()) def test_unmap_action(self): """Test permissions for unmap action on Document""" resp = self.api.delete(self.doc_relationship) self.assert200(resp) self.assertFalse( all_models.Relationship.query.filter( all_models.Relationship.id == self.doc_relationship.id).all())
class TestPermissionsOnAssessmentRelatedAssignables(TestCase): """Test check Reader permissions for Assessment related assignables Global Reader once assigned to Assessment as Assignee, should have permissions to read/update/delete URLs(Documents) related to this Assessment """ def setUp(self): super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, self.reader = self.generator.generate_person( user_role="Reader" ) audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) ac_role = all_models.AccessControlRole.query.filter_by( object_type=assessment.type, name="Assignees" ).first() factories.AccessControlListFactory( ac_role=ac_role, object=assessment, person=self.reader ) factories.RelationshipFactory(source=audit, destination=assessment) evidence = factories.EvidenceUrlFactory() evidence_id = evidence.id evid_rel = factories.RelationshipFactory(source=assessment, destination=evidence) evid_rel_id = evid_rel.id self.api.set_user(self.reader) self.evidence = all_models.Evidence.query.get(evidence_id) self.evid_relationship = all_models.Relationship.query.get(evid_rel_id) def test_delete_action(self): """Test permissions for delete action on Evidence Allow only Global Admin to delete Documents. """ resp = self.api.delete(self.evidence) self.assert403(resp) self.assertEquals(len(all_models.Evidence.query.filter( all_models.Evidence.id == self.evidence.id).all()), 1)
def test_add_comment(self): """Test add comment action.""" generator = ObjectGenerator() _, reader = generator.generate_person(user_role="Administrator") self.api.set_user(reader) assessment = factories.AssessmentFactory() context = factories.ContextFactory(related_object=assessment) assessment.context = context acrs = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.object_type == "Assessment", all_models.AccessControlRole.name.in_(["Assignees", "Creators"]), ) for acr in acrs: factories.AccessControlListFactory(ac_role=acr, object=assessment, person=reader) response = self.api.put( assessment, { "actions": { "add_related": [{ "id": None, "type": "Comment", "description": "comment", "custom_attribute_definition_id": None, }] } }) self.assert200(response) # last relationship id (newly created relationship) rel_id = max( i["id"] for i in response.json["assessment"]["related_destinations"]) relationship = all_models.Relationship.query.get(rel_id) self.assertIsNotNone(relationship) comment = all_models.Comment.query.get(relationship.destination_id) self.assertEqual(comment.description, "comment") self.assertEqual(comment.assignee_type, "Assignees,Creators") self.assertEqual(comment.context_id, assessment.context_id)
def test_import_snapshot_mapped(self, status): """Test notifications for '{}' Assessment if snapshot mapped in import.""" object_generator = ObjectGenerator() _, user = object_generator.generate_person(user_role="Creator") with factories.single_commit(): assessment = factories.AssessmentFactory() control = factories.ControlFactory() # pylint: disable=expression-not-assigned self._create_snapshots(assessment.audit, [control])[0] assessment.add_person_with_role_name(user, "Verifiers") assessment.status = status db.session.commit() response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", assessment.slug), ("Map:control versions", control.slug), ])) self._check_csv_response(response, {}) self.assert_asmnt_notifications()
class TestPermissionsOnAssessmentRelatedAssignables(TestCase): """Test check Reader permissions for Assessment related assignables Global Reader once assigned to Assessment as Assignee, should have permissions to read/update/delete URLs(Documents) related to this Assessment """ def setUp(self): super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, self.reader = self.generator.generate_person( user_role="Reader" ) audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) factories.AccessControlPersonFactory( ac_list=assessment.acr_name_acl_map["Assignees"], person=self.reader, ) factories.RelationshipFactory(source=audit, destination=assessment) evidence = factories.EvidenceUrlFactory() evidence_id = evidence.id evid_rel = factories.RelationshipFactory(source=assessment, destination=evidence) evid_rel_id = evid_rel.id self.api.set_user(self.reader) self.evidence = all_models.Evidence.query.get(evidence_id) self.evid_relationship = all_models.Relationship.query.get(evid_rel_id) def test_delete_action(self): """Test permissions for delete action on Evidence Allow only Global Admin to delete Documents. """ resp = self.api.delete(self.evidence) self.assert200(resp) self.assertEquals(len(all_models.Evidence.query.filter( all_models.Evidence.id == self.evidence.id).all()), 0)
def test_add_comment(self): """Test add comment action.""" generator = ObjectGenerator() _, reader = generator.generate_person(user_role="Administrator") self.api.set_user(reader) assessment = factories.AssessmentFactory() context = factories.ContextFactory(related_object=assessment) assessment.context = context acrs = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.object_type == "Assessment", all_models.AccessControlRole.name.in_(["Assignees", "Creators"]), ) for acr in acrs: factories.AccessControlListFactory( ac_role=acr, object=assessment, person=reader ) response = self.api.put(assessment, {"actions": {"add_related": [ { "id": None, "type": "Comment", "description": "comment", "custom_attribute_definition_id": None, } ]}}) self.assert200(response) # last relationship id (newly created relationship) relationship = _get_relationship( "Assessment", response.json["assessment"]["id"]) self.assertIsNotNone(relationship) comment = all_models.Comment.query.get(relationship.destination_id) self.assertEqual(comment.description, "comment") self.assertEqual(comment.assignee_type, "Assignees,Creators") self.assertEqual(comment.context_id, assessment.context_id)
def test_add_comment(self): """Test add comment action.""" generator = ObjectGenerator() _, reader = generator.generate_person(user_role="Reader") self.api.set_user(reader) assessment = factories.AssessmentFactory() context = factories.ContextFactory(related_object=assessment) assessment.context = context object_person_rel = factories.RelationshipFactory(source=assessment, destination=reader) factories.RelationshipAttrFactory(relationship_id=object_person_rel.id, attr_name="AssigneeType", attr_value="Creator,Assessor") response = self.api.put( assessment, { "actions": { "add_related": [{ "id": None, "type": "Comment", "description": "comment", "custom_attribute_definition_id": None, }] } }) self.assert200(response) # last relationship id (newly created relationship) rel_id = max( i["id"] for i in response.json["assessment"]["related_destinations"]) relationship = all_models.Relationship.query.get(rel_id) self.assertIsNotNone(relationship) comment = all_models.Comment.query.get(relationship.destination_id) self.assertEqual(comment.description, "comment") self.assertEqual(comment.assignee_type, "Creator,Assessor") self.assertEqual(comment.context_id, assessment.context_id)
def test_add_comment(self): """Test add comment action.""" generator = ObjectGenerator() _, reader = generator.generate_person(user_role="Reader") self.api.set_user(reader) assessment = factories.AssessmentFactory() context = factories.ContextFactory(related_object=assessment) assessment.context = context object_person_rel = factories.RelationshipFactory( source=assessment, destination=reader ) factories.RelationshipAttrFactory( relationship_id=object_person_rel.id, attr_name="AssigneeType", attr_value="Creator,Assessor" ) response = self.api.put(assessment, {"actions": {"add_related": [ { "id": None, "type": "Comment", "description": "comment", "custom_attribute_definition_id": None, } ]}}) self.assert200(response) # last relationship id (newly created relationship) rel_id = max(i["id"] for i in response.json["assessment"]["related_destinations"]) relationship = all_models.Relationship.query.get(rel_id) self.assertIsNotNone(relationship) comment = all_models.Comment.query.get(relationship.destination_id) self.assertEqual(comment.description, "comment") self.assertEqual(comment.assignee_type, "Creator,Assessor") self.assertEqual(comment.context_id, assessment.context_id)
class TestPermissions(TestCase): """Test permissions for background tasks""" def setUp(self): super(TestPermissions, self).setUp() self.api = api_helper.Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_bg_tasks_access(self): """Only admin can use admin requirement""" from ggrc.models import all_models with self.object_generator.api.as_external(): response, _ = self.object_generator.generate_object( all_models.Control, with_background_tasks=True) self.assertEqual(response.status_code, 201) for role in ("reader", "creator", "admin"): self.api.set_user(self.users[role]) content = self.api.client.get("/api/background_tasks") self.assert200(content) bg_tasks_content = \ content.json['background_tasks_collection']['background_tasks'] for bg_task_content in bg_tasks_content: self.assertEqual(set(bg_task_content.keys()), {"id", "selfLink", "status", "type"}) self.assertTrue(len(bg_tasks_content) >= 1)
def test_import_lcad_changed(self, status): """Test notifications for '{}' Assessment if LCAD changed in import.""" object_generator = ObjectGenerator() _, user = object_generator.generate_person(user_role="Creator") with factories.single_commit(): assessment = factories.AssessmentFactory() factories.CustomAttributeDefinitionFactory( title="Test LCAD", definition_type="assessment", definition_id=assessment.id, attribute_type="Text", ) assessment.add_person_with_role_name(user, "Verifiers") assessment.status = status db.session.commit() response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", assessment.slug), ("Test LCAD", "some value"), ])) self._check_csv_response(response, {}) self.assert_asmnt_notifications()
class TestCreatorAudit(TestCase): """Set up necessary objects and test Creator role with Audit roles""" def setUp(self): super(TestCreatorAudit, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """Create a dict of all possible test cases.""" self.test_cases = { "Auditor": { "audit_role": "Auditor", "objects": { "audit": { "get": 200, "put": 403, "delete": 403 }, "mapped_Issue": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Issue": { "get": 403, "put": 403, "delete": 403, "map": 403, }, "mapped_Assessment": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Assessment": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """Create a delete request for the given object.""" response = self.api.get_query(all_models.Role, "") self.roles = {} for role in response.json.get("roles_collection").get("roles"): self.roles[role.get("name")] = role def init_users(self): """Create users used by test cases.""" self.people = {} for name in ["creator", "notmapped", "mapped", "Auditor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role="Creator") self.people[name] = user _, user = self.object_generator.generate_person( data={"name": "editor"}, user_role="Editor") self.people["editor"] = user def delete(self, obj): """Create a delete request for the given object. Args: obj (model instance): target object to delete Returns: int: http response status code """ return self.api.delete(obj).status_code def get(self, obj): """Create a get request for the given object. Args: obj (model instance): target object to get Returns: int: http response status code """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """Create a put request for the given object. Args: obj (model instance): target object to put Returns: int: http response status code """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """Map audit to dest. Args: dest (model instance): target object to map to the audit Returns: int: http response status code """ response = self.api.post(all_models.Relationship, { "relationship": {"source": { "id": self.objects["audit"].id, "type": self.objects["audit"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None}, }) return response.status_code def init_objects(self, test_case_name): """Create a Program, an Audit, and a Mapped object for the test case. Args: test_case_name (string): test case to init for """ # Create a program dummy_audit = factories.AuditFactory() unrelated_audit = { "type": "Audit", "context_id": dummy_audit.context.id, "id": dummy_audit.id, } test_case = self.test_cases[test_case_name] editor = self.people.get('editor') self.api.set_user(editor) random_title = factories.random_str() response = self.api.post(all_models.Program, { "program": {"title": random_title, "context": None}, }) self.assertEqual(response.status_code, 201) program_id = response.json.get("program").get("id") self.objects["program"] = all_models.Program.query.get(program_id) response = self.api.post(all_models.Audit, { "audit": { "title": random_title + " audit", 'program': {'id': program_id}, "status": "Planned", "context": None } }) self.assertEqual(response.status_code, 201) context = response.json.get("audit").get("context") audit_id = response.json.get("audit").get("id") self.objects["audit"] = all_models.Audit.query.get(audit_id) audits = { "mapped": { "type": "Audit", "context_id": context["id"], "id": audit_id, }, "unrelated": unrelated_audit, } for prefix, audit_dict in audits.items(): random_title = factories.random_str() response = self.api.post(all_models.Issue, { "issue": { "title": random_title, "context": { "type": "Context", "id": audit_dict["context_id"], }, "audit": audit_dict, }, }) self.assertEqual(response.status_code, 201) issue_id = response.json.get("issue").get("id") self.objects[prefix + "_Issue"] = all_models.Issue.query.get(issue_id) response = self.api.post(all_models.Assessment, { "assessment": { "title": random_title, "context": { "type": "Context", "id": audit_dict["context_id"], }, "audit": audit_dict, }, }) self.assertEqual(response.status_code, 201) assessment_id = response.json.get("assessment").get("id") self.objects[prefix + "_Assessment"] = \ all_models.Assessment.query.get(assessment_id) self.assertEqual(self.map(self.objects["mapped_Issue"]), 201) self.assertEqual(self.map(self.objects["mapped_Assessment"]), 201) # Add roles to mapped users: if "audit_role" in test_case: person = self.people.get(test_case_name) role = self.roles[test_case["audit_role"]] response = self.api.post(all_models.UserRole, {"user_role": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "role": { "type": "Role", "href": "/api/roles/{}".format(role["id"]), "id": role["id"], }, "context": { "type": "Context", "id": context.get("id"), "href": "/api/contexts/{}".format(context.get("id")) }}}) self.assertEqual(response.status_code, 201) def test_creator_audit_roles(self): """ Test creator role with all audit scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj, actions in objects.iteritems(): for action in ("map", "get", "put", "delete"): if action not in actions: continue # reset sesion: db.session.commit() func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}".format( test_case, action, obj, res, actions[action])) self.assertEqual(errors, [])
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) audit_id = factories.AuditFactory().id all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": self.users["creator"].id, }, "audit": { # this is ignored on everything but Issues "id": audit_id, "type": "Audit", } }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format(model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) != 0: all_errors.append( "{} can retrieve object if not owner (collection)" .format(model_singular)) continue # Become an owner response = self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": model_singular, "id": obj_id }, "context": None}}) if response.status_code != 201: all_errors.append("{} can't create owner {}.".format( model_singular, response.status)) continue # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)" .format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['creator']) response = self.api.post(all_models.Policy, { "policy": {"title": "Creator Policy", "context": None}, }) obj_id = response.json.get("policy").get("id") self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Policy", "id": obj_id, }, "context": None}}) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual( response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_creator_cannot_be_owner(self): """Test if creator cannot become owner of the object he has not created""" self.api.set_user(self.users['admin']) _, obj = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) self.api.set_user(self.users['creator']) response = self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Regulation", "id": obj.id, }, "context": None}}) self.assertEqual(response.status_code, 403) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) _, obj_1 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation 2", "context": None}, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": {"source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None}, } ) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title): return self.generator.generate(all_models.Section, "section", { "section": {"title": title, "context": None}, })[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id) ) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected ) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Section 1") obj_2 = gen("Test Section 2") self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Section", "id": obj_2.id, }, "context": None}}) self.api.set_user(self.users["creator"]) check(obj_1, 0) check(obj_2, 2)
class TestCsvImport(TestCase): def setUp(self): super(TestCsvImport, self).setUp() self.generator = ObjectGenerator() self.client.get("/login") def tearDown(self): pass def generate_people(self, people): for person in people: self.generator.generate_person({ "name": person, "email": "{}@reciprocitylabs.com".format(person), }, "Administrator") def test_multi_basic_policy_orggroup_product(self): filename = "multi_basic_policy_orggroup_product.csv" response_json = self.import_file(filename) object_counts = { "Org Group": (4, 0, 0), "Policy": (4, 0, 0), "Product": (5, 0, 0), } for row in response_json: created, updated, ignored = object_counts[row["name"]] self.assertEqual(created, row["created"]) self.assertEqual(updated, row["updated"]) self.assertEqual(ignored, row["ignored"]) self.assertEqual(set(), set(row["row_warnings"])) self.assertEqual(Policy.query.count(), 4) self.assertEqual(OrgGroup.query.count(), 4) self.assertEqual(Product.query.count(), 5) def test_multi_basic_policy_orggroup_product_with_warnings(self): """Test multi basic policy orggroup product with warnings""" filename = "multi_basic_policy_orggroup_product_with_warnings.csv" response_json = self.import_file(filename, safe=False) row_messages = [] object_counts = { "Policy": (3, 0, 2), "Org Group": (0, 0, 4), "Product": (5, 0, 2), } for row in response_json: created, updated, ignored = object_counts[row["name"]] self.assertEqual(created, row["created"]) self.assertEqual(updated, row["updated"]) self.assertEqual(ignored, row["ignored"]) row_messages.extend(row["row_warnings"]) row_messages.extend(row["row_errors"]) expected_warnings = set([ errors.DUPLICATE_VALUE_IN_CSV.format( line="6", processed_line="5", column_name="Title", value="dolor", ), errors.DUPLICATE_VALUE_IN_CSV.format( line="7", processed_line="6", column_name="Code", value="p-4", ), errors.DUPLICATE_VALUE_IN_CSV.format( line="26", processed_line="21", column_name="Title", value="meatloaf", ), errors.DUPLICATE_VALUE_IN_CSV.format( line="26", processed_line="21", column_name="Code", value="pro 1", ), errors.DUPLICATE_VALUE_IN_CSV.format( line="27", processed_line="21", column_name="Code", value="pro 1", ), errors.OWNER_MISSING.format(line=26, column_name="Admin"), errors.MISSING_COLUMN.format(line=13, column_names="Admin", s=""), errors.MISSING_COLUMN.format(line=14, column_names="Admin", s=""), errors.MISSING_COLUMN.format(line=15, column_names="Admin", s=""), errors.MISSING_COLUMN.format(line=16, column_names="Admin", s=""), ]) self.assertEqual(expected_warnings, set(row_messages)) self.assertEqual(Policy.query.count(), 3) self.assertEqual(OrgGroup.query.count(), 0) self.assertEqual(Product.query.count(), 5) def test_multi_basic_policy_orggroup_product_with_mappings(self): def get_relationships_for(obj): return Relationship.query.filter(or_( and_(Relationship.source_id == obj.id, Relationship.source_type == obj.type), and_(Relationship.destination_id == obj.id, Relationship.destination_type == obj.type), )) filename = "multi_basic_policy_orggroup_product_with_mappings.csv" response_json = self.import_file(filename) object_counts = { "Policy": (4, 0, 0), "Org Group": (4, 0, 0), "Product": (5, 0, 0), } for row in response_json: created, updated, ignored = object_counts[row["name"]] self.assertEqual(created, row["created"]) self.assertEqual(updated, row["updated"]) self.assertEqual(ignored, row["ignored"]) self.assertEqual(set(), set(row["row_warnings"])) self.assertEqual(Policy.query.count(), 4) self.assertEqual(OrgGroup.query.count(), 4) self.assertEqual(Product.query.count(), 5) p1 = Policy.query.filter_by(slug="p-1").first() org1 = OrgGroup.query.filter_by(slug="org-1").first() self.assertEqual(get_relationships_for(p1).count(), 3) self.assertEqual(get_relationships_for(org1).count(), 5)
class TestAccessControlRole(TestCase): """TestAccessControlRole""" def setUp(self): self.clear_data() super(TestAccessControlRole, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.people = {} for name in ["Creator", "Reader", "Editor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role=name) self.people[name] = user def _post_role(self, name=None, object_type="Control"): """Helper function for POSTing roles""" if name is None: name = random_str(prefix="Access Control Role - ") return self.api.post( AccessControlRole, { "access_control_role": { "name": name, "object_type": object_type, "context": None, "read": True }, }) def test_create_after_objects(self): """Test eager creation of ACLs on existing objects with new ACR.""" program_id = factories.ProgramFactory().id role_name = "New Custom Role" self._post_role(name=role_name, object_type="Program") program = all_models.Program.query.get(program_id) self.assertIn(role_name, program.acr_name_acl_map.keys()) self.assertIsNotNone(program.acr_name_acl_map[role_name]) def test_create(self): """Test Access Control Role creation""" response = self._post_role(object_type="Program") assert response.status_code == 201, \ "Failed to create a new access control role, response was {}".format( response.status) id_ = response.json['access_control_role']['id'] role = AccessControlRole.query.filter( AccessControlRole.id == id_).first() assert role.read == 1, \ "Read permission not correctly saved {}".format(role.read) assert role.update == 1, \ "Update permission not correctly saved {}".format(role.update) assert role.delete == 1, \ "Update permission not correctly saved {}".format(role.delete) @ddt.data( { "mandatory": True, "exp_response": MANDATORY_ROLE_RESPONSE }, { "mandatory": False, "exp_response": NON_MANDATORY_ROLE_RESPONSE }, ) @ddt.unpack def test_mandatory_delete(self, mandatory, exp_response): """Test set empty field via import if acr mandatory is {mandatory}""" role = factories.AccessControlRoleFactory( name=ROLE_NAME, object_type="Program", mandatory=mandatory, ) with factories.single_commit(): user = factories.PersonFactory() program = factories.ProgramFactory() role_id = role.id factories.AccessControlPersonFactory( ac_list=program.acr_name_acl_map[ROLE_NAME], person=user, ) response = self.import_data( OrderedDict([ ("object_type", "Program"), ("Code*", program.slug), (ROLE_NAME, "--"), ])) self._check_csv_response(response, exp_response) db_data = defaultdict(set) program = all_models.Program.query.get(program.id) for person, acl in program.access_control_list: db_data[acl.ac_role_id].add(person.id) if mandatory: cur_user = all_models.Person.query.filter_by( email="*****@*****.**").first() self.assertEqual(set([cur_user.id]), db_data[role_id]) else: self.assertFalse(db_data[role_id]) def test_only_admin_can_post(self): """Only admin users should be able to POST access control roles""" for name in ("Creator", "Reader", "Editor"): person = self.people.get(name) self.api.set_user(person) response = self._post_role() assert response.status_code == 403, \ "Non admins should get forbidden error when POSTing role. {}".format( response.status) @ddt.data( ("name", "New ACR"), ("read", False), ("mandatory", False), ("non_editable", False), ) @ddt.unpack def test_modify_non_editable_role(self, field_name, field_value): """Test if user can modify non-editable role""" # Primary Contacts role of Control is non-editable ac_role = AccessControlRole.query.filter_by( object_type="Control", name="Control Operators", ).first() response = self.api.put(ac_role, {field_name: field_value}) assert response.status_code == 403, \ "Forbidden error should be thrown when non-editable " \ "role {} updated.".format(ac_role.name) def test_delete_non_editable_role(self): """Test if user can delete non-editable role""" # Primary Contacts role of Control is non-editable ac_role = AccessControlRole.query.filter_by( object_type="Control", name="Control Operators", ).first() response = self.api.delete(ac_role) assert response.status_code == 403, \ "Forbidden error should be thrown when non-editable " \ "role {} deleted.".format(ac_role.name) @ddt.data("Control") def test_create_from_ggrcq(self, object_type): """Test that create action only for GGRCQ.""" with self.api.as_external(): response = self._post_role(object_type=object_type) self.assertEqual(response.status_code, 201) @ddt.data("Control") def test_create_from_ggrc(self, object_type): """Test create action not allowed for GGRC.""" response = self._post_role(object_type=object_type) self.assertEqual(response.status_code, 405) @ddt.data("Control") def test_modify_from_ggrcq(self, object_type): """Test that modify action only for GGRCQ.""" with factories.single_commit(): acr_id = factories.AccessControlRoleFactory( object_type=object_type).id with self.api.as_external(): acr = all_models.AccessControlRole.query.get(acr_id) response = self.api.put(acr, {"name": "new acr"}) self.assertEqual(response.status_code, 200) @ddt.data("Control") def test_modify_from_ggrc(self, object_type): """Test modify action not allowed for GGRC.""" with factories.single_commit(): acr = factories.AccessControlRoleFactory(object_type=object_type) response = self.api.put(acr, {"name": "new acr"}) self.assertEqual(response.status_code, 405) @ddt.data("Control") def test_delete_from_ggrcq(self, object_type): """Test that modify action only for GGRCQ.""" with factories.single_commit(): acr_id = factories.AccessControlRoleFactory( object_type=object_type).id with self.api.as_external(): acr = all_models.AccessControlRole.query.get(acr_id) response = self.api.delete(acr) self.assertEqual(response.status_code, 200) @ddt.data("Control") def test_delete_from_ggrc(self, object_type): """Test modify action not allowed for GGRC.""" with factories.single_commit(): acr = factories.AccessControlRoleFactory(object_type=object_type) response = self.api.delete(acr) self.assertEqual(response.status_code, 405) @ddt.data( { "name": "Test 1", "update": False, "read": False, "delete": True }, { "name": "Test 2", "update": True, "read": False, "delete": False }, { "name": "Test 3", "update": True, "read": False, "delete": True }, ) @ddt.unpack def test_create_with_wrong_options(self, name, update, read, delete): """ Test if user create ACR with wrong options.""" options = [{ 'access_control_role': { 'modal_title': 'Add Custom Role to type Regulation', 'object_type': 'Regulation', 'parent_type': 'Regulation', 'context': { 'id': None }, 'delete': delete, 'update': update, 'read': read, 'name': name } }] response = self.api.post(AccessControlRole, options) self.assert400(response)
class TestReader(TestCase): """Test Assignable RBAC""" def setUp(self): super(TestReader, self).setUp() self.audit_id = factories.AuditFactory().id self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_assignable() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def init_assignable(self): """Creates the assignable object used by all the tests""" self.api.set_user(self.users["editor"]) response = self.api.post(all_models.Assessment, { "assessment": { "title": "Assessment", "context": None, "audit": { "id": self.audit_id, "type": "Audit" } } }) obj_id = response.json.get("assessment").get("id") self.assertEqual(response.status_code, 201, "Error setting up Assessment") self.obj_json = response.json self.obj = all_models.Assessment.query.get(obj_id) def _add_creator(self, asmnt, user): """Helper method for creating assignees on an object""" acr = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.object_type == "Assessment", all_models.AccessControlRole.name == "Creators", ).first() return self.api.put(asmnt, { "access_control_list": [acl_helper.get_acl_json(acr.id, user.id)] }) def test_basic_with_no_assignee(self): """Editor creates an Assessment, but doesn't assign Reader/Creator as assignee. Reader should have Read access, Creator should have no access """ # Reader should have read access, but shouldn't be allowed to edit or # create another assingee self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, self.obj_json) self.assertEqual(response.status_code, 403) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 403) # Creator should have no access. We skip the put request because we can't # get the object etag. self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 403) def test_basic_with_assignee(self): """Test if Reader/Creator have CRUD access once they become assignees""" # Admin adds reader as an assignee self.api.set_user(self.users["admin"]) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 200) # Reader is now allowed to update the object self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) self.assertEqual(response.status_code, 200) # Reader adds creator as an assignee response = self._add_creator(self.obj, self.users["creator"]) self.assertEqual(response.status_code, 200) # Creator now has CRUD access self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) # Creator should even be allowed to add new assignees response = self._add_creator(self.obj, self.users["admin"]) self.assertEqual(response.status_code, 200) def test_read_of_mapped_objects(self): """Test if assignees get Read access on all mapped objects""" # Editor creates a System object and maps it to the assignable object self.api.set_user(self.users["editor"]) response = self.api.post(all_models.System, { "system": { "title": "System", "context": None, } }) system_id = response.json.get("system").get("id") system = all_models.System.query.get(system_id) self.api.post(all_models.Relationship, { "relationship": {"source": { "id": self.obj.id, "type": "Assessment" }, "destination": { "id": system_id, "type": "System" }, "context": None}, }) # Since creator is not an assignee she should not have access to any of the # two objects self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 403) # Editor adds creator as an assignee self.api.set_user(self.users["editor"]) response = self._add_creator(self.obj, self.users["creator"]) self.assertEqual(response.status_code, 200) # Creator should now have read access on the mapped object self.api.set_user(self.users["creator"]) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 403) # But he should still not be allowed to update response = self.api.put(system, response.json) self.assertEqual(response.status_code, 403)
class TestCreatorAudit(TestCase): """Set up necessary objects and test Creator role with Audit roles""" def setUp(self): super(TestCreatorAudit, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """Create a dict of all possible test cases.""" self.test_cases = { "Auditor": { "audit_role": "Auditor", "objects": { "audit": { "get": 200, "put": 403, "delete": 403 }, "mapped_Issue": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Issue": { "get": 403, "put": 403, "delete": 403, "map": 403, }, "mapped_Assessment": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Assessment": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """Create a delete request for the given object.""" response = self.api.get_query(all_models.Role, "") self.roles = {} for role in response.json.get("roles_collection").get("roles"): self.roles[role.get("name")] = role def init_users(self): """Create users used by test cases.""" self.people = {} for name in ["creator", "notmapped", "mapped", "Auditor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role="Creator") self.people[name] = user _, user = self.object_generator.generate_person( data={"name": "editor"}, user_role="Editor") self.people["editor"] = user def delete(self, obj): """Create a delete request for the given object. Args: obj (model instance): target object to delete Returns: int: http response status code """ return self.api.delete(obj).status_code def get(self, obj): """Create a get request for the given object. Args: obj (model instance): target object to get Returns: int: http response status code """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """Create a put request for the given object. Args: obj (model instance): target object to put Returns: int: http response status code """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """Map audit to dest. Args: dest (model instance): target object to map to the audit Returns: int: http response status code """ response = self.api.post( all_models.Relationship, { "relationship": { "source": { "id": self.objects["audit"].id, "type": self.objects["audit"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None }, }) return response.status_code def init_objects(self, test_case_name): """Create a Program, an Audit, and a Mapped object for the test case. Args: test_case_name (string): test case to init for """ # Create a program dummy_audit = factories.AuditFactory() unrelated_audit = { "type": "Audit", "context_id": dummy_audit.context.id, "id": dummy_audit.id, } test_case = self.test_cases[test_case_name] editor = self.people.get('editor') self.api.set_user(editor) random_title = factories.random_str() response = self.api.post(all_models.Program, { "program": { "title": random_title, "context": None }, }) self.assertEqual(response.status_code, 201) program_id = response.json.get("program").get("id") self.objects["program"] = all_models.Program.query.get(program_id) response = self.api.post( all_models.Audit, { "audit": { "title": random_title + " audit", 'program': { 'id': program_id }, "status": "Planned", "context": None } }) self.assertEqual(response.status_code, 201) context = response.json.get("audit").get("context") audit_id = response.json.get("audit").get("id") self.objects["audit"] = all_models.Audit.query.get(audit_id) audits = { "mapped": { "type": "Audit", "context_id": context["id"], "id": audit_id, }, "unrelated": unrelated_audit, } for prefix, audit_dict in audits.items(): random_title = factories.random_str() response = self.api.post(all_models.Issue, { "issue": { "title": random_title, "context": None, }, }) self.assertEqual(response.status_code, 201) issue_id = response.json.get("issue").get("id") self.objects[prefix + "_Issue"] = all_models.Issue.query.get(issue_id) response = self.api.post( all_models.Assessment, { "assessment": { "title": random_title, "context": { "type": "Context", "id": audit_dict["context_id"], }, "audit": audit_dict, }, }) self.assertEqual(response.status_code, 201) assessment_id = response.json.get("assessment").get("id") self.objects[prefix + "_Assessment"] = \ all_models.Assessment.query.get(assessment_id) self.assertEqual(self.map(self.objects["mapped_Issue"]), 201) self.assertEqual(self.map(self.objects["mapped_Assessment"]), 201) # Add roles to mapped users: if "audit_role" in test_case: person = self.people.get(test_case_name) role = self.roles[test_case["audit_role"]] response = self.api.post( all_models.UserRole, { "user_role": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "role": { "type": "Role", "href": "/api/roles/{}".format(role["id"]), "id": role["id"], }, "context": { "type": "Context", "id": context.get("id"), "href": "/api/contexts/{}".format( context.get("id")) } } }) self.assertEqual(response.status_code, 201) def test_creator_audit_roles(self): """ Test creator role with all audit scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj, actions in objects.iteritems(): for action in ("map", "get", "put", "delete"): if action not in actions: continue # reset sesion: db.session.commit() func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}" .format(test_case, action, obj, res, actions[action])) self.assertEqual(errors, [])
class TestCustomAttributeImportExport(TestCase): """Test import and export with custom attributes.""" _set_up = True def setUp(self): """Setup stage for each test. Generate all required objects and custom attributes for import of csvs containing custom attributes. This stage also initializes a http client that is used for sending import/export requests. """ if TestCustomAttributeImportExport._set_up: super(TestCustomAttributeImportExport, self).setUp() self.generator = ObjectGenerator() self.create_custom_attributes() self.create_people() self.client.get("/login") self.headers = ObjectGenerator.get_header() TestCustomAttributeImportExport._set_up = False def create_custom_attributes(self): """Generate custom attributes needed for csv import This function generates all custom attributes on Product and Access Group, that are used in custom_attribute_tests.csv and multi_word_object_custom_attribute_test.csv files. """ gen = self.generator.generate_custom_attribute gen("product", attribute_type="Text", title="normal text") gen("product", attribute_type="Text", title="man text", mandatory=True) gen("product", attribute_type="Rich Text", title="normal RT") gen("product", attribute_type="Rich Text", title="man RT", mandatory=True) gen("product", attribute_type="Date", title="normal Date") gen("product", attribute_type="Date", title="man Date", mandatory=True, helptext="Birthday") gen("product", attribute_type="Checkbox", title="normal CH") gen("product", attribute_type="Checkbox", title="man CH", mandatory=True) gen("product", attribute_type="Dropdown", title="normal select", options=u"a,b,c,\u017e", helptext="Your favorite number.") gen("product", attribute_type="Dropdown", title="man select", options="e,f,g", mandatory=True) gen("product", attribute_type="Map:Person", title="normal person") gen("product", attribute_type="Map:Person", title="man person", mandatory=True) gen("access_group", attribute_type="Text", title="access group test custom", mandatory=True) def create_people(self): """Create people used in the csv files. This function should be removed and people should be added into the csv file as a Person block. """ emails = [ "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**", ] for email in emails: self.generator.generate_person({ "name": email.split("@")[0].title(), "email": email, }, "Administrator") def test_product_ca_import(self): """Test import of product with all custom attributes. This tests covers all possible custom attributes with mandatory flag turned off and on, and checks for all warnings that should be present. """ filename = "custom_attribute_tests.csv" response = self.import_file(filename, safe=False)[0] expected_warnings = { errors.WRONG_VALUE.format(line=6, column_name="man CH"), errors.WRONG_VALUE.format(line=8, column_name="normal select"), errors.WRONG_VALUE.format(line=10, column_name="man select"), errors.WRONG_VALUE.format(line=11, column_name="normal CH"), errors.WRONG_VALUE.format(line=12, column_name="man CH"), errors.WRONG_VALUE.format(line=14, column_name="normal Date"), errors.WRONG_VALUE.format(line=16, column_name="man Date"), errors.OWNER_MISSING.format(line=21, column_name="Admin"), errors.UNKNOWN_USER_WARNING.format(line=22, email="*****@*****.**"), errors.OWNER_MISSING.format(line=22, column_name="Admin"), errors.OWNER_MISSING.format(line=26, column_name="Admin"), errors.UNKNOWN_USER_WARNING.format( line=27, email="*****@*****.**"), errors.OWNER_MISSING.format(line=27, column_name="Admin"), } expected_errors = { "Line 6: Field 'man CH' is required. The line will be ignored.", "Line 9: Field 'man select' is required. The line will be ignored.", "Line 10: Field 'man select' is required. The line will be ignored.", "Line 12: Field 'man CH' is required. The line will be ignored.", "Line 16: Field 'man Date' is required. The line will be ignored.", "Line 18: Field 'man RT' is required. The line will be ignored.", "Line 20: Field 'man text' is required. The line will be ignored.", "Line 21: Field 'man person' is required. The line will be ignored.", "Line 28: Field 'Title' is required. The line will be ignored." } self.assertEqual(expected_warnings, set(response["row_warnings"])) self.assertEqual(expected_errors, set(response["row_errors"])) self.assertEqual(17, response["created"]) self.assertEqual(9, response["ignored"]) self.assertEqual(17, Product.query.count()) product10 = Product.query.filter_by(slug="prod10").first() people_emails = {cav.attribute_object.email for cav in product10.custom_attribute_values if cav.custom_attribute.attribute_type == "Map:Person"} self.assertEqual(people_emails, {"*****@*****.**", "*****@*****.**"}) def test_product_ca_import_update(self): """Test updating of product with all custom attributes. This tests covers updates for all possible custom attributes """ # TODO: check response data explicitly self.import_file("custom_attribute_tests.csv", safe=False) self.import_file("custom_attribute_update_tests.csv") prod_0 = Product.query.filter(Product.slug == "prod0").first() prod_0_expected = { u"normal text": u"edited normal text", u"man text": u"edited man text", u"normal RT": (u'some <br> edited rich <br> text ' u'<a href="https://www.google.com">' u'https://www.google.com</a>'), u"man RT": u"other edited <br> rich text <a>http://www.google.com</a>", u"normal Date": u"2017-09-14", u"man Date": u"2018-01-17", u"normal CH": u"1", u"man CH": u"0", u"normal select": u"\u017e", u"man select": u"f", u"normal person": u"Person", u"man person": u"Person", } prod_0_new = {c.custom_attribute.title: c.attribute_value for c in prod_0.custom_attribute_values} self.assertEqual(prod_0_expected, prod_0_new) people_emails = {cav.attribute_object.email for cav in prod_0.custom_attribute_values if cav.custom_attribute.attribute_type == "Map:Person"} self.assertEqual(people_emails, {"*****@*****.**", "*****@*****.**"}) def tests_ca_export(self): """Test exporting products with custom attributes This test checks that we get a proper response when exporting objects with custom attributes and that the response data actually contains more lines than an empty template would. This tests relys on the import tests to work. If those fail they need to be fixied before this one. """ # TODO: check response data explicitly self.import_file("custom_attribute_tests.csv", safe=False) data = { "export_to": "csv", "objects": [{ "object_name": "Product", "filters": { "expression": {}, }, "fields": "all", }] } response = self.client.post("/_service/export_csv", data=dumps(data), headers=self.headers) self.assert200(response) self.assertEqual(len(response.data.splitlines()), 33) self.assertIn("\"Accepted values are", response.data) self.assertIn("number.\n\nAccepted values are", response.data) self.assertIn("Birthday", response.data) def tests_ca_export_filters(self): """Test filtering on custom attribute values.""" # TODO: check response data explicitly self.import_file("custom_attribute_tests.csv", safe=False) data = { "export_to": "csv", "objects": [{ "object_name": "Product", "filters": { "expression": { "left": "normal text", "op": {"name": "="}, "right": "some text", }, }, "fields": "all", }] } response = self.client.post("/_service/export_csv", data=dumps(data), headers=self.headers) self.assert200(response) self.assertIn("some text", response.data) def test_multi_word_object_with_ca(self): """Test multi-word (e.g. Access Group, Data Asset) object import""" filename = "multi_word_object_custom_attribute_test.csv" response = self.import_file(filename)[0] self.assertEqual([], response["row_warnings"]) self.assertEqual([], response["row_errors"]) self.assertEqual(10, response["created"]) self.assertEqual(0, response["ignored"]) self.assertEqual(0, response["updated"]) self.assertEqual(10, AccessGroup.query.count()) for id_ in range(1, 11): access_group = AccessGroup.query.filter( AccessGroup.slug == "ag-{}".format(id_)).first() filtered = [val for val in access_group.custom_attribute_values if val.attribute_value == "some text {}".format(id_)] self.assertEqual(len(filtered), 1)
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup", ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post( model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": self.users["reader"].id, }, }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": { "title": "reader Policy", "context": None }, }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): """Check if reader can't create mappings""" self.generator.api.set_user(self.users["admin"]) _, control = self.generator.generate(all_models.Control, "control", { "control": { "title": "Test Control", "context": None }, }) self.generator.api.set_user(self.users['reader']) _, program = self.generator.generate(all_models.Program, "program", { "program": { "title": "Test Program", "context": None }, }) response, _ = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "destination": { "id": program.id, "type": "Program" }, "source": { "id": control.id, "type": "Control" }, "context": { "id": program.context.id, "type": "context" } }, }) self.assertEqual(response.status_code, 403)
class TestCycleTaskImportUpdate(BaseTestCycleTaskImportUpdate): """ This class contains simple cycle task update tests using import functionality """ CSV_DIR = join(abspath(dirname(__file__)), "test_csvs/") def setUp(self): super(TestCycleTaskImportUpdate, self).setUp() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() self.random_objects = self.object_generator.generate_random_objects(2) _, self.person_1 = self.object_generator.generate_person( user_role="Administrator") self.ftime_active = "2016-07-01" self.ftime_historical = "2014-05-01" self._create_test_cases_data() # It is needed because cycle-tasks are generated automatically with # 'slug' based on auto_increment 'id' field. # At start of each test we suppose that created cycle-task's 'slug' # lie in range from 1 to 10. db.session.execute('ALTER TABLE cycle_task_group_object_tasks ' 'AUTO_INCREMENT = 1') def test_cycle_task_correct(self): """Test cycle task update via import with correct data""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_correct.csv") self._check_csv_response(response, {}) self._cmp_tasks(self.expected_cycle_task_correct) def test_cycle_task_warnings(self): """Test cycle task update via import with data which is the reason of warnings about non-importable columns.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_warnings.csv") self._check_csv_response(response, self.expected_warnings) self._cmp_tasks(self.expected_cycle_task_correct) def test_cycle_task_create_error(self): """Test cycle task update via import with data which is the reason of errors about new cycle task creation.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_create_error.csv") self._check_csv_response(response, self.expected_create_error) self._cmp_tasks(self.expected_cycle_task_correct) def test_cycle_task_date_error(self): """Test cycle task update via import with data which is the reason of errors about incorrect dates in csv file.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_date_error.csv") self._check_csv_response(response, self.expected_date_error) self._cmp_tasks(self.expected_cycle_task_date_error) def test_cycle_task_permission_error(self): """Test cycle task update via import with non-admin user which is the reason of error. Only admin can update cycle tasks via import.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): _, creator = self.object_generator.generate_person(user_role="Creator") response = self.import_file("cycle_task_correct.csv", person=creator) self._check_csv_response(response, self.expected_permission_error) # Cycle tasks' data shouldn't be changed in test DB after import run from # non-admin user expected_cycle_task_permission_error = {} expected_cycle_task_permission_error.update( self.generated_cycle_tasks_active) expected_cycle_task_permission_error.update( self.generated_cycle_tasks_historical) self._cmp_tasks(expected_cycle_task_permission_error) def _cmp_tasks(self, expected_ctasks): """Compare tasks values from argument's list and test DB.""" for ctask in db.session.query(CycleTaskGroupObjectTask).all(): if ctask.slug not in expected_ctasks: continue exp_task = expected_ctasks[ctask.slug] for attr, val in exp_task.iteritems(): self.assertEqual(str(getattr(ctask, attr, None)), val) # pylint: disable=too-many-arguments def _activate_workflow(self, ftime, workflow, task_group, task_group_tasks, random_object, cycle_tasks): """Helper which is responsible for active cycle-tasks creation""" with freeze_time(ftime): _, wf = self.wf_generator.generate_workflow(workflow) _, tg = self.wf_generator.generate_task_group(wf, task_group) for task in task_group_tasks: self.wf_generator.generate_task_group_task(tg, task) self.wf_generator.generate_task_group_object(tg, random_object) _, cycle = self.wf_generator.generate_cycle(wf) self.wf_generator.activate_workflow(wf) for exp_slug, exp_task in cycle_tasks.iteritems(): obj = db.session.query(CycleTaskGroupObjectTask).filter_by( slug=exp_slug ).first() if exp_task["status"] == "Verified": self.wf_generator.modify_object(obj, {"status": "Finished"}) self.wf_generator.modify_object(obj, {"status": exp_task["status"]}) self._cmp_tasks(cycle_tasks) return cycle def _generate_cycle_tasks(self): """Helper which is responsible for test data creation""" self._activate_workflow(self.ftime_active, self.workflow_active, self.task_group_active, self.task_group_tasks_active, self.random_objects[0], self.generated_cycle_tasks_active) cycle = self._activate_workflow(self.ftime_historical, self.workflow_historical, self.task_group_historical, self.task_group_tasks_historical, self.random_objects[1], self.generated_cycle_tasks_historical) with freeze_time(self.ftime_historical): cycle = Cycle.query.get(cycle.id) self.wf_generator.modify_object(cycle, data={"is_current": False}) def _create_test_cases_data(self): """Create test cases data: for object generation, expected data for checks""" def person_dict(person_id): """Return person data""" return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.workflow_active = { "title": "workflow active title", "description": "workflow active description", "frequency": "one_time", "owners": [person_dict(self.person_1.id)], "notify_on_change": False, } self.task_group_active = { "title": "task group active title", "contact": person_dict(self.person_1.id), } self.task_group_tasks_active = [{ "title": "task active title 1", "description": "task active description 1", "contact": person_dict(self.person_1.id), "start_date": "07/01/2016", "end_date": "07/06/2016", }, { "title": "task active title 2", "description": "task active description 2", "contact": person_dict(self.person_1.id), "start_date": "07/07/2016", "end_date": "07/12/2016", }, { "title": "task active title 3", "description": "task active description 3", "contact": person_dict(self.person_1.id), "start_date": "07/13/2016", "end_date": "07/18/2016", }, { "title": "task active title 4", "description": "task active description 4", "contact": person_dict(self.person_1.id), "start_date": "07/19/2016", "end_date": "07/24/2016", }, { "title": "task active title 5", "description": "task active description 5", "contact": person_dict(self.person_1.id), "start_date": "07/25/2016", "end_date": "07/30/2016", }] # Active cycle tasks which should be generated from previous structure # at the beginning of each test self.generated_cycle_tasks_active = { "CYCLETASK-1": { "title": self.task_group_tasks_active[0]["title"], "description": self.task_group_tasks_active[0]["description"], "start_date": "2016-07-01", "end_date": "2016-07-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-2": { "title": self.task_group_tasks_active[1]["title"], "description": self.task_group_tasks_active[1]["description"], "start_date": "2016-07-07", "end_date": "2016-07-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-3": { "title": self.task_group_tasks_active[2]["title"], "description": self.task_group_tasks_active[2]["description"], "start_date": "2016-07-13", "end_date": "2016-07-18", "finished_date": "None", "verified_date": "None", "status": "InProgress" }, "CYCLETASK-4": { "title": self.task_group_tasks_active[3]["title"], "description": self.task_group_tasks_active[3]["description"], "start_date": "2016-07-19", "end_date": "2016-07-24", "finished_date": "2016-07-01 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-5": { "title": self.task_group_tasks_active[4]["title"], "description": self.task_group_tasks_active[4]["description"], "start_date": "2016-07-25", "end_date": "2016-07-30", "finished_date": "2016-07-01 00:00:00", "verified_date": "2016-07-01 00:00:00", "status": "Verified" } } self.workflow_historical = { "title": "workflow historical title", "description": "workflow historical description", "frequency": "one_time", "owners": [person_dict(self.person_1.id)], "notify_on_change": False, } self.task_group_historical = { "title": "task group historical title", "contact": person_dict(self.person_1.id), } self.task_group_tasks_historical = [{ "title": "task historical title 1", "description": "task historical description 1", "contact": person_dict(self.person_1.id), "start_date": "05/01/2014", "end_date": "05/06/2014", }, { "title": "task historical title 2", "description": "task historical description 2", "contact": person_dict(self.person_1.id), "start_date": "05/07/2014", "end_date": "05/12/2014", }, { "title": "task historical title 3", "description": "task historical description 3", "contact": person_dict(self.person_1.id), "start_date": "05/13/2014", "end_date": "05/18/2014", }, { "title": "task historical title 4", "description": "task historical description 4", "contact": person_dict(self.person_1.id), "start_date": "05/19/2014", "end_date": "05/24/2014", }, { "title": "task historical title 5", "description": "task historical description 5", "contact": person_dict(self.person_1.id), "start_date": "05/25/2014", "end_date": "05/30/2014", }, ] # Historical cycle tasks which should be generated from previous structure # at the beginning of each test. self.generated_cycle_tasks_historical = { "CYCLETASK-6": { "title": self.task_group_tasks_historical[0]["title"], "description": self.task_group_tasks_historical[0]["description"], "start_date": "2014-05-01", "end_date": "2014-05-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-7": { "title": self.task_group_tasks_historical[1]["title"], "description": self.task_group_tasks_historical[1]["description"], "start_date": "2014-05-07", "end_date": "2014-05-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-8": { "title": self.task_group_tasks_historical[2]["title"], "description": self.task_group_tasks_historical[2]["description"], "start_date": "2014-05-13", "end_date": "2014-05-18", "finished_date": "None", "verified_date": "None", "status": "InProgress" }, "CYCLETASK-9": { "title": self.task_group_tasks_historical[3]["title"], "description": self.task_group_tasks_historical[3]["description"], "start_date": "2014-05-19", "end_date": "2014-05-24", "finished_date": "2014-05-01 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-10": { "title": self.task_group_tasks_historical[4]["title"], "description": self.task_group_tasks_historical[4]["description"], "start_date": "2014-05-25", "end_date": "2014-05-30", "finished_date": "2014-05-01 00:00:00", "verified_date": "2014-05-01 00:00:00", "status": "Verified" } } # Expected cycle tasks which should be created in correct cycle task update # case. It is needed for most tests. self.expected_cycle_task_correct = { "CYCLETASK-1": { "title": self.task_group_tasks_active[0]["title"] + " one", "description": self.task_group_tasks_active[0]["description"] + " one", "start_date": "2016-06-01", "end_date": "2016-06-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-2": { "title": self.task_group_tasks_active[1]["title"] + " two", "description": self.task_group_tasks_active[1]["description"] + " two", "start_date": "2016-06-07", "end_date": "2016-06-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-3": { "title": self.task_group_tasks_active[2]["title"] + " three", "description": self.task_group_tasks_active[2]["description"] + " three", "start_date": "2016-06-13", "end_date": "2016-06-18", "finished_date": "None", "verified_date": "None", "status": "InProgress" }, "CYCLETASK-4": { "title": self.task_group_tasks_active[3]["title"] + " four", "description": self.task_group_tasks_active[3]["description"] + " four", "start_date": "2016-06-19", "end_date": "2016-06-24", "finished_date": "2016-07-19 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-5": { "title": self.task_group_tasks_active[4]["title"] + " five", "description": self.task_group_tasks_active[4]["description"] + " five", "start_date": "2016-06-25", "end_date": "2016-06-30", "finished_date": "2016-07-25 00:00:00", "verified_date": "2016-08-30 00:00:00", "status": "Verified" }, "CYCLETASK-6": { "title": self.task_group_tasks_historical[0]["title"] + " one", "description": self.task_group_tasks_historical[0]["description"] + " one", "start_date": "2014-04-01", "end_date": "2014-04-06", "finished_date": "2014-05-01 00:00:00", "verified_date": "2014-06-06 00:00:00", "status": "Assigned" }, "CYCLETASK-7": { "title": self.task_group_tasks_historical[1]["title"] + " two", "description": self.task_group_tasks_historical[1]["description"] + " two", "start_date": "2014-04-07", "end_date": "2014-04-12", "finished_date": "2014-05-07 00:00:00", "verified_date": "None", "status": "Declined" }, "CYCLETASK-8": { "title": self.task_group_tasks_historical[2]["title"] + " three", "description": self.task_group_tasks_historical[2]["description"] + " three", "start_date": "2014-04-13", "end_date": "2014-04-18", "finished_date": "2014-05-13 00:00:00", "verified_date": "2014-06-18 00:00:00", "status": "InProgress" }, "CYCLETASK-9": { "title": self.task_group_tasks_historical[3]["title"] + " four", "description": self.task_group_tasks_historical[3]["description"] + " four", "start_date": "2014-04-19", "end_date": "2014-04-24", "finished_date": "2014-05-19 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-10": { "title": self.task_group_tasks_historical[4]["title"] + " five", "description": self.task_group_tasks_historical[4]["description"] + " five", "start_date": "2014-04-25", "end_date": "2014-04-30", "finished_date": "2014-05-25 00:00:00", "verified_date": "2014-06-30 00:00:00", "status": "Verified" } } # Below is description of warning for non-importable columns. It is needed # for test_cycle_task_warnings. importable_column_names = [] for field_name in CycleTaskGroupObjectTask.IMPORTABLE_FIELDS: if field_name == 'slug': continue # pylint: disable=protected-access name = CycleTaskGroupObjectTask._aliases.get(field_name, field_name) if isinstance(name, dict): name = name['display_name'] importable_column_names.append(name) self.expected_warnings = self.generate_expected_warning( *importable_column_names) # This is an error message which should be shown during # test_cycle_task_create_error test self.expected_create_error = { 'Cycle Task': { 'row_errors': {errors.CREATE_INSTANCE_ERROR.format(line=13)} } } # Below is expected date errors for test_cycle_task_date_error. They should # be shown during date validator's tests. self.expected_date_error = { 'Cycle Task': { 'row_errors': { errors.INVALID_START_END_DATES.format( line=3, start_date="Start Date", end_date="End Date", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=4, date="Actual Finish Date", status="not Finished", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=5, date="Actual Verified Date", status="not Verified", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=6, date="Actual Verified Date", status="not Verified", ), errors.INVALID_START_END_DATES.format( line=7, start_date="Actual Finish Date", end_date="Actual Verified Date", ), errors.INVALID_START_END_DATES.format( line=8, start_date="Start Date", end_date="End Date", ), errors.MISSING_VALUE_ERROR.format( line=9, column_name="Actual Finish Date", ), errors.INVALID_START_END_DATES.format( line=10, start_date="Actual Finish Date", end_date="Actual Verified Date", ), }, } } # Below is expected cycle-tasks data which should appear in test DB after # test_cycle_task_date_error run self.expected_cycle_task_date_error = dict() self.expected_cycle_task_date_error.update( self.generated_cycle_tasks_active) self.expected_cycle_task_date_error.update( self.generated_cycle_tasks_historical) self.expected_cycle_task_date_error["CYCLETASK-9"] = ( self.expected_cycle_task_correct["CYCLETASK-9"]) self.expected_cycle_task_date_error["CYCLETASK-10"] = ( self.expected_cycle_task_correct["CYCLETASK-10"]) # Expected error message which should be shown after # test_cycle_task_permission_error run self.expected_permission_error = { 'Cycle Task': { 'block_errors': {errors.PERMISSION_ERROR.format(line=2)} } }
class TestPermissionsOnAssessmentTemplate(TestCase): """ Test check permissions for ProgramEditor on get and post assessment_temaplte action""" def setUp(self): super(TestPermissionsOnAssessmentTemplate, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, program = self.generator.generate_object(all_models.Program) program_id = program.id _, self.editor = self.generator.generate_person( user_role="Creator" ) role = perms.all_models.Role.query.filter( perms.all_models.Role.name == "ProgramEditor" ).first() self.generator.generate_user_role( self.editor, role, all_models.Program.query.get(program_id) ) _, audit = self.generator.generate_object( all_models.Audit, { "title": "Audit", "program": {"id": program_id}, "status": "Planned" }, ) audit_id = audit.id generated_at = self.generator.generate_object( all_models.AssessmentTemplate, { "title": "Template", "_NON_RELEVANT_OBJ_TYPES": {}, "_objectTypes": {}, "audit": {"id": audit.id}, "audit_title": audit.title, "people_value": [], "default_people": { "assessors": "Object Owners", "verifiers": "Object Owners", }, "context": {"id": audit.context.id}, } ) self.assessment_template_resp, assessment_template = generated_at assessment_template_id = assessment_template.id self.api.set_user(self.editor) self.perms_data = self.api.client.get("/permissions").json self.audit = all_models.Audit.query.get(audit_id) self.assessment_template = all_models.AssessmentTemplate.query.get( assessment_template_id) def test_post_action(self): """Test create action on AssessmentTemplate created by api""" data = [{ "assessment_template": { "_NON_RELEVANT_OBJ_TYPES": {}, "_objectTypes": {}, "audit": {"id": self.audit.id}, "audit_title": self.audit.title, "people_value": [], "default_people": { "assessors": "Object Owners", "verifiers": "Object Owners", }, "context": {"id": self.audit.context.id}, "title": "123", } }] self.api.set_user(self.editor) resp = self.api.post(all_models.AssessmentTemplate, data) self.assert200(resp) def test_get_action(self): """Test read action on AssessmentTemplate created by api""" resp = self.api.get(all_models.AssessmentTemplate, self.assessment_template.id) self.assert200(resp) def test_put_action(self): """Test update action on AssessmentTemplate created by api""" to_update = copy.deepcopy(self.assessment_template_resp.json) new_title = "new_{}".format(self.assessment_template.title) to_update['assessment_template']['title'] = new_title resp = self.api.put(self.assessment_template, to_update) self.assert200(resp) assessment_tmpl = all_models.AssessmentTemplate.query.get( self.assessment_template.id ) self.assertEqual(new_title, assessment_tmpl.title) def test_delete_action(self): """Test delete action on AssessmentTemplate created by api""" resp = self.api.delete(self.assessment_template) self.assert200(resp) self.assertFalse(all_models.AssessmentTemplate.query.filter( all_models.AssessmentTemplate == self.assessment_template.id).all())
class TestNotificationsForDeletedObjects(TestCase): """ This class contains simple one time workflow tests that are not in the gsheet test grid """ def setUp(self): super(TestNotificationsForDeletedObjects, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() Notification.query.delete() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init Notification.__init__ = init_decorator(Notification.__init__) @patch("ggrc.notifications.common.send_email") def test_delete_activated_workflow(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, workflow = self.wf_generator.generate_workflow(self.quarterly_wf_1) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) user = Person.query.get(self.user.id) with freeze_time("2015-01-01 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertNotIn(user.email, notif_data) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("cycle_starts_in", notif_data[user.email]) workflow = Workflow.query.get(workflow.id) # After workflow deletion its notifications object_ids updated to 0 # value, this is the error, them should be deleted # so this query checks existence of notifications with object_id # equal to workflow id or 0 id before and # after deletion workflow instance exists_qs = db.session.query( Notification.query.filter( Notification.object_type == workflow.__class__.__name__, Notification.object_id.in_((workflow.id, 0)) ).exists() ) self.assertTrue(exists_qs.one()[0]) response = self.wf_generator.api.delete(workflow) self.assert200(response) self.assertFalse(exists_qs.one()[0]) _, notif_data = common.get_daily_notifications() user = Person.query.get(self.user.id) self.assertNotIn(user.email, notif_data) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.quarterly_wf_1 = { "title": "quarterly wf 1", "notify_on_change": True, "description": "", "owners": [person_dict(self.user.id)], "frequency": "quarterly", "task_groups": [{ "title": "tg_1", "contact": person_dict(self.user.id), "task_group_tasks": [{ "contact": person_dict(self.user.id), "description": factories.random_str(100), "relative_start_day": 5, "relative_start_month": 2, "relative_end_day": 25, "relative_end_month": 2, }, ], }, ] }
class TestTaskOverdueNotificationsUsingAPI(TestTaskOverdueNotifications): """Tests for overdue notifications when changing Tasks with an API.""" # pylint: disable=invalid-name def setUp(self): super(TestTaskOverdueNotificationsUsingAPI, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() models.Notification.query.delete() self._fix_notification_init() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self._create_test_cases() @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_sending_overdue_notifications_for_tasks(self, is_vf_needed, _): """Overdue notifications should be sent for overdue tasks every day. Even if an overdue notification has already been sent, it should still be sent in every following daily digest f a task is still overdue. """ with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1_id = tasks[0].id task2_id = tasks[1].id user = models.Person.query.get(self.user.id) with freeze_time("2017-05-14 08:09:10"): _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) with freeze_time("2017-05-15 08:09:10"): # task 1 due date _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) with freeze_time("2017-05-16 08:09:10"): # task 2 due date _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) overdue_task_ids = sorted(user_notifs["task_overdue"].keys()) self.assertEqual(overdue_task_ids, [task1_id]) with freeze_time("2017-05-17 08:09:10"): # after both tasks' due dates _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) overdue_task_ids = sorted(user_notifs["task_overdue"].keys()) self.assertEqual(overdue_task_ids, [task1_id, task2_id]) common.send_daily_digest_notifications() # even after sending the overdue notifications, they are sent again the # day after, too with freeze_time("2017-05-18 08:09:10"): _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) overdue_task_ids = sorted(user_notifs["task_overdue"].keys()) self.assertEqual(overdue_task_ids, [task1_id, task2_id]) @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_adjust_overdue_notifications_on_task_due_date_change(self, is_vf_needed, _): """Sending overdue notifications should adjust to task due date changes.""" with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1, task2 = tasks self.wf_generator.modify_object(task2, {"end_date": date(2099, 12, 31)}) user = models.Person.query.get(self.user.id) with freeze_time("2017-05-16 08:09:10"): # a day after task1 due date _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) # change task1 due date, there should be no overdue notification anymore self.wf_generator.modify_object(task1, {"end_date": date(2017, 5, 16)}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) # change task1 due date to the past there should a notification again self.wf_generator.modify_object(task1, {"end_date": date(2017, 5, 14)}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_adjust_overdue_notifications_on_task_status_change(self, is_vf_needed, _): """Sending overdue notifications should take task status into account.""" with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1, task2 = tasks self.wf_generator.modify_object(task2, {"end_date": date(2099, 12, 31)}) user = models.Person.query.get(self.user.id) user_email = user.email if is_vf_needed: non_final_states = [CycleTaskGroupObjectTask.ASSIGNED, CycleTaskGroupObjectTask.IN_PROGRESS, CycleTaskGroupObjectTask.FINISHED, CycleTaskGroupObjectTask.DECLINED] final_state = CycleTaskGroupObjectTask.VERIFIED else: non_final_states = [CycleTaskGroupObjectTask.ASSIGNED, CycleTaskGroupObjectTask.IN_PROGRESS] final_state = CycleTaskGroupObjectTask.FINISHED with freeze_time("2017-05-16 08:09:10"): # a day after task1 due date for state in non_final_states: # clear all notifications before before changing the task status models.Notification.query.delete() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) self.wf_generator.modify_object(task1, {"status": state}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) # WITHOUT clearing the overdue notifications, move the task to "verified" # state, and the overdue notification should disappear. self.wf_generator.modify_object(task1, {"status": final_state}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertNotIn("task_overdue", user_notifs) @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_stop_sending_overdue_notification_if_task_gets_deleted(self, is_vf_needed, _): """Overdue notifications should not be sent for deleted tasks.""" with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1, task2 = tasks user = models.Person.query.get(self.user.id) user_email = user.email with freeze_time("2017-10-16 08:09:10"): # long after both task due dates _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 2) db.session.delete(task2) db.session.commit() _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) db.session.delete(task1) db.session.commit() _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) def _create_test_cases(self): """Create configuration to use for generating a new workflow.""" def person_dict(person_id): return { "href": "/api/people/" + str(person_id), "id": person_id, "type": "Person" } role_id = models.all_models.AccessControlRole.query.filter( models.all_models.AccessControlRole.name == "Task Assignees", models.all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id self.one_time_workflow = { "title": "one time test workflow", "notify_on_change": True, "description": "some test workflow", # admin will be current user with id == 1 "task_groups": [{ "title": "one time task group", "contact": person_dict(self.user.id), "task_group_tasks": [{ "title": "task 1", "description": "some task", "start_date": date(2017, 5, 5), # Friday "end_date": date(2017, 5, 15), "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], }, { "title": "task 2", "description": "some task 2", "start_date": date(2017, 5, 5), # Friday "end_date": date(2017, 5, 16), "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], }], "task_group_objects": self.random_objects }] }
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): """Permissions to admin page.""" for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) creator_id = self.users["creator"].id audit_id = factories.AuditFactory().id all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup", "Metric" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # ignored except for Document "contact": { "type": "Person", "id": creator_id, }, "audit": { # this is ignored on everything but Issues "id": audit_id, "type": "Audit", } }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format(model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if collection: all_errors.append( "{} can retrieve object if not owner (collection)" .format(model_singular)) continue # Test GET when owner acr = all_models.AccessControlRole.query.filter_by( object_type=model_singular, name="Admin" ).first() factories.AccessControlListFactory( object_id=obj_id, object_type=model_singular, ac_role=acr, person_id=creator_id ) response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)" .format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['creator']) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Policy", name="Admin" ).first().id response = self.api.post(all_models.Policy, { "policy": { "title": "Creator Policy", "context": None, "access_control_list": [ acl_helper.get_acl_json(acr_id, self.users["creator"].id)], }, }) response.json.get("policy").get("id") response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual( response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) _, obj_1 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation 2", "context": None}, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": {"source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None}, } ) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title, extra_data=None): """Generates section.""" section_content = {"title": title, "context": None} if extra_data: section_content.update(**extra_data) return self.generator.generate(all_models.Section, "section", { "section": section_content })[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id) ) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected ) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Section 1") self.api.set_user(self.users["creator"]) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Section", name="Admin" ).first().id linked_acl = { "access_control_list": [ acl_helper.get_acl_json(acr_id, self.users["creator"].id)], } check(obj_1, 0) obj_2 = gen("Test Section 2", linked_acl) obj2_acl = obj_2.access_control_list[0] check(obj_2, 1) check(obj2_acl, 1) @ddt.data("creator", "admin") def test_count_type_in_accordion(self, glob_role): """Return count of Persons in DB for side accordion.""" self.api.set_user(self.users[glob_role]) ocordion_api_person_count_link = ( "/search?" "q=&types=Program%2CWorkflow_All%2C" "Audit%2CAssessment%2CIssue%2CRegulation%2C" "Policy%2CStandard%2CContract%2CClause%2CSection%2CControl%2C" "Objective%2CPerson%2COrgGroup%2CVendor%2CAccessGroup%2CSystem%2C" "Process%2CDataAsset%2CProduct%2CProject%2CFacility%2C" "Market%2CRisk%2CThreat&counts_only=true&" "extra_columns=Workflow_All%3DWorkflow%2C" "Workflow_Active%3DWorkflow%2CWorkflow_Draft%3D" "Workflow%2CWorkflow_Inactive%3DWorkflow&contact_id=1&" "extra_params=Workflow%3Astatus%3DActive%3BWorkflow_Active" "%3Astatus%3DActive%3BWorkflow_Inactive%3Astatus%3D" "Inactive%3BWorkflow_Draft%3Astatus%3DDraft" ) resp = self.api.client.get(ocordion_api_person_count_link) self.assertIn("Person", resp.json["results"]["counts"]) self.assertEqual(all_models.Person.query.count(), resp.json["results"]["counts"]["Person"]) @ddt.data( ("/api/revisions?resource_type={}&resource_id={}", 1), ("/api/revisions?source_type={}&source_id={}", 0), ("/api/revisions?destination_type={}&destination_id={}", 1), ) @ddt.unpack def test_changelog_access(self, link, revision_count): """Test accessing changelog under GC user who is assigned to object""" with factories.single_commit(): audit = factories.AuditFactory() asmnt = factories.AssessmentFactory(audit=audit) asmnt_id = asmnt.id factories.RelationshipFactory(source=audit, destination=asmnt) verifier_role = all_models.AccessControlRole.query.filter_by( object_type="Assessment", name="Verifiers", ).first() factories.AccessControlListFactory( person=self.users["creator"], ac_role=verifier_role, object=asmnt, ) self.api.set_user(self.users["creator"]) response = self.api.client.get(link.format("Assessment", asmnt_id)) self.assert200(response) self.assertEqual( len(response.json.get("revisions_collection", {}).get("revisions")), revision_count ) @ddt.data(all_models.ControlCategory, all_models.ControlAssertion) def test_permissions_for_categories(self, category_model): """Test get collection for {0}.""" self.api.set_user(self.users["creator"]) resp = self.api.get_collection(category_model, None) plural_name = category_model._inflector.table_plural key_name = "{}_collection".format(plural_name) self.assertIn(key_name, resp.json) self.assertIn(plural_name, resp.json[key_name]) collection = resp.json[key_name][plural_name] self.assertTrue(collection, "Collection shouldn't be empty")
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): """Permissions to admin page.""" for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) creator_id = self.users["creator"].id audit_id = factories.AuditFactory().id all_errors = [] base_models = { "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup", "Metric", "ProductGroup", "TechnologyEnvironment" } for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # ignored except for Document "contact": { "type": "Person", "id": creator_id, }, "audit": { # this is ignored on everything but Issues "id": audit_id, "type": "Audit", } }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format( model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if collection: all_errors.append( "{} can retrieve object if not owner (collection)". format(model_singular)) continue # Test GET when owner acr = all_models.AccessControlRole.query.filter_by( object_type=model_singular, name="Admin").first() factories.AccessControlListFactory(object_id=obj_id, object_type=model_singular, ac_role=acr, person_id=creator_id) response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['creator']) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Policy", name="Admin").first().id response = self.api.post( all_models.Policy, { "policy": { "title": "Creator Policy", "context": None, "access_control_list": [ acl_helper.get_acl_json(acr_id, self.users["creator"].id) ], }, }) response.json.get("policy").get("id") response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title, extra_data=None): """Generates requirement.""" requirement_content = {"title": title, "context": None} if extra_data: requirement_content.update(**extra_data) return self.generator.generate( all_models.Requirement, "requirement", {"requirement": requirement_content})[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id)) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Requirement 1") self.api.set_user(self.users["creator"]) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Requirement", name="Admin").first().id linked_acl = { "access_control_list": [acl_helper.get_acl_json(acr_id, self.users["creator"].id)], } check(obj_1, 0) obj_2 = gen("Test Requirement 2", linked_acl) obj2_acl = obj_2.access_control_list[0] check(obj_2, 1) check(obj2_acl, 1) @ddt.data("creator", "admin") def test_count_type_in_accordion(self, glob_role): """Return count of Persons in DB for side accordion.""" self.api.set_user(self.users[glob_role]) ocordion_api_person_count_link = ( "/search?" "q=&types=Program%2CWorkflow_All%2C" "Audit%2CAssessment%2CIssue%2CRegulation%2C" "Policy%2CStandard%2CContract%2CClause%2CRequirement%2CControl%2C" "Objective%2CPerson%2COrgGroup%2CVendor%2CAccessGroup%2CSystem%2C" "Process%2CDataAsset%2CProduct%2CProject%2CFacility%2C" "Market%2CRisk%2CThreat&counts_only=true&" "extra_columns=Workflow_All%3DWorkflow%2C" "Workflow_Active%3DWorkflow%2CWorkflow_Draft%3D" "Workflow%2CWorkflow_Inactive%3DWorkflow&contact_id=1&" "extra_params=Workflow%3Astatus%3DActive%3BWorkflow_Active" "%3Astatus%3DActive%3BWorkflow_Inactive%3Astatus%3D" "Inactive%3BWorkflow_Draft%3Astatus%3DDraft") resp = self.api.client.get(ocordion_api_person_count_link) self.assertIn("Person", resp.json["results"]["counts"]) self.assertEqual(all_models.Person.query.count(), resp.json["results"]["counts"]["Person"]) @ddt.data( ("/api/revisions?resource_type={}&resource_id={}", 1), ("/api/revisions?source_type={}&source_id={}", 0), ("/api/revisions?destination_type={}&destination_id={}", 1), ) @ddt.unpack def test_changelog_access(self, link, revision_count): """Test accessing changelog under GC user who is assigned to object""" with factories.single_commit(): audit = factories.AuditFactory() asmnt = factories.AssessmentFactory(audit=audit) asmnt_id = asmnt.id factories.RelationshipFactory(source=audit, destination=asmnt) verifier_role = all_models.AccessControlRole.query.filter_by( object_type="Assessment", name="Verifiers", ).first() factories.AccessControlListFactory( person=self.users["creator"], ac_role=verifier_role, object=asmnt, ) self.api.set_user(self.users["creator"]) response = self.api.client.get(link.format("Assessment", asmnt_id)) self.assert200(response) self.assertEqual( len( response.json.get("revisions_collection", {}).get("revisions")), revision_count) @ddt.data(all_models.ControlCategory, all_models.ControlAssertion) def test_permissions_for_categories(self, category_model): """Test get collection for {0}.""" self.api.set_user(self.users["creator"]) resp = self.api.get_collection(category_model, None) plural_name = category_model._inflector.table_plural key_name = "{}_collection".format(plural_name) self.assertIn(key_name, resp.json) self.assertIn(plural_name, resp.json[key_name]) collection = resp.json[key_name][plural_name] self.assertTrue(collection, "Collection shouldn't be empty")
class TestEvidenceRolePropagation(TestCase): """Evidence role propagation test case""" # pylint: disable=invalid-name def setUp(self): super(TestEvidenceRolePropagation, self).setUp() self.api = Api() self.generator = ObjectGenerator() # Propagation isn't work for 'Primary Contacts', 'Secondary Contacts' # just add them to data list to check if fix works. @ddt.data("Assignees", "Creators", "Verifiers") def test_assessment_role_propagation_edit(self, role_name): """Asses user with role '{0}' should be able to edit related evidence""" _, reader = self.generator.generate_person(user_role="Creator") with factories.single_commit(): assessment = factories.AssessmentFactory() assessment.add_person_with_role_name(reader, role_name) evidence = factories.EvidenceFactory() evidence_id = evidence.id factories.RelationshipFactory(source=assessment, destination=evidence) self.api.set_user(reader) evidence = all_models.Evidence.query.get(evidence_id) new_description = 'new description' resp = self.api.modify_object(evidence, {'description': new_description}) evidence = self.refresh_object(evidence) self.assert200(resp) self.assertEquals(new_description, evidence.description) self.assertEquals(reader.id, evidence.modified_by_id) @ddt.data( ("Creator", "Audit Captains", 200), ("Creator", "Auditors", 403), ("Reader", "Audit Captains", 200), ("Reader", "Auditors", 403), ("Editor", "Audit Captains", 200), ("Editor", "Auditors", 200), ) @ddt.unpack def test_audit_role_propagation_edit(self, user_role, audit_role, status_code): """'{0}' assigned as '{1}' should get '{2}' when editing audit evidence""" _, user = self.generator.generate_person(user_role=user_role) with factories.single_commit(): audit = factories.AuditFactory() audit.add_person_with_role_name(user, audit_role) evidence = factories.EvidenceFactory() evidence_id = evidence.id factories.RelationshipFactory(source=audit, destination=evidence) self.api.set_user(user) evidence = all_models.Evidence.query.get(evidence_id) new_description = 'new description' resp = self.api.modify_object(evidence, {'description': new_description}) evidence = self.refresh_object(evidence) if status_code == 200: self.assert200(resp) self.assertEquals(new_description, evidence.description) self.assertEquals(user.id, evidence.modified_by_id) else: self.assertStatus(resp, status_code) def test_audit_role_propagation_not_delete(self): """Audit user with role Auditors can NOT delete related evidence""" role_name = "Auditors" _, reader = self.generator.generate_person(user_role="Reader") with factories.single_commit(): audit = factories.AuditFactory() audit.add_person_with_role_name(reader, role_name) evidence = factories.EvidenceFactory() evidence_id = evidence.id factories.RelationshipFactory(source=audit, destination=evidence) self.api.set_user(reader) evidence = all_models.Evidence.query.get(evidence_id) resp = self.api.delete(evidence) self.assertStatus(resp, 403) evidence = all_models.Evidence.query.get(evidence_id) self.assertTrue(evidence)
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.tc.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Issue", "Project", "AccessGroup" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post( model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": self.users["creator"].id, }, }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format( model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) != 0: all_errors.append( "{} can retrieve object if not owner (collection)". format(model_singular)) continue # Become an owner response = self.api.post( all_models.ObjectOwner, { "object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": model_singular, "id": obj_id }, "context": None } }) if response.status_code != 201: all_errors.append("{} can't create owner {}.".format( model_singular, response.status)) continue # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['creator']) response = self.api.post(all_models.Policy, { "policy": { "title": "Creator Policy", "context": None }, }) obj_id = response.json.get("policy").get("id") self.api.post( all_models.ObjectOwner, { "object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Policy", "id": obj_id, }, "context": None } }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_creator_cannot_be_owner(self): """Test if creator cannot become owner of the object he has not created""" self.api.set_user(self.users['admin']) _, obj = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) self.api.set_user(self.users['creator']) response = self.api.post( all_models.ObjectOwner, { "object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Regulation", "id": obj.id, }, "context": None } }) self.assertEqual(response.status_code, 403) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title): return self.generator.generate(all_models.Section, "section", { "section": { "title": title, "context": None }, })[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id)) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Section 1") obj_2 = gen("Test Section 2") self.api.post( all_models.ObjectOwner, { "object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Section", "id": obj_2.id, }, "context": None } }) self.api.set_user(self.users["creator"]) check(obj_1, 0) check(obj_2, 2)
class TestReader(TestCase): """Test Assignable RBAC""" def setUp(self): super(TestReader, self).setUp() self.audit_id = factories.AuditFactory().id self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_assignable() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def init_assignable(self): """Creates the assignable object used by all the tests""" self.api.set_user(self.users["editor"]) response = self.api.post( all_models.Assessment, { "assessment": { "title": "Assessment", "context": None, "audit": { "id": self.audit_id, "type": "Audit" } } }) obj_id = response.json.get("assessment").get("id") self.assertEqual(response.status_code, 201, "Error setting up Assessment") self.obj_json = response.json self.obj = all_models.Assessment.query.get(obj_id) def _add_creator(self, asmnt, user): """Helper method for creating assignees on an object""" acr = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.object_type == "Assessment", all_models.AccessControlRole.name == "Creators", ).first() return self.api.put( asmnt, { "access_control_list": [{ "ac_role_id": acr.id, "person": { "id": user.id }, "type": "AccessControlList", }] }) def test_basic_with_no_assignee(self): """Editor creates an Assessment, but doesn't assign Reader/Creator as assignee. Reader should have Read access, Creator should have no access """ # Reader should have read access, but shouldn't be allowed to edit or # create another assingee self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, self.obj_json) self.assertEqual(response.status_code, 403) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 403) # Creator should have no access. We skip the put request because we can't # get the object etag. self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 403) def test_basic_with_assignee(self): """Test if Reader/Creator have CRUD access once they become assignees""" # Admin adds reader as an assignee self.api.set_user(self.users["admin"]) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 200) # Reader is now allowed to update the object self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) self.assertEqual(response.status_code, 200) # Reader adds creator as an assignee response = self._add_creator(self.obj, self.users["creator"]) self.assertEqual(response.status_code, 200) # Creator now has CRUD access self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) # Creator should even be allowed to add new assignees response = self._add_creator(self.obj, self.users["admin"]) self.assertEqual(response.status_code, 200) def test_read_of_mapped_objects(self): """Test if assignees get Read access on all mapped objects""" # Editor creates a System object and maps it to the assignable object self.api.set_user(self.users["editor"]) response = self.api.post( all_models.System, {"system": { "title": "System", "context": None, }}) system_id = response.json.get("system").get("id") system = all_models.System.query.get(system_id) self.api.post( all_models.Relationship, { "relationship": { "source": { "id": self.obj.id, "type": "Assessment" }, "destination": { "id": system_id, "type": "System" }, "context": None }, }) # Since creator is not an assignee she should not have access to any of the # two objects self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 403) # Editor adds creator as an assignee self.api.set_user(self.users["editor"]) response = self._add_creator(self.obj, self.users["creator"]) self.assertEqual(response.status_code, 200) # Creator should now have read access on the mapped object self.api.set_user(self.users["creator"]) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 200) # But he should still not be allowed to update response = self.api.put(system, response.json) self.assertEqual(response.status_code, 403)
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user self.users["external"] = self.object_generator.generate_person( data={"email": "*****@*****.**"})[1] def test_admin_page_access(self): """Only admin can use admin requirement""" for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "System", "Process", "Project", "AccessGroup", "Metric", "TechnologyEnvironment", "ProductGroup", "KeyReport", "AccountBalance", ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response, _ = self.object_generator.generate_object( model, data={ table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # only for Document "contact": { "type": "Person", "id": self.users["reader"].id, } }, } ) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)".format( model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": {"title": "reader Policy", "context": None}, }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, first_regulation = self.object_generator.generate_object( all_models.Regulation, data={"regulation": {"title": "Test regulation", "context": None}} ) _, second_regulation = self.object_generator.generate_object( all_models.Regulation, data={"regulation": {"title": "Test regulation 2", "context": None}} ) response, rel = self.object_generator.generate_relationship( first_regulation, second_regulation ) self.assertStatus(response, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, rel.id) self.assert200(response) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): """Check if reader can't create mappings""" self.object_generator.api.set_user(self.users["external"]) _, control = self.object_generator.generate_object( all_models.Control, data={"control": {"title": "Test Control", "context": None}} ) self.object_generator.api.set_user(self.users['reader']) _, program = self.object_generator.generate_object( all_models.Program, data={"program": {"title": "Test Program", "context": None}} ) response, _ = self.object_generator.generate_relationship( control, program, program.context ) self.assert403(response) @ddt.data("creator", "reader") def test_unmap_people(self, user_role): """Test that global reader/creator can't unmap people from program""" user = self.users[user_role] with factories.single_commit(): program = factories.ProgramFactory() mapped_person = factories.ObjectPersonFactory( personable=program, person=user, context=program.context ) self.api.set_user(user) db.session.add(mapped_person) response = self.api.delete(mapped_person) self.assert403(response) def test_read_evidence_revision(self): """Global Read can read Evidence revision content""" user = self.users["reader"] link = "google.com" evidence = factories.EvidenceUrlFactory(link=link) evidence_id = evidence.id self.api.set_user(user) resp = self.api.client.get( "/api/revisions?resource_type={}&resource_id={}".format(evidence.type, evidence_id)) rev_content = resp.json["revisions_collection"]["revisions"][0]["content"] self.assertTrue(rev_content) self.assertEquals(link, rev_content["link"])
class TestCycleTaskImportUpdate(TestCase): """ This class contains simple cycle task update tests using import functionality """ CSV_DIR = join(abspath(dirname(__file__)), "test_csvs/") def setUp(self): super(TestCycleTaskImportUpdate, self).setUp() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() self.random_objects = self.object_generator.generate_random_objects(2) _, self.person_1 = self.object_generator.generate_person( user_role="Administrator") self.ftime_active = "2016-07-01" self.ftime_historical = "2014-05-01" self._create_test_cases_data() # It is needed because cycle-tasks are generated automatically with # 'slug' based on auto_increment 'id' field. # At start of each test we suppose that created cycle-task's 'slug' # lie in range from 1 to 10. db.session.execute('ALTER TABLE cycle_task_group_object_tasks ' 'AUTO_INCREMENT = 1') def test_cycle_task_correct(self): """Test cycle task update via import with correct data""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_correct.csv") self._check_csv_response(response, {}) self._cmp_tasks(self.expected_cycle_task_correct) def test_cycle_task_warnings(self): """Test cycle task update via import with data which is the reason of warnings about non-importable columns.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_warnings.csv") self._check_csv_response(response, self.expected_warnings) self._cmp_tasks(self.expected_cycle_task_correct) def test_cycle_task_create_error(self): """Test cycle task update via import with data which is the reason of errors about new cycle task creation.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_create_error.csv") self._check_csv_response(response, self.expected_create_error) self._cmp_tasks(self.expected_cycle_task_correct) def test_cycle_task_date_error(self): """Test cycle task update via import with data which is the reason of errors about incorrect dates in csv file.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): response = self.import_file("cycle_task_date_error.csv") self._check_csv_response(response, self.expected_date_error) self._cmp_tasks(self.expected_cycle_task_date_error) def test_cycle_task_permission_error(self): """Test cycle task update via import with non-admin user which is the reason of error. Only admin can update cycle tasks via import.""" self._generate_cycle_tasks() with freeze_time(self.ftime_active): _, creator = self.object_generator.generate_person( user_role="Creator") response = self.import_file("cycle_task_correct.csv", person=creator) self._check_csv_response(response, self.expected_permission_error) # Cycle tasks' data shouldn't be changed in test DB after import run from # non-admin user expected_cycle_task_permission_error = {} expected_cycle_task_permission_error.update( self.generated_cycle_tasks_active) expected_cycle_task_permission_error.update( self.generated_cycle_tasks_historical) self._cmp_tasks(expected_cycle_task_permission_error) def _cmp_tasks(self, expected_ctasks): """Compare tasks values from argument's list and test DB.""" for ctask in db.session.query(CycleTaskGroupObjectTask).all(): if ctask.slug not in expected_ctasks: continue exp_task = expected_ctasks[ctask.slug] for attr, val in exp_task.iteritems(): self.assertEqual(str(getattr(ctask, attr, None)), val) # pylint: disable=too-many-arguments def _activate_workflow(self, ftime, workflow, task_group, task_group_tasks, random_object, cycle_tasks): """Helper which is responsible for active cycle-tasks creation""" with freeze_time(ftime): _, wf = self.wf_generator.generate_workflow(workflow) _, tg = self.wf_generator.generate_task_group(wf, task_group) for task in task_group_tasks: self.wf_generator.generate_task_group_task(tg, task) self.wf_generator.generate_task_group_object(tg, random_object) _, cycle = self.wf_generator.generate_cycle(wf) self.wf_generator.activate_workflow(wf) for exp_slug, exp_task in cycle_tasks.iteritems(): obj = db.session.query(CycleTaskGroupObjectTask).filter_by( slug=exp_slug).first() if exp_task["status"] == "Verified": self.wf_generator.modify_object(obj, {"status": "Finished"}) self.wf_generator.modify_object(obj, {"status": exp_task["status"]}) self._cmp_tasks(cycle_tasks) return cycle def _generate_cycle_tasks(self): """Helper which is responsible for test data creation""" self._activate_workflow(self.ftime_active, self.workflow_active, self.task_group_active, self.task_group_tasks_active, self.random_objects[0], self.generated_cycle_tasks_active) cycle = self._activate_workflow(self.ftime_historical, self.workflow_historical, self.task_group_historical, self.task_group_tasks_historical, self.random_objects[1], self.generated_cycle_tasks_historical) with freeze_time(self.ftime_historical): cycle = Cycle.query.get(cycle.id) self.wf_generator.modify_object(cycle, data={"is_current": False}) def _create_test_cases_data(self): """Create test cases data: for object generation, expected data for checks""" def person_dict(person_id): """Return person data""" return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.workflow_active = { "title": "workflow active title", "description": "workflow active description", "frequency": "one_time", "owners": [person_dict(self.person_1.id)], "notify_on_change": False, } self.task_group_active = { "title": "task group active title", "contact": person_dict(self.person_1.id), } self.task_group_tasks_active = [{ "title": "task active title 1", "description": "task active description 1", "contact": person_dict(self.person_1.id), "start_date": "07/01/2016", "end_date": "07/06/2016", }, { "title": "task active title 2", "description": "task active description 2", "contact": person_dict(self.person_1.id), "start_date": "07/07/2016", "end_date": "07/12/2016", }, { "title": "task active title 3", "description": "task active description 3", "contact": person_dict(self.person_1.id), "start_date": "07/13/2016", "end_date": "07/18/2016", }, { "title": "task active title 4", "description": "task active description 4", "contact": person_dict(self.person_1.id), "start_date": "07/19/2016", "end_date": "07/24/2016", }, { "title": "task active title 5", "description": "task active description 5", "contact": person_dict(self.person_1.id), "start_date": "07/25/2016", "end_date": "07/30/2016", }] # Active cycle tasks which should be generated from previous structure # at the beginning of each test self.generated_cycle_tasks_active = { "CYCLETASK-1": { "title": self.task_group_tasks_active[0]["title"], "description": self.task_group_tasks_active[0]["description"], "start_date": "2016-07-01", "end_date": "2016-07-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-2": { "title": self.task_group_tasks_active[1]["title"], "description": self.task_group_tasks_active[1]["description"], "start_date": "2016-07-07", "end_date": "2016-07-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-3": { "title": self.task_group_tasks_active[2]["title"], "description": self.task_group_tasks_active[2]["description"], "start_date": "2016-07-13", "end_date": "2016-07-18", "finished_date": "None", "verified_date": "None", "status": "InProgress" }, "CYCLETASK-4": { "title": self.task_group_tasks_active[3]["title"], "description": self.task_group_tasks_active[3]["description"], "start_date": "2016-07-19", "end_date": "2016-07-24", "finished_date": "2016-07-01 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-5": { "title": self.task_group_tasks_active[4]["title"], "description": self.task_group_tasks_active[4]["description"], "start_date": "2016-07-25", "end_date": "2016-07-30", "finished_date": "2016-07-01 00:00:00", "verified_date": "2016-07-01 00:00:00", "status": "Verified" } } self.workflow_historical = { "title": "workflow historical title", "description": "workflow historical description", "frequency": "one_time", "owners": [person_dict(self.person_1.id)], "notify_on_change": False, } self.task_group_historical = { "title": "task group historical title", "contact": person_dict(self.person_1.id), } self.task_group_tasks_historical = [ { "title": "task historical title 1", "description": "task historical description 1", "contact": person_dict(self.person_1.id), "start_date": "05/01/2014", "end_date": "05/06/2014", }, { "title": "task historical title 2", "description": "task historical description 2", "contact": person_dict(self.person_1.id), "start_date": "05/07/2014", "end_date": "05/12/2014", }, { "title": "task historical title 3", "description": "task historical description 3", "contact": person_dict(self.person_1.id), "start_date": "05/13/2014", "end_date": "05/18/2014", }, { "title": "task historical title 4", "description": "task historical description 4", "contact": person_dict(self.person_1.id), "start_date": "05/19/2014", "end_date": "05/24/2014", }, { "title": "task historical title 5", "description": "task historical description 5", "contact": person_dict(self.person_1.id), "start_date": "05/25/2014", "end_date": "05/30/2014", }, ] # Historical cycle tasks which should be generated from previous structure # at the beginning of each test. self.generated_cycle_tasks_historical = { "CYCLETASK-6": { "title": self.task_group_tasks_historical[0]["title"], "description": self.task_group_tasks_historical[0]["description"], "start_date": "2014-05-01", "end_date": "2014-05-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-7": { "title": self.task_group_tasks_historical[1]["title"], "description": self.task_group_tasks_historical[1]["description"], "start_date": "2014-05-07", "end_date": "2014-05-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-8": { "title": self.task_group_tasks_historical[2]["title"], "description": self.task_group_tasks_historical[2]["description"], "start_date": "2014-05-13", "end_date": "2014-05-18", "finished_date": "None", "verified_date": "None", "status": "InProgress" }, "CYCLETASK-9": { "title": self.task_group_tasks_historical[3]["title"], "description": self.task_group_tasks_historical[3]["description"], "start_date": "2014-05-19", "end_date": "2014-05-24", "finished_date": "2014-05-01 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-10": { "title": self.task_group_tasks_historical[4]["title"], "description": self.task_group_tasks_historical[4]["description"], "start_date": "2014-05-25", "end_date": "2014-05-30", "finished_date": "2014-05-01 00:00:00", "verified_date": "2014-05-01 00:00:00", "status": "Verified" } } # Expected cycle tasks which should be created in correct cycle task update # case. It is needed for most tests. self.expected_cycle_task_correct = { "CYCLETASK-1": { "title": self.task_group_tasks_active[0]["title"] + " one", "description": self.task_group_tasks_active[0]["description"] + " one", "start_date": "2016-06-01", "end_date": "2016-06-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-2": { "title": self.task_group_tasks_active[1]["title"] + " two", "description": self.task_group_tasks_active[1]["description"] + " two", "start_date": "2016-06-07", "end_date": "2016-06-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-3": { "title": self.task_group_tasks_active[2]["title"] + " three", "description": self.task_group_tasks_active[2]["description"] + " three", "start_date": "2016-06-13", "end_date": "2016-06-18", "finished_date": "None", "verified_date": "None", "status": "InProgress" }, "CYCLETASK-4": { "title": self.task_group_tasks_active[3]["title"] + " four", "description": self.task_group_tasks_active[3]["description"] + " four", "start_date": "2016-06-19", "end_date": "2016-06-24", "finished_date": "2016-07-19 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-5": { "title": self.task_group_tasks_active[4]["title"] + " five", "description": self.task_group_tasks_active[4]["description"] + " five", "start_date": "2016-06-25", "end_date": "2016-06-30", "finished_date": "2016-07-25 00:00:00", "verified_date": "2016-08-30 00:00:00", "status": "Verified" }, "CYCLETASK-6": { "title": self.task_group_tasks_historical[0]["title"] + " one", "description": self.task_group_tasks_historical[0]["description"] + " one", "start_date": "2014-04-01", "end_date": "2014-04-06", "finished_date": "2014-05-01 00:00:00", "verified_date": "2014-06-06 00:00:00", "status": "Assigned" }, "CYCLETASK-7": { "title": self.task_group_tasks_historical[1]["title"] + " two", "description": self.task_group_tasks_historical[1]["description"] + " two", "start_date": "2014-04-07", "end_date": "2014-04-12", "finished_date": "2014-05-07 00:00:00", "verified_date": "None", "status": "Declined" }, "CYCLETASK-8": { "title": self.task_group_tasks_historical[2]["title"] + " three", "description": self.task_group_tasks_historical[2]["description"] + " three", "start_date": "2014-04-13", "end_date": "2014-04-18", "finished_date": "2014-05-13 00:00:00", "verified_date": "2014-06-18 00:00:00", "status": "InProgress" }, "CYCLETASK-9": { "title": self.task_group_tasks_historical[3]["title"] + " four", "description": self.task_group_tasks_historical[3]["description"] + " four", "start_date": "2014-04-19", "end_date": "2014-04-24", "finished_date": "2014-05-19 00:00:00", "verified_date": "None", "status": "Finished" }, "CYCLETASK-10": { "title": self.task_group_tasks_historical[4]["title"] + " five", "description": self.task_group_tasks_historical[4]["description"] + " five", "start_date": "2014-04-25", "end_date": "2014-04-30", "finished_date": "2014-05-25 00:00:00", "verified_date": "2014-06-30 00:00:00", "status": "Verified" } } # Below is description of warning for non-importable columns. It is needed # for test_cycle_task_warnings. importable_column_names = [] for field_name in CycleTaskGroupObjectTask.IMPORTABLE_FIELDS: if field_name == 'slug': continue # pylint: disable=protected-access importable_column_names.append( CycleTaskGroupObjectTask._aliases.get(field_name, field_name)) self.expected_warnings = { 'Cycle Task Group Object Task': { 'block_warnings': { errors.ONLY_IMPORTABLE_COLUMNS_WARNING.format( line=2, columns=", ".join(importable_column_names)) }, } } # This is an error message which should be shown during # test_cycle_task_create_error test self.expected_create_error = { 'Cycle Task Group Object Task': { 'row_errors': {errors.CREATE_INSTANCE_ERROR.format(line=13)} } } # Below is expected date errors for test_cycle_task_date_error. They should # be shown during date validator's tests. self.expected_date_error = { 'Cycle Task Group Object Task': { 'row_errors': { errors.INVALID_START_END_DATES.format( line=3, start_date="Start Date", end_date="End Date", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=4, date="Actual Finish Date", status="not Finished", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=5, date="Actual Verified Date", status="not Verified", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=6, date="Actual Verified Date", status="not Verified", ), errors.INVALID_START_END_DATES.format( line=7, start_date="Actual Finish Date", end_date="Actual Verified Date", ), errors.INVALID_START_END_DATES.format( line=8, start_date="Start Date", end_date="End Date", ), errors.MISSING_VALUE_ERROR.format( line=9, column_name="Actual Finish Date", ), errors.INVALID_START_END_DATES.format( line=10, start_date="Actual Finish Date", end_date="Actual Verified Date", ), }, } } # Below is expected cycle-tasks data which should appear in test DB after # test_cycle_task_date_error run self.expected_cycle_task_date_error = dict() self.expected_cycle_task_date_error.update( self.generated_cycle_tasks_active) self.expected_cycle_task_date_error.update( self.generated_cycle_tasks_historical) self.expected_cycle_task_date_error["CYCLETASK-9"] = ( self.expected_cycle_task_correct["CYCLETASK-9"]) self.expected_cycle_task_date_error["CYCLETASK-10"] = ( self.expected_cycle_task_correct["CYCLETASK-10"]) # Expected error message which should be shown after # test_cycle_task_permission_error run self.expected_permission_error = { 'Cycle Task Group Object Task': { 'block_errors': {errors.PERMISSION_ERROR.format(line=2)} } }
class TestRecurringCycleNotifications(TestCase): def setUp(self): super(TestRecurringCycleNotifications, self).setUp() self.api = Api() self.generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() _, self.assignee = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def tearDown(self): pass def test_cycle_starts_in_less_than_X_days(self): with freeze_time("2015-02-01"): _, wf = self.generator.generate_workflow(self.quarterly_wf_1) response, wf = self.generator.activate_workflow(wf) self.assert200(response) assignee = Person.query.get(self.assignee.id) with freeze_time("2015-01-01"): _, notif_data = common.get_daily_notifications() self.assertNotIn(assignee.email, notif_data) with freeze_time("2015-01-29"): _, notif_data = common.get_daily_notifications() self.assertIn(assignee.email, notif_data) with freeze_time("2015-02-01"): _, notif_data = common.get_daily_notifications() self.assertIn(assignee.email, notif_data) # TODO: this should mock google email api. @patch("ggrc.notifications.common.send_email") def test_marking_sent_notifications(self, mail_mock): mail_mock.return_value = True with freeze_time("2015-02-01"): _, wf = self.generator.generate_workflow(self.quarterly_wf_1) response, wf = self.generator.activate_workflow(wf) self.assert200(response) assignee = Person.query.get(self.assignee.id) with freeze_time("2015-01-01"): _, notif_data = common.get_daily_notifications() self.assertNotIn(assignee.email, notif_data) with freeze_time("2015-01-29"): common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertNotIn(assignee.email, notif_data) with freeze_time("2015-02-01"): _, notif_data = common.get_daily_notifications() self.assertNotIn(assignee.email, notif_data) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.quarterly_wf_1 = { "title": "quarterly wf 1", "description": "", # admin will be current user with id == 1 "unit": "month", "repeat_every": 3, "notify_on_change": True, "task_groups": [{ "title": "tg_1", "contact": person_dict(self.assignee.id), "task_group_tasks": [{ "contact": person_dict(self.assignee.id), "description": factories.random_str(100), }, ], }, ] } self.all_workflows = [ self.quarterly_wf_1, ]
class TestCsvImport(TestCase): """Tests for import of multiple objects""" def setUp(self): super(TestCsvImport, self).setUp() self.generator = ObjectGenerator() self.client.get("/login") self.policy_data = [ collections.OrderedDict([ ("object_type", "Policy"), ("Code*", ""), ("Title*", "Policy-1"), ("Admin*", "*****@*****.**"), ]), collections.OrderedDict([ ("object_type", "Policy"), ("Code*", ""), ("Title*", "Policy-2"), ("Admin*", "*****@*****.**"), ]), ] self.org_group_data = [ collections.OrderedDict([("object_type", "OrgGroup"), ("Code*", ""), ("Title*", "OrgGroup-1"), ("Admin*", "*****@*****.**"), ("Assignee", "*****@*****.**"), ("Verifier", "*****@*****.**")]), ] self.product_data = [ collections.OrderedDict([("object_type", "Product"), ("Code*", ""), ("Title*", "Product-1"), ("Admin*", "*****@*****.**"), ("Assignee", "*****@*****.**"), ("Verifier", "*****@*****.**")]), ] def tearDown(self): pass def generate_people(self, people): for person in people: self.generator.generate_person( { "name": person, "email": "{}@reciprocitylabs.com".format(person), }, "Administrator") def test_multi_basic_policy_orggroup_product(self): """Tests for import of multiple objects, defined correctly""" test_data = self.product_data + self.org_group_data + self.policy_data responses = self.import_data(*test_data) object_counts = { "Org Group": (1, 0, 0), "Policy": (2, 0, 0), "Product": (1, 0, 0), } for response in responses: created, updated, ignored = object_counts[response["name"]] self.assertEqual(created, response["created"]) self.assertEqual(updated, response["updated"]) self.assertEqual(ignored, response["ignored"]) self.assertEqual(set(), set(response["row_warnings"])) self.assertEqual(Policy.query.count(), 2) self.assertEqual(OrgGroup.query.count(), 1) self.assertEqual(Product.query.count(), 1) def test_multi_basic_policy_orggroup_product_with_warnings(self): """Test multi basic policy orggroup product with warnings""" wrong_policy_data = self.policy_data + [ collections.OrderedDict([ ("object_type", "Policy"), ("Code*", ""), ("Title*", "Policy-1"), ("Admin*", "*****@*****.**"), ]) ] wrong_org_group_data = self.org_group_data + [ collections.OrderedDict([("object_type", "OrgGroup"), ("Code*", ""), ("Title*", "OrgGroup-1"), ("Admin*", ""), ("Assignee", "*****@*****.**"), ("Verifier", "*****@*****.**")]) ] wrong_product_data = self.product_data + [ collections.OrderedDict([("object_type", "Product"), ("Code*", ""), ("Title*", "Product-2"), ("Admin*", ""), ("Assignee", "*****@*****.**"), ("Verifier", "*****@*****.**")]) ] for org_grp in wrong_org_group_data: org_grp.pop("Admin*") test_data = wrong_product_data + wrong_org_group_data + wrong_policy_data responses = self.import_data(*test_data) row_messages = [] object_counts = { "Policy": (2, 0, 1), "Org Group": (0, 0, 2), "Product": (2, 0, 0), } for response in responses: created, updated, ignored = object_counts[response["name"]] self.assertEqual(created, response["created"]) self.assertEqual(updated, response["updated"]) self.assertEqual(ignored, response["ignored"]) row_messages.extend(response["row_warnings"]) row_messages.extend(response["row_errors"]) expected_warnings = set([ errors.DUPLICATE_VALUE_IN_CSV.format( line="9", processed_line="8", column_name="Title", value="OrgGroup-1", ), errors.DUPLICATE_VALUE_IN_CSV.format( line="15", processed_line="13", column_name="Title", value="Policy-1", ), errors.OWNER_MISSING.format(line=4, column_name="Admin"), errors.MISSING_COLUMN.format(line=8, column_names="Admin", s=""), ]) self.assertEqual(expected_warnings, set(row_messages)) self.assertEqual(Policy.query.count(), 2) self.assertEqual(OrgGroup.query.count(), 0) self.assertEqual(Product.query.count(), 2) def test_multi_basic_policy_orggroup_product_with_mappings(self): """Tests mapping of multiple objects""" def get_relationships_for(obj): return Relationship.query.filter( or_( and_(Relationship.source_id == obj.id, Relationship.source_type == obj.type), and_(Relationship.destination_id == obj.id, Relationship.destination_type == obj.type), )) test_data = self.org_group_data + self.product_data responses = self.import_data(*test_data) product1 = Product.query.first() org_grp1 = OrgGroup.query.first() mapped_policy_data = [ collections.OrderedDict([ ("object_type", "Policy"), ("Code*", ""), ("Title*", "Policy-1"), ("Admin*", "*****@*****.**"), ("map:product", product1.slug), ("map:Org group", org_grp1.slug), ]), collections.OrderedDict([ ("object_type", "Policy"), ("Code*", ""), ("Title*", "Policy-2"), ("Admin*", "*****@*****.**"), ("map:product", product1.slug), ("map:Org group", ""), ]), collections.OrderedDict([ ("object_type", "Policy"), ("Code*", ""), ("Title*", "Policy-3"), ("Admin*", "*****@*****.**"), ("map:product", ""), ("map:Org group", org_grp1.slug), ]), ] responses += self.import_data(*mapped_policy_data) object_counts = { "Policy": (3, 0, 0), "Org Group": (1, 0, 0), "Product": (1, 0, 0), } for response in responses: created, updated, ignored = object_counts[response["name"]] self.assertEqual(created, response["created"]) self.assertEqual(updated, response["updated"]) self.assertEqual(ignored, response["ignored"]) self.assertEqual(set(), set(response["row_warnings"])) self.assertEqual(Policy.query.count(), 3) self.assertEqual(OrgGroup.query.count(), 1) self.assertEqual(Product.query.count(), 1) policy1 = Policy.query.filter_by(title="Policy-1").first() policy2 = Policy.query.filter_by(title="Policy-2").first() policy3 = Policy.query.filter_by(title="Policy-3").first() self.assertEqual(get_relationships_for(product1).count(), 2) self.assertEqual(get_relationships_for(org_grp1).count(), 2) self.assertEqual(get_relationships_for(policy1).count(), 2) self.assertEqual(get_relationships_for(policy2).count(), 1) self.assertEqual(get_relationships_for(policy3).count(), 1)
class TestCycleStartFailed(TestCase): """ This class contains simple one time workflow tests that are not in the gsheet test grid """ def setUp(self): TestCase.setUp(self) self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() Notification.query.delete() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init Notification.__init__ = init_decorator(Notification.__init__) @patch("ggrc.notifications.common.send_email") def test_start_failed(self, mock_mail): wf_owner = "*****@*****.**" with freeze_time("2015-02-01 13:39:20"): _, wf = self.wf_generator.generate_workflow(self.quarterly_wf) response, wf = self.wf_generator.activate_workflow(wf) print wf.next_cycle_start_date self.assert200(response) with freeze_time("2015-01-01 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertNotIn(wf_owner, notif_data) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(wf_owner, notif_data) self.assertIn("cycle_starts_in", notif_data[wf_owner]) with freeze_time("2015-03-05 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(wf_owner, notif_data) self.assertNotIn("cycle_started", notif_data[wf_owner]) self.assertIn(wf_owner, notif_data) self.assertIn("cycle_start_failed", notif_data[wf_owner]) common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertNotIn(wf_owner, notif_data) # TODO: investigate why next_cycle_start date remains the same after # start_recurring_cycles # @patch("ggrc.notifications.common.send_email") # def test_start_failed_send_notifications(self, mock_mail): # wf_owner = "*****@*****.**" # with freeze_time("2015-02-01 13:39:20"): # _, wf = self.wf_generator.generate_workflow(self.quarterly_wf) # response, wf = self.wf_generator.activate_workflow(wf) # print wf.next_cycle_start_date # self.assert200(response) # with freeze_time("2015-01-01 13:39:20"): # _, notif_data = common.get_daily_notifications() # self.assertNotIn(wf_owner, notif_data) # with freeze_time("2015-01-29 13:39:20"): # _, notif_data = common.get_daily_notifications() # self.assertIn(wf_owner, notif_data) # self.assertIn("cycle_starts_in", notif_data[wf_owner]) # with freeze_time("2015-02-05 13:39:20"): # _, notif_data = common.get_daily_notifications() # self.assertIn(wf_owner, notif_data) # self.assertNotIn("cycle_started", notif_data[wf_owner]) # self.assertIn(wf_owner, notif_data) # self.assertIn("cycle_start_failed", notif_data[wf_owner]) # start_recurring_cycles() # _, notif_data = common.get_daily_notifications() # self.assertIn(wf_owner, notif_data) # self.assertIn("cycle_started", notif_data[wf_owner]) # self.assertIn(wf_owner, notif_data) # self.assertNotIn("cycle_start_failed", notif_data[wf_owner]) # common.send_daily_digest_notifications() # _, notif_data = common.get_daily_notifications() # self.assertNotIn(wf_owner, notif_data) # @patch("ggrc.notifications.common.send_email") # def test_start_failed_send_notifications_monthly(self, mock_mail): # wf_owner = "*****@*****.**" # with freeze_time("2015-05-12 13:39:20"): # _, wf = self.wf_generator.generate_workflow(self.monthly) # response, wf = self.wf_generator.activate_workflow(wf) # with freeze_time("2015-05-14 13:39:20"): # _, wf = self.wf_generator.generate_workflow(self.monthly) # response, wf = self.wf_generator.activate_workflow(wf) # self.assert200(response) # _, notif_data = common.get_daily_notifications() # self.assertIn(wf_owner, notif_data) # self.assertNotIn("cycle_started", notif_data[wf_owner]) # self.assertIn(wf_owner, notif_data) # self.assertIn("cycle_start_failed", notif_data[wf_owner]) # start_recurring_cycles() # _, notif_data = common.get_daily_notifications() # self.assertIn(wf_owner, notif_data) # self.assertIn("cycle_started", notif_data[wf_owner]) # self.assertIn(wf_owner, notif_data) # self.assertNotIn("cycle_start_failed", notif_data[wf_owner]) # common.send_daily_digest_notifications() # _, notif_data = common.get_daily_notifications() # self.assertNotIn(wf_owner, notif_data) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.quarterly_wf = { "title": "quarterly wf forced notifications", "notify_on_change": True, "description": "", "owners": [person_dict(self.user.id)], "frequency": "quarterly", "task_groups": [ { "title": "tg_1", "contact": person_dict(self.user.id), "task_group_tasks": [ { "contact": person_dict(self.user.id), "description": self.wf_generator.random_str(100), "relative_start_day": 5, "relative_start_month": 2, "relative_end_day": 25, "relative_end_month": 2, }, ], }, ] } self.monthly = { "title": "monthly", "notify_on_change": True, "description": "", "owners": [person_dict(self.user.id)], "frequency": "monthly", "task_groups": [ { "title": "tg_1", "contact": person_dict(self.user.id), "task_group_tasks": [ { "contact": person_dict(self.user.id), "description": self.wf_generator.random_str(100), "relative_start_day": 14, "relative_end_day": 25, }, ], }, ] }
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): """Only admin can use admin section""" for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup", "Metric" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post( model, { table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # ignored except for Document "contact": { "type": "Person", "id": self.users["reader"].id, }, }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": { "title": "reader Policy", "context": None }, }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): """Check if reader can't create mappings""" self.generator.api.set_user(self.users["admin"]) _, control = self.generator.generate(all_models.Control, "control", { "control": { "title": "Test Control", "context": None }, }) self.generator.api.set_user(self.users['reader']) _, program = self.generator.generate(all_models.Program, "program", { "program": { "title": "Test Program", "context": None }, }) response, _ = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "destination": { "id": program.id, "type": "Program" }, "source": { "id": control.id, "type": "Control" }, "context": { "id": program.context.id, "type": "context" } }, }) self.assertEqual(response.status_code, 403) @ddt.data("creator", "reader") def test_unmap_people(self, user_role): """Test that global reader/creator can't unmap people from program""" user = self.users[user_role] with factories.single_commit(): program = factories.ProgramFactory() mapped_person = factories.ObjectPersonFactory( personable=program, person=user, context=program.context) self.api.set_user(user) db.session.add(mapped_person) response = self.api.delete(mapped_person) self.assertEqual(response.status_code, 403) def test_read_evidence_revision(self): """Global Read can read Evidence revision content""" user = self.users["reader"] link = "google.com" evidence = factories.EvidenceUrlFactory(link=link) evidence_id = evidence.id self.api.set_user(user) resp = self.api.client.get( "/api/revisions?resource_type={}&resource_id={}".format( evidence.type, evidence_id)) rev_content = resp.json["revisions_collection"]["revisions"][0][ "content"] self.assertTrue(rev_content) self.assertEquals(link, rev_content["link"])
class TestTaskOverdueNotificationsUsingAPI(TestTaskOverdueNotifications): """Tests for overdue notifications when changing Tasks with an API.""" # pylint: disable=invalid-name def setUp(self): super(TestTaskOverdueNotificationsUsingAPI, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() models.Notification.query.delete() self._fix_notification_init() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self._create_test_cases() @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_sending_overdue_notifications_for_tasks(self, is_vf_needed, _): """Overdue notifications should be sent for overdue tasks every day. Even if an overdue notification has already been sent, it should still be sent in every following daily digest f a task is still overdue. """ with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1_id = tasks[0].id task2_id = tasks[1].id user = models.Person.query.get(self.user.id) with freeze_time("2017-05-14 08:09:10"): _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) with freeze_time("2017-05-15 08:09:10"): # task 1 due date _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) with freeze_time("2017-05-16 08:09:10"): # task 2 due date _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) overdue_task_ids = sorted(user_notifs["task_overdue"].keys()) self.assertEqual(overdue_task_ids, [task1_id]) with freeze_time("2017-05-17 08:09:10"): # after both tasks' due dates _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) overdue_task_ids = sorted(user_notifs["task_overdue"].keys()) self.assertEqual(overdue_task_ids, [task1_id, task2_id]) common.send_daily_digest_notifications() # even after sending the overdue notifications, they are sent again the # day after, too with freeze_time("2017-05-18 08:09:10"): _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) overdue_task_ids = sorted(user_notifs["task_overdue"].keys()) self.assertEqual(overdue_task_ids, [task1_id, task2_id]) @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_adjust_overdue_notifications_on_task_due_date_change(self, is_vf_needed, _): """Sending overdue notifications should adjust to task due date changes.""" with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1, task2 = tasks self.wf_generator.modify_object(task2, {"end_date": date(2099, 12, 31)}) user = models.Person.query.get(self.user.id) with freeze_time("2017-05-16 08:09:10"): # a day after task1 due date _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) # change task1 due date, there should be no overdue notification anymore self.wf_generator.modify_object(task1, {"end_date": date(2017, 5, 16)}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) # change task1 due date to the past there should a notification again self.wf_generator.modify_object(task1, {"end_date": date(2017, 5, 14)}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_adjust_overdue_notifications_on_task_status_change(self, is_vf_needed, _): """Sending overdue notifications should take task status into account.""" with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1, task2 = tasks self.wf_generator.modify_object(task2, {"end_date": date(2099, 12, 31)}) user = models.Person.query.get(self.user.id) user_email = user.email if is_vf_needed: non_final_states = [CycleTaskGroupObjectTask.ASSIGNED, CycleTaskGroupObjectTask.IN_PROGRESS, CycleTaskGroupObjectTask.FINISHED, CycleTaskGroupObjectTask.DECLINED] final_state = CycleTaskGroupObjectTask.VERIFIED else: non_final_states = [CycleTaskGroupObjectTask.ASSIGNED, CycleTaskGroupObjectTask.IN_PROGRESS] final_state = CycleTaskGroupObjectTask.FINISHED with freeze_time("2017-05-16 08:09:10"): # a day after task1 due date for state in non_final_states: # clear all notifications before before changing the task status models.Notification.query.delete() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) self.wf_generator.modify_object(task1, {"status": state}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) # WITHOUT clearing the overdue notifications, move the task to "verified" # state, and the overdue notification should disappear. self.wf_generator.modify_object(task1, {"status": final_state}) _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertNotIn("task_overdue", user_notifs) @ddt.data(True, False) @patch("ggrc.notifications.common.send_email") def test_stop_sending_overdue_notification_if_task_gets_deleted(self, is_vf_needed, _): """Overdue notifications should not be sent for deleted tasks.""" with freeze_time("2017-05-15 14:25:36"): tmp = self.one_time_workflow.copy() tmp['is_verification_needed'] = is_vf_needed _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) tasks = workflow.cycles[0].cycle_task_group_object_tasks task1, task2 = tasks user = models.Person.query.get(self.user.id) user_email = user.email with freeze_time("2017-10-16 08:09:10"): # long after both task due dates _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 2) db.session.delete(task2) db.session.commit() _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user_email, {}) self.assertIn("task_overdue", user_notifs) self.assertEqual(len(user_notifs["task_overdue"]), 1) db.session.delete(task1) db.session.commit() _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) self.assertNotIn("task_overdue", user_notifs) def _create_test_cases(self): """Create configuration to use for generating a new workflow.""" def person_dict(person_id): return { "href": "/api/people/" + str(person_id), "id": person_id, "type": "Person" } role_id = models.all_models.AccessControlRole.query.filter( models.all_models.AccessControlRole.name == "Task Assignees", models.all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id self.one_time_workflow = { "title": "one time test workflow", "notify_on_change": True, "description": "some test workflow", "owners": [person_dict(self.user.id)], "task_groups": [{ "title": "one time task group", "contact": person_dict(self.user.id), "task_group_tasks": [{ "title": "task 1", "description": "some task", "start_date": date(2017, 5, 5), # Friday "end_date": date(2017, 5, 15), "access_control_list": [{ "person": {"id": self.user.id, }, "ac_role_id": role_id, }], }, { "title": "task 2", "description": "some task 2", "start_date": date(2017, 5, 5), # Friday "end_date": date(2017, 5, 16), "access_control_list": [{ "person": {"id": self.user.id, }, "ac_role_id": role_id, }], }], "task_group_objects": self.random_objects }] }
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 TestOneTimeWorkflowNotification(TestCase): """ Tests are defined in the g-sheet test grid under: WF EMAILS for unit tests (middle level) """ def setUp(self): super(TestOneTimeWorkflowNotification, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() self.random_objects = self.object_generator.generate_random_objects() self.random_people = [ self.object_generator.generate_person(user_role="Administrator")[1] for _ in range(5) ] self.create_test_cases() self.create_users() db.session.query(Notification).delete() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init Notification.__init__ = init_decorator(Notification.__init__) def tearDown(self): db.session.query(Notification).delete() def short_dict(self, obj, plural): return { "href": "/api/%s/%d" % (plural, obj.id), "id": obj.id, "type": obj.__class__.__name__, } def setup_cycle_tasks(self): """Prepare environment with couple of active cycle tasks.""" with freeze_time("2018-11-01"): _, workflow = self.wf_generator.generate_workflow( self.one_time_workflow_1) self.wf_generator.generate_cycle(workflow) self.wf_generator.activate_workflow(workflow) return all_models.CycleTaskGroupObjectTask.query def assert_nofication_sent_with(self, text): """Assert if text exists in sent notification.""" with mock.patch("ggrc.notifications.common.send_email") as send_email: self.client.get("/_notifications/send_daily_digest") _, _, content = send_email.call_args[0] self.assertIn(text, content) def assert_nofication_sent_without(self, text): """Assert if text doesn't exist in sent notification.""" with mock.patch("ggrc.notifications.common.send_email") as send_email: self.client.get("/_notifications/send_daily_digest") _, _, content = send_email.call_args[0] self.assertNotIn(text, content) def test_one_time_wf(self): # setup with freeze_time("2015-04-07 03:21:34"): wf_response, wf = self.wf_generator.generate_workflow( data={ # admin will be the current user "notify_on_change": True, # force real time updates "title": "One-time WF", "notify_custom_message": textwrap.dedent("""\ Hi all. Did you know that Irelnd city namd Newtownmountkennedy has 19 letters? But it's not the longest one. The recordsman is the city in New Zealand that contains 97 letter."""), }) _, tg = self.wf_generator.generate_task_group( wf, data={ "title": "TG #1 for the One-time WF", "contact": self.short_dict(self.tgassignee1, "people"), }) self.wf_generator.generate_task_group_task( tg, { "title": "task #1 for one-time workflow", "contact": self.short_dict(self.member1, "people"), "start_date": "04/07/2015", "end_date": "04/15/2015", }) self.wf_generator.generate_task_group_object( tg, self.random_objects[0]) self.wf_generator.generate_task_group_object( tg, self.random_objects[1]) # test with freeze_time("2015-04-07 03:21:34"): cycle_response, cycle = self.wf_generator.generate_cycle(wf) self.wf_generator.activate_workflow(wf) common.get_daily_notifications() def test_deprecated_ct_acl_update(self): """Test if acl update for deprecated CT will not create notification.""" cycle_task = self.setup_cycle_tasks().first() cycle_task_title = cycle_task.title response = self.api.put(cycle_task, {"status": "Deprecated"}) self.assert200(response) self.assert_nofication_sent_without(cycle_task_title) task_assignee = all_models.AccessControlRole.query.filter_by( name="Task Assignees", object_type="CycleTaskGroupObjectTask", ).first() person = self.object_generator.generate_person(user_role="Creator")[1] response = self.api.put( cycle_task, { "access_control_list": [{ "ac_role_id": task_assignee.id, "person": { "id": person.id, "type": "Person", } }] }) self.assert200(response) self.assert_nofication_sent_without(cycle_task_title) def test_restore_deprecated_ct(self): """Test notifications for CT which was restored from Deprecated.""" cycle_task = self.setup_cycle_tasks().first() cycle_task_title = cycle_task.title self.assert_nofication_sent_with(cycle_task_title) response = self.api.put(cycle_task, {"status": "Deprecated"}) self.assert200(response) self.assert_nofication_sent_without(cycle_task_title) response = self.api.put(cycle_task, {"status": "Assigned"}) self.assert200(response) self.assert_nofication_sent_with(cycle_task_title) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.one_time_workflow_1 = { "title": "one time test workflow", "description": "some test workflow", # admin will be current user with id == 1 "task_groups": [ { "title": "one time task group", "task_group_tasks": [ { "title": "task_{}".format(str(uuid.uuid4())), "description": "some task", "contact": person_dict(self.random_people[0].id), "start_date": date(2015, 5, 1), # friday "end_date": date(2015, 5, 5), }, { "title": "task_{}".format(str(uuid.uuid4())), "description": "some task", "contact": person_dict(self.random_people[1].id), "start_date": date(2015, 5, 4), "end_date": date(2015, 5, 7), } ], "task_group_objects": self.random_objects[:2] }, { "title": "another one time task group", "task_group_tasks": [ { "title": "task_{}".format(str(uuid.uuid4())), "description": "some task", "contact": person_dict(self.random_people[0].id), "start_date": date(2015, 5, 8), # friday "end_date": date(2015, 5, 12), }, { "title": "task_{}".format(str(uuid.uuid4())), "description": "some task", "contact": person_dict(self.random_people[2].id), "start_date": date(2015, 5, 1), # friday "end_date": date(2015, 5, 5), } ], "task_group_objects": [] } ] } def create_users(self): _, self.admin1 = self.object_generator.generate_person( # data={"name": "User1 Admin1", "email": "*****@*****.**"}, user_role="Administrator") _, self.tgassignee1 = self.object_generator.generate_person( # data={"name": "User2 TGassignee1", # "email": "*****@*****.**"}, user_role="Administrator") _, self.member1 = self.object_generator.generate_person( # data={"name": "User3 Member1", "email": "*****@*****.**"}, user_role="Administrator") _, self.member2 = self.object_generator.generate_person( # data={"name": "User4 Member2", "email": "*****@*****.**"}, user_role="Administrator")
class TestNotificationsForDeletedObjects(TestCase): """ This class contains simple one time workflow tests that are not in the gsheet test grid """ def setUp(self): TestCase.setUp(self) self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() Notification.query.delete() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init Notification.__init__ = init_decorator(Notification.__init__) @patch("ggrc.notifications.common.send_email") def test_delete_activated_workflow(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, workflow = self.wf_generator.generate_workflow(self.quarterly_wf_1) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) user = Person.query.get(self.user.id) with freeze_time("2015-01-01 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertNotIn(user.email, notif_data) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("cycle_starts_in", notif_data[user.email]) workflow = Workflow.query.get(workflow.id) response = self.wf_generator.api.delete(workflow) self.assert200(response) _, notif_data = common.get_daily_notifications() user = Person.query.get(self.user.id) self.assertNotIn(user.email, notif_data) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.quarterly_wf_1 = { "title": "quarterly wf 1", "notify_on_change": True, "description": "", "owners": [person_dict(self.user.id)], "frequency": "quarterly", "task_groups": [{ "title": "tg_1", "contact": person_dict(self.user.id), "task_group_tasks": [{ "contact": person_dict(self.user.id), "description": factories.random_str(100), "relative_start_day": 5, "relative_start_month": 2, "relative_end_day": 25, "relative_end_month": 2, }, ], }, ] }
class TestAccessControlRole(TestCase): """TestAccessControlRole""" def setUp(self): self.clear_data() super(TestAccessControlRole, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.people = {} for name in ["Creator", "Reader", "Editor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role=name) self.people[name] = user def _post_role(self, name=None, object_type="Control"): """Helper function for POSTing roles""" if name is None: name = random_str(prefix="Access Control Role - ") return self.api.post(AccessControlRole, { "access_control_role": { "name": name, "object_type": object_type, "context": None, "read": True }, }) def test_create_after_objects(self): """Test eager creation of ACLs on existing objects with new ACR.""" risk_id = factories.RiskFactory().id role_name = "New Custom Role" self._post_role(name=role_name, object_type="Risk") risk = all_models.Risk.query.get(risk_id) self.assertIn(role_name, risk.acr_name_acl_map.keys()) self.assertIsNotNone(risk.acr_name_acl_map[role_name]) def test_create(self): """Test Access Control Role creation""" response = self._post_role(object_type="Risk") assert response.status_code == 201, \ "Failed to create a new access control role, response was {}".format( response.status) id_ = response.json['access_control_role']['id'] role = AccessControlRole.query.filter(AccessControlRole.id == id_).first() assert role.read == 1, \ "Read permission not correctly saved {}".format(role.read) assert role.update == 1, \ "Update permission not correctly saved {}".format(role.update) assert role.delete == 1, \ "Update permission not correctly saved {}".format(role.delete) @ddt.data( {"mandatory": True, "exp_response": MANDATORY_ROLE_RESPONSE}, {"mandatory": False, "exp_response": NON_MANDATORY_ROLE_RESPONSE}, ) @ddt.unpack def test_mandatory_delete(self, mandatory, exp_response): """Test set empty field via import if acr mandatory is {mandatory}""" role = factories.AccessControlRoleFactory( name=ROLE_NAME, object_type="Risk", mandatory=mandatory, ) with factories.single_commit(): user = factories.PersonFactory() risk = factories.RiskFactory() role_id = role.id factories.AccessControlPersonFactory( ac_list=risk.acr_name_acl_map[ROLE_NAME], person=user, ) response = self.import_data(OrderedDict([ ("object_type", "Risk"), ("Code*", risk.slug), (ROLE_NAME, "--"), ])) self._check_csv_response(response, exp_response) db_data = defaultdict(set) risk = all_models.Risk.query.get(risk.id) for person, acl in risk.access_control_list: db_data[acl.ac_role_id].add(person.id) if mandatory: cur_user = all_models.Person.query.filter_by( email="*****@*****.**").first() self.assertEqual(set([cur_user.id]), db_data[role_id]) else: self.assertFalse(db_data[role_id]) def test_only_admin_can_post(self): """Only admin users should be able to POST access control roles""" for name in ("Creator", "Reader", "Editor"): person = self.people.get(name) self.api.set_user(person) response = self._post_role() assert response.status_code == 403, \ "Non admins should get forbidden error when POSTing role. {}".format( response.status) @ddt.data( ("name", "New ACR"), ("read", False), ("mandatory", False), ("non_editable", False), ) @ddt.unpack def test_modify_non_editable_role(self, field_name, field_value): """Test if user can modify non-editable role""" # Primary Contacts role of Control is non-editable ac_role = AccessControlRole.query.filter_by( object_type="Control", name="Control Operators", ).first() response = self.api.put(ac_role, {field_name: field_value}) assert response.status_code == 403, \ "Forbidden error should be thrown when non-editable " \ "role {} updated.".format(ac_role.name) def test_delete_non_editable_role(self): """Test if user can delete non-editable role""" # Primary Contacts role of Control is non-editable ac_role = AccessControlRole.query.filter_by( object_type="Control", name="Control Operators", ).first() response = self.api.delete(ac_role) assert response.status_code == 403, \ "Forbidden error should be thrown when non-editable " \ "role {} deleted.".format(ac_role.name) @ddt.data("Control") def test_create_from_ggrcq(self, object_type): """Test that create action only for GGRCQ.""" with self.api.as_external(): response = self._post_role(object_type=object_type) self.assertEqual(response.status_code, 201) @ddt.data("Control") def test_create_from_ggrc(self, object_type): """Test create action not allowed for GGRC.""" response = self._post_role(object_type=object_type) self.assertEqual(response.status_code, 405) @ddt.data("Control") def test_modify_from_ggrcq(self, object_type): """Test that modify action only for GGRCQ.""" with factories.single_commit(): acr_id = factories.AccessControlRoleFactory(object_type=object_type).id with self.api.as_external(): acr = all_models.AccessControlRole.query.get(acr_id) response = self.api.put(acr, {"name": "new acr"}) self.assertEqual(response.status_code, 200) @ddt.data("Control") def test_modify_from_ggrc(self, object_type): """Test modify action not allowed for GGRC.""" with factories.single_commit(): acr = factories.AccessControlRoleFactory(object_type=object_type) response = self.api.put(acr, {"name": "new acr"}) self.assertEqual(response.status_code, 405) @ddt.data("Control") def test_delete_from_ggrcq(self, object_type): """Test that modify action only for GGRCQ.""" with factories.single_commit(): acr_id = factories.AccessControlRoleFactory(object_type=object_type).id with self.api.as_external(): acr = all_models.AccessControlRole.query.get(acr_id) response = self.api.delete(acr) self.assertEqual(response.status_code, 200) @ddt.data("Control") def test_delete_from_ggrc(self, object_type): """Test modify action not allowed for GGRC.""" with factories.single_commit(): acr = factories.AccessControlRoleFactory(object_type=object_type) response = self.api.delete(acr) self.assertEqual(response.status_code, 405)
class TestCsvImport(TestCase): def setUp(self): super(TestCsvImport, self).setUp() self.generator = ObjectGenerator() self.client.get("/login") def tearDown(self): pass def generate_people(self, people): for person in people: self.generator.generate_person({ "name": person, "email": "{}@reciprocitylabs.com".format(person), }, "Administrator") def test_multi_basic_policy_orggroup_product(self): filename = "multi_basic_policy_orggroup_product.csv" response_json = self.import_file(filename) object_counts = { "Org Group": (4, 0, 0), "Policy": (4, 0, 0), "Product": (5, 0, 0), } for row in response_json: created, updated, ignored = object_counts[row["name"]] self.assertEqual(created, row["created"]) self.assertEqual(updated, row["updated"]) self.assertEqual(ignored, row["ignored"]) self.assertEqual(set(), set(row["row_warnings"])) self.assertEqual(Policy.query.count(), 4) self.assertEqual(OrgGroup.query.count(), 4) self.assertEqual(Product.query.count(), 5) def test_multi_basic_policy_orggroup_product_with_warnings(self): filename = "multi_basic_policy_orggroup_product_with_warnings.csv" response_json = self.import_file(filename) row_messages = [] object_counts = { "Policy": (3, 0, 2), "Org Group": (0, 0, 4), "Product": (5, 0, 2), } for row in response_json: created, updated, ignored = object_counts[row["name"]] self.assertEqual(created, row["created"]) self.assertEqual(updated, row["updated"]) self.assertEqual(ignored, row["ignored"]) row_messages.extend(row["row_warnings"]) row_messages.extend(row["row_errors"]) expected_warnings = set([ errors.DUPLICATE_VALUE_IN_CSV.format( line_list="5, 6", column_name="Title", value="dolor", s="", ignore_lines="6"), errors.DUPLICATE_VALUE_IN_CSV.format( line_list="6, 7", column_name="Code", value="p-4", s="", ignore_lines="7"), errors.DUPLICATE_VALUE_IN_CSV.format( line_list="21, 26", column_name="Title", value="meatloaf", s="", ignore_lines="26"), errors.DUPLICATE_VALUE_IN_CSV.format( line_list="21, 26, 27", column_name="Code", value="pro 1", s="s", ignore_lines="26, 27"), errors.OWNER_MISSING.format(line=26, column_name="Owner"), errors.MISSING_COLUMN.format(line=13, column_names="Owner", s=""), errors.MISSING_COLUMN.format(line=14, column_names="Owner", s=""), errors.MISSING_COLUMN.format(line=15, column_names="Owner", s=""), errors.MISSING_COLUMN.format(line=16, column_names="Owner", s=""), ]) self.assertEqual(expected_warnings, set(row_messages)) self.assertEqual(Policy.query.count(), 3) self.assertEqual(OrgGroup.query.count(), 0) self.assertEqual(Product.query.count(), 5) def test_multi_basic_policy_orggroup_product_with_mappings(self): def get_relationships_for(obj): return Relationship.query.filter(or_( and_(Relationship.source_id == obj.id, Relationship.source_type == obj.type), and_(Relationship.destination_id == obj.id, Relationship.destination_type == obj.type), )) filename = "multi_basic_policy_orggroup_product_with_mappings.csv" response_json = self.import_file(filename) object_counts = { "Policy": (4, 0, 0), "Org Group": (4, 0, 0), "Product": (5, 0, 0), } for row in response_json: created, updated, ignored = object_counts[row["name"]] self.assertEqual(created, row["created"]) self.assertEqual(updated, row["updated"]) self.assertEqual(ignored, row["ignored"]) self.assertEqual(set(), set(row["row_warnings"])) self.assertEqual(Policy.query.count(), 4) self.assertEqual(OrgGroup.query.count(), 4) self.assertEqual(Product.query.count(), 5) p1 = Policy.query.filter_by(slug="p-1").first() org1 = OrgGroup.query.filter_by(slug="org-1").first() self.assertEqual(get_relationships_for(p1).count(), 3) self.assertEqual(get_relationships_for(org1).count(), 5) def test_big_import_with_mappings(self): response = self.import_file("data_for_export_testing.csv") self._check_csv_response(response, {})
class TestEnableAndDisableNotifications(TestCase): """ This class contains simple one time workflow tests that are not in the gsheet test grid """ def setUp(self): super(TestEnableAndDisableNotifications, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() models.Notification.query.delete() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init models.Notification.__init__ = init_decorator(models.Notification.__init__) @patch("ggrc.notifications.common.send_email") def test_default_notifications_settings(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, wf = self.wf_generator.generate_workflow(self.quarterly_wf) response, wf = self.wf_generator.activate_workflow(wf) self.assert200(response) user = models.Person.query.get(self.user.id) with freeze_time("2015-01-01 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertNotIn(user.email, notif_data) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) @patch("ggrc.notifications.common.send_email") def test_disabled_notifications(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, wf = self.wf_generator.generate_workflow(self.quarterly_wf) response, wf = self.wf_generator.activate_workflow(wf) self.assert200(response) self.object_generator.generate_notification_setting( self.user.id, "Email_Digest", False) user = models.Person.query.get(self.user.id) with freeze_time("2015-01-01 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertNotIn(user.email, notif_data) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertNotIn(user.email, notif_data) @patch("ggrc.notifications.common.send_email") def test_enabled_notifications(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, wf = self.wf_generator.generate_workflow(self.quarterly_wf) response, wf = self.wf_generator.activate_workflow(wf) self.assert200(response) with freeze_time("2015-01-29 13:39:20"): user = models.Person.query.get(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.object_generator.generate_notification_setting( self.user.id, "Email_Digest", True) user = models.Person.query.get(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) @patch("ggrc.notifications.common.send_email") def test_forced_notifications(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, wf = self.wf_generator.generate_workflow(self.quarterly_wf_forced) response, wf = self.wf_generator.activate_workflow(wf) self.assert200(response) user = models.Person.query.get(self.user.id) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.object_generator.generate_notification_setting( self.user.id, "Email_Digest", True) user = models.Person.query.get(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) @patch("ggrc.notifications.common.send_email") def test_force_one_wf_notifications(self, mock_mail): with freeze_time("2015-02-01 13:39:20"): _, wf_forced = self.wf_generator.generate_workflow( self.quarterly_wf_forced) response, wf_forced = self.wf_generator.activate_workflow(wf_forced) _, wf = self.wf_generator.generate_workflow(self.quarterly_wf) response, wf = self.wf_generator.activate_workflow(wf) self.assert200(response) user = models.Person.query.get(self.user.id) with freeze_time("2015-01-29 13:39:20"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("cycle_starts_in", notif_data[user.email]) self.assertIn(wf_forced.id, notif_data[user.email]["cycle_starts_in"]) self.assertIn(wf.id, notif_data[user.email]["cycle_starts_in"]) self.object_generator.generate_notification_setting( self.user.id, "Email_Digest", False) user = models.Person.query.get(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("cycle_starts_in", notif_data[user.email]) self.assertIn(wf_forced.id, notif_data[user.email]["cycle_starts_in"]) self.assertNotIn(wf.id, notif_data[user.email]["cycle_starts_in"]) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.quarterly_wf_forced = { "title": "quarterly wf forced notifications", "notify_on_change": True, "description": "", # admin will be current user with id == 1 "unit": "month", "repeat_every": 3, "task_groups": [{ "title": "tg_1", "contact": person_dict(self.user.id), "task_group_tasks": [{ "contact": person_dict(self.user.id), "description": factories.random_str(100), }, ], }, ] } self.quarterly_wf = { "title": "quarterly wf 1", "description": "", # admin will be current user with id == 1 "unit": "month", "repeat_every": 3, "task_groups": [{ "title": "tg_1", "contact": person_dict(self.user.id), "task_group_tasks": [{ "contact": person_dict(self.user.id), "description": factories.random_str(100), }, ], }, ] }
class TestOneTimeWfEndDateChange(TestCase): """ This class contains simple one time workflow tests that are not in the gsheet test grid """ def setUp(self): super(TestOneTimeWfEndDateChange, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() Notification.query.delete() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init Notification.__init__ = init_decorator(Notification.__init__) @patch("ggrc.notifications.common.send_email") def test_no_date_change(self, mock_mail): def get_person(person_id): return db.session.query(Person).filter(Person.id == person_id).one() with freeze_time("2015-04-10 03:21:34"): _, workflow = self.wf_generator.generate_workflow( self.one_time_workflow_1) _, cycle = self.wf_generator.generate_cycle(workflow) self.wf_generator.activate_workflow(workflow) with freeze_time("2015-04-11 03:21:34"): user = get_person(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn("cycle_started", notif_data[user.email]) with freeze_time("2015-05-02 03:21:34"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("cycle_started", notif_data[user.email]) self.assertNotIn("due_in", notif_data[user.email]) self.assertNotIn("due_today", notif_data[user.email]) with freeze_time("2015-05-02 03:21:34"): common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) # one email to owner and one to assigne self.assertEqual(mock_mail.call_count, 2) with freeze_time("2015-05-04 03:21:34"): # one day before due date _, notif_data = common.get_daily_notifications() user = get_person(self.user.id) self.assertIn("due_in", notif_data[user.email]) self.assertEqual(len(notif_data[user.email]["due_in"]), 2) with freeze_time("2015-05-04 03:21:34"): # one day before due date common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) # one email to owner and one to assigne self.assertEqual(mock_mail.call_count, 3) with freeze_time("2015-05-05 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertIn("due_today", notif_data[user.email]) self.assertEqual(len(notif_data[user.email]["due_today"]), 2) @patch("ggrc.notifications.common.send_email") def test_move_end_date_to_future(self, mock_mail): """ test moving the end date to the future, befor due_in and due_today notifications have been sent """ def get_person(person_id): return db.session.query(Person).filter(Person.id == person_id).one() with freeze_time("2015-04-10 03:21:34"): _, workflow = self.wf_generator.generate_workflow( self.one_time_workflow_1) _, cycle = self.wf_generator.generate_cycle(workflow) self.wf_generator.activate_workflow(workflow) with freeze_time("2015-04-11 03:21:34"): user = get_person(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn("cycle_started", notif_data[user.email]) with freeze_time("2015-05-02 03:21:34"): _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("cycle_started", notif_data[user.email]) self.assertNotIn("due_in", notif_data[user.email]) self.assertNotIn("due_today", notif_data[user.email]) with freeze_time("2015-05-02 03:21:34"): common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) # one email to owner and one to assigne self.assertEqual(mock_mail.call_count, 2) with freeze_time("2015-05-03 03:21:34"): cycle = Cycle.query.get(cycle.id) task1 = CycleTaskGroupObjectTask.query.get( cycle.cycle_task_group_object_tasks[0].id) task2 = CycleTaskGroupObjectTask.query.get( cycle.cycle_task_group_object_tasks[1].id) self.wf_generator.modify_object( task1, data={"end_date": date(2015, 5, 15)}) self.wf_generator.modify_object( task2, data={"end_date": date(2015, 5, 15)}) with freeze_time("2015-05-04 03:21:34"): # one day befor due date _, notif_data = common.get_daily_notifications() user = get_person(self.user.id) self.assertEqual(notif_data, {}) with freeze_time("2015-05-05 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) with freeze_time("2015-05-14 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("due_in", notif_data[user.email]) self.assertEqual(len(notif_data[user.email]["due_in"]), len(self.random_objects)) with freeze_time("2015-05-15 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) # yesterdays mail has not been sent self.assertIn("due_in", notif_data[user.email]) self.assertIn("due_today", notif_data[user.email]) self.assertEqual(len(notif_data[user.email]["due_today"]), len(self.random_objects)) @patch("ggrc.notifications.common.send_email") def test_move_end_date_to_past(self, mock_mail): def get_person(person_id): return db.session.query(Person).filter(Person.id == person_id).one() with freeze_time("2015-04-10 03:21:34"): _, workflow = self.wf_generator.generate_workflow( self.one_time_workflow_1) _, cycle = self.wf_generator.generate_cycle(workflow) self.wf_generator.activate_workflow(workflow) with freeze_time("2015-05-02 03:21:34"): common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) # one email to owner and one to assigne self.assertEqual(mock_mail.call_count, 2) with freeze_time("2015-05-03 03:21:34"): cycle = Cycle.query.get(cycle.id) task1 = CycleTaskGroupObjectTask.query.get( cycle.cycle_task_group_object_tasks[0].id) task2 = CycleTaskGroupObjectTask.query.get( cycle.cycle_task_group_object_tasks[1].id) self.wf_generator.modify_object( task1, data={"end_date": date(2015, 5, 1)}) self.wf_generator.modify_object( task2, data={"end_date": date(2015, 5, 1)}) with freeze_time("2015-05-03 03:21:34"): # one day befor due date _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) with freeze_time("2015-05-04 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) with freeze_time("2015-05-05 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) @patch("ggrc.notifications.common.send_email") def test_move_end_date_to_today(self, mock_mail): def get_person(person_id): return db.session.query(Person).filter(Person.id == person_id).one() with freeze_time("2015-04-10 03:21:34"): _, workflow = self.wf_generator.generate_workflow( self.one_time_workflow_1) _, cycle = self.wf_generator.generate_cycle(workflow) self.wf_generator.activate_workflow(workflow) with freeze_time("2015-05-02 03:21:34"): common.send_daily_digest_notifications() _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) # one email to owner and one to assigne self.assertEqual(mock_mail.call_count, 2) with freeze_time("2015-05-03 03:21:34"): cycle = Cycle.query.get(cycle.id) task1 = CycleTaskGroupObjectTask.query.get( cycle.cycle_task_group_object_tasks[0].id) task2 = CycleTaskGroupObjectTask.query.get( cycle.cycle_task_group_object_tasks[1].id) self.wf_generator.modify_object( task1, data={"end_date": date(2015, 5, 3)}) self.wf_generator.modify_object( task2, data={"end_date": date(2015, 5, 4)}) with freeze_time("2015-05-03 03:21:34"): # one day befor due date user = get_person(self.user.id) _, notif_data = common.get_daily_notifications() self.assertNotEquals(notif_data, {}) self.assertIn(user.email, notif_data) self.assertIn("due_today", notif_data[user.email]) self.assertIn("due_in", notif_data[user.email]) self.assertEqual(len(notif_data[user.email]["due_today"]), 1) common.send_daily_digest_notifications() with freeze_time("2015-05-04 03:21:34"): # due date user = get_person(self.user.id) _, notif_data = common.get_daily_notifications() self.assertIn(user.email, notif_data) self.assertIn("due_today", notif_data[user.email]) self.assertNotIn("due_in", notif_data[user.email]) common.send_daily_digest_notifications() with freeze_time("2015-05-05 03:21:34"): # due date _, notif_data = common.get_daily_notifications() self.assertEqual(notif_data, {}) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.one_time_workflow_1 = { "title": "one time test workflow", "notify_on_change": True, "description": "some test workflow", "owners": [person_dict(self.user.id)], "task_groups": [{ "title": "one time task group", "contact": person_dict(self.user.id), "task_group_tasks": [{ "title": "task 1", "description": "some task", "contact": person_dict(self.user.id), "start_date": date(2015, 5, 1), # friday "end_date": date(2015, 5, 5), }, { "title": "task 2", "description": "some task 2", "contact": person_dict(self.user.id), "start_date": date(2015, 5, 1), # friday "end_date": date(2015, 5, 5), }], "task_group_objects": self.random_objects }] }
class TestMonthlyWorkflowNotification(TestCase): """ This class contains simple one time workflow tests that are not in the gsheet test grid """ def setUp(self): super(TestMonthlyWorkflowNotification, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() self.random_objects = self.object_generator.generate_random_objects() _, self.person_1 = self.object_generator.generate_person( user_role="Administrator") _, self.person_2 = self.object_generator.generate_person( user_role="Administrator") self.create_test_cases() def init_decorator(init): def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = dt.datetime.now() return new_init Notification.__init__ = init_decorator(Notification.__init__) @patch("ggrc.notifications.common.send_email") def test_auto_generate_cycle(self, mock_mail): person_1_email = Person.query.get(self.person_1.id).email with freeze_time("2015-04-01"): _, wf = self.wf_generator.generate_workflow(self.monthly_workflow_1) self.wf_generator.activate_workflow(wf) _, notif_data = common.get_daily_notifications() self.assertNotIn(person_1_email, notif_data) with freeze_time("2015-04-02"): self.api.client.get("nightly_cron_endpoint") _, notif_data = common.get_daily_notifications() self.assertNotIn(person_1_email, notif_data) start_recurring_cycles() _, notif_data = common.get_daily_notifications() self.assertNotIn(person_1_email, notif_data) # cycle starts on monday - 6th, and not on 5th with freeze_time("2015-04-03"): start_recurring_cycles() _, notif_data = common.get_daily_notifications() self.assertIn(person_1_email, notif_data) self.assertIn("cycle_started", notif_data[person_1_email]) with freeze_time("2015-04-15"): # one day befor due date _, notif_data = common.get_daily_notifications() self.assertIn(person_1_email, notif_data) with freeze_time("2015-04-25"): # due date _, notif_data = common.get_daily_notifications() self.assertIn(person_1_email, notif_data) @patch("ggrc.notifications.common.send_email") def test_manual_generate_cycle(self, mock_mail): with freeze_time("2015-04-01"): _, wf = self.wf_generator.generate_workflow(self.monthly_workflow_1) self.wf_generator.activate_workflow(wf) person_1 = Person.query.get(self.person_1.id) with freeze_time("2015-04-03"): _, notif_data = common.get_daily_notifications() with freeze_time("2015-04-03"): _, cycle = self.wf_generator.generate_cycle(wf) _, notif_data = common.get_daily_notifications() person_1 = Person.query.get(self.person_1.id) self.assertIn("cycle_started", notif_data[person_1.email]) with freeze_time("2015-05-03"): # two days befor due date _, notif_data = common.get_daily_notifications() person_1 = Person.query.get(self.person_1.id) self.assertIn(person_1.email, notif_data) def create_test_cases(self): def person_dict(person_id): return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } self.monthly_workflow_1 = { "title": "test monthly wf notifications", "notify_on_change": True, "description": "some test workflow", # admin will be current user with id == 1 "unit": "month", "recurrences": True, "repeat_every": 1, "task_groups": [{ "title": "one time task group", "contact": person_dict(self.person_1.id), "task_group_tasks": [{ "title": "task 1", "description": "some task", "contact": person_dict(self.person_1.id), "start_date": dt.date(2015, 4, 5), "end_date": dt.date(2015, 4, 25), }, { "title": "task 2", "description": "some task", "contact": person_dict(self.person_1.id), "start_date": dt.date(2015, 4, 10), "end_date": dt.date(2015, 4, 21), }], "task_group_objects": self.random_objects[:2] }, { "title": "another one time task group", "contact": person_dict(self.person_1.id), "task_group_tasks": [{ "title": "task 1 in tg 2", "description": "some task", "contact": person_dict(self.person_1.id), "start_date": dt.date(2015, 4, 15), "end_date": dt.date(2015, 4, 15), }, { "title": "task 2 in tg 2", "description": "some task", "contact": person_dict(self.person_2.id), "start_date": dt.date(2015, 4, 15), "end_date": dt.date(2015, 4, 28), }], "task_group_objects": [] }] }
class TestTaskDueNotifications(TestCase): """Test suite for task due soon/today notifications.""" # pylint: disable=invalid-name def _fix_notification_init(self): """Fix Notification object init function. This is a fix needed for correct created_at field when using freezgun. By default the created_at field is left empty and filed by database, which uses system time and not the fake date set by freezugun plugin. This fix makes sure that object created in freeze_time block has all dates set with the correct date and time. """ def init_decorator(init): """"Adjust the value of the object's created_at attribute to now.""" @functools.wraps(init) def new_init(self, *args, **kwargs): init(self, *args, **kwargs) if hasattr(self, "created_at"): self.created_at = datetime.now() return new_init models.Notification.__init__ = init_decorator(models.Notification.__init__) def setUp(self): super(TestTaskDueNotifications, self).setUp() self.api = Api() self.wf_generator = WorkflowsGenerator() self.object_generator = ObjectGenerator() models.Notification.query.delete() self._fix_notification_init() self.random_objects = self.object_generator.generate_random_objects(2) _, self.user = self.object_generator.generate_person( user_role="Administrator") role_id = models.all_models.AccessControlRole.query.filter( models.all_models.AccessControlRole.name == "Task Assignees", models.all_models.AccessControlRole.object_type == "TaskGroupTask", ).one().id self.one_time_workflow = { "title": "one time test workflow", "notify_on_change": True, "description": "some test workflow", "is_verification_needed": False, # admin will be current user with id == 1 "task_groups": [{ "title": "one time task group", "contact": { "href": "/api/people/{}".format(self.user.id), "id": self.user.id, "type": "Person", }, "task_group_tasks": [{ "title": "task 1", "description": "some task", "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], "start_date": date(2017, 5, 15), "end_date": date(2017, 6, 11), }, { "title": "task 2", "description": "some task 2", "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], "start_date": date(2017, 5, 8), "end_date": date(2017, 6, 12), }, { "title": "task 3", "description": "some task 3", "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], "start_date": date(2017, 5, 31), "end_date": date(2017, 6, 13), }, { "title": "task 4", "description": "some task 4", "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], "start_date": date(2017, 6, 2), "end_date": date(2017, 6, 14), }, { "title": "task 5", "description": "some task 5", "access_control_list": [ acl_helper.get_acl_json(role_id, self.user.id)], "start_date": date(2017, 6, 8), "end_date": date(2017, 6, 15), }], "task_group_objects": self.random_objects }] } @ddt.unpack @ddt.data( ("2017-06-12 12:12:12", ["task 1"], ["task 2"], ["task 3"]), ("2017-06-13 13:13:13", ["task 1", "task 2"], ["task 3"], ["task 4"]), ) @patch("ggrc.notifications.common.send_email") def test_creating_obsolete_notifications( self, fake_now, expected_overdue, expected_due_today, expected_due_in, _ ): """Notifications already obsolete on creation date should not be created. """ with freeze_time("2017-06-12 09:39:32"): tmp = self.one_time_workflow.copy() _, workflow = self.wf_generator.generate_workflow(tmp) self.wf_generator.generate_cycle(workflow) response, workflow = self.wf_generator.activate_workflow(workflow) self.assert200(response) user = models.Person.query.get(self.user.id) with freeze_time(fake_now): # mark all yeasterday notifications as sent models.all_models.Notification.query.filter( sa.func.DATE(models.all_models.Notification.send_on) < date.today() ).update({models.all_models.Notification.sent_at: datetime.now() - timedelta(1)}, synchronize_session="fetch") _, notif_data = common.get_daily_notifications() user_notifs = notif_data.get(user.email, {}) actual_overdue = [n['title'] for n in user_notifs.get("task_overdue", {}).itervalues()] actual_overdue.sort() self.assertEqual(actual_overdue, expected_overdue) self.assertEqual( [n['title'] for n in user_notifs.get("due_today", {}).itervalues()], expected_due_today) self.assertEqual( [n['title'] for n in user_notifs.get("due_in", {}).itervalues()], expected_due_in)