예제 #1
0
 def test_iter_issue_batches_error(self):
     """Tests handling error fetching issues from Issue Tracer in batches."""
     cli_mock = mock.MagicMock()
     cli_mock.search.side_effect = integrations_errors.HttpError('Test')
     with mock.patch.object(utils.issues, 'Client', return_value=cli_mock):
         actual = list(utils._iter_issue_batches([1, 2, 3]))
         self.assertEqual(actual, [])
예제 #2
0
  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])
예제 #3
0
 def test_update_issue_with_raise(self):
     """Tests updating issue with raising an exception."""
     cli_mock = mock.MagicMock()
     exception = integrations_errors.HttpError('Test', status=429)
     cli_mock.update_issue.side_effect = iter([
         exception,
         exception,
         exception,
         exception,
         exception,
     ])
     with mock.patch.object(utils.time, 'sleep') as sleep_mock:
         with self.assertRaises(integrations_errors.HttpError) as exc_mock:
             utils._update_issue(cli_mock, 1, 'params')
             self.assertEqual(exc_mock.exception.status, 429)
             self.assertEqual(cli_mock.update_issue.call_args_list, [
                 mock.call(1, 'params'),
                 mock.call(1, 'params'),
                 mock.call(1, 'params'),
                 mock.call(1, 'params'),
                 mock.call(1, 'params'),
             ])
             self.assertEqual(sleep_mock.call_args_list, [
                 mock.call(1),
                 mock.call(1),
                 mock.call(1),
                 mock.call(1),
             ])
예제 #4
0
    def test_rate_limited_update(self):
        """Test tickets update when issuetracker raise 429 error."""
        _, assessment_ids = self.setup_assessments(3)
        for issue in all_models.IssuetrackerIssue.query.all():
            issue.issue_id = self.issue_id
        db.session.commit()

        error = integrations_errors.HttpError(data="Test Error", status=429)
        with mock.patch("ggrc.integrations.issues.Client.update_issue",
                        side_effect=error) as update_issue_mock:
            with mock.patch("time.sleep"):
                response = self.api.send_request(self.api.client.post,
                                                 api_link="/update_issues",
                                                 data={
                                                     "objects":
                                                     [{
                                                         "type": "Assessment",
                                                         "id": id_
                                                     }
                                                      for id_ in assessment_ids
                                                      ],
                                                 })
        self.assert200(response)
        expected_errors = [["Assessment", id_, "429 Test Error"]
                           for id_ in assessment_ids]
        self.assertEqual(response.json.get("errors"), expected_errors)
        # 10 times for each assessment
        self.assertEqual(update_issue_mock.call_count, 30)
예제 #5
0
    def test_invalid_component_id(self, error):
        """Test generation of issues if '{}' error raised."""
        audit_id, assessment_ids = self.setup_assessments(3)

        error = error.format("12345")
        with mock.patch("ggrc.integrations.issues.Client.create_issue",
                        side_effect=integrations_errors.HttpError(
                            error)) as create_issue_mock:
            response = self.api.send_request(
                self.api.client.post,
                api_link="/generate_children_issues",
                data={
                    "parent": {
                        "type": "Audit",
                        "id": audit_id
                    },
                    "child_type": "Assessment"
                })
        self.assert200(response)
        self.assertEqual(
            response.json.get("errors"),
            [["Assessment", assessment_ids[0], "500 {}".format(error)]])
        self.assertEqual(create_issue_mock.call_count, 1)
        query = all_models.IssuetrackerIssue.query.filter(
            all_models.IssuetrackerIssue.issue_id.isnot(None))
        self.assertEqual(query.count(), 0)
예제 #6
0
 def test_update_issue_with_retry(self):
   """Tests updating issue with retry."""
   cli_mock = mock.MagicMock()
   exception = integrations_errors.HttpError('Test', status=429)
   cli_mock.update_issue.side_effect = iter([
       exception,
       exception,
       exception,
       exception,
       None,
   ])
   with mock.patch.object(sync_utils.time, 'sleep') as sleep_mock:
     sync_utils.update_issue(cli_mock, 1, 'params')
     self.assertEqual(cli_mock.update_issue.call_args_list, [
         mock.call(1, 'params'),
         mock.call(1, 'params'),
         mock.call(1, 'params'),
         mock.call(1, 'params'),
         mock.call(1, 'params'),
     ])
     self.assertEqual(sleep_mock.call_args_list, [
         mock.call(1),
         mock.call(1),
         mock.call(1),
         mock.call(1),
     ])
