def test_reindex_snapshots_option_without_title(self): """Test that reindex processed successfully. Reindex processed successfully with Option without 'title' attribute. """ with factories.single_commit(): product = factories.ProductFactory() audit = factories.AuditFactory() option = factories.OptionFactory() audit_id = audit.id product_id = product.id option_title = option.title revision = all_models.Revision.query.filter( all_models.Revision.resource_id == product.id, all_models.Revision.resource_type == product.type).one() revision_content = revision.content revision_content["kind"] = { "context_id": "null", "href": "/api/options/{}".format(option.id), "type": "Option", "id": option.id } revision.content = revision_content db.session.add(revision) db.session.commit() self._create_snapshots(audit, [product]) self.client.post("/admin/reindex_snapshots") snapshot = all_models.Snapshot.query.filter( all_models.Snapshot.parent_id == audit_id, all_models.Snapshot.parent_type == "Audit", all_models.Snapshot.child_id == product_id, all_models.Snapshot.child_type == "Product", ).one() self.assert_indexed_fields(snapshot, "kind", {"": option_title})
def test_custom_role(self, url, role_name, role_read, role_update, role_delete, expected_status): """Test {0} for user with custom role {1}""" # pylint: disable=too-many-arguments role_creator = all_models.Role.query.filter( all_models.Role.name == "Creator").one() factories.AccessControlRoleFactory(name=role_name, object_type="Product", read=role_read, update=role_update, delete=role_delete) with factories.single_commit(): obj = factories.ProductFactory(folder="a") person = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role_creator, person=person) factories.AccessControlPersonFactory( ac_list=obj.acr_name_acl_map[role_name], person=person, ) obj_id = obj.id person_id = person.id self.api.set_user(all_models.Person.query.get(person_id)) response = self.api.client.post(url, content_type="application/json", data=self._get_request_data( 'Product', obj_id, folder="a")) self.assertStatus(response, expected_status)
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_unmap_snapshotable(self): """Unmap snapshotable should change review status""" control = factories.ControlFactory() resp, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": control.type, "id": control.id, }, "context": None, "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl(), "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE }, ) review_id = review.id _, rel = self.generator.generate_relationship( source=control, destination=factories.ProductFactory(), context=None, ) review = all_models.Review.query.get(review_id) resp = self.api.modify_object( review, {"status": all_models.Review.STATES.REVIEWED}) self.assert200(resp) resp = self.api.delete(rel) self.assert200(resp) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)
def test_map_snapshotable_notification(self, notification_type, expected_notifications): """Map snapshotable should change review status and add notification""" with factories.single_commit(): program = factories.ProgramFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program, notification_type=notification_type) review_id = review.id self.generator.generate_relationship( source=program, destination=factories.ProductFactory(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) review_notif_types = all_models.Review.NotificationObjectTypes notyf_unreviewed_type = all_models.Notification.query.join( all_models.NotificationType).filter( all_models.NotificationType.name == review_notif_types.STATUS_UNREVIEWED).all() self.assertEqual(expected_notifications, len(notyf_unreviewed_type))
def test_comment_imported(self, send_email_mock): """Test sending mention email after import an object with comments.""" with factories.single_commit(): factories.PersonFactory(email="*****@*****.**") obj = factories.ProductFactory(title="Product4") obj_slug = obj.slug url = urljoin(get_url_root(), utils.view_url_for(obj)) first_comment = u"One <a href=\"mailto:[email protected]\"></a>" second_comment = u"Two <a href=\"mailto:[email protected]\"></a>" import_data = OrderedDict([("object_type", "Product"), ("Code*", obj_slug), ("comments", first_comment + u";;" + second_comment)]) with freeze_time("2018-01-10 07:31:42"): response = self.import_data(import_data) self._check_csv_response(response, {}) expected_title = (u"[email protected] mentioned you on " u"a comment within Product4") body = settings.EMAIL_MENTIONED_PERSON.render( person_mention={ "comments": [ (u"[email protected] mentioned you on a comment within Product4 " u"at 01/09/2018 23:31:42 PST:\n" + first_comment + u"\n"), (u"[email protected] mentioned you on a comment within Product4 " u"at 01/09/2018 23:31:42 PST:\n" + second_comment + u"\n"), ], "url": url, }) send_email_mock.assert_called_once_with(u"*****@*****.**", expected_title, body)
def test_map_object(self): """It should be possible to map an object to an audit.""" with factories.single_commit(): program = factories.ProgramFactory() audit = factories.AuditFactory(program=program) factories.RelationshipFactory(source=audit, destination=program) product = factories.ProductFactory() factories.RelationshipFactory(source=program, destination=product) data = [{ "relationship": { "context": None, "destination": { "id": product.id, "type": "Product", "href": "/api/products/{}".format(product.id) }, "source": { "id": audit.id, "type": "Audit", "href": "/api/audits/{}".format(audit.id) } } }] response = self.api.client.post("/api/relationships", data=json.dumps(data), headers=self.headers) self.assert200(response)
def test_handle_one_comment(self, send_email_mock): """Test handling of mapped comment.""" with factories.single_commit(): person = factories.PersonFactory(email="*****@*****.**") obj = factories.ProductFactory(title="Product1") comment = factories.CommentFactory( description=u"One <a href=\"mailto:[email protected]\"></a>", ) comment.modified_by_id = person.id comment.created_at = datetime.datetime(2018, 1, 10, 7, 31, 42) url = urljoin(get_url_root(), utils.view_url_for(obj)) people_mentions.handle_comment_mapped(obj, [comment]) expected_title = (u"[email protected] mentioned you " u"on a comment within Product1") expected_body = ( u"[email protected] mentioned you on a comment within Product1 " u"at 01/09/2018 23:31:42 PST:\n" u"One <a href=\"mailto:[email protected]\"></a>\n") body = settings.EMAIL_MENTIONED_PERSON.render( person_mention={ "comments": [expected_body], "url": url, }) send_email_mock.assert_called_once_with(u"*****@*****.**", expected_title, body)
def test_snapshottable_import(self): """Revert state for snapshottable object via import. Review -> UNREVIEWED Email Notification added """ program = factories.ProgramFactory( title="Test program" ) product = factories.ProductFactory() product_slug = product.slug resp, review = generate_review_object( program, state=all_models.Review.STATES.REVIEWED) program_id = program.id self.assertEqual(201, resp.status_code) import_data = OrderedDict( [ ("object_type", "Program"), ("Code*", program.slug), ("map:Product", product_slug) ] ) response = self.import_data(import_data) self._check_csv_response(response, {}) program = all_models.Program.query.get(program_id) self.assertEqual( all_models.Review.STATES.UNREVIEWED, program.review_status ) notification = all_models.Notification.query.filter_by( object_id=review.id, object_type="Review" ).one() self.assertTrue(notification)
def test_relevant_to_previous_export(self): """Test relevant to previous export""" with factories.single_commit(): products = [factories.ProductFactory(title="product-{}".format(i)) for i in range(1, 3)] policies = [factories.PolicyFactory(title="policy-{}".format(i)) for i in range(1, 3)] programs = [factories.ProgramFactory(title="program-{}".format(i)) for i in range(1, 3)] product_slugs = [product.slug for product in products] policy_slugs = [policy.slug for policy in policies] program_slugs = [program.slug for program in programs] policy_data = [ get_object_data("Policy", policy_slugs[0], product=product_slugs[0]), get_object_data("Policy", policy_slugs[1], product="\n".join(product_slugs[:2])), ] self.import_data(*policy_data) program_data = [ get_object_data("Program", program_slugs[0], policy=policy_slugs[0], product=product_slugs[1]), get_object_data("Program", program_slugs[1], policy=policy_slugs[1], product=product_slugs[0]), ] self.import_data(*program_data) data = [{ "object_name": "Program", # program-1 "filters": { "expression": define_op_expr("title", "=", "program-1"), }, "fields": ["slug", "title", "description"], }, { "object_name": "Product", # product-2 "filters": { "expression": define_relevant_expr("__previous__", obj_ids=["0"]), }, "fields": ["slug", "title", "description"], }, { "object_name": "Policy", # policy-2 "filters": { "expression": define_relevant_expr("__previous__", obj_ids=["1"]) }, "fields": ["slug", "title", "description"], } ] response = self.export_csv(data) self.assertIn(",program-1,", response.data) self.assertNotIn(",program-2,", response.data) self.assertIn(",product-2,", response.data) self.assertNotIn(",product-1,", response.data) self.assertIn(",policy-2,", response.data) self.assertNotIn(",policy-{},", response.data)
def test_handle_empty_comment(self, send_email_mock): """Test handling of mapped comment with no mention.""" with factories.single_commit(): person = factories.PersonFactory(email="*****@*****.**") obj = factories.ProductFactory(title="Product2") comment = factories.CommentFactory(description=u"test") comment.created_at = datetime.datetime(2018, 1, 10, 7, 31, 42) comment.modified_by_id = person.id people_mentions.handle_comment_mapped(obj, [comment]) send_email_mock.assert_not_called()
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_several_mentions_imported(self, send_email_mock): """Test sending mention email after import an object with comments with mentions of different persons.""" with factories.single_commit(): factories.PersonFactory(email="*****@*****.**") factories.PersonFactory(email="*****@*****.**") obj = factories.ProductFactory(title="Product5") obj_slug = obj.slug first_comment = u"One <a href=\"mailto:[email protected]\"></a>" second_comment = u"Two <a href=\"mailto:[email protected]\"></a>" \ u"<a href=\"mailto:[email protected]\"></a>" import_data = OrderedDict([("object_type", "Product"), ("Code*", obj_slug), ("comments", first_comment + u";;" + second_comment)]) with freeze_time("2018-01-10 07:31:42"): response = self.import_data(import_data) self._check_csv_response(response, {}) obj = all_models.Product.query.filter_by(title="Product5").one() url = urljoin(get_url_root(), utils.view_url_for(obj)) expected_title = (u"[email protected] mentioned you on " u"a comment within Product5") first_body = settings.EMAIL_MENTIONED_PERSON.render( person_mention={ "comments": [ (u"[email protected] mentioned you on a comment within Product5 " u"at 01/09/2018 23:31:42 PST:\n" + first_comment + u"\n"), (u"[email protected] mentioned you on a comment within Product5 " u"at 01/09/2018 23:31:42 PST:\n" + second_comment + u"\n"), ], "url": url, }) first_call = mock.call(u"*****@*****.**", expected_title, first_body) second_body = settings.EMAIL_MENTIONED_PERSON.render( person_mention={ "comments": [(u"[email protected] mentioned you on a comment within Product5 " u"at 01/09/2018 23:31:42 PST:\n" + second_comment + u"\n")], "url": url, }) second_call = mock.call(u"*****@*****.**", expected_title, second_body) send_email_mock.assert_has_calls([second_call, first_call])
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)
def test_update_reg_user_ext_relationship(self): """Validation regular app user updates external relationship.""" self.api.set_user(self.person) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() self.create_relationship(product, system, True, self.person) response = self.api.client.post(self.REL_URL, data=self.build_relationship_json( product, system, False), headers=self.HEADERS) self.assert200(response)
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, "External application can create only external relationships." ])
def test_anon_user(self, url): """Test anon user for {0}""" with factories.single_commit(): obj_id = factories.ProductFactory().id self.api.client.get("/logout") response = self.api.client.post(url, content_type="application/json", data=self._get_request_data( 'Product', obj_id, 'abc')) self.assert401(response)
def test_not_found(self, url): """Test on non-existing object for {0}""" with factories.single_commit(): obj_id = factories.ProductFactory().id self.api.login_as_normal() response = self.api.client.post(url, content_type="application/json", data=self._get_request_data( 'Product', obj_id + 1, 'abc')) self.assert404(response)
def test_person_mentioned_create(self, send_email_mock, *_): """Test that a user with authorized domain is created when mentioned.""" with factories.single_commit(): obj = factories.ProductFactory(title="Product6") comment = factories.CommentFactory( description=u"One <a href=\"mailto:[email protected]" u"\"></a>", ) comment.created_at = datetime.datetime(2018, 1, 10, 7, 31, 42) people_mentions.handle_comment_mapped(obj, [comment]) person = all_models.Person.query.filter_by( email="*****@*****.**").first() self.assertIsNotNone(person) send_email_mock.assert_called_once()
def test_external_user(self, url): """Test external user access for {0}""" with factories.single_commit(): obj_id = factories.ProductFactory().id self.api.login_as_external() response = self.api.client.post(url, content_type="application/json", data=self._get_request_data( 'Product', obj_id, 'abc')) self.assert403(response)
def test_relation_comment_posted(self, send_email_mock): """Test sending mention email after posting a relationship to comment.""" with factories.single_commit(): author_person = factories.PersonFactory(email="*****@*****.**") factories.PersonFactory(email="*****@*****.**") obj = factories.ProductFactory(title="Product3") obj_id = obj.id comment = factories.CommentFactory( description= u"One <a href=\"mailto:[email protected]\"></a>", ) comment_id = comment.id comment.created_at = datetime.datetime(2018, 07, 10, 8, 31, 42) comment.modified_by_id = author_person.id url = urljoin(get_url_root(), utils.view_url_for(obj)) author_person = all_models.Person.query.filter_by( email="*****@*****.**").one() api = api_helper.Api() api.set_user(author_person) response = api.post( all_models.Relationship, { "relationship": { "source": { "id": obj_id, "type": obj.type, }, "destination": { "id": comment_id, "type": comment.type }, "context": None }, }) self.assertEqual(response.status_code, 201) expected_title = (u"[email protected] mentioned you on " u"a comment within Product3") expected_body = ( u"[email protected] mentioned you on a comment within Product3 " u"at 07/10/2018 01:31:42 PDT:\n" u"One <a href=\"mailto:[email protected]\"></a>\n") body = settings.EMAIL_MENTIONED_PERSON.render( person_mention={ "comments": [expected_body], "url": url, }) send_email_mock.assert_called_once_with(u"*****@*****.**", expected_title, body)
def test_mimetype(self, url, mimetype, folder, new_folder, expected_code): """Test mimetype for '{0}' '{1}' '{2}' '{3}""" # pylint: disable=too-many-arguments with factories.single_commit(): obj_id = factories.ProductFactory(folder=folder).id self.api.login_as_normal() response = self.api.client.post(url, content_type=mimetype, data=self._get_request_data( 'Product', obj_id, new_folder)) self.assertStatus(response, expected_code)
def test_delete_ext_user_reg_relationship(self): """Validation external app user deletes 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.assert400(response) self.assertEqual( response.json, { 'message': 'External application can delete only external ' 'relationships.', 'code': 400 })
def test_update_ext_user_reg_relationship(self): """External app user can update regular relationship.""" self.api.set_user(self.person_ext) with factories.single_commit(): product = factories.ProductFactory() system = factories.SystemFactory() self.create_relationship(product, system, False, 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) self.assertEqual(response.json[0][1]["relationship"]["is_external"], True)
def test_global_role(self, url, role_name, expected_status): """Test {0} for user with global role {1}""" role_obj = all_models.Role.query.filter( all_models.Role.name == role_name).one() with factories.single_commit(): obj_id = factories.ProductFactory(folder="a").id person = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role_obj, person=person) person_id = person.id self.api.set_user(all_models.Person.query.get(person_id)) response = self.api.client.post(url, content_type="application/json", data=self._get_request_data( 'Product', obj_id, folder="a")) self.assertStatus(response, expected_status)
def test_none(self, url, set_obj_id, set_obj_type, new_folder, expected_code): """Test None for '{0}' '{1}' '{2}' '{3}'""" # pylint: disable=too-many-arguments with factories.single_commit(): obj_id = factories.ProductFactory(folder="Z").id self.api.login_as_normal() request_data = self._get_request_data( obj_type='Product' if set_obj_type else None, obj_id=obj_id if set_obj_id else None, folder=new_folder, ) response = self.api.client.post(url, content_type="application/json", data=request_data) self.assertStatus(response, expected_code)
def test_unmap_snapshotable(self): """Unmap snapshotable should change review status""" control = factories.ControlFactory() resp, review = generate_review_object(control) review_id = review.id _, rel = self.generator.generate_relationship( source=control, destination=factories.ProductFactory(), context=None, ) review = all_models.Review.query.get(review_id) resp = self.api.modify_object( review, {"status": all_models.Review.STATES.REVIEWED}) self.assert200(resp) resp = self.api.delete(rel) self.assert200(resp) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)
def test_export_query_count(self): """Test for a constant number of queries for snapshot export The number of database queries should not be linked to the amount of data that is being exported. """ # pylint: disable=too-many-locals self._create_cads("product") user_details = ("Administrator", "Creator", "Editor", "Reader") with factories.single_commit(): roles = {r.name: r for r in all_models.Role.query.all()} for user in user_details: person = factories.PersonFactory( name=user, email="{}@example.com".format(user)) rbac_factories.UserRoleFactory(role=roles[user], person=person) factories.ProductFactory(title="Product {}".format(user)) product = models.Product.query.all() audit = factories.AuditFactory() snapshots = self._create_snapshots(audit, product) count = len(snapshots) assessments = [factories.AssessmentFactory() for _ in range(count)] issues = [factories.IssueFactory() for _ in range(count)] for snapshot, assessment, issue in zip(snapshots, assessments, issues): factories.RelationshipFactory(source=snapshot, destination=assessment) factories.RelationshipFactory(source=issue, destination=snapshot) with QueryCounter() as counter: search_request = [{ "object_name": "Snapshot", "filters": { "expression": { "left": { "left": "child_type", "op": { "name": "=" }, "right": "Product", }, "op": { "name": "AND" }, "right": { "left": "title", "op": { "name": "=" }, "right": "Product Editor", }, }, }, "fields": ["mappings"], }] self.assertEqual( len( self.export_parsed_csv(search_request) ["Product Snapshot"]), 1, ) single_query_count = counter.get with QueryCounter() as counter: search_request = [{ "object_name": "Snapshot", "filters": { "expression": { "left": "child_type", "op": { "name": "=" }, "right": "Product", }, }, "fields": ["mappings"], }] self.assertEqual( len( self.export_parsed_csv(search_request) ["Product Snapshot"]), 4, ) multiple_query_count = counter.get self.assertEqual(multiple_query_count, single_query_count)