diff options
Diffstat (limited to 'spec/lib/atlassian')
-rw-r--r-- | spec/lib/atlassian/jira_connect/client_spec.rb | 165 | ||||
-rw-r--r-- | spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb | 52 |
2 files changed, 194 insertions, 23 deletions
diff --git a/spec/lib/atlassian/jira_connect/client_spec.rb b/spec/lib/atlassian/jira_connect/client_spec.rb index cefd1fa3274..6a161854dfb 100644 --- a/spec/lib/atlassian/jira_connect/client_spec.rb +++ b/spec/lib/atlassian/jira_connect/client_spec.rb @@ -7,8 +7,10 @@ RSpec.describe Atlassian::JiraConnect::Client do subject { described_class.new('https://gitlab-test.atlassian.net', 'sample_secret') } + let_it_be(:project) { create_default(:project, :repository) } + around do |example| - Timecop.freeze { example.run } + freeze_time { example.run } end describe '.generate_update_sequence_id' do @@ -19,41 +21,158 @@ RSpec.describe Atlassian::JiraConnect::Client do end end - describe '#store_dev_info' do - let_it_be(:project) { create_default(:project, :repository) } - let_it_be(:merge_requests) { create_list(:merge_request, 2, :unique_branches) } + describe '#send_info' do + it 'calls store_build_info and store_dev_info as appropriate' do + expect(subject).to receive(:store_build_info).with( + project: project, + update_sequence_id: :x, + pipelines: :y + ).and_return(:build_stored) + + expect(subject).to receive(:store_dev_info).with( + project: project, + update_sequence_id: :x, + commits: :a, + branches: :b, + merge_requests: :c + ).and_return(:dev_stored) + + args = { + project: project, + update_sequence_id: :x, + commits: :a, + branches: :b, + merge_requests: :c, + pipelines: :y + } + + expect(subject.send_info(**args)).to contain_exactly(:dev_stored, :build_stored) + end - let(:expected_jwt) do - Atlassian::Jwt.encode( - Atlassian::Jwt.build_claims( - Atlassian::JiraConnect.app_key, - '/rest/devinfo/0.10/bulk', - 'POST' - ), - 'sample_secret' - ) + it 'only calls methods that we need to call' do + expect(subject).to receive(:store_dev_info).with( + project: project, + update_sequence_id: :x, + commits: :a + ).and_return(:dev_stored) + + args = { + project: project, + update_sequence_id: :x, + commits: :a + } + + expect(subject.send_info(**args)).to contain_exactly(:dev_stored) + end + + it 'raises an argument error if there is nothing to send (probably a typo?)' do + expect { subject.send_info(project: project, builds: :x) } + .to raise_error(ArgumentError) + end + end + + def expected_headers(path) + expected_jwt = Atlassian::Jwt.encode( + Atlassian::Jwt.build_claims(Atlassian::JiraConnect.app_key, path, 'POST'), + 'sample_secret' + ) + + { + 'Authorization' => "JWT #{expected_jwt}", + 'Content-Type' => 'application/json' + } + end + + describe '#store_build_info' do + let_it_be(:mrs_by_title) { create_list(:merge_request, 4, :unique_branches, :jira_title) } + let_it_be(:mrs_by_branch) { create_list(:merge_request, 2, :jira_branch) } + let_it_be(:red_herrings) { create_list(:merge_request, 1, :unique_branches) } + + let_it_be(:pipelines) do + (red_herrings + mrs_by_branch + mrs_by_title).map do |mr| + create(:ci_pipeline, merge_request: mr) + end + end + + let(:build_info_payload_schema) do + Atlassian::Schemata.build_info_payload + end + + let(:body) do + matcher = be_valid_json.according_to_schema(build_info_payload_schema) + + ->(text) { matcher.matches?(text) } end before do - stub_full_request('https://gitlab-test.atlassian.net/rest/devinfo/0.10/bulk', method: :post) - .with( - headers: { - 'Authorization' => "JWT #{expected_jwt}", - 'Content-Type' => 'application/json' - } - ) + path = '/rest/builds/0.1/bulk' + stub_full_request('https://gitlab-test.atlassian.net' + path, method: :post) + .with(body: body, headers: expected_headers(path)) + end + + it "calls the API with auth headers" do + subject.send(:store_build_info, project: project, pipelines: pipelines) + end + + it 'only sends information about relevant MRs' do + expect(subject).to receive(:post).with('/rest/builds/0.1/bulk', { builds: have_attributes(size: 6) }) + + subject.send(:store_build_info, project: project, pipelines: pipelines) + end + + it 'does not call the API if there is nothing to report' do + expect(subject).not_to receive(:post) + + subject.send(:store_build_info, project: project, pipelines: pipelines.take(1)) + end + + it 'does not call the API if the feature flag is not enabled' do + stub_feature_flags(jira_sync_builds: false) + + expect(subject).not_to receive(:post) + + subject.send(:store_build_info, project: project, pipelines: pipelines) + end + + it 'does call the API if the feature flag enabled for the project' do + stub_feature_flags(jira_sync_builds: project) + + expect(subject).to receive(:post).with('/rest/builds/0.1/bulk', { builds: Array }) + + subject.send(:store_build_info, project: project, pipelines: pipelines) + end + + it 'avoids N+1 database queries' do + baseline = ActiveRecord::QueryRecorder.new do + subject.send(:store_build_info, project: project, pipelines: pipelines) + end + + pipelines << create(:ci_pipeline, head_pipeline_of: create(:merge_request, :jira_branch)) + + expect { subject.send(:store_build_info, project: project, pipelines: pipelines) }.not_to exceed_query_limit(baseline) + end + end + + describe '#store_dev_info' do + let_it_be(:merge_requests) { create_list(:merge_request, 2, :unique_branches) } + + before do + path = '/rest/devinfo/0.10/bulk' + + stub_full_request('https://gitlab-test.atlassian.net' + path, method: :post) + .with(headers: expected_headers(path)) end it "calls the API with auth headers" do - subject.store_dev_info(project: project) + subject.send(:store_dev_info, project: project) end it 'avoids N+1 database queries' do - control_count = ActiveRecord::QueryRecorder.new { subject.store_dev_info(project: project, merge_requests: merge_requests) }.count + control_count = ActiveRecord::QueryRecorder.new { subject.send(:store_dev_info, project: project, merge_requests: merge_requests) }.count merge_requests << create(:merge_request, :unique_branches) - expect { subject.store_dev_info(project: project, merge_requests: merge_requests) }.not_to exceed_query_limit(control_count) + expect { subject.send(:store_dev_info, project: project, merge_requests: merge_requests) }.not_to exceed_query_limit(control_count) end end end diff --git a/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb b/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb new file mode 100644 index 00000000000..52e475d20ca --- /dev/null +++ b/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Atlassian::JiraConnect::Serializers::BuildEntity do + let_it_be(:user) { create_default(:user) } + let_it_be(:project) { create_default(:project) } + + subject { described_class.represent(pipeline) } + + context 'when the pipeline does not belong to any Jira issue' do + let_it_be(:pipeline) { create(:ci_pipeline) } + + describe '#issue_keys' do + it 'is empty' do + expect(subject.issue_keys).to be_empty + end + end + + describe '#to_json' do + it 'can encode the object' do + expect(subject.to_json).to be_valid_json + end + + it 'is invalid, since it has no issue keys' do + expect(subject.to_json).not_to be_valid_json.according_to_schema(Atlassian::Schemata.build_info) + end + end + end + + context 'when the pipeline does belong to a Jira issue' do + let(:pipeline) { create(:ci_pipeline, merge_request: merge_request) } + + %i[jira_branch jira_title].each do |trait| + context "because it belongs to an MR with a #{trait}" do + let(:merge_request) { create(:merge_request, trait) } + + describe '#issue_keys' do + it 'is not empty' do + expect(subject.issue_keys).not_to be_empty + end + end + + describe '#to_json' do + it 'is valid according to the build info schema' do + expect(subject.to_json).to be_valid_json.according_to_schema(Atlassian::Schemata.build_info) + end + end + end + end + end +end |