def setUp(self): super(TestVerifiedDate, self).setUp() self.api_helper = api_helper.Api() self.assessment = factories.AssessmentFactory( status=Assessment.PROGRESS_STATE, )
def test_empty_list_assessment(self): """Test actions with empty lists on assessments.""" assessment = factories.AssessmentFactory() response = self.api.put(assessment, {"actions": {"add_related": [], "remove_related": []}}) self.assert200(response)
def setUp(self): super(TestValidateOnComplete, self).setUp() self.assessment = factories.AssessmentFactory( status=Assessment.PROGRESS_STATE, )
def setUp(self): super(TestPreconditionsFailed, self).setUp() self.assessment = factories.AssessmentFactory( status=Assessment.PROGRESS_STATE, )
def test_complex_propagation_count(self): """Test multiple object ACL propagation. This test is meant to catch invalid ACL entries for propagation that can not happen. Example for this is propagation control -> relationships -> document. In that propagation rule we should only propagate control acl entries to relationships to documents. But what can happen is; when a control has multiple relationships, some to objects and only one to document, all of those relationships would get an ACL entry even though in some cases that is a propagation dead end. Setup for this test is: Objects: control regulation objective program audit assessment, assessment_2 Relationships: control - regulation control - objective objective - regulations program - control, regulation, objective, audit audit - assessment, assessment_2, audit - control-snapshot, regulation-snapshot, objective-snapshot control_snapshot - regulation_snapshot control_snapshot - objective_snapshot objective_snapshot - regulations_snapshot document - regulation, objective, control evidence - assessment """ # pylint: disable=too-many-locals with factories.single_commit(): control = factories.ControlFactory() regulation = factories.RegulationFactory() objective = factories.ObjectiveFactory() normal_objects = [control, regulation, objective] for obj1, obj2 in itertools.combinations(normal_objects, 2): if control in (obj1, obj2): with mock.patch( 'ggrc.models.relationship.is_external_app_user', return_value=True): factories.RelationshipFactory(source=obj1, destination=obj2, is_external=True) else: factories.RelationshipFactory(source=obj1, destination=obj2) assessment = factories.AssessmentFactory() assessment_2 = factories.AssessmentFactory(audit=assessment.audit) factories.RelationshipFactory( source=assessment, destination=assessment.audit, ) factories.RelationshipFactory( source=assessment_2, destination=assessment.audit, ) factories.RelationshipFactory( source=assessment.audit, destination=assessment.audit.program, ) for obj in normal_objects: factories.RelationshipFactory( source=assessment.audit.program, destination=obj, ) snapshots = self._create_snapshots(assessment.audit, normal_objects) for snapshot in snapshots: factories.RelationshipFactory( source=assessment.audit, destination=snapshot, ) for obj1, obj2 in itertools.combinations(snapshots, 2): factories.RelationshipFactory(source=obj1, destination=obj2) for obj in normal_objects: document = factories.DocumentFactory() factories.RelationshipFactory(source=obj, destination=document) evidence = factories.EvidenceUrlFactory() factories.RelationshipFactory(source=evidence, destination=assessment) acl_entry = control._access_control_list[0] propagation._propagate([acl_entry.id], self.user_id) self.assertEqual( all_models.AccessControlList.query.filter( all_models.AccessControlList.parent_id.isnot(None)).count(), 2, # 1 for relationship to document and 1 for document. ) acl_entry = next( acl for acl in assessment.audit.program._access_control_list if acl.ac_role.name == "Program Editors") propagation._propagate([acl_entry.id], self.user_id) self.assertEqual( all_models.AccessControlList.query.filter( all_models.AccessControlList.parent_id.isnot(None)).count(), 2 + 2 + 4 + 6 + 2 + 6 + 6 # 2 previous entries for control # 2 for audit (relationship + audit propagation) # 4 for assessments (2 assessments and 2 relationships for them) # 6 for snapshots (3 snapshots with relationships) # 2 assessment document with relationships # 6 for normal objects # 6 for normal object documents )
def test_asmnt_map_same_docs(self): """Test Audit summary when all Assessments mapped to same Documents""" with factories.single_commit(): audit = factories.AuditFactory() asmnt_statuses = all_models.Assessment.VALID_STATES docs = [ factories.DocumentFactory(document_type=doc_type) for doc_type in all_models.Document.VALID_DOCUMENT_TYPES ] for status in asmnt_statuses: asmnt = factories.AssessmentFactory(audit=audit, status=status) for doc in docs: factories.RelationshipFactory(source=asmnt, destination=doc) summary_link = "/api/{}/{}/summary".format( audit._inflector.table_plural, audit.id ) response = self.api.client.get(summary_link) self.assert200(response) doc_count = len(all_models.Document.VALID_DOCUMENT_TYPES) expected_data = { "statuses": [ { "name": "Completed", "assessments": 1, "documents": doc_count, "verified": 0 }, { "name": "Completed", "assessments": 1, "documents": doc_count, "verified": 1 }, { "name": "Deprecated", "assessments": 1, "documents": doc_count, "verified": 0 }, { "name": "In Progress", "assessments": 1, "documents": doc_count, "verified": 0 }, { "name": "In Review", "assessments": 1, "documents": doc_count, "verified": 0 }, { "name": "Not Started", "assessments": 1, "documents": doc_count, "verified": 0 }, { "name": "Rework Needed", "assessments": 1, "documents": doc_count, "verified": 0 } ], "total": { "assessments": 7, "documents": doc_count } } self.assertEqual(response.json, expected_data)
def test_update_ccs_many_audit_captains(self, mock_update_issue): """CCS of assessment should include secondary audit captains.""" with mock.patch.object(assessment_integration, '_is_issue_tracker_enabled', return_value=True): audit = factories.AuditFactory() audit_captains = factories.PersonFactory.create_batch(2) audit_captain_role = all_models.AccessControlRole.query.filter_by( name="Audit Captains", object_type="Audit").one() response_audit = self.api.put( audit, { "access_control_list": [{ "ac_role_id": audit_captain_role.id, "person": { "id": audit_captain.id, "type": "Person" } } for audit_captain in audit_captains] }) self.assert200(response_audit) issue_tracker_audit = all_models.IssuetrackerIssue.query.filter_by( object_id=audit.id, object_type=audit.type).one() audit_cc = issue_tracker_audit.cc_list self.assertEqual(audit_cc, audit_captains[1].email) assessment = factories.AssessmentFactory(audit=audit) assessment_issue = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=assessment, component_id="11111", hotlist_id="222222", ) assessment_persons = factories.PersonFactory.create_batch(3) assignee_role = all_models.AccessControlRole.query.filter_by( name="Assignees", object_type="Assessment").one() creator_role = all_models.AccessControlRole.query.filter_by( name="Creators", object_type="Assessment").one() response_assessment = self.api.put( assessment, { "issue_tracker": { "component_id": "11111", "enabled": True, "hotlist_id": "222222", "issue_priority": "P2", "issue_severity": "S2", "issue_type": "PROCESS", "issue_id": assessment_issue.issue_id }, "access_control_list": [{ "ac_role_id": creator_role.id if not index else assignee_role.id, "id": index + 1, "person": { "context_id": None, "href": "/api/people/{}".format(person.id), "id": person.id, "type": "Person" }, "person_email": person.email, "person_id": person.id, "person_name": person.name, "type": "AccessControlList" } for index, person in enumerate(assessment_persons)] }) self.assert200(response_assessment) issue_tracker_assessment = all_models.IssuetrackerIssue.query.filter_by( object_id=assessment.id, object_type=assessment.type).one() issue_tracker_cc = issue_tracker_assessment.cc_list.split(',')[0] assessment_emails = [person.email for person in assessment_persons] self.assertIn(issue_tracker_cc, assessment_emails)
def _test_revision_with_empty_cads(self, attribute_type, attribute_value, is_global): """Population cavs and cads depend on is_global flag and send params.""" asmnt = factories.AssessmentFactory() asmnt_id = asmnt.id cad_params = { "title": "test_cad", "definition_type": "assessment", "attribute_type": attribute_type } if not is_global: cad_params["definition_id"] = asmnt_id with factories.single_commit(): cad = factories.CustomAttributeDefinitionFactory(**cad_params) cad_id = cad.id revisions = ggrc.models.Revision.query.filter( ggrc.models.Revision.resource_id == asmnt_id, ggrc.models.Revision.resource_type == "Assessment", ).order_by(ggrc.models.Revision.id.desc()).all() self.assertEqual(1, len(revisions)) revision = revisions[0] # pylint: disable=protected-access self.assertIn("custom_attribute_values", revision._content) self.assertIn("custom_attribute_definitions", revision._content) self.assertEqual([], revision._content["custom_attribute_values"]) self.assertEqual([], revision._content["custom_attribute_definitions"]) self.assertIn("custom_attribute_values", revision.content) self.assertEqual([], revision.content["custom_attribute_values"]) self.assertIn("custom_attribute_definitions", revision.content) self.assertEqual([], revision.content["custom_attribute_definitions"]) self.gen.api.modify_object( asmnt, { "custom_attribute_values": [ { "attributable_id": asmnt.id, "attributable_type": "assessment", "attribute_value": attribute_value, "custom_attribute_id": cad.id, }, ], }, ) revisions = ggrc.models.Revision.query.filter( ggrc.models.Revision.resource_id == asmnt_id, ggrc.models.Revision.resource_type == "Assessment", ).order_by(ggrc.models.Revision.id.desc()).all() self.assertEqual(2, len(revisions)) revision = revisions[0] self.assertEqual(1, len(revision.content["custom_attribute_values"])) cav = revision.content["custom_attribute_values"][0] self.assertEqual(asmnt_id, cav["attributable_id"]) self.assertEqual(cad_id, cav["custom_attribute_id"]) self.assertIn("custom_attribute_definitions", revision.content) self.assertEqual(1, len(revision.content["custom_attribute_definitions"])) cad = all_models.CustomAttributeDefinition.query.get(cad_id) self.assertEqual( cad.id, revision.content["custom_attribute_definitions"][0]["id"]) old_revision = revisions[1] self.assertEqual([], old_revision.content["custom_attribute_values"]) self.assertEqual([], old_revision.content["custom_attribute_definitions"])
def test_audit_summary(self, assessment_count): """Test Audit summary when each type of Asmnt linked to each Evid type""" with factories.single_commit(): audit = factories.AuditFactory() for status in all_models.Assessment.VALID_STATES: for _ in range(assessment_count): assessment = factories.AssessmentFactory(audit=audit, status=status) evidence_url = factories.EvidenceFactory( kind=all_models.Evidence.URL) factories.RelationshipFactory(source=assessment, destination=evidence_url) evidence_file = factories.EvidenceFactory( kind=all_models.Evidence.FILE, source_gdrive_id='12345') factories.RelationshipFactory(source=assessment, destination=evidence_file) summary_link = "/api/{}/{}/summary".format( audit._inflector.table_plural, audit.id) response = self.api.client.get(summary_link) self.assert200(response) evid_count = len(all_models.Evidence.VALID_EVIDENCE_KINDS) expected_data = { "statuses": [{ "name": "Completed", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 0 }, { "name": "Completed", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 1 }, { "name": "Deprecated", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 0 }, { "name": "In Progress", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 0 }, { "name": "In Review", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 0 }, { "name": "Not Started", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 0 }, { "name": "Rework Needed", "assessments": assessment_count, "evidence": evid_count * assessment_count, "verified": 0 }], "total": { "assessments": 7 * assessment_count, "evidence": 7 * evid_count * assessment_count } } self.assertEqual(response.json, expected_data)
def test_needs_verification_two_diff_cads(self): """Test two cads from two assessments""" with factories.single_commit(): asmt1 = factories.AssessmentFactory() asmt2 = factories.AssessmentFactory() asmt1.add_person_with_role_name(factories.PersonFactory(), "Verifiers") cad1 = factories.CustomAttributeDefinitionFactory( title="test_LCA_1", definition_type="assessment", definition_id=asmt1.id, attribute_type="Text", ) cad2 = factories.CustomAttributeDefinitionFactory( title="test_LCA_2", definition_type="assessment", definition_id=asmt2.id, attribute_type="Text", ) asmt_ids = [asmt1.id, asmt2.id] data = { "assessments_ids": asmt_ids, "attributes": [{ "attribute_value": "cav_value_1", "attribute_title": cad1.title, "attribute_type": "Text", "extra": { "comment": {}, "urls": [], "files": [], }, "bulk_update": [ { "assessment_id": asmt1.id, "attribute_definition_id": cad1.id, "slug": asmt1.slug, }, ] }, { "attribute_value": "cav_value_2", "attribute_title": cad2.title, "attribute_type": "Text", "extra": { "comment": {}, "urls": [], "files": [], }, "bulk_update": [ { "assessment_id": asmt2.id, "attribute_definition_id": cad2.id, "slug": asmt2.slug, }, ] }] } builder = csvbuilder.CsvBuilder(data) expected_data = { asmt1.id: { "files": [], "urls": [], "cavs": { "test_LCA_1": "cav_value_1" }, "slug": asmt1.slug, "verification": True, "comments": [] }, asmt2.id: { "files": [], "urls": [], "cavs": { "test_LCA_2": "cav_value_2" }, "slug": asmt2.slug, "verification": False, "comments": [] }, } self.assert_assessments(builder, expected_data) self.assertEqual(builder.assessment_ids, asmt_ids)
def test_asmnt_map_same_docs(self): """Test Audit summary when all Assessments mapped to same Evidences""" with factories.single_commit(): audit = factories.AuditFactory() asmnt_statuses = all_models.Assessment.VALID_STATES evidences = [ factories.EvidenceFactory(kind=all_models.Evidence.URL), factories.EvidenceFactory(kind=all_models.Evidence.FILE, source_gdrive_id='12345') ] for status in asmnt_statuses: asmnt = factories.AssessmentFactory(audit=audit, status=status) for evidence in evidences: factories.RelationshipFactory(source=asmnt, destination=evidence) summary_link = "/api/{}/{}/summary".format( audit._inflector.table_plural, audit.id) response = self.api.client.get(summary_link) self.assert200(response) evid_count = len(all_models.Evidence.VALID_EVIDENCE_KINDS) expected_data = { "statuses": [{ "name": "Completed", "assessments": 1, "evidence": evid_count, "verified": 0 }, { "name": "Completed", "assessments": 1, "evidence": evid_count, "verified": 1 }, { "name": "Deprecated", "assessments": 1, "evidence": evid_count, "verified": 0 }, { "name": "In Progress", "assessments": 1, "evidence": evid_count, "verified": 0 }, { "name": "In Review", "assessments": 1, "evidence": evid_count, "verified": 0 }, { "name": "Not Started", "assessments": 1, "evidence": evid_count, "verified": 0 }, { "name": "Rework Needed", "assessments": 1, "evidence": evid_count, "verified": 0 }], "total": { "assessments": 7, "evidence": evid_count } } self.assertEqual(response.json, expected_data)
def setUp(self): self.clear_data() super(TestWithLastAssessmentDate, self).setUp() self.generator = integration.ggrc.generator.ObjectGenerator() self.client.get("/login") self.api = Api() program = factories.ProgramFactory(title="Last Assessment Date") controls = [factories.ControlFactory() for _ in range(3)] self.control_ids = [c.id for c in controls] for control in controls: factories.RelationshipFactory(source=program, destination=control) objectives = [factories.ObjectiveFactory() for _ in range(3)] self.objective_ids = [c.id for c in objectives] for objective in objectives: factories.RelationshipFactory(source=program, destination=objective) self._create_audit(program=program, title="Last Assessment Date Audit") c_snapshots = (db.session.query(all_models.Snapshot) .filter_by(child_type="Control").all()) o_snapshots = (db.session.query(all_models.Snapshot) .filter_by(child_type="Objective").all()) c_id_to_snap_id = {s.child_id: s.id for s in c_snapshots} o_id_to_snap_id = {s.child_id: s.id for s in o_snapshots} assessments = [factories.AssessmentFactory() for _ in range(3)] self.assessment_ids = [a.id for a in assessments] # Mappings: # controls[0]: assessments[0], assessments[1], assessments[2], # controls[1]: assessments[1], assessments[2], # controls[2]: assessments[2] # objectives[0]: assessments[0], # objectives[1]: assessments[0], assessments[1], # objectives[2]: assessments[0], assessments[1], assessments[2], # the first Assessment is completed earlier than the second, the third # Assessment is not completed. self._create_relationships( (c_id_to_snap_id[self.control_ids[0]], assessments[0]), (c_id_to_snap_id[self.control_ids[0]], assessments[1]), (c_id_to_snap_id[self.control_ids[0]], assessments[2]), (c_id_to_snap_id[self.control_ids[1]], assessments[1]), (c_id_to_snap_id[self.control_ids[1]], assessments[2]), (c_id_to_snap_id[self.control_ids[2]], assessments[2]), (o_id_to_snap_id[self.objective_ids[2]], assessments[0]), (o_id_to_snap_id[self.objective_ids[2]], assessments[1]), (o_id_to_snap_id[self.objective_ids[2]], assessments[2]), (o_id_to_snap_id[self.objective_ids[1]], assessments[0]), (o_id_to_snap_id[self.objective_ids[1]], assessments[1]), (o_id_to_snap_id[self.objective_ids[0]], assessments[0]), ) self.finished_dates = [datetime.datetime(2017, 2, 20, 13, 40, 0), datetime.datetime(2017, 3, 30, 14, 55, 0)] with freezegun.freeze_time(self.finished_dates[0]): assessments[0].status = all_models.Assessment.FINAL_STATE db.session.add(assessments[0]) with freezegun.freeze_time(self.finished_dates[1]): assessments[1].status = all_models.Assessment.FINAL_STATE db.session.add(assessments[1]) db.session.commit() query = all_models.Revision.query.filter_by(resource_type="Assessment") revision_ids = [revision.id for revision in query] computed_attributes.compute_attributes(revision_ids)
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)
def test_put_without_actions_assessment(self): """Test assessment put without actions on assessment.""" assessment = factories.AssessmentFactory() response = self.api.put(assessment, {"description": "test"}) self.assert200(response)
def test_custom_comment_value(self): """Test add custom attribute value comment action.""" ca_def_title = "def1" value = "yes" desc = "some comment" context_id = 6 with factories.single_commit(): assessment = factories.AssessmentFactory() ca_def = factories.CustomAttributeDefinitionFactory( title=ca_def_title, definition_type="assessment", definition_id=assessment.id, attribute_type="Dropdown", multi_choice_options="no,yes", multi_choice_mandatory="0,3") ca_val = factories.CustomAttributeValueFactory( custom_attribute=ca_def, attributable=assessment, attribute_value=value) request_data = { "id": assessment.id, "custom_attribute_values": [{ "id": ca_val.id, "custom_attribute_id": ca_def.id, "attribute_value": value, "type": "CustomAttributeValue", }], } response = self.api.put(assessment, request_data) self.assert200(response) request_data = [{ "comment": { "description": "<p>{}</p>".format(desc), "context": { "id": context_id, }, "assignee_type": "Assignees,Verifiers,Creators", "custom_attribute_revision_upd": { "custom_attribute_value": { "id": ca_val.id, }, "custom_attribute_definition": { "id": ca_def.id, }, }, }, }] response = self.api.post(all_models.Comment, request_data) self.assert200(response) comment = response.json[0][1]["comment"] self.assertEqual( comment["custom_attribute_revision"] ["custom_attribute_stored_value"], value) self.assertEqual( comment["custom_attribute_revision"]["custom_attribute"]["title"], ca_def_title) saved_comment = all_models.Comment.query.get(comment["id"]) revision = saved_comment.custom_attribute_revision self.assertEqual(revision["custom_attribute_stored_value"], value) self.assertEqual(revision["custom_attribute"]["title"], ca_def_title) request_data = { "actions": { "add_related": [{ "id": comment["id"], "type": "Comment", }] }, } response = self.api.put(assessment, request_data) self.assert200(response) relationship = _get_relationship("Assessment", assessment.id) self.assertIsNotNone(relationship)
def test_multiply_actions(self): """Test multiply actions""" assessment = factories.AssessmentFactory() evid_map = factories.EvidenceUrlFactory(link="google1.com") evid_del = factories.EvidenceUrlFactory(link="google2.com") factories.RelationshipFactory(source=assessment, destination=evid_del) ca_def = factories.CustomAttributeDefinitionFactory( title="def1", definition_type="assessment", definition_id=assessment.id, attribute_type="Dropdown", multi_choice_options="no,yes", multi_choice_mandatory="0,3" ) ca_val = factories.CustomAttributeValueFactory( custom_attribute=ca_def, attributable=assessment, attribute_value="no" ) response = self.api.put(assessment, { "custom_attribute_values": [ { "id": ca_val.id, "custom_attribute_id": ca_def.id, "attribute_value": "yes", "type": "CustomAttributeValue", }], "actions": {"add_related": [ { "id": None, "type": "Evidence", "kind": "FILE", "title": "evidence1", "link": "google3.com", "source_gdrive_id": "source_gdrive_id", }, { "id": evid_map.id, "type": "Evidence", }, { "id": None, "type": "Comment", "description": "comment1", "custom_attribute_definition_id": ca_def.id, } ], "remove_related": [ { "id": evid_del.id, "type": "Evidence", }]}}) self.assert200(response) preconditions_failed = response.json["assessment"]["preconditions_failed"] self.assertIs(preconditions_failed, True) assessment_by_url = self.simple_query( "Assessment", expression=["evidence url", "~", "google1.com"] ) self.assertEqual(len(assessment_by_url), 1) assessment_by_url = self.simple_query( "Assessment", expression=["evidence url", "~", "google2.com"] ) self.assertFalse(assessment_by_url) assessment_by_evidence = self.simple_query( "Assessment", expression=["evidence file", "~", "google3.com"] ) self.assertEqual(len(assessment_by_evidence), 1) assessment_by_comment = self.simple_query( "Assessment", expression=["comment", "~", "comment1"] ) self.assertEqual(len(assessment_by_comment), 1)
def test_update_ccs_many_audit_captains(self, mock_update_issue): """CCS shouldn't be calculated on update, only synchronization""" del mock_update_issue # Unused with mock.patch.object( assessment_integration.AssessmentTrackerHandler, '_is_tracker_enabled', return_value=True ): audit = factories.AuditFactory() audit_captains = factories.PersonFactory.create_batch(2) audit_captain_role = all_models.AccessControlRole.query.filter_by( name="Audit Captains", object_type="Audit" ).one() self.api.put( audit, { "access_control_list": [ { "ac_role_id": audit_captain_role.id, "person": { "id": audit_captain.id, "type": "Person" } } for audit_captain in audit_captains] } ) assessment = factories.AssessmentFactory( audit=audit ) assessment_issue = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=assessment, component_id="11111", hotlist_id="222222", ) assessment_persons = factories.PersonFactory.create_batch(3) assignee_role = all_models.AccessControlRole.query.filter_by( name="Assignees", object_type="Assessment" ).one() creator_role = all_models.AccessControlRole.query.filter_by( name="Creators", object_type="Assessment" ).one() response_assessment = self.api.put( assessment, { "issue_tracker": { "component_id": "11111", "enabled": True, "hotlist_id": "222222", "issue_priority": "P2", "issue_severity": "S2", "title": "Assessment Title", "issue_type": "PROCESS", "issue_id": assessment_issue.issue_id, "issue_url": integration_utils.build_issue_tracker_url( assessment_issue.issue_id ) }, "access_control_list": [ { "ac_role_id": creator_role.id if not index else assignee_role.id, "id": index + 1, "person": { "context_id": None, "href": "/api/people/{}".format( person.id ), "id": person.id, "type": "Person" }, "person_email": person.email, "person_id": person.id, "person_name": person.name, "type": "AccessControlList" } for index, person in enumerate(assessment_persons)] } ) self.assert200(response_assessment) issue_tracker_assessment = all_models.IssuetrackerIssue.query.filter_by( object_id=assessment.id, object_type=assessment.type ).one() issue_tracker_cc = issue_tracker_assessment.cc_list.split(',')[0] self.assertIn(issue_tracker_cc, "")
def test_complex_propagation_count(self): """Test multiple object ACL propagation. This test is meant to catch invalid ACL entries for propagation that can not happen. Example for this is propagation control -> relationships -> document. In that propagation rule we should only propagate control acl entries to relationships to documents. But what can happen is; when a control has multiple relationships, some to objects and only one to document, all of those relationships would get an ACL entry even though in some cases that is a propagation dead end. Setup for this test is: Objects: control regulation objective program audit assessment, assessment_2 Relationships: control - regulation control - objective objective - regulations program - control, regulation, objective, audit audit - assessment, assessment_2, audit - control-snapshot, regulation-snapshot, objective-snapshot control_snapshot - regulation_snapshot control_snapshot - objective_snapshot objective_snapshot - regulations_snapshot document - regulation, objective, control evidence - assessment """ with factories.single_commit(): person = factories.PersonFactory() control = factories.ControlFactory() regulation = factories.RegulationFactory() objective = factories.ObjectiveFactory() normal_objects = [control, regulation, objective] for obj1, obj2 in itertools.combinations(normal_objects, 2): factories.RelationshipFactory(source=obj1, destination=obj2) assessment = factories.AssessmentFactory() assessment_2 = factories.AssessmentFactory(audit=assessment.audit) factories.RelationshipFactory( source=assessment, destination=assessment.audit, ) factories.RelationshipFactory( source=assessment_2, destination=assessment.audit, ) factories.RelationshipFactory( source=assessment.audit, destination=assessment.audit.program, ) for obj in normal_objects: factories.RelationshipFactory( source=assessment.audit.program, destination=obj, ) snapshots = self._create_snapshots(assessment.audit, normal_objects) for snapshot in snapshots: factories.RelationshipFactory( source=assessment.audit, destination=snapshot, ) for obj1, obj2 in itertools.combinations(snapshots, 2): factories.RelationshipFactory(source=obj1, destination=obj2) for obj in normal_objects: document = factories.DocumentFactory() factories.RelationshipFactory(source=obj, destination=document) evidence = factories.EvidenceUrlFactory() factories.RelationshipFactory(source=evidence, destination=assessment) acl_entry = factories.AccessControlListFactory( person=person, ac_role=self.roles["Control"]["Admin"], object=control, ) propagation._propagate([acl_entry.id]) self.assertEqual( all_models.AccessControlList.query.count(), 3, # 1 for control, 1 for relationship to document and 1 for document. ) acl_entry = factories.AccessControlListFactory( person=person, ac_role=self.roles["Program"]["Program Editors"], object=assessment.audit.program, ) propagation._propagate([acl_entry.id]) self.assertEqual( all_models.AccessControlList.query.count(), 3 + 1 + 2 + 4 + 6 + 2 + 6 + 6 # 3 previous entries for control # 1 original program ACL entry # 2 for audit (relationship + audit propagation) # 4 for assessments (2 assessments and 2 relationships for them) # 6 for snapshots (3 snapshots with relationships) # 2 assessment document with relationships # 6 for normal objects # 6 for normal object documents )
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. """ self._create_cads("control") self.import_file("control_snapshot_data_multiple.csv") # Duplicate import because we have a bug in logging revisions and this # makes sure that the fixture created properly. self.import_file("control_snapshot_data_multiple.csv") controls = models.Control.query.all() with factories.single_commit(): audit = factories.AuditFactory() snapshots = self._create_snapshots(audit, controls) 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": "Control", }, "op": {"name": "AND"}, "right": { "left": "Code", "op": {"name": "="}, "right": "Control 1", }, }, }, "fields": ["mappings"], }] self.assertEqual( len(self.export_parsed_csv(search_request)["Control Snapshot"]), 1, ) single_query_count = counter.get with QueryCounter() as counter: search_request = [{ "object_name": "Snapshot", "filters": { "expression": { "left": "child_type", "op": {"name": "="}, "right": "Control", }, }, "fields": ["mappings"], }] self.assertEqual( len(self.export_parsed_csv(search_request)["Control Snapshot"]), 5, ) multiple_query_count = counter.get self.assertEqual(multiple_query_count, single_query_count)
def test_asmt_issue_related(self, asmnt_types, asmnt_related, issues_exist): """Test Issues related to assessments.""" # pylint: disable=too-many-locals # Test object has to be created before others to produce revision obj = factories.RiskFactory() with factories.single_commit(): assessments = [] for asmnt_type in asmnt_types: audit = factories.AuditFactory() assessment = factories.AssessmentFactory( audit=audit, assessment_type=asmnt_type) assessments.append(assessment) snapshot = factories.SnapshotFactory( parent=audit, child_id=obj.id, child_type=obj.type, revision_id=models.Revision.query.filter_by( resource_type=obj.type).one().id) factories.RelationshipFactory(source=audit, destination=assessment) factories.RelationshipFactory(source=snapshot, destination=assessment) # Create one issue in the last audit linked to snapshot/assessment issue = factories.IssueFactory(audit=audit) factories.RelationshipFactory(source=audit, destination=issue) factories.RelationshipFactory(source=snapshot, destination=issue) if asmnt_related: factories.RelationshipFactory(source=issue, destination=assessment) query = [] for assessment in assessments: query.append({ "object_name": "Issue", "type": "ids", "filters": { "expression": { "left": { "object_name": "Assessment", "op": { "name": "relevant" }, "ids": [assessment.id], }, "op": { "name": "OR" }, "right": { "object_name": "Assessment", "op": { "name": "similar" }, "ids": [assessment.id], }, }, }, }) expected_ids = [issue.id] response = self.client.post( "/query", data=json.dumps(query), headers={"Content-Type": "application/json"}, ) for num, data in enumerate(response.json): if issues_exist[num]: self.assertListEqual(data["Issue"]["ids"], expected_ids) else: self.assertListEqual(data["Issue"]["ids"], [])
def test_same_cads(self): """Test group by same cads""" with factories.single_commit(): asmt1 = factories.AssessmentFactory(assessment_type="Control") cad_obj1 = factories.CustomAttributeDefinitionFactory( title="text_LCA", definition_type="assessment", definition_id=asmt1.id, attribute_type="Text", ) factories.CustomAttributeValueFactory( custom_attribute=cad_obj1, attributable=asmt1, attribute_value="test_value", ) asmt2 = factories.AssessmentFactory(assessment_type="Control") cad_obj2 = factories.CustomAttributeDefinitionFactory( title="text_LCA", definition_type="assessment", definition_id=asmt2.id, attribute_type="Text", ) data = {"ids": [asmt1.id, asmt2.id]} expected_response = [{ "attribute": { "attribute_type": "Text", "title": "text_LCA", "default_value": "", "multi_choice_options": None, "multi_choice_mandatory": None, "mandatory": False, "placeholder": None, }, "related_assessments": { "count": 2, "values": [{ "assessments_type": "Control", "assessments": [{ "id": asmt1.id, "attribute_definition_id": cad_obj1.id, "slug": asmt1.slug, }, { "id": asmt2.id, "attribute_definition_id": cad_obj2.id, "slug": asmt2.slug, }] }], }, "assessments_with_values": [{ "id": asmt1.id, "title": asmt1.title, "attribute_value": "test_value", "attribute_person_id": None, }] }] response = self.client.post(self.ENDPOINT_URL, data=json.dumps(data), headers=self.headers) self.assert200(response) self.assertEqual(expected_response, response.json)
def setUp(self): super(TestLastAssessmentDate, self).setUp() self.api = Api() self.generator = generator.ObjectGenerator() self.client.get("/login") person = models.Person.query.first() admin_control = models.AccessControlRole.query.filter_by( name="Admin", object_type="Control").first() admin_objective = models.AccessControlRole.query.filter_by( name="Admin", object_type="Objective").first() with factories.single_commit(): controls = [ factories.ControlFactory(slug="Control_{}".format(i), title="Control_{}".format(i)) for i in range(5) ] objectives = [ factories.ObjectiveFactory(slug="Objective_{}".format(i), title="Objective_{}".format(i)) for i in range(2) ] for obj in itertools.chain(controls, objectives): acr = admin_control if obj.type == "Control" else admin_objective factories.AccessControlList(object=obj, person=person, ac_role=acr) audit_0 = factories.AuditFactory(title="Audit_0") audit_1 = factories.AuditFactory(title="Audit_1") audit_0_snapshots = self._create_snapshots( audit_0, controls[:2] + objectives[:1]) audit_1_snapshots = self._create_snapshots( audit_1, controls[1:4] + objectives) assessment_0 = factories.AssessmentFactory(title="Assessment_0", audit=audit_0) assessment_1 = factories.AssessmentFactory(title="Assessment_1", audit=audit_1) factories.RelationshipFactory(source=assessment_0, destination=audit_0) factories.RelationshipFactory(source=audit_1, destination=assessment_1) # Audit 0 assessment mappings: factories.RelationshipFactory( source=assessment_0, destination=audit_0_snapshots[1], # snapshot of control_1 ) factories.RelationshipFactory( source=assessment_0, destination=audit_0_snapshots[2], # snapshot of objective_0 ) # Audit 1 assessment mappings: factories.RelationshipFactory( source=audit_1_snapshots[0], # snapshot of control_1 destination=assessment_1, ) factories.RelationshipFactory( source=assessment_1, destination=audit_1_snapshots[1], # snapshot of control_2 ) factories.RelationshipFactory( source=assessment_1, destination=audit_1_snapshots[3], # snapshot of objective_0 ) factories.RelationshipFactory( source=audit_1_snapshots[4], # snapshot of objective_1 destination=assessment_1, )
def test_snapshot_del_w_asmt(self): """Test validation of deletion of snapshot with mapped assessment, issue""" # pylint: disable=too-many-locals, too-many-statements # Prepare assessment with control and objective and raised issue rel = all_models.Relationship control = factories.ControlFactory() revision_c = all_models.Revision.query.filter( all_models.Revision.resource_id == control.id, all_models.Revision.resource_type == control.__class__.__name__).order_by( all_models.Revision.id.desc()).first() with factories.single_commit(): program = factories.ProgramFactory() audit = factories.AuditFactory(program=program) snapshot_c = factories.SnapshotFactory( parent=audit, child_id=control.id, child_type=control.__class__.__name__, revision_id=revision_c.id) snapshot_c_id = snapshot_c.id assessment = factories.AssessmentFactory(audit=audit) assessment_id = assessment.id issue = factories.IssueFactory() issue_id = issue.id factories.RelationshipFactory(source=program, destination=control) factories.RelationshipFactory(source=program, destination=audit) factories.RelationshipFactory(source=snapshot_c, destination=audit) factories.RelationshipFactory(source=assessment, destination=audit) factories.RelationshipFactory(source=snapshot_c, destination=assessment) factories.RelationshipFactory(source=issue, destination=audit) factories.RelationshipFactory(source=issue, destination=assessment) # Check related_objects endpoint related_objects = self._get_related_objects(snapshot_c_id) self.assertEqual(len(related_objects), 3) self.assertEqual(len(related_objects["Assessment"]), 1) self.assertEqual(len(related_objects["Audit"]), 1) self.assertEqual(len(related_objects["Issue"]), 1) # Check validation forbids deletion with linked asmts and issues resp = self.api.delete(all_models.Snapshot, snapshot_c_id) self.assertEqual(resp.status_code, 409) # Unmap assessment and issue from control snapshot issue = all_models.Issue.query.get(issue_id) assessment = all_models.Assessment.query.get(assessment_id) snapshot_c = all_models.Snapshot.query.get(snapshot_c_id) issue_snapshot = rel.find_related(issue, snapshot_c).id asmt_snapshot = rel.find_related(assessment, snapshot_c).id self.api.delete(rel, issue_snapshot) self.api.delete(rel, asmt_snapshot) # Check related_objects endpoint related_objects = self._get_related_objects(snapshot_c_id) self.assertEqual(len(related_objects), 1) self.assertEqual(len(related_objects["Audit"]), 1) # Check successful deletion of control snapshot resp = self.api.delete(all_models.Snapshot, snapshot_c_id) self.assertEqual(resp.status_code, 200) self.assertFalse(all_models.Snapshot.query.get(snapshot_c_id)) # Check that snapshot unmapped from all objects successfully self.check_no_relationship(snapshot_c_id)
def setUp(self): super(TestLabeledMixin, self).setUp() self.client.get("/login") self.api = api_helper.Api() self.assessment = factories.AssessmentFactory()
def test_auto_slug_generation(self): """Test auto slug generation""" factories.AssessmentFactory(title="Some title") ca = all_models.Assessment.query.first() self.assertEqual("ASSESSMENT-{}".format(ca.id), ca.slug)
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") self.import_file("product_snapshot_data_multiple.csv") product = models.Product.query.all() with factories.single_commit(): 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": "Code", "op": { "name": "=" }, "right": "Product 1", }, }, }, "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"]), 5, ) multiple_query_count = counter.get self.assertEqual(multiple_query_count, single_query_count)
def test_generation_with_template_ids_given_2(self): """ Test multiple assessment templates ids filter 2 - test that multiple assessment templates ids are processed properly. """ included_template_ids = [] with factories.single_commit(): included_template_0 = factories.AssessmentTemplateFactory() included_template_1 = factories.AssessmentTemplateFactory() excluded_template = factories.AssessmentTemplateFactory() assessment = factories.AssessmentFactory() assessment.audit = included_template_0.audit cad = factories.CustomAttributeDefinitionFactory( definition_type="assessment_template", title="Included LCAD 0", definition_id=included_template_0.id, ) factories.CustomAttributeValueFactory( custom_attribute=cad, attributable=assessment, attribute_value="Test CAD 0", ) included_template_ids.append(included_template_0.id) cad = factories.CustomAttributeDefinitionFactory( definition_type="assessment_template", title="Included LCAD 1", definition_id=included_template_1.id, ) factories.CustomAttributeValueFactory( custom_attribute=cad, attributable=assessment, attribute_value="Test CAD 1", ) included_template_ids.append(included_template_1.id) cad = factories.CustomAttributeDefinitionFactory( definition_type="assessment_template", title="Excluded LCAD", definition_id=excluded_template.id) factories.CustomAttributeValueFactory( custom_attribute=cad, attributable=assessment, attribute_value="Test CAD 2", ) objects = [{ "object_name": "Assessment", "template_ids": included_template_ids, }] response = self.export_csv_template(objects) self.assertIn('Included LCAD 0', response.data) self.assertIn('Included LCAD 1', response.data) self.assertNotIn("Excluded LCAD", response.data)