def __init__(self, jiraObj, projectKey): ''' :param jiraObj - initiated (created) JIRA object :param projectKey - string which identify project key you want to work with :param ''' self.errLog = '' self.projectKey = '' if isinstance(jiraObj, JIRA): self.jira = jiraObj else: raise JIRAError('jiraObj is not instance of JIRA class') if isstring(projectKey): for p in self.jira.projects(): if p.key == projectKey: self.projectKey = projectKey break if not self.projectKey: raise JIRAError(projectKey + ' is not found or user has no access') self.cfDict = self.__customFiledsMapping() self.components = list() for c in self.jira.project_components(self.projectKey): self.components.append(c.name) print('Components in project: ', self.components) self.epics = list() jqlString = 'project = ' + self.projectKey + ' and issueType = Epic' epics = self.jira.search_issues(jqlString) for e in epics: self.epics.append({'key':e.key, 'summary':e.fields.summary, 'Epic Name':getattr(e.fields, self.cfDict['Epic Name'])})
def raise_on_error(r, verb="???", **kwargs): request = kwargs.get("request", None) # headers = kwargs.get('headers', None) if r is None: raise JIRAError(None, **kwargs) if r.status_code >= 400: error = "" if r.status_code == 403 and "x-authentication-denied-reason" in r.headers: error = r.headers["x-authentication-denied-reason"] elif r.text: try: response = json.loads(r.text) if "message" in response: # Jira 5.1 errors error = response["message"] elif "errorMessages" in response and len(response["errorMessages"]) > 0: # Jira 5.0.x error messages sometimes come wrapped in this array # Sometimes this is present but empty errorMessages = response["errorMessages"] if isinstance(errorMessages, (list, tuple)): error = errorMessages[0] else: error = errorMessages # Catching only 'errors' that are dict. See https://github.com/pycontribs/jira/issues/350 elif ( "errors" in response and len(response["errors"]) > 0 and isinstance(response["errors"], dict) ): # Jira 6.x error messages are found in this array. error_list = response["errors"].values() error = ", ".join(error_list) else: error = r.text except ValueError: error = r.text raise JIRAError( r.status_code, error, r.url, request=request, response=r, **kwargs ) # for debugging weird errors on CI if r.status_code not in [200, 201, 202, 204]: raise JIRAError(r.status_code, request=request, response=r, **kwargs) # testing for the WTH bug exposed on # https://answers.atlassian.com/questions/11457054/answers/11975162 if ( r.status_code == 200 and len(r.content) == 0 and "X-Seraph-LoginReason" in r.headers and "AUTHENTICATED_FAILED" in r.headers["X-Seraph-LoginReason"] ): pass
def raise_on_error(r, verb='???', **kwargs): request = kwargs.get('request', None) # headers = kwargs.get('headers', None) if r is None: raise JIRAError(None, **kwargs) if r.status_code >= 400: error = '' if r.status_code == 403 and "x-authentication-denied-reason" in r.headers: error = r.headers["x-authentication-denied-reason"] elif r.text: try: response = json.loads(r.text) if 'message' in response: # JIRA 5.1 errors error = response['message'] elif 'errorMessages' in response and len( response['errorMessages']) > 0: # JIRA 5.0.x error messages sometimes come wrapped in this array # Sometimes this is present but empty errorMessages = response['errorMessages'] if isinstance(errorMessages, (list, tuple)): error = errorMessages[0] else: error = errorMessages elif 'errors' in response and len(response['errors']) > 0: # JIRA 6.x error messages are found in this array. error_list = response['errors'].values() error = ", ".join(error_list) else: error = r.text except ValueError: error = r.text raise JIRAError(r.status_code, error, r.url, request=request, response=r, **kwargs) # for debugging weird errors on CI if r.status_code not in [200, 201, 202, 204]: raise JIRAError(r.status_code, request=request, response=r, **kwargs) # testing for the WTH bug exposed on # https://answers.atlassian.com/questions/11457054/answers/11975162 if r.status_code == 200 and len(r.content) == 0 \ and 'X-Seraph-LoginReason' in r.headers \ and 'AUTHENTICATED_FAILED' in r.headers['X-Seraph-LoginReason']: pass
def test_create_jira_issue_cannot_get_existing(self): self.handler.get_issue_from_summary = MagicMock() self.handler.create_base_jira_issue = MagicMock() self.handler.assign_issue_to_user = MagicMock() self.handler.transition_issue_to_proper_status = MagicMock() self.handler.add_comments = MagicMock() project = "project" ticket = MagicMock() title = "title" ticket.title = title jira_issue = MagicMock() self.handler.get_issue_from_summary.side_effect = JIRAError("Error") self.handler.create_base_jira_issue.return_value = jira_issue self.handler.create_jira_issue(ticket, project) self.handler.get_issue_from_summary.assert_called_once_with( project, ticket.title, ) self.handler.create_base_jira_issue.assert_not_called() self.handler.assign_issue_to_user.assert_not_called() self.handler.transition_issue_to_proper_status.assert_not_called() self.handler.add_comments.assert_not_called()
def test_jira_error_request_added(self): err = JIRAError( request=self.MockResponse(headers=DUMMY_HEADERS, text=DUMMY_TEXT)) err_str = str(err) assert f"headers = {DUMMY_HEADERS}" in err_str assert f"text = {DUMMY_TEXT}" in err_str
def get_jira_meta(jira, jira_project): meta = jira.createmeta( projectKeys=jira_project.project_key, issuetypeNames=jira_project.jira_instance.default_issue_type, expand="projects.issuetypes.fields") # logger.debug("get_jira_meta: %s", json.dumps(meta, indent=4)) # this is None safe # meta['projects'][0]['issuetypes'][0]['fields']: meta_data_error = False if len(meta['projects']) == 0: # non-existent project, or no permissions # [09/Nov/2020 21:04:22] DEBUG [dojo.jira_link.helper:595] get_jira_meta: { # "expand": "projects", # "projects": [] # } meta_data_error = True message = 'unable to retrieve metadata from JIRA %s for project %s. Invalid project key or no permissions to this project?' % ( jira_project.jira_instance, jira_project.project_key) elif len(meta['projects'][0]['issuetypes']) == 0: # default issue type doesn't exist in project # [09/Nov/2020 21:09:03] DEBUG [dojo.jira_link.helper:595] get_jira_meta: { # "expand": "projects", # "projects": [ # { # "expand": "issuetypes", # "self": "https://jira-uat.com/rest/api/2/project/1212", # "id": "1212", # "key": "ISO", # "name": "ISO ISMS", # "avatarUrls": { # "48x48": "https://jira-uat.com/secure/projectavatar?pid=14431&avatarId=17200", # "24x24": "https://jira-uat.com/secure/projectavatar?size=small&pid=14431&avatarId=17200", # "16x16": "https://jira-uat.com/secure/projectavatar?size=xsmall&pid=14431&avatarId=17200", # "32x32": "https://jira-uat.com/secure/projectavatar?size=medium&pid=14431&avatarId=17200" # }, # "issuetypes": [] # } # ] # } meta_data_error = True message = 'unable to retrieve metadata from JIRA %s for issuetype %s in project %s. Invalid default issue type configured in Defect Dojo?' % ( jira_project.jira_instance, jira_project.jira_instance.default_issue_type, jira_project.project_key) if meta_data_error: logger.warn(message) logger.warn("get_jira_meta: %s", json.dumps(meta, indent=4)) # this is None safe messages.add_message(get_current_request(), messages.ERROR, message, extra_tags='alert-danger') raise JIRAError(text=message) else: return meta
def test_jira_error_malformed_request(self): # GIVEN: a malformed Response object, without headers or text set bad_repsonse = self.MalformedMockResponse() # WHEN: The JiraError's __str__ method is called err = JIRAError(request=bad_repsonse) err_str = str(err) # THEN: there are no errors and neither headers nor text are in the result assert "headers = " not in err_str assert "text = " not in err_str
def createTestPlan(self, summary, priority='Normal'): if priority not in JiraHelper.priorities: raise JIRAError('incorrect priority ') issueDict = dict() issueDict['project'] = {'key': self.projectKey} issueDict['issuetype'] = {'name': 'Test Plan'} issueDict['summary'] = summary issueDict['priority'] = {'name': priority} self.testPlanIssue = jira.create_issue(fields=issueDict) return self.testPlanIssue.key
def test_create_vase_jira_issue_creation_error(self): self.handler.get_issue_from_summary = MagicMock() self.handler.create_issue = MagicMock() project = "project" ticket = MagicMock() title = "title" ticket.title = title jira_issue = MagicMock() self.handler.get_issue_from_summary.return_value = jira_issue self.handler.create_issue.side_effect = JIRAError() output = self.handler.create_base_jira_issue(ticket, project) self.assertEqual(output, None)
def test_process_request_w_error(self): """ Tests the process_request method when a JIRA error is thrown. """ error_text = 'an error occurred' status_code = 400 jira_error = JIRAError(status_code=status_code, text=error_text) self.mock_auth.create_issue = Mock(side_effect=jira_error) with patch('distilleries.models.Distillery.find_by_id', return_value=self.mock_data): alert = Alert.objects.get(pk=2) cargo = self.handler_w_user.process_request(alert) self.assertEqual(cargo.status_code, str(status_code)) self.assertEqual(cargo.data, []) self.assertEqual(cargo.notes, error_text)
def __init__(self, jiraObj, projectKey): ''' :param jiraObj - initiated (created) JIRA object :param projectKey - string which identify project key you want to work with :param ''' self.errLog = '' self.projectKey = '' if isinstance(jiraObj, JIRA): self.jira = jiraObj else: raise JIRAError('jiraObj is not instance of JIRA class') self.cfDict = self.__customFiledsMapping() if isstring(projectKey): for p in self.jira.projects(): if p.key == projectKey: self.projectKey = projectKey break if not self.projectKey: raise JIRAError(projectKey + ' is not found or user has no access') self.components = list()
def test_transition_issue_to_proper_status_mapping_error(self): self.handler.update_status_mappings = MagicMock() self.handler.transition_issue = MagicMock() ticket = MagicMock() status = "status" ticket.status = status jira_issue = MagicMock() self.handler.status_mappings = {} self.handler.update_status_mappings.side_effect = JIRAError() self.handler.transition_issue_to_proper_status(jira_issue, ticket) self.handler.update_status_mappings.assert_called_once() self.handler.transition_issue.assert_not_called()
def test_add_jira_instance_invalid_credentials(self, jira_mock): jira_mock.side_effect = JIRAError(status_code=401, text='Login failed') data = self.data_jira_instance # test UI validation error # self.client.force_login('admin', backend='django.contrib.auth.backends.ModelBackend') # Client.raise_request_exception = False # needs Django 3.0 # can't use helper method which has patched connection raw method response = self.client.post( reverse('add_jira'), urlencode(data), content_type='application/x-www-form-urlencoded') self.assertEqual(200, response.status_code) content = response.content.decode('utf-8') self.assertTrue('Login failed' in content) self.assertTrue('Unable to authenticate to JIRA' in content)
def test_jira_error_log_to_tempfile_not_used_if_env_var_not_set(self): # GIVEN: no env vars are set and the tempfile's filename env_vars = {} test_jira_error_filename = ( Path(__file__).parent / "test_jira_error_log_to_tempfile.bak" ) # https://docs.python.org/3/library/unittest.mock.html#mock-open mocked_open = mock_open() # WHEN: a JIRAError's __str__ method is called with patch.dict("os.environ", env_vars), patch( f"{PATCH_BASE}.tempfile.mkstemp", autospec=True ) as mock_mkstemp, patch(f"{PATCH_BASE}.open", mocked_open): mock_mkstemp.return_value = 0, str(test_jira_error_filename) str(JIRAError(response=self.MockResponse(text=DUMMY_TEXT))) # THEN: no files are opened mocked_open.assert_not_called()
def test_assign_issue_to_user_error(self): self.handler.search_users = MagicMock() self.handler.assign_issue = MagicMock() user = MagicMock() user_account_id = MagicMock() user_account_id.accountId = user self.handler.search_users.return_value = [user_account_id] self.handler.assign_issue.side_effect = JIRAError() ticket = MagicMock() assignee = "assignee" ticket.assignee = assignee jira_issue = MagicMock() self.handler.assign_issue_to_user(jira_issue, ticket) self.handler.search_users.assert_called_once_with(user=assignee) self.handler.assign_issue.assert_called_once_with(jira_issue, user)
def test_jira_error_log_to_tempfile_if_env_var_set(self): # GIVEN: the right env vars are set and the tempfile's filename env_vars = {"PYJIRA_LOG_TO_TEMPFILE": "so true"} test_jira_error_filename = ( Path(__file__).parent / "test_jira_error_log_to_tempfile.bak" ) # https://docs.python.org/3/library/unittest.mock.html#mock-open mocked_open = mock_open() # WHEN: a JIRAError's __str__ method is called and # log details are expected to be sent to the tempfile with patch.dict("os.environ", env_vars), patch( f"{PATCH_BASE}.tempfile.mkstemp", autospec=True ) as mock_mkstemp, patch(f"{PATCH_BASE}.open", mocked_open): mock_mkstemp.return_value = 0, str(test_jira_error_filename) str(JIRAError(response=self.MockResponse(text=DUMMY_TEXT))) # THEN: the known filename is opened and contains the exception details mocked_open.assert_called_once_with(str(test_jira_error_filename), "w") mock_file_stream = mocked_open() assert f"text = {DUMMY_TEXT}" in mock_file_stream.write.call_args[0][0]
def test_manager_raises_invalid_connection_exception_if_search_query_fails( self, mock_load, mock_search, mock_jira_client): key = 'jira' mock_jira_client.return_value = None mock_search.side_effect = JIRAError(status_code=500, text='Server Error') data = DataProviders._test_data_for_search_results() with patch('pyccata.core.configuration.Configuration.manager', new_callable=PropertyMock) as mock_manager: with patch( 'pyccata.core.configuration.Configuration._configuration', new_callable=PropertyMock) as mock_config: mock_config.return_value = DataProviders._get_config_for_test() mock_manager.return_value = key manager = ProjectManager() self.assertIsInstance(manager.client.client, JIRA) with self.assertRaisesRegexp( InvalidConnectionError, 'Recieved HTTP/500 whilst establishing.*'): manager.search_issues(search_query='assignee = "bob123"', max_results=2, fields=[])
def test_manager_raises_exception_on_client_initialisation_failure( self, mock_load, mock_jira_client): key = 'jira' mock_jira_client.return_value = None mock_jira_client.side_effect = JIRAError(status_code=500, text='something') with patch('pyccata.core.configuration.Configuration.manager', new_callable=PropertyMock) as mock_manager: with patch( 'pyccata.core.configuration.Configuration._configuration', new_callable=PropertyMock) as mock_config: mock_config.return_value = DataProviders._get_config_for_test( port='') mock_manager.return_value = key with self.assertRaises(InvalidConnectionError) as cm: manager = ProjectManager() v = manager.client.client e = cm.exception self.assertEqual(500, e._code) self.assertEqual('something', e._error) self.assertRegexpMatches( str(e), 'Recieved HTTP\/\d+ whilst establishing connection to .*')
def transition_issue(self, issue, transition, comment, fields): if issue.id == "12345": return "Success" raise JIRAError("Key error")
def test_open_jira_session_raises_exception(self): with patch('icinga2jira.JIRA') as JIRA: JIRA.side_effect = JIRAError() self.assertRaises(JIRAError, i2j.open_jira_session, 'spam', 'eggs', 'ham')
def test_transition_issue_raises_jira_error(self): self.mock_jira_instance.transition_issue.side_effect = JIRAError() with self.assertRaises(JIRAError): self.client.transition_issue(DUMMY_ISSUE_KEY, DUMMY_STATUS)
def test_jira_error_status_code_added(self): assert f"JiraError HTTP {DUMMY_STATUS_CODE}" in str( JIRAError(status_code=DUMMY_STATUS_CODE))
def test_jira_error_url_added(self): assert f"url: {DUMMY_URL}" in str(JIRAError(url=DUMMY_URL))
def test_add_comment_raises_jira_error(self): self.mock_jira_instance.add_comment.side_effect = JIRAError() with self.assertRaises(JIRAError): self.client.add_comment(DUMMY_ISSUE_KEY, DUMMY_COMMENT)
def side_effect(*args, **kwargs): raise JIRAError('error message')
def test_jira_error_text_added(self): dummy_text = "wow\tthis\nis\nso cool" assert f"text: {dummy_text}" in str(JIRAError(text=dummy_text))