class TestResource(TestCase): """ Test /search REST API """ def setUp(self): super(TestResource, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.create_objects() def create_objects(self): """Create objects to be searched. Creates five Requirements and makes relationships. 0 1 2 3 4 |---| |---| | |-------|-------| """ self.objects = [ self.object_generator.generate_object(all_models.Requirement)[1].id for _ in xrange(5) ] self.objects = all_models.Requirement.eager_query().filter( all_models.Requirement.id.in_(self.objects) ).all() for src, dst in [(0, 1), (0, 2), (2, 3), (2, 4)]: self.object_generator.generate_relationship( self.objects[src], self.objects[dst] ) def search(self, *args, **kwargs): res, _ = self.api.search(*args, **kwargs) return res.json["results"]["entries"] def test_search_all(self): """Test search for all objects of a type.""" res, _ = self.api.search("Requirement") self.assertEqual(len(res.json["results"]["entries"]), 5) def test_search_query(self): """Test search with query by title.""" entries = self.search("Requirement", query=self.objects[0].title) self.assertEqual({entry["id"] for entry in entries}, {self.objects[0].id}) def test_search_relevant(self): """Test search with 'relevant to' single object.""" relevant_objects = "Requirement:{}".format(self.objects[0].id) entries = self.search("Requirement", relevant_objects=relevant_objects) self.assertEqual({entry["id"] for entry in entries}, {self.objects[i].id for i in [1, 2]}) def test_search_relevant_multi(self): """Test search with 'relevant to' multiple objects.""" ids = ",".join("Requirement:{}".format(self.objects[i].id) for i in (0, 3)) entries = self.search("Requirement", relevant_objects=ids) self.assertEqual({entry["id"] for entry in entries}, {self.objects[2].id})
class TestResource(TestCase): """ Test /search REST API """ def setUp(self): super(TestResource, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.create_objects() def create_objects(self): """Create objects to be searched. Creates five Requirements and makes relationships. 0 1 2 3 4 |---| |---| | |-------|-------| """ self.objects = [ self.object_generator.generate_object(all_models.Requirement)[1].id for _ in xrange(5) ] self.objects = all_models.Requirement.eager_query().filter( all_models.Requirement.id.in_(self.objects)).all() for src, dst in [(0, 1), (0, 2), (2, 3), (2, 4)]: self.object_generator.generate_relationship( self.objects[src], self.objects[dst]) def search(self, *args, **kwargs): res, _ = self.api.search(*args, **kwargs) return res.json["results"]["entries"] def test_search_all(self): """Test search for all objects of a type.""" res, _ = self.api.search("Requirement") self.assertEqual(len(res.json["results"]["entries"]), 5) def test_search_query(self): """Test search with query by title.""" entries = self.search("Requirement", query=self.objects[0].title) self.assertEqual({entry["id"] for entry in entries}, {self.objects[0].id}) def test_search_relevant(self): """Test search with 'relevant to' single object.""" relevant_objects = "Requirement:{}".format(self.objects[0].id) entries = self.search("Requirement", relevant_objects=relevant_objects) self.assertEqual({entry["id"] for entry in entries}, {self.objects[i].id for i in [1, 2]}) def test_search_relevant_multi(self): """Test search with 'relevant to' multiple objects.""" ids = ",".join("Requirement:{}".format(self.objects[i].id) for i in (0, 3)) entries = self.search("Requirement", relevant_objects=ids) self.assertEqual({entry["id"] for entry in entries}, {self.objects[2].id})
class TestRelationship(TestCase): """Integration test suite for Relationship.""" # pylint: disable=invalid-name def setUp(self): """Create a Person, an Assessment, prepare a Relationship json.""" super(TestRelationship, self).setUp() self.api = api_helper.Api() self.client.get("/login") self.object_generator = ObjectGenerator() self.person = factories.PersonFactory() self.assessment = factories.AssessmentFactory() HEADERS = { "Content-Type": "application/json", "X-requested-by": "GGRC", } REL_URL = "/api/relationships" @staticmethod def build_relationship_json(source, destination, is_external=False): """Builds relationship create request json.""" return json.dumps([{ "relationship": { "source": { "id": source.id, "type": source.type }, "destination": { "id": destination.id, "type": destination.type }, "context": { "id": None }, "is_external": is_external } }]) def test_local_user_create_external_relationship(self): """Test that local user can't create external relationships""" with factories.single_commit(): program = factories.ProgramFactory() comment = factories.CommentFactory() response = self.api.client.post( self.REL_URL, data=self.build_relationship_json(program, comment, is_external=True), headers=self.HEADERS) rel = all_models.Relationship.query.first() self.assert400(response) self.assertIsNone(rel) def test_changing_log_on_doc_change(self): """Changing object documents should generate new object revision.""" url_link = u"www.foo.com" with factories.single_commit(): control = factories.ControlFactory() url = factories.DocumentReferenceUrlFactory(link=url_link) def get_revisions(): return all_models.Revision.query.filter( all_models.Revision.resource_id == control.id, all_models.Revision.resource_type == control.type, ).order_by(all_models.Revision.id.desc()).all() # attach an url to a control revisions = get_revisions() count = len(revisions) response = self.client.post(self.REL_URL, data=self.build_relationship_json( control, url), headers=self.HEADERS) self.assert200(response) relationship = all_models.Relationship.query.get( response.json[0][-1]["relationship"]["id"]) # check if a revision was created and contains the attached url revisions = get_revisions() self.assertEqual(count + 1, len(revisions)) url_list = revisions[0].content.get("documents_reference_url") or [] self.assertEqual(1, len(url_list)) self.assertIn("link", url_list[0]) self.assertEqual(url_link, url_list[0]["link"]) # now test whether a new revision is created when url is unmapped self.assert200(self.api.delete(relationship)) revisions = get_revisions() self.assertEqual(count + 2, len(revisions)) url_list = revisions[0].content.get("documents_reference_url") or [] self.assertEqual(url_list, []) def test_relationship_disallowed_type(self): """Validation fails when source-destination are snapshottable.""" audit = factories.AuditFactory() snapshottable = factories.ControlFactory() ctrl_revision = all_models.Revision.query.filter( all_models.Revision.resource_id == snapshottable.id, all_models.Revision.resource_type == snapshottable.type, ).first() snapshot = factories.SnapshotFactory( parent=audit, revision_id=ctrl_revision.id, child_type=snapshottable.type, child_id=snapshottable.id, ) with self.assertRaises(ValidationError): factories.RelationshipFactory(source=snapshottable, destination=snapshot) with self.assertRaises(ValidationError): factories.RelationshipFactory(source=snapshot, destination=snapshottable) def test_relationship_validation(self): """Test validator that forbid creation of Relationship with the same object as source and destination""" response = self.client.post(self.REL_URL, data=self.build_relationship_json( self.assessment, self.assessment), headers=self.HEADERS) self.assert400(response) self.assertEqual(response.json[0][1], "The mapping of object on itself is not possible") def test_reuse_relationship_on_post_swapped(self): """Test relationship is reused for 2nd POST with swapped src/dst""" with factories.single_commit(): p1 = factories.ProgramFactory() p2 = factories.ProgramFactory() p1_id = p1.id p2_id = p2.id r1_id = factories.RelationshipFactory(source=p1, destination=p2).id resp, r2 = self.object_generator.generate_relationship( all_models.Program.query.get(p2_id), all_models.Program.query.get(p1_id)) self.assert201(resp) self.assertEqual(r1_id, r2.id) def test_reuse_relationship_on_post_not_swapped(self): """Test relationship is reused for 2nd POST with not swapped src/dst""" with factories.single_commit(): p1 = factories.ProgramFactory() p2 = factories.ProgramFactory() p1_id = p1.id p2_id = p2.id r1_id = factories.RelationshipFactory(source=p1, destination=p2).id resp, r2 = self.object_generator.generate_relationship( all_models.Program.query.get(p1_id), all_models.Program.query.get(p2_id)) self.assert201(resp) self.assertEqual(r1_id, r2.id)
class TestExternalRelationship(TestCase): """Integration test suite for External Relationship.""" # pylint: disable=invalid-name def setUp(self): """Init API helper""" super(TestExternalRelationship, self).setUp() self.object_generator = ObjectGenerator() self.api = api_helper.Api() with factories.single_commit(): editor_role = all_models.Role.query.filter( all_models.Role.name == "Editor").first() self.person_ext = factories.PersonFactory( email="*****@*****.**") self.person_ext_id = self.person_ext.id self.person = factories.PersonFactory( email="*****@*****.**") self.person_id = self.person.id rbac_factories.UserRoleFactory(role=editor_role, person=self.person) HEADERS = { "Content-Type": "application/json", "X-requested-by": "External App", "X-ggrc-user": "******"email\": \"[email protected]\"}", "X-appengine-inbound-appid": "test_external_app", } REL_URL = "/api/relationships" @staticmethod def build_relationship_json(source, destination, is_external=True): """Builds relationship create request json.""" return json.dumps([{ "relationship": { "source": { "id": source.id, "type": source.type }, "destination": { "id": destination.id, "type": destination.type }, "context": { "id": None }, "is_external": is_external } }]) @staticmethod def create_relationship(source, destination, is_external, user): """Creates relationship in database with given params.""" return factories.RelationshipFactory( source=source, destination=destination, is_external=is_external, modified_by_id=user.id, ) def test_create_ext_user_ext_relationship(self): """Validation external app user creates external relationship.""" self.api.set_user(self.person_ext) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() response = self.api.client.post(self.REL_URL, data=self.build_relationship_json( product, system, True), headers=self.HEADERS) self.assert200(response) relationship = all_models.Relationship.query.get( response.json[0][-1]["relationship"]["id"]) self.assertEqual(relationship.source_type, "Product") self.assertEqual(relationship.source_id, product.id) self.assertEqual(relationship.destination_type, "System") self.assertEqual(relationship.destination_id, system.id) self.assertTrue(relationship.is_external) self.assertEqual(relationship.modified_by_id, self.person_ext.id) self.assertIsNone(relationship.parent_id) self.assertIsNone(relationship.automapping_id) self.assertIsNone(relationship.context_id) def test_create_ext_user_reg_relationship(self): """Validation external app user creates regular relationship.""" self.api.set_user(self.person_ext) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() response = self.api.client.post(self.REL_URL, data=self.build_relationship_json( product, system, False), headers=self.HEADERS) self.assert400(response) self.assertEqual(response.json[0], [ 400, "You do not have the necessary permissions to " "create regular relationships.", ]) def test_update_ext_user_ext_relationship(self): """Validation external app user updates external relationship.""" self.api.set_user(self.person_ext) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() self.create_relationship(product, system, True, self.person_ext) response = self.api.client.post(self.REL_URL, data=self.build_relationship_json( product, system, True), headers=self.HEADERS) self.assert200(response) relationship = all_models.Relationship.query.get( response.json[0][-1]["relationship"]["id"]) self.assertEqual(relationship.source_type, "Product") self.assertEqual(relationship.source_id, product.id) self.assertEqual(relationship.destination_type, "System") self.assertEqual(relationship.destination_id, system.id) self.assertTrue(relationship.is_external) self.assertEqual(relationship.modified_by_id, self.person_ext.id) self.assertIsNone(relationship.parent_id) self.assertIsNone(relationship.automapping_id) self.assertIsNone(relationship.context_id) def test_update_ext_user_reg_relationship(self): """External app user can update regular relationship.""" with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() self.create_relationship(product, system, False, self.person) product_id = product.id system_id = system.id self.api.set_user(self.person_ext) product = all_models.Product.query.get(product_id) system = all_models.System.query.get(system_id) response = self.api.client.post(self.REL_URL, data=self.build_relationship_json( product, system, True), headers=self.HEADERS) self.assert200(response) self.assertEqual(response.json[0][1]["relationship"]["is_external"], True) def test_delete_ext_user_ext_relationship(self): """Validation external app user deletes external relationship.""" self.api.set_user(self.person_ext) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() rel = self.create_relationship(product, system, True, self.person_ext) response = self.api.delete(rel) self.assert200(response) relationship = all_models.Relationship.query.get(rel.id) self.assertIsNone(relationship) def test_delete_ext_user_reg_relationship(self): """External app user can delete regular relationship.""" self.api.set_user(self.person_ext) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() rel = self.create_relationship(product, system, False, self.person_ext) response = self.api.delete(rel) self.assert200(response) def test_update_reg_user_ext_relationship(self): """Validation regular app user updates external relationship.""" with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() self.create_relationship(product, system, True, self.person_ext) product_id = product.id system_id = system.id self.api.set_user(self.person) product = all_models.Product.query.get(product_id) system = all_models.System.query.get(system_id) response = self.api.client.post(self.REL_URL, data=self.build_relationship_json( product, system, False), headers=self.HEADERS) self.assert200(response) def test_delete_reg_user_ext_relationship(self): """Validation regular user deletes external relationship.""" with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() self.create_relationship(product, system, True, self.person_ext) self.api.set_user(self.person) rel = all_models.Relationship.query.first() response = self.api.delete(rel) self.assert200(response) relationship = all_models.Relationship.query.get(rel.id) self.assertIsNone(relationship) @ddt.data(*READONLY_MAPPING_PAIRS) @ddt.unpack def test_local_delete_relationship_scoping_directive(self, model1, model2): """Test deletion of relationship between {0.__name__} and {1.__name__}""" # Set up relationships with self.object_generator.api.as_external(): _, obj1 = self.object_generator.generate_object(model1) _, obj2 = self.object_generator.generate_object(model2) _, rel = self.object_generator.generate_relationship( obj1, obj2, is_external=True) # check that relationship cannot be deleted by regular user self.api.set_user(all_models.Person.query.get(self.person_id)) relationship = all_models.Relationship.query.get(rel.id) response = self.api.delete(relationship) self.assert400(response) @ddt.data(*READONLY_MAPPING_PAIRS) @ddt.unpack def test_local_create_relationship_scoping_directive(self, model1, model2): """Test creation of relationship between {0.__name__} and {1.__name__}""" # Set up relationships with self.object_generator.api.as_external(): _, obj1 = self.object_generator.generate_object(model1) _, obj2 = self.object_generator.generate_object(model2) self.object_generator.api.set_user( all_models.Person.query.get(self.person_id)) response, _ = self.object_generator.generate_relationship( obj1, obj2, is_external=True) self.assert400(response) @ddt.data(*READONLY_MAPPING_PAIRS) @ddt.unpack def test_ext_create_delete_relationship_scoping_directive( self, model1, model2): """Test ext user and relationship between {0.__name__} and {1.__name__}""" # Set up relationships with self.object_generator.api.as_external(): _, obj1 = self.object_generator.generate_object(model1) _, obj2 = self.object_generator.generate_object(model2) _, rel = self.object_generator.generate_relationship( obj1, obj2, is_external=True) self.assertIsNotNone(rel) # check that external relationship can be deleted by external user self.api.set_user(all_models.Person.query.get(self.person_ext_id)) relationship = all_models.Relationship.query.get(rel.id) response = self.api.delete(relationship) print response.json self.assert200(response)
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 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 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([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "System", "Process", "Project", "AccessGroup", "Metric", "TechnologyEnvironment", "ProductGroup", ]) 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["admin"]) _, 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 TestResource(TestCase): """ Test /search REST API """ def setUp(self): super(TestResource, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.create_objects() def create_objects(self): """Create objects to be searched. Creates five controls and makes relationships. 0 1 2 3 4 |---| |---| | |-------|-------| """ self.objects = [ self.object_generator.generate_object(Control)[1].id for _ in xrange(5) ] self.objects = Control.eager_query().filter( Control.id.in_(self.objects)).all() for src, dst in [(0, 1), (0, 2), (2, 3), (2, 4)]: self.object_generator.generate_relationship( self.objects[src], self.objects[dst]) def search(self, *args, **kwargs): res, _ = self.api.search(*args, **kwargs) return res.json["results"]["entries"] def test_search_all(self): """Test search for all objects of a type.""" res, _ = self.api.search("Control") self.assertEqual(len(res.json["results"]["entries"]), 5) def test_search_query(self): """Test search with query by title.""" entries = self.search("Control", query=self.objects[0].title) self.assertEqual({entry["id"] for entry in entries}, {self.objects[0].id}) def test_search_relevant(self): """Test search with 'relevant to' single object.""" relevant_objects = "Control:{}".format(self.objects[0].id) entries = self.search("Control", relevant_objects=relevant_objects) self.assertEqual({entry["id"] for entry in entries}, {self.objects[i].id for i in [1, 2]}) def test_search_relevant_multi(self): """Test search with 'relevant to' multiple objects.""" ids = ",".join("Control:{}".format(self.objects[i].id) for i in (0, 3)) entries = self.search("Control", relevant_objects=ids) self.assertEqual({entry["id"] for entry in entries}, {self.objects[2].id}) def test_search_fail_with_terms_none(self): """Test search to fail with BadRequest (400 Error) when terms are None.""" query = '/search?types={}&counts_only={}'.format("Control", False) response = self.api.client.get(query) self.assert400(response) self.assertEqual( response.json['message'], 'Query parameter "q" ' 'specifying search terms must be provided.')
class TestWithReadOnlyAccessAPI(TestCase, query_helper.WithQueryApi): """Test WithReadOnlyAccess mixin""" def setUp(self): super(TestWithReadOnlyAccessAPI, self).setUp() self.object_generator = ObjectGenerator() self.object_generator.api.login_as_normal() @ddt.data( ('System', True), ('System', False), ('System', None), ('System', _NOT_SPECIFIED), ('System', "qwert"), ) @ddt.unpack def test_readonly_ignored_on_post(self, obj_type, readonly): """Test flag readonly ignored on object {0} POST for body readonly={1}""" dct = dict() if readonly is not _NOT_SPECIFIED: dct['readonly'] = readonly resp, obj = self.object_generator.generate_object( get_model(obj_type), dct, ) self.assertStatus(resp, 201) self.assertFalse(obj.readonly) @ddt.data( ('System', True, True), ('System', False, False), ('System', None, False), ('System', _NOT_SPECIFIED, False), ) @ddt.unpack def test_readonly_set_on_post_as_external(self, obj_type, readonly, result): """Test flag readonly on {0} POST for body readonly={1} as external user""" dct = dict() if readonly is not _NOT_SPECIFIED: dct['readonly'] = readonly with self.object_generator.api.as_external(): resp, obj = self.object_generator.generate_object( get_model(obj_type), dct, ) obj_id = obj.id self.assertStatus(resp, 201) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, result) @ddt.data( ('System', False, False, 200), ('System', False, True, 200), ('System', False, None, 200), ('System', False, _NOT_SPECIFIED, 200), ('System', False, "qwerty", 200), ('System', True, False, 405), ('System', True, True, 405), ('System', True, None, 405), ('System', True, _NOT_SPECIFIED, 405), ('System', True, "qwerty", 405), ) @ddt.unpack def test_put(self, obj_type, current, new, exp_code): """Test {0} PUT readonly={2} for current readonly={1}""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=current) obj_id = obj.id data = {'title': 'b'} if new is not _NOT_SPECIFIED: data['readonly'] = new resp = self.object_generator.api.put(obj, data) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, current) @ddt.data( ('System', False, False, 200, False), ('System', False, True, 200, True), ('System', False, None, 200, False), ('System', False, _NOT_SPECIFIED, 200, False), ('System', True, False, 200, False), ('System', True, True, 200, True), ('System', True, None, 200, True), ('System', True, _NOT_SPECIFIED, 200, True), ) @ddt.unpack def test_put_as_external(self, obj_type, current, new, exp_code, exp_readonly): """Test {0} PUT readonly={2} for current readonly={1} for external user""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=current) obj_id = obj.id data = {'title': 'b'} if new is not _NOT_SPECIFIED: data['readonly'] = new with self.object_generator.api.as_external(): obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.put(obj, data) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, exp_readonly) @ddt.data('System') def test_403_if_put_readonly_without_perms(self, obj_type): """Test {0} with readonly=True PUT returns 401 instead of 405 This test ensures that user without permission for the object cannot obtain value for flag readonly """ role_obj = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factory = factories.get_model_factory(obj_type) with factories.single_commit(): # create Global Creator person = factories.PersonFactory() person_id = person.id rbac_factories.UserRoleFactory(role=role_obj, person=person) # Create object obj = factory(title='a', readonly=True) obj_id = obj.id self.object_generator.api.set_user(all_models.Person.query.get(person_id)) obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.put(obj, {'title': 'b'}) self.assert403(resp) @ddt.data( ('System', True, False, 200, True), ('System', True, True, 405, False), ('System', False, False, 200, True), ('System', False, True, 405, False), ) @ddt.unpack def test_delete(self, obj_type, is_external, readonly, exp_code, exp_deleted): """Test {0} DELETE if readonly={1}""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) obj_id = obj.id if is_external: self.object_generator.api.login_as_external() else: self.object_generator.api.login_as_normal() obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.delete(obj) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) if exp_deleted: self.assertIsNone(obj) else: self.assertIsNotNone(obj) @ddt.data('System') def test_403_if_delete_readonly_without_perms(self, obj_type): """Test {0} with readonly=True DELETE returns 401 This test ensures that user without permission for the object cannot obtain value for flag readonly """ role_obj = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factory = factories.get_model_factory(obj_type) with factories.single_commit(): # create Global Creator person = factories.PersonFactory() person_id = person.id rbac_factories.UserRoleFactory(role=role_obj, person=person) # Create object obj = factory(title='a', readonly=True) obj_id = obj.id self.object_generator.api.set_user(all_models.Person.query.get(person_id)) obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.delete(obj) self.assert403(resp) obj = get_model(obj_type).query.get(obj_id) self.assertIsNotNone(obj) @ddt.data( ('System', False, 'Document', True, 201), ('System', False, 'Document', False, 201), ('System', True, 'Document', True, 405), ('System', True, 'Document', False, 405), ('System', False, 'Comment', True, 201), ('System', False, 'Comment', False, 201), ('System', True, 'Comment', True, 201), ('System', True, 'Comment', False, 201), ) @ddt.unpack def test_relationship_post(self, obj_type, readonly, rel_obj_type, swap, expected_code): """Test PUT relationship {0}.readonly={1}, related object type {2}""" factory = factories.get_model_factory(obj_type) rel_factory = factories.get_model_factory(rel_obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) rel_obj = rel_factory() if swap: source, destination = rel_obj, obj else: source, destination = obj, rel_obj resp, _ = self.object_generator.generate_relationship( source=source, destination=destination ) self.assertStatus(resp, expected_code) @ddt.data( ('System', False, 'Document', True, 200), ('System', False, 'Document', False, 200), ('System', True, 'Document', True, 405), ('System', True, 'Document', False, 405), ('System', False, 'Comment', True, 200), ('System', False, 'Comment', False, 200), ('System', True, 'Comment', True, 200), ('System', True, 'Comment', False, 200), ) @ddt.unpack def test_relationship_delete(self, obj_type, readonly, rel_obj_type, swap, expected_code): """Test DELETE relationship {0}.readonly={1}, related object type {2}""" factory = factories.get_model_factory(obj_type) rel_factory = factories.get_model_factory(rel_obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) rel_obj = rel_factory() if swap: source, destination = rel_obj, obj else: source, destination = obj, rel_obj robj = factories.RelationshipFactory(source=source, destination=destination) resp = self.object_generator.api.delete(robj) self.assertStatus(resp, expected_code) @ddt.data( ("yes", "readonly system"), ("no", "non readonly system"), ) @ddt.unpack def test_readonly_searchable(self, test_value, expected_title): """Test filtration by readonly attribute""" with factories.single_commit(): factories.SystemFactory(title="readonly system", readonly=True) factories.SystemFactory(title="non readonly system") self.client.get("/login") actual_systems = self.simple_query( "System", expression=["readonly", "=", test_value] ) self.assertEqual( [s.get("title") for s in actual_systems], [expected_title] )
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() 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", "Requirement", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "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.object_generator.generate_object( model, data={ table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", # ignored except for Document "link": "https://example.com", "contact": { "type": "Person", "id": creator_id }, # this is ignored on everything but Issues "audit": { "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").one() acl = all_models.AccessControlList.query.filter_by( object_id=obj_id, object_type=model_singular, ac_role=acr, ).one() factories.AccessControlPersonFactory( ac_list=acl, 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']) _, 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) 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.object_generator.generate_object( all_models.Requirement, data={"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][1] 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%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) factories.AccessControlPersonFactory( ac_list=asmnt.acr_name_acl_map["Verifiers"], person=self.users["creator"], ) 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 TestWithReadOnlyAccessAPI(TestCase, query_helper.WithQueryApi): """Test WithReadOnlyAccess mixin""" def setUp(self): super(TestWithReadOnlyAccessAPI, self).setUp() self.object_generator = ObjectGenerator() self.object_generator.api.login_as_normal() @ddt.data( ('System', True), ('System', False), ('System', None), ('System', _NOT_SPECIFIED), ('System', "qwert"), ) @ddt.unpack def test_readonly_ignored_on_post(self, obj_type, readonly): """Test flag readonly ignored on object {0} POST for body readonly={1}""" dct = dict() if readonly is not _NOT_SPECIFIED: dct['readonly'] = readonly resp, obj = self.object_generator.generate_object( get_model(obj_type), dct, ) self.assertStatus(resp, 201) self.assertFalse(obj.readonly) @ddt.data( ('System', True, True), ('System', False, False), ('System', None, False), ('System', _NOT_SPECIFIED, False), ) @ddt.unpack def test_readonly_set_on_post_as_external(self, obj_type, readonly, result): """Test flag readonly on {0} POST for body readonly={1} as external user""" dct = dict() if readonly is not _NOT_SPECIFIED: dct['readonly'] = readonly with self.object_generator.api.as_external(): resp, obj = self.object_generator.generate_object( get_model(obj_type), dct, ) obj_id = obj.id self.assertStatus(resp, 201) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, result) @ddt.data( ('System', False, False, 200), ('System', False, True, 200), ('System', False, None, 200), ('System', False, _NOT_SPECIFIED, 200), ('System', False, "qwerty", 200), ('System', True, False, 405), ('System', True, True, 405), ('System', True, None, 405), ('System', True, _NOT_SPECIFIED, 405), ('System', True, "qwerty", 405), ) @ddt.unpack def test_put(self, obj_type, current, new, exp_code): """Test {0} PUT readonly={2} for current readonly={1}""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=current) obj_id = obj.id data = {'title': 'b'} if new is not _NOT_SPECIFIED: data['readonly'] = new resp = self.object_generator.api.put(obj, data) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, current) @ddt.data( ('System', False, False, 200, False), ('System', False, True, 200, True), ('System', False, None, 200, False), ('System', False, _NOT_SPECIFIED, 200, False), ('System', True, False, 200, False), ('System', True, True, 200, True), ('System', True, None, 200, True), ('System', True, _NOT_SPECIFIED, 200, True), ) @ddt.unpack def test_put_as_external(self, obj_type, current, new, exp_code, exp_readonly): """Test {0} PUT readonly={2} for current readonly={1} for external user""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=current) obj_id = obj.id data = {'title': 'b'} if new is not _NOT_SPECIFIED: data['readonly'] = new with self.object_generator.api.as_external(): obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.put(obj, data) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, exp_readonly) @ddt.data('System') def test_403_if_put_readonly_without_perms(self, obj_type): """Test {0} with readonly=True PUT returns 401 instead of 405 This test ensures that user without permission for the object cannot obtain value for flag readonly """ role_obj = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factory = factories.get_model_factory(obj_type) with factories.single_commit(): # create Global Creator person = factories.PersonFactory() person_id = person.id rbac_factories.UserRoleFactory(role=role_obj, person=person) # Create object obj = factory(title='a', readonly=True) obj_id = obj.id self.object_generator.api.set_user( all_models.Person.query.get(person_id)) obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.put(obj, {'title': 'b'}) self.assert403(resp) @ddt.data( ('System', True, False, 200, True), ('System', True, True, 405, False), ('System', False, False, 200, True), ('System', False, True, 405, False), ) @ddt.unpack def test_delete(self, obj_type, is_external, readonly, exp_code, exp_deleted): """Test {0} DELETE if readonly={1}""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) obj_id = obj.id if is_external: self.object_generator.api.login_as_external() else: self.object_generator.api.login_as_normal() obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.delete(obj) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) if exp_deleted: self.assertIsNone(obj) else: self.assertIsNotNone(obj) @ddt.data('System') def test_403_if_delete_readonly_without_perms(self, obj_type): """Test {0} with readonly=True DELETE returns 401 This test ensures that user without permission for the object cannot obtain value for flag readonly """ role_obj = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factory = factories.get_model_factory(obj_type) with factories.single_commit(): # create Global Creator person = factories.PersonFactory() person_id = person.id rbac_factories.UserRoleFactory(role=role_obj, person=person) # Create object obj = factory(title='a', readonly=True) obj_id = obj.id self.object_generator.api.set_user( all_models.Person.query.get(person_id)) obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.delete(obj) self.assert403(resp) obj = get_model(obj_type).query.get(obj_id) self.assertIsNotNone(obj) @ddt.data( ('System', False, 'Document', True, 201), ('System', False, 'Document', False, 201), ('System', True, 'Document', True, 405), ('System', True, 'Document', False, 405), ('System', False, 'Comment', True, 201), ('System', False, 'Comment', False, 201), ('System', True, 'Comment', True, 201), ('System', True, 'Comment', False, 201), ) @ddt.unpack def test_relationship_post(self, obj_type, readonly, rel_obj_type, swap, expected_code): """Test PUT relationship {0}.readonly={1}, related object type {2}""" factory = factories.get_model_factory(obj_type) rel_factory = factories.get_model_factory(rel_obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) rel_obj = rel_factory() if swap: source, destination = rel_obj, obj else: source, destination = obj, rel_obj resp, _ = self.object_generator.generate_relationship( source=source, destination=destination) self.assertStatus(resp, expected_code) @ddt.data( ('System', False, 'Document', True, 200), ('System', False, 'Document', False, 200), ('System', True, 'Document', True, 405), ('System', True, 'Document', False, 405), ('System', False, 'Comment', True, 200), ('System', False, 'Comment', False, 200), ('System', True, 'Comment', True, 200), ('System', True, 'Comment', False, 200), ) @ddt.unpack def test_relationship_delete(self, obj_type, readonly, rel_obj_type, swap, expected_code): """Test DELETE relationship {0}.readonly={1}, related object type {2}""" factory = factories.get_model_factory(obj_type) rel_factory = factories.get_model_factory(rel_obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) rel_obj = rel_factory() if swap: source, destination = rel_obj, obj else: source, destination = obj, rel_obj robj = factories.RelationshipFactory(source=source, destination=destination) resp = self.object_generator.api.delete(robj) self.assertStatus(resp, expected_code) @ddt.data( ("yes", "readonly system"), ("no", "non readonly system"), ) @ddt.unpack def test_readonly_searchable(self, test_value, expected_title): """Test filtration by readonly attribute""" with factories.single_commit(): factories.SystemFactory(title="readonly system", readonly=True) factories.SystemFactory(title="non readonly system") self.client.get("/login") actual_systems = self.simple_query( "System", expression=["readonly", "=", test_value]) self.assertEqual([s.get("title") for s in actual_systems], [expected_title])
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() 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 = { "DataAsset", "Contract", "Requirement", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "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.object_generator.generate_object( model, data={ table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", # ignored except for Document "link": "https://example.com", "contact": { "type": "Person", "id": creator_id }, # this is ignored on everything but Issues "audit": { "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" ).one() acl = all_models.AccessControlList.query.filter_by( object_id=obj_id, object_type=model_singular, ac_role=acr, ).one() factories.AccessControlPersonFactory( ac_list=acl, 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']) _, 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 ) 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.object_generator.generate_object( all_models.Requirement, data={"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][1] 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%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) factories.AccessControlPersonFactory( ac_list=asmnt.acr_name_acl_map["Verifiers"], person=self.users["creator"], ) 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 ) @staticmethod def _query_revisions(api, resource_type, resource_id): """Helper function querying revisions related to particular object.""" return api.send_request( api.client.post, api_link="/query", data=[{ "object_name": "Revision", "type": "ids", "filters": { "expression": { "left": { "left": { "left": "resource_type", "op": {"name": "="}, "right": resource_type, }, "op": {"name": "AND"}, "right": { "left": "resource_id", "op": {"name": "="}, "right": resource_id, }, }, "op": {"name": "OR"}, "right": { "left": { "left": { "left": "source_type", "op": {"name": "="}, "right": resource_type, }, "op": {"name": "AND"}, "right": { "left": "source_id", "op": {"name": "="}, "right": resource_id, } }, "op": {"name": "OR"}, "right": { "left": { "left": "destination_type", "op": {"name": "="}, "right": resource_type, }, "op": {"name": "AND"}, "right": { "left": "destination_id", "op": {"name": "="}, "right": resource_id, } } } }, }, }], ) def test_revision_access_query(self): """Test GC assigned to obj can access revisions through query API.""" with factories.single_commit(): program = factories.ProgramFactory() audit = factories.AuditFactory() factories.RelationshipFactory( source=audit, destination=program, ) factories.AccessControlPersonFactory( ac_list=audit.acr_name_acl_map["Auditors"], person=self.users["creator"], ) audit_id = audit.id self.api.set_user(self.users["creator"]) response = self._query_revisions(self.api, audit.type, audit_id) self.assert200(response) self.assertEqual(response.json[0]["Revision"]["count"], 2) def test_rev_access_query_no_right(self): """Test GC has no access to revisions of objects it has no right on.""" with factories.single_commit(): program = factories.ProgramFactory() audit = factories.AuditFactory() factories.RelationshipFactory( source=audit, destination=program, ) audit_id = audit.id self.api.set_user(self.users["creator"]) response = self._query_revisions(self.api, audit.type, audit_id) self.assert200(response) self.assertEqual(response.json[0]["Revision"]["count"], 0)
class TestWithReadOnlyAccessAPI(TestCase): """Test WithReadOnlyAccess mixin""" def setUp(self): super(TestWithReadOnlyAccessAPI, self).setUp() self.object_generator = ObjectGenerator() self.object_generator.api.login_as_normal() @ddt.data( ('System', True), ('System', False), ('System', None), ('System', "qwert"), ) @ddt.unpack def test_readonly_ignored_on_post(self, obj_type, readonly): """Test flag readonly ignored on object {0} POST for body readonly={1}""" dct = dict() if readonly is not None: dct['readonly'] = readonly resp, obj = self.object_generator.generate_object( get_model(obj_type), {'readonly': readonly}, ) self.assertStatus(resp, 201) self.assertFalse(obj.readonly) @ddt.data( ('System', False, False, 200), ('System', False, True, 200), ('System', False, None, 200), ('System', True, False, 405), ('System', True, True, 405), ('System', True, None, 405), ) @ddt.unpack def test_put(self, obj_type, current, new, exp_code): """Test {0} PUT readonly={2} for current readonly={1}""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=current) obj_id = obj.id data = {'title': 'b'} if new is not None: data['readonly'] = new resp = self.object_generator.api.put(obj, data) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) self.assertEqual(obj.readonly, current) @ddt.data('System') def test_403_if_put_readonly_without_perms(self, obj_type): """Test {0} with readonly=True PUT returns 401 instead of 405 This test ensures that user without permission for the object cannot obtain value for flag readonly """ role_obj = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factory = factories.get_model_factory(obj_type) with factories.single_commit(): # create Global Creator person = factories.PersonFactory() person_id = person.id rbac_factories.UserRoleFactory(role=role_obj, person=person) # Create object obj = factory(title='a', readonly=True) obj_id = obj.id self.object_generator.api.set_user(all_models.Person.query.get(person_id)) obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.put(obj, {'title': 'b'}) self.assert403(resp) @ddt.data( ('System', False, 200, True), ('System', True, 405, False), ) @ddt.unpack def test_delete(self, obj_type, readonly, exp_code, exp_deleted): """Test {0} DELETE if readonly={1}""" factory = factories.get_model_factory(obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) obj_id = obj.id resp = self.object_generator.api.delete(obj) self.assertStatus(resp, exp_code) obj = get_model(obj_type).query.get(obj_id) if exp_deleted: self.assertIsNone(obj) else: self.assertIsNotNone(obj) @ddt.data('System') def test_403_if_delete_readonly_without_perms(self, obj_type): """Test {0} with readonly=True DELETE returns 401 This test ensures that user without permission for the object cannot obtain value for flag readonly """ role_obj = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factory = factories.get_model_factory(obj_type) with factories.single_commit(): # create Global Creator person = factories.PersonFactory() person_id = person.id rbac_factories.UserRoleFactory(role=role_obj, person=person) # Create object obj = factory(title='a', readonly=True) obj_id = obj.id self.object_generator.api.set_user(all_models.Person.query.get(person_id)) obj = get_model(obj_type).query.get(obj_id) resp = self.object_generator.api.delete(obj) self.assert403(resp) obj = get_model(obj_type).query.get(obj_id) self.assertIsNotNone(obj) @ddt.data( ('System', False, 'Document', True, 201), ('System', False, 'Document', False, 201), ('System', True, 'Document', True, 405), ('System', True, 'Document', False, 405), ('System', False, 'Comment', True, 201), ('System', False, 'Comment', False, 201), ('System', True, 'Comment', True, 201), ('System', True, 'Comment', False, 201), ) @ddt.unpack def test_relationship_post(self, obj_type, readonly, rel_obj_type, swap, expected_code): """Test PUT relationship {0}.readonly={1}, related object type {2}""" factory = factories.get_model_factory(obj_type) rel_factory = factories.get_model_factory(rel_obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) rel_obj = rel_factory() if swap: source, destination = rel_obj, obj else: source, destination = obj, rel_obj resp, _ = self.object_generator.generate_relationship( source=source, destination=destination ) self.assertStatus(resp, expected_code) @ddt.data( ('System', False, 'Document', True, 200), ('System', False, 'Document', False, 200), ('System', True, 'Document', True, 405), ('System', True, 'Document', False, 405), ('System', False, 'Comment', True, 200), ('System', False, 'Comment', False, 200), ('System', True, 'Comment', True, 200), ('System', True, 'Comment', False, 200), ) @ddt.unpack def test_relationship_delete(self, obj_type, readonly, rel_obj_type, swap, expected_code): """Test DELETE relationship {0}.readonly={1}, related object type {2}""" factory = factories.get_model_factory(obj_type) rel_factory = factories.get_model_factory(rel_obj_type) with factories.single_commit(): obj = factory(title='a', readonly=readonly) rel_obj = rel_factory() if swap: source, destination = rel_obj, obj else: source, destination = obj, rel_obj robj = factories.RelationshipFactory(source=source, destination=destination) resp = self.object_generator.api.delete(robj) self.assertStatus(resp, expected_code)
class TestResource(TestCase): """ Test /search REST API """ def setUp(self): super(TestResource, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.create_objects() def create_objects(self): """Create objects to be searched. Creates five controls and makes relationships. 0 1 2 3 4 |---| |---| | |-------|-------| """ self.objects = [ self.object_generator.generate_object(Control)[1].id for _ in xrange(5) ] self.objects = Control.eager_query().filter( Control.id.in_(self.objects) ).all() for src, dst in [(0, 1), (0, 2), (2, 3), (2, 4)]: self.object_generator.generate_relationship( self.objects[src], self.objects[dst] ) def search(self, *args, **kwargs): res, _ = self.api.search(*args, **kwargs) return res.json["results"]["entries"] def test_search_all(self): """Test search for all objects of a type.""" res, _ = self.api.search("Control") self.assertEqual(len(res.json["results"]["entries"]), 5) def test_search_query(self): """Test search with query by title.""" entries = self.search("Control", query=self.objects[0].title) self.assertEqual({entry["id"] for entry in entries}, {self.objects[0].id}) def test_search_relevant(self): """Test search with 'relevant to' single object.""" relevant_objects = "Control:{}".format(self.objects[0].id) entries = self.search("Control", relevant_objects=relevant_objects) self.assertEqual({entry["id"] for entry in entries}, {self.objects[i].id for i in [1, 2]}) def test_search_relevant_multi(self): """Test search with 'relevant to' multiple objects.""" ids = ",".join("Control:{}".format(self.objects[i].id) for i in (0, 3)) entries = self.search("Control", relevant_objects=ids) self.assertEqual({entry["id"] for entry in entries}, {self.objects[2].id}) def test_search_fail_with_terms_none(self): """Test search to fail with BadRequest (400 Error) when terms are None.""" query = '/search?types={}&counts_only={}'.format("Control", False) response = self.api.client.get(query) self.assert400(response) self.assertEqual(response.json['message'], 'Query parameter "q" ' 'specifying search terms must be provided.')