예제 #7
0
 def test_issue_tracker_error(self, issue_tracker_enabled, issue_id):
     """ Test that issue tracker does not change state
     in case receiving an error."""
     with mock.patch(self.ISSUE_TRACKED_NAMESPACE +
                     '._update_issuetracker_issue') as update_issue_mock, \
         mock.patch(self.ISSUE_TRACKED_NAMESPACE +
                    '._update_issuetracker_info') as update_info_mock, \
         mock.patch(self.ISSUE_TRACKED_NAMESPACE +
                    '._collect_assessment_emails',
                    side_effect=[(None, [])]):
         error_data = integrations_errors.HttpError('data')
         update_issue_mock.side_effect = error_data
         src = {
             'issue_tracker': {
                 'enabled': issue_tracker_enabled,
                 'issue_id': issue_id
             }
         }
         all_models.IssuetrackerIssue.get_issue = mock.MagicMock()
         # pylint: disable=protected-access
         assessment_integration._handle_issuetracker(sender=None,
                                                     obj=mock.MagicMock(),
                                                     src=src)
         update_info_mock.assert_called_once()
         self.assertEqual(update_info_mock.call_args[0][1]['enabled'],
                          issue_tracker_enabled)
예제 #8
0
    def _perform_request(self,
                         url,
                         method=urlfetch.GET,
                         payload=None,
                         headers=None):
        """Performs request to given URL on integration service endpoint.

    Args:
      url: A string for request URL.
      method: A urlfetch method.
      payload: A string for request body. Ignored if method is not POST,
          PUT or PATCH.
      headers: An optional dict to use as HTTP headers.

    Returns:
      A string content from response.

    Raises:
      integrations_errors.HttpError: If not expected HTTP status occurs
          or fetch is not successful.
    """
        headers = headers or {}
        if self.DEFAULT_HEADERS:
            headers.update(self.DEFAULT_HEADERS)

        url = urlparse.urljoin(self.ENDPOINT, url)
        try:
            response = urlfetch.fetch(
                url,
                method=method,
                payload=payload,
                headers=headers,
                follow_redirects=False,
                deadline=30,
            )

            if response.status_code != 200:
                logging.error('Unable to perform request to %s: %s %s', url,
                              response.status_code, response.content)
                raise integrations_errors.HttpError(
                    response.content, status=response.status_code)

            return response.content
        except urlfetch_errors.Error as error:
            logging.exception('Unable to perform urlfetch request: %s', error)
            raise integrations_errors.HttpError('Unable to perform a request')
예제 #9
0
 def test_integration_disabled_on_bulk_create_error(self, model):
     """Test if {} integration was disabled if bulk creation failed"""
     user = all_models.Person.query.first()
     with factories.single_commit():
         obj = factories.get_model_factory(model)(modified_by=user)
         iti = factories.IssueTrackerIssueFactory(
             issue_tracked_obj=obj,
             enabled=True,
             issue_id=None,
         )
     bulk_creator = issuetracker_bulk_sync.IssueTrackerBulkCreator()
     objects = [issuetracker_bulk_sync.IssuetrackedObjInfo(obj)]
     with mock.patch.object(bulk_creator, "sync_issue") as sync_mock:
         sync_mock.side_effect = integrations_errors.HttpError("error")
         bulk_creator.handle_issuetracker_sync(objects)
     sync_mock.assert_called_once()
     self.assertFalse(iti.enabled)
예제 #10
0
  def test_issue_tracker_error(self, issue_tracker_enabled, issue_id):
    """ Test that issue tracker does not change state
        in case receiving an error."""
    with mock.patch(self.ISSUE_TRACKED_NAMESPACE +
                    '._update_issuetracker_issue') as update_issue_mock, \
        mock.patch(self.ISSUE_TRACKED_NAMESPACE +
                   '._update_issuetracker_info') as update_info_mock, \
        mock.patch(self.ISSUE_TRACKED_NAMESPACE +
                   '._collect_assessment_emails',
                   side_effect=[(None, [])]), \
        mock.patch.object(common_handlers,
                          'global_synchronization_enabled',
                          return_value=True):
      error_data = integrations_errors.HttpError('data')
      update_issue_mock.side_effect = error_data
      src = {
          'issue_tracker': {
              'enabled': issue_tracker_enabled,
              'issue_id': issue_id
          }
      }
      all_models.IssuetrackerIssue.get_issue = mock.MagicMock()
      # pylint: disable=protected-access
      issue_obj = mock.MagicMock()

      # pylint: disable=unused-argument
      def mock_to_dict(**kwargs):
        return {"issue_id": issue_id}
      issue_obj.to_dict = mock_to_dict

      with mock.patch(
          "ggrc.models.issuetracker_issue.IssuetrackerIssue.get_issue",
          return_value=issue_obj
      ):
        assessment_integration._handle_issuetracker(sender=None,
                                                    obj=mock.MagicMock(),
                                                    src=src)
      update_info_mock.assert_called_once()
      self.assertEqual(update_info_mock.call_args[0][1]['enabled'],
                       issue_tracker_enabled)
