2019-07-07 11:18:12 +05:30
# frozen_string_literal: true
2015-04-26 12:48:37 +05:30
require 'spec_helper'
2021-09-04 01:27:46 +05:30
RSpec . describe Integrations :: Jira do
2018-11-08 19:23:39 +05:30
include AssetsHelpers
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
let_it_be ( :project ) { create ( :project , :repository ) }
2021-03-11 19:13:27 +05:30
let ( :current_user ) { build_stubbed ( :user ) }
2019-12-04 20:38:33 +05:30
let ( :url ) { 'http://jira.example.com' }
let ( :api_url ) { 'http://api-jira.example.com' }
let ( :username ) { 'jira-username' }
let ( :password ) { 'jira-password' }
let ( :transition_id ) { 'test27' }
2020-11-24 15:15:51 +05:30
let ( :server_info_results ) { { 'deploymentType' = > 'Cloud' } }
2021-03-08 18:12:59 +05:30
let ( :jira_service ) do
described_class . new (
project : project ,
url : url ,
username : username ,
password : password
)
end
2020-11-24 15:15:51 +05:30
before do
WebMock . stub_request ( :get , / serverInfo / ) . to_return ( body : server_info_results . to_json )
end
2019-12-04 20:38:33 +05:30
2018-03-17 18:26:18 +05:30
describe '#options' do
2019-12-21 20:55:43 +05:30
let ( :options ) do
{
2021-03-08 18:12:59 +05:30
project : project ,
2018-03-17 18:26:18 +05:30
active : true ,
username : 'username' ,
password : 'test' ,
jira_issue_transition_id : 24 ,
2021-09-04 01:27:46 +05:30
url : 'http://jira.test.com:1234/path/'
2019-12-21 20:55:43 +05:30
}
2018-03-17 18:26:18 +05:30
end
2021-09-04 01:27:46 +05:30
let ( :integration ) { described_class . create! ( options ) }
2019-12-21 20:55:43 +05:30
2018-03-17 18:26:18 +05:30
it 'sets the URL properly' do
2019-12-21 20:55:43 +05:30
# jira-ruby gem parses the URI and handles trailing slashes fine:
# https://github.com/sumoheavy/jira-ruby/blob/v1.7.0/lib/jira/http_client.rb#L62
2021-09-04 01:27:46 +05:30
expect ( integration . options [ :site ] ) . to eq ( 'http://jira.test.com:1234' )
2018-03-17 18:26:18 +05:30
end
it 'leaves out trailing slashes in context' do
2021-09-04 01:27:46 +05:30
expect ( integration . options [ :context_path ] ) . to eq ( '/path' )
end
context 'URL without a path' do
before do
integration . url = 'http://jira.test.com/'
end
it 'leaves out trailing slashes in context' do
expect ( integration . options [ :site ] ) . to eq ( 'http://jira.test.com' )
expect ( integration . options [ :context_path ] ) . to eq ( '' )
end
end
context 'URL with query string parameters' do
before do
integration . url << '?nosso&foo=bar'
end
it 'removes query string parameters' do
expect ( integration . options [ :site ] ) . to eq ( 'http://jira.test.com:1234' )
expect ( integration . options [ :context_path ] ) . to eq ( '/path' )
end
2018-03-17 18:26:18 +05:30
end
2019-12-21 20:55:43 +05:30
context 'username with trailing whitespaces' do
before do
options . merge! ( username : 'username ' )
end
it 'leaves out trailing whitespaces in username' do
2021-09-04 01:27:46 +05:30
expect ( integration . options [ :username ] ) . to eq ( 'username' )
2019-12-21 20:55:43 +05:30
end
end
it 'provides additional cookies to allow basic auth with oracle webgate' do
2021-09-04 01:27:46 +05:30
expect ( integration . options [ :use_cookies ] ) . to eq ( true )
expect ( integration . options [ :additional_cookies ] ) . to eq ( [ 'OBBasicAuth=fromDialog' ] )
2019-12-21 20:55:43 +05:30
end
context 'using api URL' do
before do
options . merge! ( api_url : 'http://jira.test.com/api_path/' )
end
it 'leaves out trailing slashes in context' do
2021-09-04 01:27:46 +05:30
expect ( integration . options [ :context_path ] ) . to eq ( '/api_path' )
2019-12-21 20:55:43 +05:30
end
end
2018-03-17 18:26:18 +05:30
end
2021-02-22 17:27:13 +05:30
describe '#fields' do
let ( :service ) { create ( :jira_service ) }
subject ( :fields ) { service . fields }
2021-04-29 21:17:54 +05:30
it 'returns custom fields' do
expect ( fields . pluck ( :name ) ) . to eq ( %w[ url api_url username password ] )
2021-02-22 17:27:13 +05:30
end
end
2018-11-20 20:47:30 +05:30
describe 'Associations' do
2015-04-26 12:48:37 +05:30
it { is_expected . to belong_to :project }
it { is_expected . to have_one :service_hook }
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
describe '.reference_pattern' do
2020-05-24 23:13:21 +05:30
using RSpec :: Parameterized :: TableSyntax
where ( :key , :result ) do
'#123' | ''
'1#23#12' | ''
'JIRA-1234A' | 'JIRA-1234'
'JIRA-1234-some_tag' | 'JIRA-1234'
'JIRA-1234_some_tag' | 'JIRA-1234'
'EXT_EXT-1234' | 'EXT_EXT-1234'
'EXT3_EXT-1234' | 'EXT3_EXT-1234'
'3EXT_EXT-1234' | ''
end
2016-11-03 12:29:30 +05:30
2020-05-24 23:13:21 +05:30
with_them do
specify do
expect ( described_class . reference_pattern . match ( key ) . to_s ) . to eq ( result )
end
2016-11-03 12:29:30 +05:30
end
end
2019-09-30 21:07:59 +05:30
describe '#create' do
let ( :params ) do
{
2021-03-08 18:12:59 +05:30
project : project ,
2021-09-04 01:27:46 +05:30
url : url ,
api_url : api_url ,
2019-12-04 20:38:33 +05:30
username : username , password : password ,
jira_issue_transition_id : transition_id
2019-09-30 21:07:59 +05:30
}
end
2020-11-24 15:15:51 +05:30
subject { described_class . create! ( params ) }
2019-09-30 21:07:59 +05:30
2019-12-04 20:38:33 +05:30
it 'does not store data into properties' do
expect ( subject . properties ) . to be_nil
end
2020-11-24 15:15:51 +05:30
it 'stores data in data_fields correctly' do
2019-12-04 20:38:33 +05:30
service = subject
expect ( service . jira_tracker_data . url ) . to eq ( url )
expect ( service . jira_tracker_data . api_url ) . to eq ( api_url )
expect ( service . jira_tracker_data . username ) . to eq ( username )
expect ( service . jira_tracker_data . password ) . to eq ( password )
expect ( service . jira_tracker_data . jira_issue_transition_id ) . to eq ( transition_id )
2020-11-24 15:15:51 +05:30
expect ( service . jira_tracker_data . deployment_cloud? ) . to be_truthy
end
context 'when loading serverInfo' do
2021-09-04 01:27:46 +05:30
let ( :jira_service ) { subject }
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
context 'from a Cloud instance' do
2020-11-24 15:15:51 +05:30
let ( :server_info_results ) { { 'deploymentType' = > 'Cloud' } }
it 'is detected' do
expect ( jira_service . jira_tracker_data . deployment_cloud? ) . to be_truthy
end
end
2021-09-04 01:27:46 +05:30
context 'from a Server instance' do
2020-11-24 15:15:51 +05:30
let ( :server_info_results ) { { 'deploymentType' = > 'Server' } }
it 'is detected' do
expect ( jira_service . jira_tracker_data . deployment_server? ) . to be_truthy
end
end
2021-09-04 01:27:46 +05:30
context 'from an Unknown instance' do
2020-11-24 15:15:51 +05:30
let ( :server_info_results ) { { 'deploymentType' = > 'FutureCloud' } }
2021-09-04 01:27:46 +05:30
context 'and URL ends in .atlassian.net' do
let ( :api_url ) { 'http://example-api.atlassian.net' }
it 'deployment_type is set to cloud' do
expect ( jira_service . jira_tracker_data . deployment_cloud? ) . to be_truthy
end
end
context 'and URL is something else' do
let ( :api_url ) { 'http://my-jira-api.someserver.com' }
it 'deployment_type is set to server' do
expect ( jira_service . jira_tracker_data . deployment_server? ) . to be_truthy
end
end
end
context 'and no ServerInfo response is received' do
let ( :server_info_results ) { { } }
context 'and URL ends in .atlassian.net' do
let ( :api_url ) { 'http://example-api.atlassian.net' }
it 'deployment_type is set to cloud' do
expect ( Gitlab :: AppLogger ) . to receive ( :warn ) . with ( message : " Jira API returned no ServerInfo, setting deployment_type from URL " , server_info : server_info_results , url : api_url )
expect ( jira_service . jira_tracker_data . deployment_cloud? ) . to be_truthy
end
end
context 'and URL is something else' do
let ( :api_url ) { 'http://my-jira-api.someserver.com' }
it 'deployment_type is set to server' do
expect ( Gitlab :: AppLogger ) . to receive ( :warn ) . with ( message : " Jira API returned no ServerInfo, setting deployment_type from URL " , server_info : server_info_results , url : api_url )
expect ( jira_service . jira_tracker_data . deployment_server? ) . to be_truthy
end
2020-11-24 15:15:51 +05:30
end
end
2019-12-04 20:38:33 +05:30
end
2019-09-30 21:07:59 +05:30
end
2019-12-04 20:38:33 +05:30
# we need to make sure we are able to read both from properties and jira_tracker_data table
2019-12-21 20:55:43 +05:30
# TODO: change this as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
2019-09-30 21:07:59 +05:30
context 'overriding properties' do
let ( :access_params ) do
2019-12-04 20:38:33 +05:30
{ url : url , api_url : api_url , username : username , password : password ,
jira_issue_transition_id : transition_id }
2019-09-30 21:07:59 +05:30
end
2020-10-24 23:57:45 +05:30
2019-12-04 20:38:33 +05:30
let ( :data_params ) do
{
url : url , api_url : api_url ,
username : username , password : password ,
jira_issue_transition_id : transition_id
}
end
shared_examples 'handles jira fields' do
let ( :data_params ) do
{
url : url , api_url : api_url ,
username : username , password : password ,
jira_issue_transition_id : transition_id
}
end
context 'reading data' do
it 'reads data correctly' do
expect ( service . url ) . to eq ( url )
expect ( service . api_url ) . to eq ( api_url )
expect ( service . username ) . to eq ( username )
expect ( service . password ) . to eq ( password )
expect ( service . jira_issue_transition_id ) . to eq ( transition_id )
end
end
2019-09-30 21:07:59 +05:30
2020-03-13 15:44:24 +05:30
describe '#update' do
2019-12-04 20:38:33 +05:30
context 'basic update' do
2020-11-24 15:15:51 +05:30
let_it_be ( :new_username ) { 'new_username' }
let_it_be ( :new_url ) { 'http://jira-new.example.com' }
2019-12-04 20:38:33 +05:30
before do
2020-11-24 15:15:51 +05:30
service . update! ( username : new_username , url : new_url )
2019-12-04 20:38:33 +05:30
end
it 'leaves properties field emtpy' do
# expect(service.reload.properties).to be_empty
end
it 'stores updated data in jira_tracker_data table' do
data = service . jira_tracker_data . reload
expect ( data . url ) . to eq ( new_url )
expect ( data . api_url ) . to eq ( api_url )
expect ( data . username ) . to eq ( new_username )
expect ( data . password ) . to eq ( password )
expect ( data . jira_issue_transition_id ) . to eq ( transition_id )
end
end
2020-11-24 15:15:51 +05:30
context 'when updating the url, api_url, username, or password' do
2021-09-04 01:27:46 +05:30
context 'when updating the integration' do
it 'updates deployment type' do
service . update! ( url : 'http://first.url' )
service . jira_tracker_data . update! ( deployment_type : 'server' )
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
expect ( service . jira_tracker_data . deployment_server? ) . to be_truthy
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
service . update! ( api_url : 'http://another.url' )
service . jira_tracker_data . reload
expect ( service . jira_tracker_data . deployment_cloud? ) . to be_truthy
expect ( WebMock ) . to have_requested ( :get , / serverInfo / ) . twice
end
end
context 'when removing the integration' do
let ( :server_info_results ) { { } }
it 'updates deployment type' do
service . update! ( url : nil , api_url : nil , active : false )
service . jira_tracker_data . reload
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
expect ( service . jira_tracker_data . deployment_unknown? ) . to be_truthy
end
2020-11-24 15:15:51 +05:30
end
it 'calls serverInfo for url' do
service . update! ( url : 'http://first.url' )
expect ( WebMock ) . to have_requested ( :get , / serverInfo / )
end
it 'calls serverInfo for api_url' do
service . update! ( api_url : 'http://another.url' )
expect ( WebMock ) . to have_requested ( :get , / serverInfo / )
end
it 'calls serverInfo for username' do
service . update! ( username : 'test-user' )
expect ( WebMock ) . to have_requested ( :get , / serverInfo / )
end
it 'calls serverInfo for password' do
service . update! ( password : 'test-password' )
expect ( WebMock ) . to have_requested ( :get , / serverInfo / )
end
end
context 'when not updating the url, api_url, username, or password' do
it 'does not update deployment type' do
expect { service . update! ( jira_issue_transition_id : 'jira_issue_transition_id' ) } . to raise_error ( ActiveRecord :: RecordInvalid )
expect ( WebMock ) . not_to have_requested ( :get , / serverInfo / )
end
end
context 'when not allowed to test an instance or group' do
it 'does not update deployment type' do
allow ( service ) . to receive ( :can_test? ) . and_return ( false )
service . update! ( url : 'http://first.url' )
expect ( WebMock ) . not_to have_requested ( :get , / serverInfo / )
end
end
2019-12-04 20:38:33 +05:30
context 'stored password invalidation' do
context 'when a password was previously set' do
context 'when only web url present' do
let ( :data_params ) do
{
url : url , api_url : nil ,
username : username , password : password ,
jira_issue_transition_id : transition_id
}
end
it 'resets password if url changed' do
service
service . url = 'http://jira_edited.example.com'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . url ) . to eq ( 'http://jira_edited.example.com' )
expect ( service . password ) . to be_nil
end
it 'does not reset password if url "changed" to the same url as before' do
service . url = 'http://jira.example.com'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . url ) . to eq ( 'http://jira.example.com' )
expect ( service . password ) . not_to be_nil
end
it 'resets password if url not changed but api url added' do
service . api_url = 'http://jira_edited.example.com/rest/api/2'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . api_url ) . to eq ( 'http://jira_edited.example.com/rest/api/2' )
expect ( service . password ) . to be_nil
end
it 'does not reset password if new url is set together with password, even if it\'s the same password' do
service . url = 'http://jira_edited.example.com'
service . password = password
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . password ) . to eq ( password )
expect ( service . url ) . to eq ( 'http://jira_edited.example.com' )
end
it 'resets password if url changed, even if setter called multiple times' do
service . url = 'http://jira1.example.com/rest/api/2'
service . url = 'http://jira1.example.com/rest/api/2'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . password ) . to be_nil
end
it 'does not reset password if username changed' do
service . username = 'some_name'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . password ) . to eq ( password )
end
it 'does not reset password if password changed' do
service . url = 'http://jira_edited.example.com'
service . password = 'new_password'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . password ) . to eq ( 'new_password' )
end
it 'does not reset password if the password is touched and same as before' do
service . url = 'http://jira_edited.example.com'
service . password = password
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . password ) . to eq ( password )
end
end
context 'when both web and api url present' do
let ( :data_params ) do
{
url : url , api_url : 'http://jira.example.com/rest/api/2' ,
username : username , password : password ,
jira_issue_transition_id : transition_id
}
end
it 'resets password if api url changed' do
service . api_url = 'http://jira_edited.example.com/rest/api/2'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . password ) . to be_nil
end
it 'does not reset password if url changed' do
service . url = 'http://jira_edited.example.com'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . password ) . to eq ( password )
end
it 'resets password if api url set to empty' do
2020-11-24 15:15:51 +05:30
service . update! ( api_url : '' )
2019-12-04 20:38:33 +05:30
expect ( service . reload . password ) . to be_nil
end
end
end
context 'when no password was previously set' do
let ( :data_params ) do
{
url : url , username : username
}
end
it 'saves password if new url is set together with password' do
service . url = 'http://jira_edited.example.com/rest/api/2'
service . password = 'password'
2020-11-24 15:15:51 +05:30
service . save!
2019-12-04 20:38:33 +05:30
expect ( service . reload . password ) . to eq ( 'password' )
expect ( service . reload . url ) . to eq ( 'http://jira_edited.example.com/rest/api/2' )
end
end
end
end
end
2019-12-21 20:55:43 +05:30
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
2019-09-30 21:07:59 +05:30
context 'when data are stored in properties' do
2020-07-28 23:09:34 +05:30
let ( :properties ) { data_params }
2019-12-04 20:38:33 +05:30
let! ( :service ) do
2019-12-21 20:55:43 +05:30
create ( :jira_service , :without_properties_callback , properties : properties . merge ( additional : 'something' ) )
2019-09-30 21:07:59 +05:30
end
2019-12-04 20:38:33 +05:30
it_behaves_like 'handles jira fields'
2019-09-30 21:07:59 +05:30
end
context 'when data are stored in separated fields' do
let ( :service ) do
2020-07-28 23:09:34 +05:30
create ( :jira_service , data_params . merge ( properties : { } ) )
2019-09-30 21:07:59 +05:30
end
2019-12-04 20:38:33 +05:30
it_behaves_like 'handles jira fields'
2019-09-30 21:07:59 +05:30
end
context 'when data are stored in both properties and separated fields' do
2020-07-28 23:09:34 +05:30
let ( :properties ) { data_params }
2019-09-30 21:07:59 +05:30
let ( :service ) do
2021-06-08 01:23:25 +05:30
create ( :jira_service , :without_properties_callback , active : false , properties : properties ) . tap do | integration |
create ( :jira_tracker_data , data_params . merge ( integration : integration ) )
2019-12-04 20:38:33 +05:30
end
2019-09-30 21:07:59 +05:30
end
2019-12-04 20:38:33 +05:30
it_behaves_like 'handles jira fields'
2019-09-30 21:07:59 +05:30
end
end
2021-03-08 18:12:59 +05:30
describe '#find_issue' do
let ( :issue_key ) { 'JIRA-123' }
let ( :issue_url ) { " #{ url } /rest/api/2/issue/ #{ issue_key } " }
before do
stub_request ( :get , issue_url ) . with ( basic_auth : [ username , password ] )
end
it 'call the Jira API to get the issue' do
jira_service . find_issue ( issue_key )
expect ( WebMock ) . to have_requested ( :get , issue_url )
end
2021-03-11 19:13:27 +05:30
context 'with options' do
2021-04-29 21:17:54 +05:30
let ( :issue_url ) { " #{ url } /rest/api/2/issue/ #{ issue_key } ?expand=renderedFields,transitions " }
2021-03-11 19:13:27 +05:30
it 'calls the Jira API with the options to get the issue' do
2021-04-29 21:17:54 +05:30
jira_service . find_issue ( issue_key , rendered_fields : true , transitions : true )
2021-03-11 19:13:27 +05:30
expect ( WebMock ) . to have_requested ( :get , issue_url )
end
end
2021-03-08 18:12:59 +05:30
end
2017-08-17 22:00:37 +05:30
describe '#close_issue' do
let ( :custom_base_url ) { 'http://custom_url' }
2015-12-23 02:04:40 +05:30
2018-11-20 20:47:30 +05:30
shared_examples 'close_issue' do
2021-04-17 20:07:23 +05:30
let ( :issue_key ) { 'JIRA-123' }
let ( :issue_url ) { " #{ url } /rest/api/2/issue/ #{ issue_key } " }
let ( :transitions_url ) { " #{ issue_url } /transitions " }
let ( :comment_url ) { " #{ issue_url } /comment " }
let ( :remote_link_url ) { " #{ issue_url } /remotelink " }
let ( :transitions ) { nil }
let ( :issue_fields ) do
{
id : issue_key ,
self : issue_url ,
transitions : transitions
}
end
subject ( :close_issue ) do
jira_service . close_issue ( resource , ExternalIssue . new ( issue_key , project ) )
end
2018-11-20 20:47:30 +05:30
before do
2021-04-29 21:17:54 +05:30
jira_service . jira_issue_transition_id = '999'
2015-12-23 02:04:40 +05:30
2021-09-04 01:27:46 +05:30
# These stubs are needed to test Integrations::Jira#close_issue.
2018-11-20 20:47:30 +05:30
# We close the issue then do another request to API to check if it got closed.
# Here is stubbed the API return with a closed and an opened issues.
2021-04-17 20:07:23 +05:30
open_issue = JIRA :: Resource :: Issue . new ( jira_service . client , attrs : issue_fields . deep_stringify_keys )
2018-11-20 20:47:30 +05:30
closed_issue = open_issue . dup
allow ( open_issue ) . to receive ( :resolution ) . and_return ( false )
allow ( closed_issue ) . to receive ( :resolution ) . and_return ( true )
allow ( JIRA :: Resource :: Issue ) . to receive ( :find ) . and_return ( open_issue , closed_issue )
2017-08-17 22:00:37 +05:30
2021-04-29 21:17:54 +05:30
allow_any_instance_of ( JIRA :: Resource :: Issue ) . to receive ( :key ) . and_return ( issue_key )
2018-11-20 20:47:30 +05:30
allow ( JIRA :: Resource :: Remotelink ) . to receive ( :all ) . and_return ( [ ] )
2015-12-23 02:04:40 +05:30
2021-04-17 20:07:23 +05:30
WebMock . stub_request ( :get , issue_url ) . with ( basic_auth : %w( jira-username jira-password ) )
WebMock . stub_request ( :post , transitions_url ) . with ( basic_auth : %w( jira-username jira-password ) )
WebMock . stub_request ( :post , comment_url ) . with ( basic_auth : %w( jira-username jira-password ) )
WebMock . stub_request ( :post , remote_link_url ) . with ( basic_auth : %w( jira-username jira-password ) )
2018-11-20 20:47:30 +05:30
end
2017-08-17 22:00:37 +05:30
2021-03-11 19:13:27 +05:30
let ( :external_issue ) { ExternalIssue . new ( 'JIRA-123' , project ) }
def close_issue
2021-04-17 20:07:23 +05:30
jira_service . close_issue ( resource , external_issue , current_user )
2021-03-11 19:13:27 +05:30
end
2019-09-30 21:07:59 +05:30
it 'calls Jira API' do
2021-03-11 19:13:27 +05:30
close_issue
2017-08-17 22:00:37 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , comment_url ) . with (
2018-11-20 20:47:30 +05:30
body : / Issue solved with /
) . once
end
2017-09-10 17:25:29 +05:30
2021-03-11 19:13:27 +05:30
it 'tracks usage' do
expect ( Gitlab :: UsageDataCounters :: HLLRedisCounter )
. to receive ( :track_event )
. with ( 'i_ecosystem_jira_service_close_issue' , values : current_user . id )
close_issue
end
2019-09-04 21:01:54 +05:30
it 'does not fail if remote_link.all on issue returns nil' do
allow ( JIRA :: Resource :: Remotelink ) . to receive ( :all ) . and_return ( nil )
2021-03-11 19:13:27 +05:30
expect { close_issue } . not_to raise_error
2019-09-04 21:01:54 +05:30
end
2018-11-20 20:47:30 +05:30
# Check https://developer.atlassian.com/jiradev/jira-platform/guides/other/guide-jira-remote-issue-links/fields-in-remote-issue-links
# for more information
2019-09-30 21:07:59 +05:30
it 'creates Remote Link reference in Jira for comment' do
2021-03-11 19:13:27 +05:30
close_issue
2018-11-20 20:47:30 +05:30
favicon_path = " http://localhost/assets/ #{ find_asset ( 'favicon.png' ) . digest_path } "
# Creates comment
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , comment_url )
2019-09-30 21:07:59 +05:30
# Creates Remote Link in Jira issue fields
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , remote_link_url ) . with (
2018-11-20 20:47:30 +05:30
body : hash_including (
GlobalID : 'GitLab' ,
2019-07-07 11:18:12 +05:30
relationship : 'mentioned on' ,
2018-11-20 20:47:30 +05:30
object : {
2020-03-13 15:44:24 +05:30
url : " #{ Gitlab . config . gitlab . url } / #{ project . full_path } /-/commit/ #{ commit_id } " ,
2019-07-07 11:18:12 +05:30
title : " Solved by commit #{ commit_id } . " ,
2018-11-20 20:47:30 +05:30
icon : { title : 'GitLab' , url16x16 : favicon_path } ,
status : { resolved : true }
}
)
) . once
end
2017-09-10 17:25:29 +05:30
2020-01-01 13:55:28 +05:30
context 'when "comment_on_event_enabled" is set to false' do
it 'creates Remote Link reference but does not create comment' do
2021-04-17 20:07:23 +05:30
allow ( jira_service ) . to receive_messages ( comment_on_event_enabled : false )
2021-03-11 19:13:27 +05:30
close_issue
2020-01-01 13:55:28 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . not_to have_requested ( :post , comment_url )
expect ( WebMock ) . to have_requested ( :post , remote_link_url )
2020-01-01 13:55:28 +05:30
end
end
2020-04-08 14:13:33 +05:30
context 'when Remote Link already exists' do
let ( :remote_link ) do
double (
'remote link' ,
object : {
url : " #{ Gitlab . config . gitlab . url } / #{ project . full_path } /-/commit/ #{ commit_id } "
} . with_indifferent_access
)
end
it 'does not create comment' do
allow ( JIRA :: Resource :: Remotelink ) . to receive ( :all ) . and_return ( [ remote_link ] )
expect ( remote_link ) . to receive ( :save! )
2021-03-11 19:13:27 +05:30
close_issue
2020-04-08 14:13:33 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . not_to have_requested ( :post , comment_url )
2020-04-08 14:13:33 +05:30
end
end
2018-11-20 20:47:30 +05:30
it 'does not send comment or remote links to issues already closed' do
allow_any_instance_of ( JIRA :: Resource :: Issue ) . to receive ( :resolution ) . and_return ( true )
2017-09-10 17:25:29 +05:30
2021-03-11 19:13:27 +05:30
close_issue
2017-08-17 22:00:37 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . not_to have_requested ( :post , comment_url )
expect ( WebMock ) . not_to have_requested ( :post , remote_link_url )
2018-11-20 20:47:30 +05:30
end
2017-08-17 22:00:37 +05:30
2018-11-20 20:47:30 +05:30
it 'does not send comment or remote links to issues with unknown resolution' do
allow_any_instance_of ( JIRA :: Resource :: Issue ) . to receive ( :respond_to? ) . with ( :resolution ) . and_return ( false )
2017-08-17 22:00:37 +05:30
2021-03-11 19:13:27 +05:30
close_issue
2017-08-17 22:00:37 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . not_to have_requested ( :post , comment_url )
expect ( WebMock ) . not_to have_requested ( :post , remote_link_url )
2017-08-17 22:00:37 +05:30
end
2018-11-20 20:47:30 +05:30
it 'references the GitLab commit' do
stub_config_setting ( base_url : custom_base_url )
2017-08-17 22:00:37 +05:30
2021-03-11 19:13:27 +05:30
close_issue
2018-11-20 20:47:30 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , comment_url ) . with (
2020-03-13 15:44:24 +05:30
body : %r{ #{ custom_base_url } / #{ project . full_path } /-/commit/ #{ commit_id } }
2018-11-20 20:47:30 +05:30
) . once
end
it 'references the GitLab commit' do
stub_config_setting ( relative_url_root : '/gitlab' )
stub_config_setting ( url : Settings . send ( :build_gitlab_url ) )
allow ( described_class ) . to receive ( :default_url_options ) do
{ script_name : '/gitlab' }
end
2021-03-11 19:13:27 +05:30
close_issue
2017-08-17 22:00:37 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , comment_url ) . with (
2020-03-13 15:44:24 +05:30
body : %r{ #{ Gitlab . config . gitlab . url } / #{ project . full_path } /-/commit/ #{ commit_id } }
2018-11-20 20:47:30 +05:30
) . once
end
it 'logs exception when transition id is not valid' do
2021-04-17 20:07:23 +05:30
allow ( jira_service ) . to receive ( :log_error )
WebMock . stub_request ( :post , transitions_url ) . with ( basic_auth : %w( jira-username jira-password ) ) . and_raise ( " Bad Request " )
2017-08-17 22:00:37 +05:30
2021-03-11 19:13:27 +05:30
close_issue
2018-11-18 11:00:15 +05:30
2021-04-17 20:07:23 +05:30
expect ( jira_service ) . to have_received ( :log_error ) . with (
2020-04-08 14:13:33 +05:30
" Issue transition failed " ,
error : hash_including (
exception_class : 'StandardError' ,
exception_message : " Bad Request "
) ,
client_url : " http://jira.example.com "
)
2018-11-18 11:00:15 +05:30
end
2018-11-20 20:47:30 +05:30
it 'calls the api with jira_issue_transition_id' do
2021-03-11 19:13:27 +05:30
close_issue
2018-11-18 11:00:15 +05:30
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , transitions_url ) . with (
body : / "id":"999" /
2018-11-18 11:00:15 +05:30
) . once
end
2021-04-29 21:17:54 +05:30
context 'when custom transition IDs are blank' do
before do
jira_service . jira_issue_transition_id = ''
end
it 'does not transition the issue' do
close_issue
expect ( WebMock ) . not_to have_requested ( :post , transitions_url )
end
end
context 'when using automatic issue transitions' do
let ( :transitions ) do
[
{ id : '1' } ,
{ id : '2' , to : { statusCategory : { key : 'new' } } } ,
{ id : '3' , to : { statusCategory : { key : 'done' } } } ,
{ id : '4' , to : { statusCategory : { key : 'done' } } }
]
end
before do
jira_service . jira_issue_transition_automatic = true
close_issue
end
it 'uses the next transition with a status category of done' do
expect ( WebMock ) . to have_requested ( :post , transitions_url ) . with (
body : / "id":"3" /
) . once
end
context 'when no done transition is available' do
let ( :transitions ) do
[
{ id : '1' , to : { statusCategory : { key : 'new' } } }
]
end
it 'does not attempt to transition' do
expect ( WebMock ) . not_to have_requested ( :post , transitions_url )
end
end
context 'when no valid transitions are returned' do
let ( :transitions ) { 'foo' }
it 'does not attempt to transition' do
expect ( WebMock ) . not_to have_requested ( :post , transitions_url )
end
end
end
2021-04-17 20:07:23 +05:30
context 'when using multiple transition ids' do
before do
allow ( jira_service ) . to receive_messages ( jira_issue_transition_id : '1,2,3' )
end
2018-11-18 11:00:15 +05:30
2021-04-17 20:07:23 +05:30
it 'calls the api with transition ids separated by comma' do
2021-03-11 19:13:27 +05:30
close_issue
2018-11-18 11:00:15 +05:30
1 . upto ( 3 ) do | transition_id |
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , transitions_url ) . with (
body : / "id":" #{ transition_id } " /
2018-11-18 11:00:15 +05:30
) . once
end
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , comment_url )
2018-11-18 11:00:15 +05:30
end
2018-11-20 20:47:30 +05:30
it 'calls the api with transition ids separated by semicolon' do
2021-04-17 20:07:23 +05:30
allow ( jira_service ) . to receive_messages ( jira_issue_transition_id : '1;2;3' )
2018-11-18 11:00:15 +05:30
2021-03-11 19:13:27 +05:30
close_issue
2018-11-18 11:00:15 +05:30
1 . upto ( 3 ) do | transition_id |
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , transitions_url ) . with (
body : / "id":" #{ transition_id } " /
2018-11-18 11:00:15 +05:30
) . once
end
2021-04-17 20:07:23 +05:30
expect ( WebMock ) . to have_requested ( :post , comment_url )
end
context 'when a transition fails' do
before do
WebMock . stub_request ( :post , transitions_url ) . with ( basic_auth : %w( jira-username jira-password ) ) . to_return do | request |
{ status : request . body . include? ( '"id":"2"' ) ? 500 : 200 }
end
end
it 'stops the sequence' do
close_issue
1 . upto ( 2 ) do | transition_id |
expect ( WebMock ) . to have_requested ( :post , transitions_url ) . with (
body : / "id":" #{ transition_id } " /
)
end
expect ( WebMock ) . not_to have_requested ( :post , transitions_url ) . with (
body : / "id":"3" /
)
expect ( WebMock ) . not_to have_requested ( :post , comment_url )
end
2018-11-18 11:00:15 +05:30
end
end
2015-12-23 02:04:40 +05:30
end
2018-11-20 20:47:30 +05:30
context 'when resource is a merge request' do
let ( :resource ) { create ( :merge_request ) }
let ( :commit_id ) { resource . diff_head_sha }
it_behaves_like 'close_issue'
end
context 'when resource is a commit' do
let ( :resource ) { project . commit ( 'master' ) }
let ( :commit_id ) { resource . id }
it_behaves_like 'close_issue'
end
2015-12-23 02:04:40 +05:30
end
2020-05-24 23:13:21 +05:30
describe '#create_cross_reference_note' do
2021-03-08 18:12:59 +05:30
let_it_be ( :user ) { build_stubbed ( :user ) }
2021-04-29 21:17:54 +05:30
2020-05-24 23:13:21 +05:30
let ( :jira_issue ) { ExternalIssue . new ( 'JIRA-123' , project ) }
subject { jira_service . create_cross_reference_note ( jira_issue , resource , user ) }
shared_examples 'creates a comment on Jira' do
let ( :issue_url ) { " #{ url } /rest/api/2/issue/JIRA-123 " }
let ( :comment_url ) { " #{ issue_url } /comment " }
let ( :remote_link_url ) { " #{ issue_url } /remotelink " }
before do
allow ( JIRA :: Resource :: Remotelink ) . to receive ( :all ) . and_return ( [ ] )
stub_request ( :get , issue_url ) . with ( basic_auth : [ username , password ] )
stub_request ( :post , comment_url ) . with ( basic_auth : [ username , password ] )
stub_request ( :post , remote_link_url ) . with ( basic_auth : [ username , password ] )
end
it 'creates a comment on Jira' do
subject
expect ( WebMock ) . to have_requested ( :post , comment_url ) . with (
body : / mentioned this issue in /
) . once
end
2021-03-11 19:13:27 +05:30
it 'tracks usage' do
expect ( Gitlab :: UsageDataCounters :: HLLRedisCounter )
. to receive ( :track_event )
. with ( 'i_ecosystem_jira_service_cross_reference' , values : user . id )
subject
end
2020-05-24 23:13:21 +05:30
end
context 'when resource is a commit' do
let ( :resource ) { project . commit ( 'master' ) }
context 'when disabled' do
before do
2021-09-04 01:27:46 +05:30
allow_next_instance_of ( described_class ) do | instance |
2020-05-24 23:13:21 +05:30
allow ( instance ) . to receive ( :commit_events ) { false }
end
end
it { is_expected . to eq ( 'Events for commits are disabled.' ) }
end
context 'when enabled' do
it_behaves_like 'creates a comment on Jira'
end
end
context 'when resource is a merge request' do
let ( :resource ) { build_stubbed ( :merge_request , source_project : project ) }
context 'when disabled' do
before do
2021-09-04 01:27:46 +05:30
allow_next_instance_of ( described_class ) do | instance |
2020-05-24 23:13:21 +05:30
allow ( instance ) . to receive ( :merge_requests_events ) { false }
end
end
it { is_expected . to eq ( 'Events for merge requests are disabled.' ) }
end
context 'when enabled' do
it_behaves_like 'creates a comment on Jira'
end
end
end
2020-03-13 15:44:24 +05:30
describe '#test' do
2020-11-24 15:15:51 +05:30
let ( :server_info_results ) { { 'url' = > 'http://url' , 'deploymentType' = > 'Cloud' } }
2017-08-17 22:00:37 +05:30
2020-11-24 15:15:51 +05:30
def server_info
2017-09-10 17:25:29 +05:30
jira_service . test ( nil )
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
context 'when the test succeeds' do
2020-03-13 15:44:24 +05:30
it 'gets Jira project with URL when API URL not set' do
2020-11-24 15:15:51 +05:30
expect ( server_info ) . to eq ( success : true , result : server_info_results )
expect ( WebMock ) . to have_requested ( :get , / jira.example.com / )
2017-09-10 17:25:29 +05:30
end
2020-03-13 15:44:24 +05:30
it 'gets Jira project with API URL if set' do
2020-11-24 15:15:51 +05:30
jira_service . update! ( api_url : 'http://jira.api.com' )
2020-03-13 15:44:24 +05:30
2020-11-24 15:15:51 +05:30
expect ( server_info ) . to eq ( success : true , result : server_info_results )
expect ( WebMock ) . to have_requested ( :get , / jira.api.com / )
2017-09-10 17:25:29 +05:30
end
end
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
context 'when the test fails' do
it 'returns result with the error' do
test_url = 'http://jira.example.com/rest/api/2/serverInfo'
2020-06-23 00:09:42 +05:30
error_message = 'Some specific failure.'
2020-03-13 15:44:24 +05:30
WebMock . stub_request ( :get , test_url ) . with ( basic_auth : [ username , password ] )
2020-06-23 00:09:42 +05:30
. to_raise ( JIRA :: HTTPError . new ( double ( message : error_message ) ) )
2017-09-10 17:25:29 +05:30
2020-03-13 15:44:24 +05:30
expect ( jira_service ) . to receive ( :log_error ) . with (
2020-06-23 00:09:42 +05:30
'Error sending message' ,
client_url : 'http://jira.example.com' ,
error : error_message
2020-03-13 15:44:24 +05:30
)
2020-06-23 00:09:42 +05:30
expect ( jira_service . test ( nil ) ) . to eq ( success : false , result : error_message )
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
end
end
2015-04-26 12:48:37 +05:30
describe 'project and issue urls' do
context 'when gitlab.yml was initialized' do
2019-09-30 21:07:59 +05:30
it 'is prepopulated with the settings' do
2015-12-23 02:04:40 +05:30
settings = {
2017-09-10 17:25:29 +05:30
'jira' = > {
'url' = > 'http://jira.sample/projects/project_a' ,
'api_url' = > 'http://jira.sample/api'
2015-04-26 12:48:37 +05:30
}
}
allow ( Gitlab . config ) . to receive ( :issues_tracker ) . and_return ( settings )
2019-09-30 21:07:59 +05:30
service = project . create_jira_service ( active : true )
2015-04-26 12:48:37 +05:30
2019-12-04 20:38:33 +05:30
expect ( service . url ) . to eq ( 'http://jira.sample/projects/project_a' )
expect ( service . api_url ) . to eq ( 'http://jira.sample/api' )
2015-04-26 12:48:37 +05:30
end
end
2019-10-12 21:52:04 +05:30
it 'removes trailing slashes from url' do
service = described_class . new ( url : 'http://jira.test.com/path/' )
expect ( service . url ) . to eq ( 'http://jira.test.com/path' )
end
2015-04-26 12:48:37 +05:30
end
2018-11-08 19:23:39 +05:30
2019-12-21 20:55:43 +05:30
describe 'favicon urls' do
2018-11-08 19:23:39 +05:30
it 'includes the standard favicon' do
props = described_class . new . send ( :build_remote_link_props , url : 'http://example.com' , title : 'title' )
expect ( props [ :object ] [ :icon ] [ :url16x16 ] ) . to match %r{ ^http://localhost/assets/favicon(?:- \ h+).png$ }
end
it 'includes returns the custom favicon' do
create :appearance , favicon : fixture_file_upload ( 'spec/fixtures/dk.png' )
props = described_class . new . send ( :build_remote_link_props , url : 'http://example.com' , title : 'title' )
expect ( props [ :object ] [ :icon ] [ :url16x16 ] ) . to match %r{ ^http://localhost/uploads/-/system/appearance/favicon/ \ d+/dk.png$ }
end
end
2019-10-12 21:52:04 +05:30
context 'generating external URLs' do
2021-09-04 01:27:46 +05:30
let ( :integration ) { described_class . new ( url : 'http://jira.test.com/path/' ) }
describe '#web_url' do
it 'handles paths, slashes, and query string' do
expect ( integration . web_url ) . to eq ( integration . url )
expect ( integration . web_url ( 'subpath/' ) ) . to eq ( 'http://jira.test.com/path/subpath' )
expect ( integration . web_url ( '/subpath/' ) ) . to eq ( 'http://jira.test.com/path/subpath' )
expect ( integration . web_url ( 'subpath' , foo : :bar ) ) . to eq ( 'http://jira.test.com/path/subpath?foo=bar' )
end
it 'preserves existing query string' do
integration . url = 'http://jira.test.com/path/?nosso&foo=bar%20bar'
expect ( integration . web_url ) . to eq ( " http://jira.test.com/path?foo=bar%20bar&nosso " )
expect ( integration . web_url ( 'subpath/' ) ) . to eq ( 'http://jira.test.com/path/subpath?foo=bar%20bar&nosso' )
expect ( integration . web_url ( '/subpath/' ) ) . to eq ( 'http://jira.test.com/path/subpath?foo=bar%20bar&nosso' )
expect ( integration . web_url ( 'subpath' , bar : 'baz baz' ) ) . to eq ( 'http://jira.test.com/path/subpath?bar=baz%20baz&foo=bar%20bar&nosso' )
end
it 'returns an empty string if URL is not set' do
integration . url = nil
expect ( integration . web_url ) . to eq ( '' )
end
it 'includes Atlassian referrer for gitlab.com' do
allow ( Gitlab ) . to receive ( :com? ) . and_return ( true )
expect ( integration . web_url ) . to eq ( " http://jira.test.com/path? #{ described_class :: ATLASSIAN_REFERRER_GITLAB_COM . to_query } " )
allow ( Gitlab ) . to receive ( :staging? ) . and_return ( true )
expect ( integration . web_url ) . to eq ( integration . url )
end
it 'includes Atlassian referrer for self-managed' do
allow ( Gitlab ) . to receive ( :dev_or_test_env? ) . and_return ( false )
expect ( integration . web_url ) . to eq ( " http://jira.test.com/path? #{ described_class :: ATLASSIAN_REFERRER_SELF_MANAGED . to_query } " )
end
end
describe '#project_url' do
it 'returns the correct URL' do
expect ( integration . project_url ) . to eq ( 'http://jira.test.com/path' )
end
it 'returns an empty string if URL is not set' do
integration . url = nil
expect ( integration . project_url ) . to eq ( '' )
end
end
2019-10-12 21:52:04 +05:30
describe '#issues_url' do
2021-09-04 01:27:46 +05:30
it 'returns the correct URL' do
expect ( integration . issues_url ) . to eq ( 'http://jira.test.com/path/browse/:id' )
end
it 'returns an empty string if URL is not set' do
integration . url = nil
expect ( integration . issues_url ) . to eq ( '' )
2019-10-12 21:52:04 +05:30
end
end
describe '#new_issue_url' do
2021-09-04 01:27:46 +05:30
it 'returns the correct URL' do
expect ( integration . new_issue_url ) . to eq ( 'http://jira.test.com/path/secure/CreateIssue!default.jspa' )
end
it 'returns an empty string if URL is not set' do
integration . url = nil
expect ( integration . new_issue_url ) . to eq ( '' )
2019-10-12 21:52:04 +05:30
end
end
end
2021-04-29 21:17:54 +05:30
describe '#issue_transition_enabled?' do
it 'returns true if automatic transitions are enabled' do
jira_service . jira_issue_transition_automatic = true
expect ( jira_service . issue_transition_enabled? ) . to be ( true )
end
it 'returns true if custom transitions are set' do
jira_service . jira_issue_transition_id = '1, 2, 3'
expect ( jira_service . issue_transition_enabled? ) . to be ( true )
end
it 'returns false if automatic and custom transitions are disabled' do
expect ( jira_service . issue_transition_enabled? ) . to be ( false )
end
end
2015-04-26 12:48:37 +05:30
end