class TestReviewStatusUpdate(TestCase): """Base TestCase class automatic review status update.""" def setUp(self): super(TestReviewStatusUpdate, self).setUp() self.api = Api() self.api.client.get("/login") self.generator = generator.ObjectGenerator() @ddt.data( ("title", "new title"), ("description", "new description"), ("test_plan", "new test_plan"), ("notes", "new notes"), ("fraud_related", 1), ("key_control", 1), ("start_date", "2020-01-01"), ("status", "Active"), ("kind", get_kind_data), ("means", get_mean_data), ("verify_frequency", get_verify_frequency_data), ("assertions", get_assertions_data), ("categories", get_categories_data), ) @ddt.unpack def test_reviewable_attributes(self, attr_to_modify, new_value): """If attribute '{0}' modified move review to Unreviewed state""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id reviewable = review.reviewable self.api.modify_object(reviewable, { attr_to_modify: new_value() if callable(new_value) else new_value }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_gca(self): """if GCA of reviewable is changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="control", title="rich_test_gca", attribute_type="Rich Text") control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_reference_url(self): """If reference url is updated state should not updated""" with factories.single_commit(): control = factories.ControlFactory() doc = factories.DocumentReferenceUrlFactory( title="Simple title", link="some_url.com", description="mega description", parent_obj={ "id": control.id, "type": "Control" }) review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id self.api.modify_object(doc, {"link": "new_link.com"}) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_acl_roles(self): """Update of reviewable ACL shouldn't change review status""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id ac_role_id = all_models.AccessControlRole.query.filter_by( name="Primary Contacts", object_type="Control").one().id user_id = all_models.Person.query.filter_by( email="*****@*****.**").one().id self.api.modify_object( control, { "access_control_list": [{ "ac_role_id": ac_role_id, "person": { "id": user_id }, }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_comments(self): """Add comment to reviewable shouldn't update review state""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id self.generator.generate_comment(control, "Verifiers", "some comment", send_notification="false") review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_mapping_non_snapshotable(self): """Map non-snapshotable shouldn't change review status""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id factories.RelationshipFactory(source=control, destination=factories.IssueFactory()) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) @ddt.data("Standard", "Regulation", "Requirement", "Objective", "Control", "Product", "System", "Process", "AccessGroup", "Contract", "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk", "Threat", "Vendor") def test_map_snapshotable(self, snapshotable): """Map '{}' should change review status""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) review_id = review.id self.generator.generate_relationship( source=control, destination=factories.get_model_factory(snapshotable)(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) 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) @ddt.data( "Assessment", "Issue", "Program", "Project", "Audit", "RiskAssessment", "AssessmentTemplate", "Person", ) def test_map_nonsnapshotable(self, nonsnapshotable): """Map '{}' shouldn't change review status""" control = factories.ControlFactory() _, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": control.type, "id": control.id, }, "context": None, "status": all_models.Review.STATES.REVIEWED, "access_control_list": build_reviewer_acl(), "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE }, ) review_id = review.id review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.generator.generate_relationship( source=control, destination=factories.get_model_factory(nonsnapshotable)(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_unmap_nonsnapshotable(self): """Unmap nonsnapshotable shouldn't 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.REVIEWED, "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.ProgramFactory(), 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) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) resp = self.api.delete(rel) self.assert200(resp) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_proposal_apply(self): """Reviewable object changed via proposal -> review.state-> UNREVIEWED""" control = factories.ControlFactory() _, 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 proposal_content = { "fields": { "title": "new title" }, } proposal = factories.ProposalFactory(instance=control, content=proposal_content, agenda="agenda content") self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED}) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)
class TestAuditDeprecated(TestCase): """Test for correct working field last_deprecated_date """ def setUp(self): super(TestAuditDeprecated, self).setUp() self.api = Api() def test_redefine_status(self): """Test create audit and change status to Deprecated""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, {"status": "Deprecated"}) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id).one() self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_keep_date_unchanged(self): """Test set status audit to Deprecated, and then set status to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, {"status": "Deprecated"}) with freeze_time("2017-01-26"): self.api.modify_object(audit, {"status": "Planned"}) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_repeat_deprecated_state(self): """Test set status audit to Deprecated, then to Planned, then to Deprecated and then to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, {"status": "Deprecated"}) with freeze_time("2017-01-26"): self.api.modify_object(audit, {"status": "Planned"}) with freeze_time("2017-02-25"): self.api.modify_object(audit, {"status": "Deprecated"}) with freeze_time("2017-02-26"): self.api.modify_object(audit, {"status": "Planned"}) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 2, 25)) def test_filter_by_deprecated_date(self): """Test filter audits by last deprecated date""" amount_of_audits = 5 list_of_ids = [] with factories.single_commit(): with freeze_time("2017-01-25"): for _ in range(amount_of_audits): list_of_ids.append( factories.AuditFactory(status="Deprecated").id) query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': { 'name': '=' }, 'right': "2017-01-25", }, }, 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"]) def test_sort_by_deprecated_date(self): """Test sorting results of filter audits by deprecated date""" dict_of_dates = {} date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"] with factories.single_commit(): for date in date_list: with freeze_time(date): dict_of_dates[factories.AuditFactory( status="Deprecated").id] = date sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1)) sorted_list_ids = [item[0] for item in sorted_dict] query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': { 'name': '=' }, 'right': "2017-01", }, }, "order_by": [{ "name": "last_deprecated_date" }], 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])
class TestAuditRBAC(TestCase): """Test audit RBAC""" # pylint: disable=too-many-instance-attributes CSV_DIR = join(abspath(dirname(__file__)), "test_csvs") def setUp(self): """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests""" TestCase.clear_data() self.api = Api() self.objgen = integration.ggrc.generator.ObjectGenerator() self.csv_files = itertools.cycle([ "audit_rbac_snapshot_create.csv", "audit_rbac_snapshot_update.csv" ]) self._import_file(next(self.csv_files)) self.people = all_models.Person.eager_query().all() self.program = db.session.query(all_models.Program).filter( all_models.Program.slug == "PMRBACPROGRAM-1" ).one() sources = set(r.source for r in self.program.related_sources) destinations = set(r.destination for r in self.program.related_destinations) related = [obj for obj in sources.union(destinations) if not isinstance(obj, all_models.Person)] self.related_objects = related self.api = Api() self.client.get("/login") self.audit = self.create_audit() self.snapshots = all_models.Snapshot.eager_query().all() self.sanity_check() def create_audit(self): """Create default audit for audit snapshot RBAC tests""" _, audit = self.objgen.generate_object(all_models.Audit, { "title": "Snapshotable audit", "program": {"id": self.program.id}, "status": "Planned", "snapshots": { "operation": "create", }, "context": { "type": "Context", "id": self.program.context_id, "href": "/api/contexts/{}".format(self.program.context_id) } }) self.add_auditors(audit) return audit def add_auditors(self, audit): """Add auditors to audits via POST user_role call""" auditor_emails = [ "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**", ] program_reader_emails = [ "*****@*****.**", ] auditor_role = db.session.query(all_models.Role).filter( all_models.Role.name == "Auditor" ).one() program_reader_role = db.session.query(all_models.Role).filter( all_models.Role.name == "ProgramReader" ).one() program = db.session.query(all_models.Program).filter( all_models.Program.slug == "PMRBACPROGRAM-1" ).one() user_roles = [ (auditor_emails, auditor_role, audit.context), (program_reader_emails, program_reader_role, program.context) ] for emails, role, context in user_roles: for email in emails: auditor = all_models.Person.query.filter( all_models.Person.email == email).one() self.objgen.generate_user_role(auditor, role, context) def update_audit(self): """Update default audit""" self._import_file(next(self.csv_files)) audit = all_models.Audit.query.filter( all_models.Audit.title == "Snapshotable audit" ).one() self.audit = audit self.api.modify_object(self.audit, { "snapshots": { "operation": "upsert" } }) def sanity_check(self): """Sanity check if the audit_rbac.csv was imported correctly""" assert len(self.people) == 21, \ "Expecting 21 people not {}.".format(len(self.people)) assert len(self.related_objects) == 19, \ "Expecting 19 objects mapped to program not {}.".format( len(self.related_objects)) assert len(self.snapshots) == 19, \ "Expecting 19 snapshots for default audit not {}.".format( len(self.snapshots)) assert all(ss.parent_id == self.audit.id for ss in self.snapshots), \ "All snapshots should be in default audit scope!" def read(self, objects): """Attempt to do a GET request for every object in the objects list""" responses = [] for obj in objects: status_code = self.api.get(obj.__class__, obj.id).status_code responses.append((obj.type, status_code)) return responses def update(self, objects): """Attempt to do a PUT request for every object in the objects list""" scope_response = self.api.get(self.audit.__class__, self.audit.id) if scope_response.status_code == 200: self.update_audit() responses = [] for obj in objects: response = self.api.get(obj.__class__, obj.id) status_code = response.status_code if response.status_code == 200: data = response.json if obj.type == "Snapshot": data.update({ "update_revision": "latest" }) put_call = self.api.put(obj, data) status_code = put_call.status_code responses.append((obj.type, status_code)) return responses def call_api(self, method, expected_statuses): """Calls the REST api with a given method and returns a list of status_codes that do not match the expected_statuses dict""" all_errors = [] for person in self.people: self.api.set_user(person) responses = method(self.snapshots + [self.audit]) for type_, code in responses: if code != expected_statuses[person.email][type_]: all_errors.append("{} does not have {} access to {} ({})".format( person.email, method.__name__, type_, code)) return all_errors def test_read_access_on_mapped(self): """Test READ access to snapshotted objects of default audit""" expected_statuses = defaultdict(lambda: defaultdict(lambda: 200)) exceptional_users = ( ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ) for user, exceptions in exceptional_users: for type_, status_code in exceptions.items(): expected_statuses[user][type_] = status_code errors = self.call_api(self.read, expected_statuses) assert not errors, "\n".join(errors) def test_update_access_on_mapped(self): """Test UPDATE access to snapshotted objects of default audit""" expected_statuses = defaultdict(lambda: defaultdict(lambda: 200)) exceptional_users = ( ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), # Auditor roles ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS), ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS) ) for user, exceptions in exceptional_users: for type_, status_code in exceptions.items(): expected_statuses[user][type_] = status_code errors = self.call_api(self.update, expected_statuses) assert not errors, "\n".join(errors)
class TestAuditRBAC(TestCase): """Test audit RBAC""" # pylint: disable=too-many-instance-attributes CSV_DIR = join(abspath(dirname(__file__)), "test_csvs") def setUp(self): """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests""" TestCase.clear_data() self.api = Api() self.objgen = integration.ggrc.generator.ObjectGenerator() self.csv_files = itertools.cycle([ "audit_rbac_snapshot_create.csv", "audit_rbac_snapshot_update.csv" ]) response = self._import_file(next(self.csv_files)) self._check_csv_response(response, {}) self.people = all_models.Person.eager_query().all() self.program = db.session.query(all_models.Program).filter( all_models.Program.slug == "PMRBACPROGRAM-1").one() sources = set(r.source for r in self.program.related_sources) destinations = set(r.destination for r in self.program.related_destinations) related = [ obj for obj in sources.union(destinations) if not isinstance(obj, all_models.Person) ] self.related_objects = related self.api = Api() self.client.get("/login") self.audit = self.create_audit() self.snapshots = all_models.Snapshot.eager_query().all() def create_audit(self): """Create default audit for audit snapshot RBAC tests""" _, audit = self.objgen.generate_object( all_models.Audit, { "title": "Snapshotable audit", "program": { "id": self.program.id }, "status": "Planned", "snapshots": { "operation": "create", }, "context": { "type": "Context", "id": self.program.context_id, "href": "/api/contexts/{}".format(self.program.context_id) } }) self.add_auditors(audit) return audit def add_auditors(self, audit): """Add auditors to audits via POST user_role call""" auditor_emails = [ "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**", ] program_reader_emails = [ "*****@*****.**", ] auditor_role = db.session.query( all_models.Role).filter(all_models.Role.name == "Auditor").one() program_reader_role = db.session.query(all_models.Role).filter( all_models.Role.name == "ProgramReader").one() program = db.session.query(all_models.Program).filter( all_models.Program.slug == "PMRBACPROGRAM-1").one() user_roles = [(auditor_emails, auditor_role, audit.context), (program_reader_emails, program_reader_role, program.context)] for emails, role, context in user_roles: for email in emails: auditor = all_models.Person.query.filter( all_models.Person.email == email).one() self.objgen.generate_user_role(auditor, role, context) def update_audit(self): """Update default audit""" response = self._import_file(next(self.csv_files)) self._check_csv_response(response, {}) audit = all_models.Audit.query.filter( all_models.Audit.title == "Snapshotable audit").one() self.audit = audit self.api.modify_object(self.audit, {"snapshots": { "operation": "upsert" }}) def read(self, objects): """Attempt to do a GET request for every object in the objects list""" responses = [] for obj in objects: status_code = self.api.get(obj.__class__, obj.id).status_code responses.append((obj.type, status_code)) return responses def update(self, objects): """Attempt to do a PUT request for every object in the objects list""" scope_response = self.api.get(self.audit.__class__, self.audit.id) if scope_response.status_code == 200: self.update_audit() responses = [] for obj in objects: response = self.api.get(obj.__class__, obj.id) status_code = response.status_code if response.status_code == 200: data = response.json if obj.type == "Snapshot": data.update({"update_revision": "latest"}) put_call = self.api.put(obj, data) status_code = put_call.status_code responses.append((obj.type, status_code)) return responses def call_api(self, method, expected_statuses): """Calls the REST api with a given method and returns a list of status_codes that do not match the expected_statuses dict""" all_errors = [] for person in self.people: self.api.set_user(person) responses = method(self.snapshots + [self.audit]) for type_, code in responses: if code != expected_statuses[person.email][type_]: all_errors.append( "{} does not have {} access to {} ({})".format( person.email, method.__name__, type_, code)) return all_errors def test_read_access_on_mapped(self): """Test READ access to snapshotted objects of default audit""" expected_statuses = defaultdict(lambda: defaultdict(lambda: 200)) exceptional_users = (("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ) for user, exceptions in exceptional_users: for type_, status_code in exceptions.items(): expected_statuses[user][type_] = status_code errors = self.call_api(self.read, expected_statuses) assert not errors, "\n".join(errors) def test_update_access_on_mapped(self): """Test UPDATE access to snapshotted objects of default audit""" expected_statuses = defaultdict(lambda: defaultdict(lambda: 200)) exceptional_users = ( ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), # Auditor roles ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS), ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS)) for user, exceptions in exceptional_users: for type_, status_code in exceptions.items(): expected_statuses[user][type_] = status_code errors = self.call_api(self.update, expected_statuses) assert not errors, "\n".join(errors)
class TestReviewStatusUpdate(TestCase): """Base TestCase class automatic review status update.""" def setUp(self): super(TestReviewStatusUpdate, self).setUp() self.api = Api() self.api.login_as_external() self.generator = generator.ObjectGenerator() def test_gca(self): """if GCA of reviewable is changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory( definition_type="risk", title="rich_test_gca", attribute_type="Rich Text" ) risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_update_gca(self): """if existing GCA value changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory( definition_type="risk", title="rich_test_gca", attribute_type="Rich Text" ) risk = factories.RiskFactory() risk.custom_attribute_values = [{ "attribute_value": "starting_value", "custom_attribute_id": gca.id }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) @ddt.data("custom attr", "slug", "self") def test_gca_with_varying_titles(self, title): """if GCA with any title is changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory( definition_type="risk", title=title, attribute_type="Rich Text" ) risk = factories.RiskFactory() risk.custom_attribute_values = [{ "attribute_value": "starting_value", "custom_attribute_id": gca.id }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_map_person_gca(self): """if Map:Person GCA value added review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory( definition_type="risk", title="map_test_gca", attribute_type="Map:Person" ) user_id = all_models.Person.query.filter_by( email="*****@*****.**" ).one().id risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_object_id": user_id, "attribute_value": "Person", }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_update_map_person_gca(self): """if existing Map:Person GCA value changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory( definition_type="risk", title="map_test_gca", attribute_type="Map:Person" ) first_user_id = all_models.Person.query.filter_by( email="*****@*****.**" ).one().id second_user_id = factories.PersonFactory().id risk = factories.RiskFactory() risk.custom_attribute_values = [{ "attribute_object_id": first_user_id, "custom_attribute_id": gca.id, "attribute_value": "Person" }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_object_id": second_user_id, "attribute_value": "Person", }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_delete_map_person_gca(self): """if existing Map:Person GCA value deleted review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory( definition_type="risk", title="map_test_gca", attribute_type="Map:Person" ) user_id = all_models.Person.query.filter_by( email="*****@*****.**" ).one().id risk = factories.RiskFactory() risk.custom_attribute_values = [{ "attribute_object_id": user_id, "custom_attribute_id": gca.id, "attribute_value": "Person" }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_object_id": None, "attribute_object": None, "attribute_value": "Person", }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_reference_url(self): """If reference url is updated state should not updated""" with factories.single_commit(): risk = factories.RiskFactory() doc = factories.DocumentReferenceUrlFactory( title="Simple title", link="some_url.com", description="mega description", parent_obj={ "id": risk.id, "type": "Risk" } ) review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id self.api.modify_object(doc, {"link": "new_link.com"}) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_acl_roles(self): """Update of reviewable ACL shouldn't change review status""" with factories.single_commit(): risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id ac_role_id = all_models.AccessControlRole.query.filter_by( name="Admin", object_type="Risk" ).one().id user_id = all_models.Person.query.filter_by( email="*****@*****.**" ).one().id self.api.modify_object( risk, { "access_control_list": [{ "ac_role_id": ac_role_id, "person": { "id": user_id }, }], } ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_comments(self): """Add comment to reviewable shouldn't update review state""" with factories.single_commit(): risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id self.generator.generate_comment( risk, "Verifiers", "some comment", send_notification="false" ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_mapping_non_snapshotable(self): """Map non-snapshotable shouldn't change review status""" with factories.single_commit(): risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id factories.RelationshipFactory( source=risk, destination=factories.IssueFactory() ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) @ddt.data( "Standard", "Regulation", "Requirement", "Objective", "Control", "Product", "System", "Process", "AccessGroup", "Contract", "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk", "Threat", "Vendor" ) def test_map_snapshotable(self, snapshotable): """Map '{}' should change review status""" with factories.single_commit(): risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk ) review_id = review.id self.generator.generate_relationship( source=risk, destination=factories.get_model_factory(snapshotable)(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_unmap_snapshotable(self): """Unmap snapshotable should change review status""" self.api.login_as_normal() risk = factories.RiskFactory() resp, review = generate_review_object(risk) review_id = review.id _, rel = self.generator.generate_relationship( source=risk, 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) @ddt.data( "Assessment", "Issue", "Program", "Project", "Audit", "RiskAssessment", "AssessmentTemplate", "Person", ) def test_map_nonsnapshotable(self, nonsnapshotable): """Map '{}' shouldn't change review status""" risk = factories.RiskFactory() _, review = generate_review_object( risk, state=all_models.Review.STATES.REVIEWED) review_id = review.id review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.generator.generate_relationship( source=risk, destination=factories.get_model_factory(nonsnapshotable)(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_unmap_nonsnapshotable(self): """Unmap nonsnapshotable shouldn't change review status""" self.api.login_as_normal() risk = factories.RiskFactory() resp, review = generate_review_object( risk, state=all_models.Review.STATES.REVIEWED) review_id = review.id _, rel = self.generator.generate_relationship( source=risk, destination=factories.ProgramFactory(), 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) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) resp = self.api.delete(rel) self.assert200(resp) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_proposal_apply(self): """Reviewable object changed via proposal -> review.state-> UNREVIEWED""" risk = factories.RiskFactory() _, review = generate_review_object(risk) review_id = review.id proposal_content = { "fields": { "title": "new title" }, } proposal = factories.ProposalFactory( instance=risk, content=proposal_content, agenda="agenda content" ) self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED}) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_review_status_update(self): """Test updating folder preserves review status""" risk = factories.RiskFactory() factories.ReviewFactory( reviewable=risk, status=all_models.Review.STATES.REVIEWED, ) self.api.put(risk, {"folder": factories.random_str()}) risk = all_models.Risk.query.get(risk.id) self.assertEqual(risk.review.status, all_models.Review.STATES.REVIEWED)
class TestAuditRBAC(TestCase): """Test audit RBAC""" # pylint: disable=too-many-instance-attributes def setUp(self): """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests""" TestCase.clear_data() self.api = Api() self.objgen = integration.ggrc.generator.ObjectGenerator() def create_audit(self, audit_role, userid): """Create default audit for audit snapshot RBAC tests""" is_auditor = False if audit_role == "Auditors": is_auditor = True auditor_role = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Auditors").one() program = db.session.query(all_models.Program).get(self.program_id) _, audit = self.objgen.generate_object( all_models.Audit, { "title": "Snapshotable audit", "program": { "id": self.program_id }, "status": "Planned", "snapshots": { "operation": "create", }, "access_control_list": [acl_helper.get_acl_json(auditor_role.id, userid)] if is_auditor else None, "context": { "type": "Context", "id": program.context_id, "href": "/api/contexts/{}".format(program.context_id) } }) return audit def create_program(self, program_role, userid): """Create default program for audit snapshot RBAC tests""" if program_role and program_role != "Auditors": program_role = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == program_role).one() else: program_role = None _, program = self.objgen.generate_object( all_models.Program, { "title": "test program", "access_control_list": [acl_helper.get_acl_json(program_role.id, userid)] if program_role else None }) for model_type in Types.all - Types.external: model = get_model(model_type) _, model_object = self.objgen.generate_object( model, { "title": "Test Snapshot - {}".format(model_type), }) self.objgen.generate_relationship(program, model_object) return program def update_audit(self): """Update default audit""" for model_type in Types.all - Types.external: model = get_model(model_type) obj = model.query.filter_by( title="Test Snapshot - {}".format(model_type)).first() self.api.modify_object( obj, {"title": "Test Snapshot - {} EDIT".format(model_type)}) audit = all_models.Audit.query.filter( all_models.Audit.title == "Snapshotable audit").one() self.api.modify_object(audit, {"snapshots": {"operation": "upsert"}}) def read(self, objects): """Attempt to do a GET request for every object in the objects list""" responses = [] for obj in objects: status_code = self.api.get(obj.__class__, obj.id).status_code responses.append((obj.type, status_code)) return responses def update(self, objects): """Attempt to do a PUT request for every object in the objects list""" scope_response = self.api.get(all_models.Audit, self.audit_id) if scope_response.status_code == 200: self.update_audit() responses = [] for obj in objects: response = self.api.get(obj.__class__, obj.id) status_code = response.status_code if response.status_code == 200: data = response.json if obj.type == "Snapshot": data.update({"update_revision": "latest"}) put_call = self.api.put(obj, data) status_code = put_call.status_code responses.append((obj.type, status_code)) return responses # pylint: disable=attribute-defined-outside-init @ddt.data( ("Administrator", "", DEFAULT_PERMISSIONS), ("Creator", "", DEFAULT_LACK_OF_PERMISSIONS), ("Reader", "", DEFAULT_PERMISSIONS), ("Editor", "", DEFAULT_PERMISSIONS), ("Administrator", "Program Managers", DEFAULT_PERMISSIONS), ("Creator", "Program Managers", DEFAULT_PERMISSIONS), ("Reader", "Program Managers", DEFAULT_PERMISSIONS), ("Editor", "Program Managers", DEFAULT_PERMISSIONS), ("Administrator", "Program Editors", DEFAULT_PERMISSIONS), ("Creator", "Program Editors", DEFAULT_PERMISSIONS), ("Reader", "Program Editors", DEFAULT_PERMISSIONS), ("Editor", "Program Editors", DEFAULT_PERMISSIONS), ("Administrator", "Program Readers", DEFAULT_PERMISSIONS), ("Creator", "Program Readers", DEFAULT_PERMISSIONS), ("Reader", "Program Readers", DEFAULT_PERMISSIONS), ("Editor", "Program Readers", DEFAULT_PERMISSIONS), ("Administrator", "Auditors", DEFAULT_PERMISSIONS), ("Creator", "Auditors", DEFAULT_PERMISSIONS), ("Reader", "Auditors", DEFAULT_PERMISSIONS), ("Editor", "Auditors", DEFAULT_PERMISSIONS), ) @ddt.unpack def test_read_access_on_mapped(self, rolename, object_role, expected_status): """Test if {0} with {1} role, has READ access to snapshotted objects of default audit""" user = self.create_user_with_role(rolename) user_id = user.id program = self.create_program(object_role, user_id) self.program_id = program.id audit = self.create_audit(object_role, user_id) snapshots = all_models.Snapshot.eager_query().all() objects = snapshots + [audit] user = all_models.Person.query.get(user_id) self.api.set_user(user) responses = self.read(objects) all_errors = [] for type_, code in responses: if code != expected_status[type_]: all_errors.append( "{} does not have read access to {} ({})".format( user.email, type_, code)) assert not all_errors, "\n".join(all_errors) # pylint: disable=attribute-defined-outside-init @ddt.data( ("Administrator", "", DEFAULT_PERMISSIONS), ("Creator", "", DEFAULT_LACK_OF_PERMISSIONS), ("Reader", "", DEFAULT_LACK_OF_PERMISSIONS), ("Editor", "", DEFAULT_PERMISSIONS), ("Administrator", "Program Managers", DEFAULT_PERMISSIONS), ("Creator", "Program Managers", DEFAULT_PERMISSIONS), ("Reader", "Program Managers", DEFAULT_PERMISSIONS), ("Editor", "Program Managers", DEFAULT_PERMISSIONS), ("Administrator", "Program Editors", DEFAULT_PERMISSIONS), ("Creator", "Program Editors", DEFAULT_PERMISSIONS), ("Reader", "Program Editors", DEFAULT_PERMISSIONS), ("Editor", "Program Editors", DEFAULT_PERMISSIONS), ("Administrator", "Program Readers", DEFAULT_PERMISSIONS), ("Creator", "Program Readers", DEFAULT_LACK_OF_PERMISSIONS), ("Reader", "Program Readers", DEFAULT_LACK_OF_PERMISSIONS), ("Editor", "Program Readers", DEFAULT_PERMISSIONS), ("Administrator", "Auditors", DEFAULT_PERMISSIONS), ("Creator", "Auditors", DEFAULT_AUDITOR_PERMISSIONS), ("Reader", "Auditors", DEFAULT_AUDITOR_PERMISSIONS), ("Editor", "Auditors", DEFAULT_PERMISSIONS), ) @ddt.unpack def test_update_access_on_mapped(self, rolename, object_role, expected_status): """Test if {0} with {1} role, has UPDATE access to snapshotted objects of default audit""" user = self.create_user_with_role(rolename) user_id = user.id program = self.create_program(object_role, user_id) self.program_id = program.id audit = self.create_audit(object_role, user_id) self.audit_id = audit.id snapshots = all_models.Snapshot.eager_query().all() objects = snapshots + [audit] user = all_models.Person.query.get(user_id) self.api.set_user(user) responses = self.update(objects) all_errors = [] for type_, code in responses: if code != expected_status[type_]: all_errors.append( "{} does not have update access to {} ({})".format( user.email, type_, code)) assert not all_errors, "\n".join(all_errors)
class TestReviewStatusUpdate(TestCase): """Base TestCase class automatic review status update.""" def setUp(self): super(TestReviewStatusUpdate, self).setUp() self.api = Api() self.generator = generator.ObjectGenerator() def test_gca(self): """if GCA of reviewable is changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="program", title="rich_test_gca", attribute_type="Rich Text") program = factories.ProgramFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_update_gca(self): """if existing GCA value changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="program", title="rich_test_gca", attribute_type="Rich Text") program = factories.ProgramFactory() program.custom_attribute_values = [{ "attribute_value": "starting_value", "custom_attribute_id": gca.id }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) @ddt.data("custom attr", "slug", "self") def test_gca_with_varying_titles(self, title): """if GCA with any title is changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="program", title=title, attribute_type="Rich Text") program = factories.ProgramFactory() program.custom_attribute_values = [{ "attribute_value": "starting_value", "custom_attribute_id": gca.id }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_value": "new_value", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_map_person_gca(self): """if Map:Person GCA value added review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="program", title="map_test_gca", attribute_type="Map:Person") user_id = all_models.Person.query.filter_by( email="*****@*****.**").one().id program = factories.ProgramFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_object_id": user_id, "attribute_value": "Person", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_update_map_person_gca(self): """if existing Map:Person GCA value changed review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="program", title="map_test_gca", attribute_type="Map:Person") first_user_id = all_models.Person.query.filter_by( email="*****@*****.**").one().id second_user_id = factories.PersonFactory().id program = factories.ProgramFactory() program.custom_attribute_values = [{ "attribute_object_id": first_user_id, "custom_attribute_id": gca.id, "attribute_value": "Person" }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_object_id": second_user_id, "attribute_value": "Person", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_delete_map_person_gca(self): """if existing Map:Person GCA value deleted review -> unreviewed""" with factories.single_commit(): ca_factory = factories.CustomAttributeDefinitionFactory gca = ca_factory(definition_type="program", title="map_test_gca", attribute_type="Map:Person") user_id = all_models.Person.query.filter_by( email="*****@*****.**").one().id program = factories.ProgramFactory() program.custom_attribute_values = [{ "attribute_object_id": user_id, "custom_attribute_id": gca.id, "attribute_value": "Person" }] review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id reviewable = review.reviewable review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.api.modify_object( reviewable, { "custom_attribute_values": [{ "custom_attribute_id": gca.id, "attribute_object_id": None, "attribute_object": None, "attribute_value": "Person", }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_reference_url(self): """If reference url is updated state should not updated""" with factories.single_commit(): program = factories.ProgramFactory() doc = factories.DocumentReferenceUrlFactory( title="Simple title", link="some_url.com", description="mega description", parent_obj={ "id": program.id, "type": "Program" }) review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id self.api.modify_object(doc, {"link": "new_link.com"}) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_acl_roles(self): """Update of reviewable ACL shouldn't change review status""" with factories.single_commit(): threat = factories.ThreatFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=threat) review_id = review.id ac_role_id = all_models.AccessControlRole.query.filter_by( name="Primary Contacts", object_type="Threat").one().id user_id = all_models.Person.query.filter_by( email="*****@*****.**").one().id self.api.modify_object( threat, { "access_control_list": [{ "ac_role_id": ac_role_id, "person": { "id": user_id }, }], }) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_comments(self): """Add comment to reviewable shouldn't update review state""" with factories.single_commit(): program = factories.ProgramFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id self.generator.generate_comment(program, "Verifiers", "some comment", send_notification="false") review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_mapping_non_snapshotable(self): """Map non-snapshotable shouldn't change review status""" with factories.single_commit(): program = factories.ProgramFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id factories.RelationshipFactory(source=program, destination=factories.IssueFactory()) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) @ddt.data("Standard", "Regulation", "Requirement", "Objective", "Control", "Product", "System", "Process", "AccessGroup", "Contract", "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk", "Threat", "Vendor") def test_map_snapshotable(self, snapshotable): """Map '{}' should change review status""" with factories.single_commit(): program = factories.ProgramFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=program) review_id = review.id self.generator.generate_relationship( source=program, destination=factories.get_model_factory(snapshotable)(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_unmap_snapshotable(self): """Unmap snapshotable should change review status""" program = factories.ProgramFactory() resp, review = generate_review_object(program) review_id = review.id _, rel = self.generator.generate_relationship( source=program, 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) @ddt.data( "Assessment", "Issue", "Program", "Project", "Audit", "RiskAssessment", "AssessmentTemplate", "Person", ) def test_map_nonsnapshotable(self, nonsnapshotable): """Map '{}' shouldn't change review status""" program = factories.ProgramFactory() _, review = generate_review_object( program, state=all_models.Review.STATES.REVIEWED) review_id = review.id review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.generator.generate_relationship( source=program, destination=factories.get_model_factory(nonsnapshotable)(), context=None, ) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_unmap_nonsnapshotable(self): """Unmap nonsnapshotable shouldn't change review status""" program = factories.ProgramFactory() resp, review = generate_review_object( program, state=all_models.Review.STATES.REVIEWED) review_id = review.id _, rel = self.generator.generate_relationship( source=program, destination=factories.ProgramFactory(), 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) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) resp = self.api.delete(rel) self.assert200(resp) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) def test_proposal_apply(self): """Reviewable object changed via proposal -> review.state-> UNREVIEWED""" program = factories.ProgramFactory() _, review = generate_review_object(program) review_id = review.id proposal_content = { "fields": { "title": "new title" }, } proposal = factories.ProposalFactory(instance=program, content=proposal_content, agenda="agenda content") self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED}) review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED) def test_review_status_update(self): """Test updating folder preserves review status""" threat = factories.ThreatFactory() factories.ReviewFactory( reviewable=threat, status=all_models.Review.STATES.REVIEWED, ) self.api.put(threat, {"folder": factories.random_str()}) program = all_models.Threat.query.get(threat.id) self.assertEqual(program.review.status, all_models.Review.STATES.REVIEWED)
class TestCycleTaskDeprecated(TestCase): """Test for correct working field last_deprecated_date.""" def setUp(self): super(TestCycleTaskDeprecated, self).setUp() self.api = Api() def test_redefine_status(self): """Test cycle task create and change status to Deprecated.""" cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")() with freeze_time("2017-01-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.id == cycle_task.id ).one() self.assertEquals(cycle_task_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_keep_date_unchanged(self): """Test set status to Deprecated, and then set status to Finished.""" cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")() with freeze_time("2017-01-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(cycle_task, { "status": "Finished" }) cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.id == cycle_task.id ).one() self.assertEquals(cycle_task_result.status, "Finished") self.assertEquals(cycle_task_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_repeat_deprecated_state(self): """Test updating of last deprecated date by multiply changing of status.""" cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")() with freeze_time("2017-01-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(cycle_task, { "status": "Finished" }) with freeze_time("2017-02-25"): self.api.modify_object(cycle_task, { "status": "Deprecated" }) with freeze_time("2017-02-26"): self.api.modify_object(cycle_task, { "status": "Finished" }) cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.id == cycle_task.id ).one() self.assertEquals(cycle_task_result.status, "Finished") self.assertEquals(cycle_task_result.last_deprecated_date, datetime.date(2017, 2, 25)) def test_filter_by_deprecated_date(self): """Test filter cycle task by last deprecated date.""" amount_of_cycle_tasks = 5 list_of_ids = [] cycle_task_factory = factories.get_model_factory( "CycleTaskGroupObjectTask") with factories.single_commit(): with freeze_time("2017-01-25"): for _ in range(amount_of_cycle_tasks): list_of_ids.append( cycle_task_factory(status="Deprecated").id ) query_request_data = [{ "object_name": "CycleTaskGroupObjectTask", 'filters': { 'expression': { 'left': 'task Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01-25", }, }, 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(list_of_ids, result.json[0]["CycleTaskGroupObjectTask"]["ids"]) def test_sort_by_deprecated_date(self): """Test sorting results of filter cycle tasks by deprecated date.""" dict_of_dates = {} date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"] cycle_task_factory = factories.get_model_factory( "CycleTaskGroupObjectTask") with factories.single_commit(): for date in date_list: with freeze_time(date): dict_of_dates[cycle_task_factory(status="Deprecated").id] = date sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1)) sorted_list_ids = [item[0] for item in sorted_dict] query_request_data = [{ "object_name": "CycleTaskGroupObjectTask", 'filters': { 'expression': { 'left': 'task Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01", }, }, "order_by": [{"name": "last_deprecated_date"}], 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(sorted_list_ids, result.json[0]["CycleTaskGroupObjectTask"]["ids"])
class TestAuditDeprecated(TestCase): """Test for correct working field last_deprecated_date """ def setUp(self): super(TestAuditDeprecated, self).setUp() self.api = Api() def test_redefine_status(self): """Test create audit and change status to Deprecated""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, { "status": "Deprecated" }) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id ).one() self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_keep_date_unchanged(self): """Test set status audit to Deprecated, and then set status to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(audit, { "status": "Planned" }) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id ).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 1, 25)) def test_repeat_deprecated_state(self): """Test set status audit to Deprecated, then to Planned, then to Deprecated and then to Planned""" audit = factories.AuditFactory() with freeze_time("2017-01-25"): self.api.modify_object(audit, { "status": "Deprecated" }) with freeze_time("2017-01-26"): self.api.modify_object(audit, { "status": "Planned" }) with freeze_time("2017-02-25"): self.api.modify_object(audit, { "status": "Deprecated" }) with freeze_time("2017-02-26"): self.api.modify_object(audit, { "status": "Planned" }) audit_result = all_models.Audit.query.filter( all_models.Audit.id == audit.id ).one() self.assertEquals(audit_result.status, "Planned") self.assertEquals(audit_result.last_deprecated_date, datetime.date(2017, 2, 25)) def test_filter_by_deprecated_date(self): """Test filter audits by last deprecated date""" amount_of_audits = 5 list_of_ids = [] with factories.single_commit(): with freeze_time("2017-01-25"): for _ in range(amount_of_audits): list_of_ids.append( factories.AuditFactory(status="Deprecated").id ) query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01-25", }, }, 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"]) def test_sort_by_deprecated_date(self): """Test sorting results of filter audits by deprecated date""" dict_of_dates = {} date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"] with factories.single_commit(): for date in date_list: with freeze_time(date): dict_of_dates[factories.AuditFactory(status="Deprecated").id] = date sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1)) sorted_list_ids = [item[0] for item in sorted_dict] query_request_data = [{ "object_name": "Audit", 'filters': { 'expression': { 'left': 'Last Deprecated Date', 'op': {'name': '='}, 'right': "2017-01", }, }, "order_by": [{"name": "last_deprecated_date"}], 'type': 'ids', }] result = self.api.send_request(self.api.client.post, data=query_request_data, api_link="/query") self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])