diff options
Diffstat (limited to 'spec/models/project_services/jira_service_spec.rb')
-rw-r--r-- | spec/models/project_services/jira_service_spec.rb | 186 |
1 files changed, 130 insertions, 56 deletions
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 78bd0e91208..ef0bc930152 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -82,11 +82,8 @@ RSpec.describe JiraService do subject(:fields) { service.fields } - it 'includes transition help link' do - transition_id_field = fields.find { |field| field[:name] == 'jira_issue_transition_id' } - - expect(transition_id_field[:title]).to eq('Jira workflow transition IDs') - expect(transition_id_field[:help]).to include('/help/user/project/integrations/jira') + it 'returns custom fields' do + expect(fields.pluck(:name)).to eq(%w[url api_url username password]) end end @@ -460,10 +457,10 @@ RSpec.describe JiraService do end context 'with options' do - let(:issue_url) { "#{url}/rest/api/2/issue/#{issue_key}?expand=renderedFields" } + let(:issue_url) { "#{url}/rest/api/2/issue/#{issue_key}?expand=renderedFields,transitions" } it 'calls the Jira API with the options to get the issue' do - jira_service.find_issue(issue_key, rendered_fields: true) + jira_service.find_issue(issue_key, rendered_fields: true, transitions: true) expect(WebMock).to have_requested(:get, issue_url) end @@ -474,52 +471,56 @@ RSpec.describe JiraService do let(:custom_base_url) { 'http://custom_url' } shared_examples 'close_issue' do + 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 + before do - @jira_service = described_class.new - allow(@jira_service).to receive_messages( - project_id: project.id, - project: project, - url: 'http://jira.example.com', - username: 'gitlab_jira_username', - password: 'gitlab_jira_password', - jira_issue_transition_id: '999' - ) + allow(jira_service).to receive_messages(jira_issue_transition_id: '999') # These stubs are needed to test JiraService#close_issue. # 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. - open_issue = JIRA::Resource::Issue.new(@jira_service.client, attrs: { 'id' => 'JIRA-123' }) + open_issue = JIRA::Resource::Issue.new(jira_service.client, attrs: issue_fields.deep_stringify_keys) 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) - allow_any_instance_of(JIRA::Resource::Issue).to receive(:key).and_return('JIRA-123') + allow_any_instance_of(JIRA::Resource::Issue).to receive(:key).and_return(issue_key) allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) - @jira_service.save! - - project_issues_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123' - @transitions_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123/transitions' - @comment_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123/comment' - @remote_link_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123/remotelink' - - WebMock.stub_request(:get, project_issues_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)) - WebMock.stub_request(:post, @transitions_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)) - WebMock.stub_request(:post, @comment_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)) - WebMock.stub_request(:post, @remote_link_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)) + 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)) end let(:external_issue) { ExternalIssue.new('JIRA-123', project) } def close_issue - @jira_service.close_issue(resource, external_issue, current_user) + jira_service.close_issue(resource, external_issue, current_user) end it 'calls Jira API' do close_issue - expect(WebMock).to have_requested(:post, @comment_url).with( + expect(WebMock).to have_requested(:post, comment_url).with( body: /Issue solved with/ ).once end @@ -546,9 +547,9 @@ RSpec.describe JiraService do favicon_path = "http://localhost/assets/#{find_asset('favicon.png').digest_path}" # Creates comment - expect(WebMock).to have_requested(:post, @comment_url) + expect(WebMock).to have_requested(:post, comment_url) # Creates Remote Link in Jira issue fields - expect(WebMock).to have_requested(:post, @remote_link_url).with( + expect(WebMock).to have_requested(:post, remote_link_url).with( body: hash_including( GlobalID: 'GitLab', relationship: 'mentioned on', @@ -564,11 +565,11 @@ RSpec.describe JiraService do context 'when "comment_on_event_enabled" is set to false' do it 'creates Remote Link reference but does not create comment' do - allow(@jira_service).to receive_messages(comment_on_event_enabled: false) + allow(jira_service).to receive_messages(comment_on_event_enabled: false) close_issue - expect(WebMock).not_to have_requested(:post, @comment_url) - expect(WebMock).to have_requested(:post, @remote_link_url) + expect(WebMock).not_to have_requested(:post, comment_url) + expect(WebMock).to have_requested(:post, remote_link_url) end end @@ -589,7 +590,7 @@ RSpec.describe JiraService do close_issue - expect(WebMock).not_to have_requested(:post, @comment_url) + expect(WebMock).not_to have_requested(:post, comment_url) end end @@ -598,8 +599,8 @@ RSpec.describe JiraService do close_issue - expect(WebMock).not_to have_requested(:post, @comment_url) - expect(WebMock).not_to have_requested(:post, @remote_link_url) + expect(WebMock).not_to have_requested(:post, comment_url) + expect(WebMock).not_to have_requested(:post, remote_link_url) end it 'does not send comment or remote links to issues with unknown resolution' do @@ -607,8 +608,8 @@ RSpec.describe JiraService do close_issue - expect(WebMock).not_to have_requested(:post, @comment_url) - expect(WebMock).not_to have_requested(:post, @remote_link_url) + expect(WebMock).not_to have_requested(:post, comment_url) + expect(WebMock).not_to have_requested(:post, remote_link_url) end it 'references the GitLab commit' do @@ -616,7 +617,7 @@ RSpec.describe JiraService do close_issue - expect(WebMock).to have_requested(:post, @comment_url).with( + expect(WebMock).to have_requested(:post, comment_url).with( body: %r{#{custom_base_url}/#{project.full_path}/-/commit/#{commit_id}} ).once end @@ -631,18 +632,18 @@ RSpec.describe JiraService do close_issue - expect(WebMock).to have_requested(:post, @comment_url).with( + expect(WebMock).to have_requested(:post, comment_url).with( body: %r{#{Gitlab.config.gitlab.url}/#{project.full_path}/-/commit/#{commit_id}} ).once end it 'logs exception when transition id is not valid' do - allow(@jira_service).to receive(:log_error) - WebMock.stub_request(:post, @transitions_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)).and_raise("Bad Request") + 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") close_issue - expect(@jira_service).to have_received(:log_error).with( + expect(jira_service).to have_received(:log_error).with( "Issue transition failed", error: hash_including( exception_class: 'StandardError', @@ -655,34 +656,107 @@ RSpec.describe JiraService do it 'calls the api with jira_issue_transition_id' do close_issue - expect(WebMock).to have_requested(:post, @transitions_url).with( - body: /999/ + expect(WebMock).to have_requested(:post, transitions_url).with( + body: /"id":"999"/ ).once end - context 'when have multiple transition ids' do - it 'calls the api with transition ids separated by comma' do - allow(@jira_service).to receive_messages(jira_issue_transition_id: '1,2,3') + 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 + allow(jira_service).to receive_messages(jira_issue_transition_id: '') 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 + + context 'when using multiple transition ids' do + before do + allow(jira_service).to receive_messages(jira_issue_transition_id: '1,2,3') + end + + it 'calls the api with transition ids separated by comma' do + close_issue 1.upto(3) do |transition_id| - expect(WebMock).to have_requested(:post, @transitions_url).with( - body: /#{transition_id}/ + expect(WebMock).to have_requested(:post, transitions_url).with( + body: /"id":"#{transition_id}"/ ).once end + + expect(WebMock).to have_requested(:post, comment_url) end it 'calls the api with transition ids separated by semicolon' do - allow(@jira_service).to receive_messages(jira_issue_transition_id: '1;2;3') + allow(jira_service).to receive_messages(jira_issue_transition_id: '1;2;3') close_issue 1.upto(3) do |transition_id| - expect(WebMock).to have_requested(:post, @transitions_url).with( - body: /#{transition_id}/ + expect(WebMock).to have_requested(:post, transitions_url).with( + body: /"id":"#{transition_id}"/ ).once end + + 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 end end end |