def test_object_fields(self): """Test that objects contain mandatory fields. Front-end relies on audits and issues containing id, type, title, and description. This tests ensures that those fields are returned in the related_objects response. """ with factories.single_commit(): assessment = factories.AssessmentFactory() factories.IssueFactory() # unrelated issue for _ in range(2): issue = factories.IssueFactory() factories.RelationshipFactory.randomize(assessment, issue) related_objects = self._get_related_objects(assessment) expected_keys = {"id", "type", "title", "description"} self.assertLessEqual( expected_keys, set(related_objects["Audit"].keys()) ) for issue in related_objects["Issue"]: self.assertLessEqual( expected_keys, set(issue.keys()) )
def setUp(self): super(TestIssueAutomappings, self).setUp() # TODO: replace this hack with a special test util from ggrc.login import noop noop.login( ) # this is needed to pass the permission checks in automapper snapshottable = factories.ControlFactory() with factories.single_commit(): self.audit, self.asmt, self.snapshot = self._make_audit_asmt_snapshot( snapshottable, ) self.issue = factories.IssueFactory() self.issue_audit = factories.IssueFactory() self.issue_snapshot = factories.IssueFactory() factories.RelationshipFactory(source=self.issue_audit, destination=self.audit) # to map an Issue to a Snapshot, you first should map it to Audit factories.RelationshipFactory(source=self.issue_snapshot, destination=self.audit) factories.RelationshipFactory(source=self.issue_snapshot, destination=self.snapshot)
def test_snapshot_counts_query(self): """Test snapshot_counts endpoint""" with factories.single_commit(): audit = factories.AuditFactory() issue_1 = factories.IssueFactory(audit=audit) control = factories.ControlFactory() regulation = factories.RegulationFactory() factories.RelationshipFactory( source=issue_1, destination=control ) issue_2 = factories.IssueFactory(audit=audit) with factories.single_commit(): revision = all_models.Revision.query.filter( all_models.Revision.resource_type == "Issue", all_models.Revision.resource_id == issue_1.id ).first() revision_2 = all_models.Revision.query.filter( all_models.Revision.resource_type == "Issue", all_models.Revision.resource_id == issue_2.id ).first() snapshot_1 = factories.SnapshotFactory( parent=issue_1.audit, child_type=control.type, child_id=control.id, revision=revision ) factories.RelationshipFactory( source=issue_1, destination=snapshot_1, ) snapshot_2 = factories.SnapshotFactory( parent=issue_2.audit, child_type=regulation.type, child_id=regulation.id, revision=revision_2 ) factories.RelationshipFactory( source=issue_2, destination=snapshot_2, ) issues = [issue_1, issue_2] expected_snapshot_counts = { issue_1.id: {"Control": 1}, issue_2.id: {"Regulation": 1}, } for issue in issues: response = self.api.client.get( "/api/issues/{}/snapshot_counts".format(issue.id), ) snapshot_counts = json.loads(response.data) self.assertEqual(snapshot_counts, expected_snapshot_counts[issue.id])
def test_fields_in_response(self): """Test that objects contain only expected field.""" with factories.single_commit(): assessment = factories.AssessmentFactory() factories.IssueFactory() # unrelated issue for _ in range(2): issue = factories.IssueFactory() factories.RelationshipFactory.randomize(assessment, issue) expected_fields = {"Audit", "Comment", "Snapshot", "Evidence:URL", "Evidence:FILE"} related_objects = self._get_related_objects(assessment) self.assertEqual(expected_fields, set(related_objects.keys()))
def test_sync_due_date(self): """Test adding due_date in Issue""" due_date = "2018-09-13" date_format = "%Y-%m-%d" iti1 = factories.IssueTrackerIssueFactory( enabled=True, issue_id="1", issue_tracked_obj=factories.IssueFactory(status="Draft") ) iti2 = factories.IssueTrackerIssueFactory( enabled=True, issue_id="2", issue_tracked_obj=factories.IssueFactory(status="Draft") ) batches = [ { "1": { "status": "new", "type": "BUG", "priority": "P2", "severity": "S2", "custom_fields": [{ constants.CUSTOM_FIELDS_DUE_DATE: due_date }], }, "2": { "status": "new", "type": "BUG", "priority": "P2", "severity": "S2", "custom_fields": [], } } ] # Perform action. with mock.patch.object(sync_utils, "iter_issue_batches", return_value=batches): issue_sync_job.sync_issue_attributes() # Assert results. issue1 = all_models.Issue.query.get(iti1.issue_tracked_obj.id) self.assertEquals(issue1.due_date.strftime(date_format), due_date) issue2 = all_models.Issue.query.get(iti2.issue_tracked_obj.id) self.assertIsNone(issue2.due_date)
def test_non_snapshottable_import(self): """Reviewable mapped to non snapshotable via import Review -> REVIEWED """ program = factories.ProgramFactory() issue = factories.IssueFactory() issue_slug = issue.slug resp, review = generate_review_object( program, state=all_models.Review.STATES.REVIEWED) del review program_id = program.id self.assertEqual(201, resp.status_code) import_data = OrderedDict( [ ("object_type", "Program"), ("Code*", program.slug), ("map:Issue", issue_slug), ] ) response = self.import_data(import_data) self._check_csv_response(response, {}) program = all_models.Program.query.get(program_id) self.assertEqual( all_models.Review.STATES.REVIEWED, program.review_status )
def test_wrong_add_action_issue(self): """Test wrong add action on issue.""" issue = factories.IssueFactory() response = self.api.put(issue, {"actions": {"add_related": [{}]}}) self.assert400(response) response = self.api.put(issue, {"actions": {"add_related": [ { "type": "Document", } ]}}) self.assert400(response) response = self.api.put(issue, {"actions": {"add_related": [ { "id": None, } ]}}) self.assert400(response) response = self.api.put(issue, {"actions": {"add_related": [ { "id": None, "type": "Document", } ]}}) self.assert400(response)
def test_audit_change(self): """Test audit changing""" with factories.single_commit(): audit = factories.AuditFactory() issue = factories.IssueFactory() response = self.import_data( OrderedDict([ ("object_type", "Issue"), ("Code*", issue.slug), ("map:Audit", audit.slug), ])) self._check_csv_response(response, {}) another_audit = factories.AuditFactory() response = self.import_data( OrderedDict([ ("object_type", "Issue"), ("Code*", issue.slug), ("map:Audit", another_audit.slug), ])) self._check_csv_response( response, { "Issue": { "row_warnings": { errors.SINGLE_AUDIT_RESTRICTION.format( line=3, mapped_type="Audit", object_type="Issue", ) } } })
def test_prepare_update_json(self): """Test prepare_update_json method for Issue.""" with factories.single_commit(): issue = factories.IssueFactory() iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=issue, title='title', component_id=123, hotlist_id=321, issue_type="PROCESS", issue_priority="P3", issue_severity="S3", ) without_info = issue_integration.prepare_issue_update_json(issue) issue_info = issue.issue_tracker with_info = issue_integration.prepare_issue_update_json( issue, issue_info) expected_info = { 'component_id': 123, 'severity': u'S3', 'title': iti.title, 'hotlist_ids': [ 321, ], 'priority': u'P3', 'type': u'PROCESS', } self.assertEqual(expected_info, with_info) self.assertEqual(without_info, with_info)
def test_mapping_document(self, update_issue_mock): """Test map document action on issue. Issue in Issue tracker shouldn't be updated when reference url has been added to issue. """ iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=factories.IssueFactory()) document = factories.DocumentFactory() response = self.api.put( iti.issue_tracked_obj, { "actions": { "add_related": [ { "id": document.id, "type": "Document", }, ] } }) self.assert200(response) relationship = all_models.Relationship.query.filter( all_models.Relationship.source_type == "Issue", all_models.Relationship.source_id == response.json["issue"]["id"], ).order_by(all_models.Relationship.id.desc()).first() self.assertEqual(relationship.destination_id, document.id) self.assertEqual(relationship.source_id, iti.issue_tracked_obj.id) # Check that issue in Issue Tracker hasn't been updated. update_issue_mock.assert_not_called()
def test_existing_issue_link(self, update_mock): """Test Issue link to another ticket """ iti = factories.IssueTrackerIssueFactory( enabled=True, issue_id=TICKET_ID, issue_tracked_obj=factories.IssueFactory()) new_ticket_id = TICKET_ID + 1 new_data = {"issue_id": new_ticket_id} issue_request_payload = self.put_request_payload_builder(new_data) response_payload = self.response_payload_builder(new_data) with mock.patch("ggrc.integrations.issues.Client.get_issue", return_value=response_payload) as get_mock: with mock.patch.object(integration_utils, "exclude_auditor_emails", return_value={ u"*****@*****.**", }): response = self.api.put(iti.issue_tracked_obj, issue_request_payload) get_mock.assert_called_once() self.assert200(response) # check if data was changed in our DB issue_id = response.json.get("issue").get("id") issue_tracker_issue = models.IssuetrackerIssue.get_issue( "Issue", issue_id) self.assertEqual(int(issue_tracker_issue.issue_id), new_ticket_id) # check detach comment was sent detach_comment_template = params_builder.IssueParamsBuilder.DETACH_TMPL comment = detach_comment_template.format(new_ticket_id=new_ticket_id) expected_args = (TICKET_ID, {"status": "OBSOLETE", "comment": comment}) self.assertEqual(expected_args, update_mock.call_args[0])
def test_update_untracked_fields(self, issue_attrs, mock_update_issue): """Test updating issue with fields which shouldn't be sync.""" iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=factories.IssueFactory()) with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.put(iti.issue_tracked_obj, issue_attrs) mock_update_issue.assert_not_called()
def test_adding_comment_to_issue(self, update_issue_mock, url_builder_mock): """Test adding comment to issue.""" role = all_models.Role.query.filter( all_models.Role.name == "Administrator" ).one() with factories.single_commit(): client_user = factories.PersonFactory(name="Test User") rbac_factories.UserRoleFactory(role=role, person=client_user) self.api.set_user(client_user) self.client.get("/login") iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=factories.IssueFactory() ) comment = factories.CommentFactory(description="test comment") expected_result = { "comment": params_builder.BaseIssueTrackerParamsBuilder.COMMENT_TMPL.format( author=client_user.name, comment=comment.description, model="Issue", link="http://issue_url.com", ) } with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.post(all_models.Relationship, { "relationship": { "source": {"id": iti.issue_tracked_obj.id, "type": "Issue"}, "destination": {"id": comment.id, "type": "comment"}, "context": None }, }) url_builder_mock.assert_called_once() update_issue_mock.assert_called_with(iti.issue_id, expected_result)
def test_snapshot_mappings_export(self): """Test exporting snapshots with object mappings.""" with factories.single_commit(): control = factories.ControlFactory(slug="Control 1") audit = factories.AuditFactory() snapshot = self._create_snapshots(audit, [control])[0] assessments = [factories.AssessmentFactory() for _ in range(3)] issues = [factories.IssueFactory() for _ in range(3)] assessment_slugs = {assessment.slug for assessment in assessments} issue_slugs = {issue.slug for issue in issues} for assessment, issue in zip(assessments, issues): factories.RelationshipFactory(source=snapshot, destination=assessment) factories.RelationshipFactory(source=issue, destination=snapshot) self.search_request[0]["fields"] = ["mappings"] parsed_data = self.export_parsed_csv( self.search_request)["Control Snapshot"] exported_control_dict = parsed_data[0] self.assertEqual( set(exported_control_dict["Map: Assessment"].splitlines()), assessment_slugs, ) self.assertEqual( set(exported_control_dict["Map: Issue"].splitlines()), issue_slugs, )
def test_import_sox302_assmt_mapping_issue(self): """Test user sox302 update restricted mappings""" error_msg = ("Line 3: You don't have permission " "to update mappings for Issue: {slug}.") with factories.single_commit(): user = self.generate_person() assessment = factories.AssessmentFactory(sox_302_enabled=True) assmnt_slug = assessment.slug person_id = user.id self.assign_person(assessment, "Assignees", person_id) issue = factories.IssueFactory() issue_slug = issue.slug self.set_current_person(user) response = self.import_data( collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", assmnt_slug), ("map: Issue", issue_slug), ]), person=all_models.Person.query.get(person_id)) exp_errors = { 'Assessment': { 'row_warnings': {error_msg.format(slug=issue_slug.lower())}, } } self._check_csv_response(response, exp_errors)
def test_issue_due_date_get(self): """Test GET HTTP requests to Issue.due_date""" issue = factories.IssueFactory(due_date=datetime.date(2018, 6, 14)) response = self.api.get(all_models.Issue, issue.id) issue_json = response.json self.assert200(response) self.assertEqual(issue_json["issue"]["due_date"], "2018-06-14")
def __init__(self, user_id, acr, parent=None): """Set up objects for Issue permission tests. Args: user_id: Id of user under which all operations will be run. acr: Instance of ACR that should be assigned for tested user. parent: Model name in scope of which objects should be set up. """ self.setup_program_scope(user_id, acr) with factories.single_commit(): issue = factories.IssueFactory() if parent == "Audit": self.mapping_id = factories.RelationshipFactory( source=self.audit, destination=issue).id elif parent == "Assessment": self.mapping_id = factories.RelationshipFactory( source=self.assessment, destination=issue).id self.issue_id = issue.id self.parent = parent self.admin_acr_id = all_models.AccessControlRole.query.filter_by( name="Admin", object_type="Issue", ).one().id self.user_id = user_id self.api = Api() self.objgen = generator.ObjectGenerator() self.objgen.api = self.api if user_id: user = all_models.Person.query.get(user_id) self.api.set_user(user)
def setUp(self): """Setup tests data""" super(TestIssueUnmap, self).setUp() self.generator = generator.ObjectGenerator(fail_no_json=False) with factories.single_commit(): audit = factories.AuditFactory() self.audit_id = audit.id assessments = [ factories.AssessmentFactory(audit=audit) for _ in range(2) ] objectives = [factories.ObjectiveFactory() for _ in range(2)] snapshots = self._create_snapshots(audit, objectives) self.snapshot_ids = [s.id for s in snapshots] issue = factories.IssueFactory() self.issue_id = issue.id factories.RelationshipFactory(source=audit, destination=assessments[0]) factories.RelationshipFactory(source=audit, destination=assessments[1]) factories.RelationshipFactory(source=assessments[0], destination=snapshots[0]) factories.RelationshipFactory(source=assessments[0], destination=snapshots[1]) factories.RelationshipFactory(source=assessments[1], destination=snapshots[1]) self.unmap_rel_id1 = factories.RelationshipFactory( source=issue, destination=assessments[0]).id self.unmap_rel_id2 = factories.RelationshipFactory( source=issue, destination=assessments[1]).id
def test_sync_issue_statuses(self, issuetracker_status, issue_status): """Test updating issue statuses in GGRC.""" # Arrange test data. issue_tracker_issue_id = "1" iti = factories.IssueTrackerIssueFactory( enabled=True, issue_id=issue_tracker_issue_id, issue_tracked_obj=factories.IssueFactory(status="Draft")) batches = [{ issue_tracker_issue_id: { "status": issuetracker_status, "type": "BUG", "priority": "P2", "severity": "S2", } }] # Perform action. with mock.patch.object(sync_utils, "iter_issue_batches", return_value=batches): issue_sync_job.sync_issue_attributes() # Assert results. issue = all_models.Issue.query.get(iti.issue_tracked_obj.id) self.assertEquals(issue.status, issue_status)
def test_issue_tracker_error(self, update_issue_mock): """Test issue tracker errors. Issue in Issue tracker doesn't change state in case receiving an error. """ iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=factories.IssueFactory() ) update_issue_mock.side_effect = integrations_errors.HttpError("data") issue_attrs = { "issue_tracker": { "enabled": True, "hotlist_id": "123", "issue_id": iti.issue_id, } } with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True),\ mock.patch.object(all_models.IssuetrackerIssue, "create_or_update_from_dict") as update_info_mock: self.api.put(iti.issue_tracked_obj, issue_attrs) # Check that "enabled" flag hasn't been changed. self.assertTrue("enabled" not in update_info_mock.call_args[0][1])
def test_creating_new_ticket_for_linked_issue(self, update_mock): """Test create new ticket for already linked issue""" iti = factories.IssueTrackerIssueFactory( enabled=True, issue_id=TICKET_ID, issue_tracked_obj=factories.IssueFactory()) new_data = {"issue_id": ''} issue_request_payload = self.put_request_payload_builder(new_data) with mock.patch.object(integration_utils, "exclude_auditor_emails", return_value={ u"*****@*****.**", }): with mock.patch("ggrc.integrations.issues.Client.create_issue", return_value={"issueId": TICKET_ID + 1}) as create_mock: response = self.api.put(iti.issue_tracked_obj, issue_request_payload) self.assert200(response) # Detach comment should be sent to previous ticket update_mock.assert_called_once() self.assertEqual(TICKET_ID, update_mock.call_args[0][0]) create_mock.assert_called_once() # check if data was changed in our DB issue_id = response.json.get("issue").get("id") issue_tracker_issue = models.IssuetrackerIssue.get_issue( "Issue", issue_id) self.assertNotEqual(int(issue_tracker_issue.issue_id), TICKET_ID)
def setup_snapshots_and_issue(self): """Create snapshot & issue objects""" self.snapshots = {} self.issues = {} self.control = factories.ControlFactory() for is_archived in (False, True): audit = self.audits[is_archived] self.snapshots[is_archived] = self._create_snapshots( audit, [self.control], )[0] factories.RelationshipFactory( source=audit, destination=self.snapshots[is_archived], ) # Create an issue issue = factories.IssueFactory() self.issues[is_archived] = issue # Map issue to audit factories.RelationshipFactory( source=audit, destination=issue, context=audit.context )
def test_issue_deletion(self, mock_update_issue): """Test deleting Issue object with disabled integration for issue.""" iti = factories.IssueTrackerIssueFactory( enabled=False, issue_tracked_obj=factories.IssueFactory()) with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.delete(iti.issue_tracked_obj) mock_update_issue.assert_not_called()
def test_adding_comment_to_issue(self, update_issue_mock, url_builder_mock): """Test adding comment to issue.""" iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=factories.IssueFactory()) comment = factories.CommentFactory(description="test comment") expected_result = { "comment": u"A new comment is added by 'Example User' to the 'Issue': " u"'test comment'.\nUse the following to link to get more " u"information from the GGRC 'Issue'. Link - " u"http://issue_url.com" } with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.post( all_models.Relationship, { "relationship": { "source": { "id": iti.issue_tracked_obj.id, "type": "Issue" }, "destination": { "id": comment.id, "type": "comment" }, "context": None }, }) url_builder_mock.assert_called_once() update_issue_mock.assert_called_with(iti.issue_id, expected_result)
def setUp(self): super(TestIssueRelevantFilter, self).setUp() self.client.get("/login") self.snapshottable = factories.ObjectiveFactory() revision = all_models.Revision.query.filter_by( resource_id=self.snapshottable.id, resource_type=self.snapshottable.type, ).first() with factories.single_commit(): self.control = factories.ControlFactory() self.audit = factories.AuditFactory() self.issue = factories.IssueFactory() self.snapshot = factories.SnapshotFactory( parent=self.audit, child_id=self.snapshottable.id, child_type=self.snapshottable.type, revision_id=revision.id, ) factories.RelationshipFactory(source=self.issue, destination=self.control) factories.RelationshipFactory(source=self.issue, destination=self.audit) factories.RelationshipFactory(source=self.issue, destination=self.snapshot) self.objects = { "Issue": self.issue, "Control": self.control, "Snapshot": self.snapshot, "Snapshottable": self.snapshottable, }
def test_wrong_remove_action_issue(self): """Test wrong remove action on issue.""" issue = factories.IssueFactory() document_id = factories.DocumentFactory().id response = self.api.put(issue, {"actions": {"remove_related": [{}]}}) self.assert400(response) response = self.api.put(issue, {"actions": {"remove_related": [ { "id": document_id, } ]}}) self.assert400(response) response = self.api.put(issue, {"actions": {"remove_related": [ { "type": "Document", } ]}}) self.assert400(response) response = self.api.put(issue, {"actions": {"remove_related": [ { "id": None, "type": "Document", } ]}}) self.assert400(response)
def test_ticket_generation_disallowed_on_update(self, status): """Test ticket generation disallowed for Issue in {} status on update""" with factories.single_commit(): obj = factories.IssueFactory(status=status) factories.IssueTrackerIssueFactory( issue_tracked_obj=obj, enabled=False, issue_id=None, ) expected_warning = ( errors.WRONG_TICKET_STATUS.format( line=3, column_name="Ticket Tracker Integration", ) ) expected_messages = { "Issue": { "row_warnings": {expected_warning}, } } response = self.import_data(OrderedDict([ ("object_type", "Issue"), ("Code*", obj.slug), ("Ticket Tracker Integration", "On"), ])) self._check_csv_response(response, expected_messages) obj = all_models.Issue.query.one() self.assertFalse(obj.issue_tracker["enabled"])
def setUp(self): super(TestIssue, self).setUp() self.api = Api() with factories.single_commit(): audit = factories.AuditFactory() for status in all_models.Issue.VALID_STATES: factories.IssueFactory(audit=audit, status=status)
def setup_snapshots_and_issue(self): """Create snapshot & issue objects""" self.snapshots = {} self.issues = {} self.control = factories.ControlFactory() revision = all_models.Revision.query.filter( all_models.Revision.resource_type == self.control.type).first() for is_archived in (False, True): audit = self.audits[is_archived] # Create a snapshot self.snapshots[is_archived] = factories.SnapshotFactory( child_id=revision.resource_id, child_type=revision.resource_type, revision=revision, parent=audit, context=audit.context, ) # Create an issue issue = factories.IssueFactory() self.issues[is_archived] = issue # Map issue to audit factories.RelationshipFactory( source=audit, destination=issue, context=audit.context )
def test_issue_due_date_put(self): """Test PUT HTTP requests to Issue.due_date""" issue = factories.IssueFactory(due_date=datetime.date(2018, 6, 14)) data = issue.log_json() data["due_date"] = "2018-06-15" response = self.api.put(issue, data) self.assert200(response) self.assertEqual(response.json["issue"]["due_date"], "2018-06-15")