예제 #11
0
 def test_errors_task_status(self):
     """Test background task status if it failed."""
     audit_id, assessment_ids = self.setup_assessments(2)
     with mock.patch(
             "ggrc.integrations.issues.Client.create_issue",
             side_effect=integrations_errors.HttpError("Test Error")):
         response = self.api.send_request(
             self.api.client.post,
             api_link="/generate_children_issues",
             data={
                 "parent": {
                     "type": "Audit",
                     "id": audit_id
                 },
                 "child_type": "Assessment"
             })
     self.assert200(response)
     url = "background_task_status/{}/{}".format("audit", audit_id)
     response = self.api.client.get(url)
     self.assert200(response)
     self.assertEqual(response.json.get("status"), "Success")
     self.assertEqual(response.json.get("errors"),
                      [["Assessment", id_, "500 Test Error"]
                       for id_ in assessment_ids])
예제 #12
0
class TestDisabledIssueIntegration(ggrc.TestCase):
    """Tests for IssueTracker integration functionality with disabled sync."""
    def setUp(self):
        super(TestDisabledIssueIntegration, self).setUp()
        self.api = api_helper.Api()
        self.client.get("/login")

    @mock.patch("ggrc.integrations.issues.Client.create_issue")
    def test_issue_creation(self, mock_create_issue):
        """Test creating Issue object with disabled integration."""
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": "test title",
                        "context": None,
                        "issue_tracker": {
                            "enabled": False,
                        },
                        "due_date": "10/10/2019"
                    },
                })
        mock_create_issue.assert_not_called()
        self.assertEqual(response.status_code, 201)
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertIsNone(issue_tracker_issue)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    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()

    @ddt.data(
        {
            "description": "new description",
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "enabled": False
            }
        },
        {
            "test_plan": "new test plan",
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "component_id": "123",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "hotlist_id": "321",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "issue_priority": "P2",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "issue_severity": "S2",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "title": "title1",
                "enabled": False
            }
        },
    )
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue_object(self, issue_attrs, mock_update_issue):
        """Test updating issue object with disabled integration for issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=False,
            issue_id=TICKET_ID,
            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()

    @mock.patch("ggrc.integrations.issues.Client.create_issue",
                side_effect=[
                    integrations_errors.HttpError(data=''), {
                        "issueId": "issueId"
                    }
                ])
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_issue_recreation(self, _):
        """Test retrying to turn on integration after failed creation."""
        # Arrange data.
        component_id = "1234"
        hotlist_id = "4321"
        issue_type = "Default Issue type"
        issue_priority = "P2"
        issue_severity = "S1"
        title = "test title"
        issue_tracker_attrs = {
            "enabled": True,
            "component_id": int(component_id),
            "hotlist_id": int(hotlist_id),
            "issue_type": issue_type,
            "issue_priority": issue_priority,
            "issue_severity": issue_severity,
        }

        # Perform actions and assert results.
        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):

            # Try to create issue. create_issue should raise exception here.
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": title,
                        "context": None,
                        "issue_tracker": issue_tracker_attrs,
                        "due_date": "10/10/2019"
                    },
                })

            issue_id = response.json.get("issue").get("id")
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertIsNone(issue_tracker_issue.issue_id)
            self.assertIsNone(issue_tracker_issue.issue_url)

            # Try to turn on integration on already created issue.
            self.api.put(issue_tracker_issue.issue_tracked_obj,
                         {"issue_tracker": issue_tracker_attrs})

            issue_id = issue_tracker_issue.issue_tracked_obj.id
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertEqual(issue_tracker_issue.issue_url,
                             "http://issue/issueId")

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_adding_comment_to_issue(self, update_issue_mock):
        """Test not adding comment to issue when issue tracker disabled."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=False, issue_tracked_obj=factories.IssueFactory())
        comment = factories.CommentFactory(description="test comment")

        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
                    },
                })
        update_issue_mock.assert_not_called()

    @mock.patch("ggrc.integrations.issues.Client.create_issue",
                side_effect=[integrations_errors.HotlistPermissionError()])
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_no_permissions_hotlist(self, _):
        """Test warning message if no permissions to Hotlist."""
        issue_tracker_attrs = {
            "enabled": True,
            "component_id": 1234,
            "hotlist_id": 4321,
            "issue_type": "Default Issue type",
            "issue_priority": "P2",
            "issue_severity": "S1",
        }

        response = self.api.post(
            all_models.Issue, {
                "issue": {
                    "title": "test title",
                    "context": None,
                    "issue_tracker": issue_tracker_attrs,
                    "due_date": "10/10/2019"
                },
            })

        self.assertIn(
            constants.WarningsDescription.HOTLIST_PERMISSIONS_ERROR,
            response.json.get("issue", {}).get("issue_tracker",
                                               {}).get("_warnings", []))