diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-12 18:08:41 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-12 18:08:41 +0300 |
commit | 27859ed5eaeae234162b7cce7fd8bd351b5f9369 (patch) | |
tree | 5a62db348c3fd73516df87262c78e3546d4ec770 /spec | |
parent | 784fae4b9d7e92350075df2a43d06893080ed1e6 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/lib/gitlab/danger/changelog_spec.rb | 163 | ||||
-rw-r--r-- | spec/lib/gitlab/danger/danger_spec_helper.rb | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/danger/helper_spec.rb | 17 | ||||
-rw-r--r-- | spec/lib/sentry/client/projects_spec.rb | 119 | ||||
-rw-r--r-- | spec/lib/sentry/client_spec.rb | 185 | ||||
-rw-r--r-- | spec/models/error_tracking/project_error_tracking_setting_spec.rb | 2 | ||||
-rw-r--r-- | spec/support/helpers/sentry_client_helpers.rb | 14 | ||||
-rw-r--r-- | spec/support/shared_examples/lib/sentry/client_shared_examples.rb | 56 |
8 files changed, 379 insertions, 194 deletions
diff --git a/spec/lib/gitlab/danger/changelog_spec.rb b/spec/lib/gitlab/danger/changelog_spec.rb new file mode 100644 index 00000000000..888094eaf6e --- /dev/null +++ b/spec/lib/gitlab/danger/changelog_spec.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'rspec-parameterized' +require_relative 'danger_spec_helper' + +require 'gitlab/danger/changelog' + +describe Gitlab::Danger::Changelog do + using RSpec::Parameterized::TableSyntax + include DangerSpecHelper + + let(:added_files) { nil } + let(:fake_git) { double('fake-git', added_files: added_files) } + + let(:mr_labels) { nil } + let(:mr_json) { nil } + let(:fake_gitlab) { double('fake-gitlab', mr_labels: mr_labels, mr_json: mr_json) } + + let(:changes_by_category) { nil } + let(:ee?) { false } + let(:fake_helper) { double('fake-helper', changes_by_category: changes_by_category, ee?: ee?) } + + let(:fake_danger) { new_fake_danger.include(described_class) } + + subject(:changelog) { fake_danger.new(git: fake_git, gitlab: fake_gitlab, helper: fake_helper) } + + describe '#needed?' do + subject { changelog.needed? } + + [ + { docs: nil }, + { none: nil }, + { docs: nil, none: nil } + ].each do |categories| + let(:changes_by_category) { categories } + it "is falsy when categories don't require a changelog" do + is_expected.to be_falsy + end + end + + where(:categories, :labels) do + { backend: nil } | %w[backend backstage] + { frontend: nil, docs: nil } | ['ci-build'] + { engineering_productivity: nil, none: nil } | ['meta'] + end + + with_them do + let(:changes_by_category) { categories } + let(:mr_labels) { labels } + + it "is falsy when labels require no changelog" do + is_expected.to be_falsy + end + end + + where(:categories, :labels) do + { frontend: nil, docs: nil } | ['database::review pending', 'feature'] + { backend: nil } | ['backend', 'technical debt'] + { engineering_productivity: nil, none: nil } | ['frontend'] + end + + with_them do + let(:changes_by_category) { categories } + let(:mr_labels) { labels } + + it "is truthy when categories and labels require a changelog" do + is_expected.to be_truthy + end + end + end + + describe '#found' do + subject { changelog.found } + + context 'added files contain a changelog' do + [ + 'changelogs/unreleased/entry.md', + 'ee/changelogs/unreleased/entry.md', + 'changelogs/unreleased-ee/entry.md', + 'ee/changelogs/unreleased-ee/entry.md' + ].each do |file_path| + let(:added_files) { [file_path] } + + it { is_expected.to be_truthy } + end + end + + context 'added files do not contain a changelog' do + [ + 'app/models/model.rb', + 'app/assets/javascripts/file.js' + ].each do |file_path| + let(:added_files) { [file_path] } + it { is_expected.to eq(nil) } + end + end + end + + describe '#presented_no_changelog_labels' do + subject { changelog.presented_no_changelog_labels } + + it 'returns the labels formatted' do + is_expected.to eq('~backstage, ~ci-build, ~meta') + end + end + + describe '#sanitized_mr_title' do + subject { changelog.sanitized_mr_title } + + [ + 'WIP: My MR title', + 'My MR title' + ].each do |mr_title| + let(:mr_json) { { "title" => mr_title } } + it { is_expected.to eq("My MR title") } + end + end + + describe '#ee_changelog?' do + context 'is ee changelog' do + [ + 'changelogs/unreleased-ee/entry.md', + 'ee/changelogs/unreleased-ee/entry.md' + ].each do |file_path| + subject { changelog.ee_changelog?(file_path) } + + it { is_expected.to be_truthy } + end + end + + context 'is not ee changelog' do + [ + 'changelogs/unreleased/entry.md', + 'ee/changelogs/unreleased/entry.md' + ].each do |file_path| + subject { changelog.ee_changelog?(file_path) } + + it { is_expected.to be_falsy } + end + end + end + + describe '#ce_port_changelog?' do + where(:helper_ee?, :file_path, :expected) do + true | 'changelogs/unreleased-ee/entry.md' | false + true | 'ee/changelogs/unreleased-ee/entry.md' | false + false | 'changelogs/unreleased-ee/entry.md' | false + false | 'ee/changelogs/unreleased-ee/entry.md' | false + true | 'changelogs/unreleased/entry.md' | true + true | 'ee/changelogs/unreleased/entry.md' | true + false | 'changelogs/unreleased/entry.md' | false + false | 'ee/changelogs/unreleased/entry.md' | false + end + + with_them do + let(:ee?) { helper_ee? } + subject { changelog.ce_port_changelog?(file_path) } + + it { is_expected.to eq(expected) } + end + end +end diff --git a/spec/lib/gitlab/danger/danger_spec_helper.rb b/spec/lib/gitlab/danger/danger_spec_helper.rb new file mode 100644 index 00000000000..b1e84b3c13d --- /dev/null +++ b/spec/lib/gitlab/danger/danger_spec_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module DangerSpecHelper + def new_fake_danger + Class.new do + attr_reader :git, :gitlab, :helper + + # rubocop:disable Gitlab/ModuleWithInstanceVariables + def initialize(git: nil, gitlab: nil, helper: nil) + @git = git + @gitlab = gitlab + @helper = helper + end + # rubocop:enable Gitlab/ModuleWithInstanceVariables + end + end +end diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb index 8056418e697..d7e67444fca 100644 --- a/spec/lib/gitlab/danger/helper_spec.rb +++ b/spec/lib/gitlab/danger/helper_spec.rb @@ -2,29 +2,22 @@ require 'fast_spec_helper' require 'rspec-parameterized' +require_relative 'danger_spec_helper' require 'gitlab/danger/helper' describe Gitlab::Danger::Helper do using RSpec::Parameterized::TableSyntax - - class FakeDanger - include Gitlab::Danger::Helper - - attr_reader :git, :gitlab - - def initialize(git:, gitlab:) - @git = git - @gitlab = gitlab - end - end + include DangerSpecHelper let(:fake_git) { double('fake-git') } let(:mr_author) { nil } let(:fake_gitlab) { double('fake-gitlab', mr_author: mr_author) } - subject(:helper) { FakeDanger.new(git: fake_git, gitlab: fake_gitlab) } + let(:fake_danger) { new_fake_danger.include(described_class) } + + subject(:helper) { fake_danger.new(git: fake_git, gitlab: fake_gitlab) } describe '#gitlab_helper' do context 'when gitlab helper is not available' do diff --git a/spec/lib/sentry/client/projects_spec.rb b/spec/lib/sentry/client/projects_spec.rb new file mode 100644 index 00000000000..462f74eaac9 --- /dev/null +++ b/spec/lib/sentry/client/projects_spec.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Sentry::Client::Projects do + include SentryClientHelpers + + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } + let(:token) { 'test-token' } + let(:client) { Sentry::Client.new(sentry_url, token) } + let(:projects_sample_response) do + Gitlab::Utils.deep_indifferent_access( + JSON.parse(fixture_file('sentry/list_projects_sample_response.json')) + ) + end + + shared_examples 'has correct return type' do |klass| + it "returns objects of type #{klass}" do + expect(subject).to all( be_a(klass) ) + end + end + + shared_examples 'has correct length' do |length| + it { expect(subject.length).to eq(length) } + end + + describe '#projects' do + let(:sentry_list_projects_url) { 'https://sentrytest.gitlab.com/api/0/projects/' } + let(:sentry_api_response) { projects_sample_response } + let!(:sentry_api_request) { stub_sentry_request(sentry_list_projects_url, body: sentry_api_response) } + + subject { client.projects } + + it_behaves_like 'calls sentry api' + + it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project + it_behaves_like 'has correct length', 2 + + context 'essential keys missing in API response' do + let(:sentry_api_response) do + projects_sample_response[0...1].map do |project| + project.except(:slug) + end + end + + it 'raises exception' do + expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "slug"') + end + end + + context 'optional keys missing in sentry response' do + let(:sentry_api_response) do + projects_sample_response[0...1].map do |project| + project[:organization].delete(:id) + project.delete(:id) + project.except(:status) + end + end + + it_behaves_like 'calls sentry api' + + it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project + it_behaves_like 'has correct length', 1 + end + + context 'error object created from sentry response' do + using RSpec::Parameterized::TableSyntax + + where(:sentry_project_object, :sentry_response) do + :id | :id + :name | :name + :status | :status + :slug | :slug + :organization_name | [:organization, :name] + :organization_id | [:organization, :id] + :organization_slug | [:organization, :slug] + end + + with_them do + it do + expect(subject[0].public_send(sentry_project_object)).to( + eq(sentry_api_response[0].dig(*sentry_response)) + ) + end + end + end + + context 'redirects' do + let(:sentry_api_url) { sentry_list_projects_url } + + it_behaves_like 'no Sentry redirects' + end + + # Sentry API returns 404 if there are extra slashes in the URL! + context 'extra slashes in URL' do + let(:sentry_url) { 'https://sentrytest.gitlab.com/api//0/projects//' } + let!(:valid_req_stub) do + stub_sentry_request(sentry_list_projects_url) + end + + it 'removes extra slashes in api url' do + expect(Gitlab::HTTP).to receive(:get).with( + URI(sentry_list_projects_url), + anything + ).and_call_original + + subject + + expect(valid_req_stub).to have_been_requested + end + end + + context 'when exception is raised' do + let(:sentry_request_url) { sentry_list_projects_url } + + it_behaves_like 'maps Sentry exceptions' + end + end +end diff --git a/spec/lib/sentry/client_spec.rb b/spec/lib/sentry/client_spec.rb index 388a6418929..cff06bf4a5f 100644 --- a/spec/lib/sentry/client_spec.rb +++ b/spec/lib/sentry/client_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe Sentry::Client do + include SentryClientHelpers + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } let(:token) { 'test-token' } let(:default_httparty_options) do @@ -18,89 +20,18 @@ describe Sentry::Client do ) end - let(:projects_sample_response) do - Gitlab::Utils.deep_indifferent_access( - JSON.parse(fixture_file('sentry/list_projects_sample_response.json')) - ) - end - subject(:client) { described_class.new(sentry_url, token) } - # Requires sentry_api_url and subject to be defined - shared_examples 'no redirects' do - let(:redirect_to) { 'https://redirected.example.com' } - let(:other_url) { 'https://other.example.org' } - - let!(:redirected_req_stub) { stub_sentry_request(other_url) } - - let!(:redirect_req_stub) do - stub_sentry_request( - sentry_api_url, - status: 302, - headers: { location: redirect_to } - ) - end - - it 'does not follow redirects' do - expect { subject }.to raise_exception(Sentry::Client::Error, 'Sentry response status code: 302') - expect(redirect_req_stub).to have_been_requested - expect(redirected_req_stub).not_to have_been_requested - end - end - - shared_examples 'has correct return type' do |klass| - it "returns objects of type #{klass}" do - expect(subject).to all( be_a(klass) ) - end - end - shared_examples 'issues has correct return type' do |klass| it "returns objects of type #{klass}" do expect(subject[:issues]).to all( be_a(klass) ) end end - shared_examples 'has correct length' do |length| - it { expect(subject.length).to eq(length) } - end - shared_examples 'issues has correct length' do |length| it { expect(subject[:issues].length).to eq(length) } end - # Requires sentry_api_request and subject to be defined - shared_examples 'calls sentry api' do - it 'calls sentry api' do - subject - - expect(sentry_api_request).to have_been_requested - end - end - - shared_examples 'maps exceptions' do - exceptions = { - Gitlab::HTTP::Error => 'Error when connecting to Sentry', - Net::OpenTimeout => 'Connection to Sentry timed out', - SocketError => 'Received SocketError when trying to connect to Sentry', - OpenSSL::SSL::SSLError => 'Sentry returned invalid SSL data', - Errno::ECONNREFUSED => 'Connection refused', - StandardError => 'Sentry request failed due to StandardError' - } - - exceptions.each do |exception, message| - context "#{exception}" do - before do - stub_request(:get, sentry_request_url).to_raise(exception) - end - - it do - expect { subject } - .to raise_exception(Sentry::Client::Error, message) - end - end - end - end - describe '#list_issues' do let(:issue_status) { 'unresolved' } let(:limit) { 20 } @@ -174,7 +105,7 @@ describe Sentry::Client do context 'redirects' do let(:sentry_api_url) { sentry_url + '/issues/?limit=20&query=is:unresolved' } - it_behaves_like 'no redirects' + it_behaves_like 'no Sentry redirects' end # Sentry API returns 404 if there are extra slashes in the URL! @@ -265,7 +196,7 @@ describe Sentry::Client do end end - it_behaves_like 'maps exceptions' + it_behaves_like 'maps Sentry exceptions' context 'when search term is present' do let(:search_term) { 'NoMethodError' } @@ -287,112 +218,4 @@ describe Sentry::Client do it_behaves_like 'issues has correct length', 1 end end - - describe '#list_projects' do - let(:sentry_list_projects_url) { 'https://sentrytest.gitlab.com/api/0/projects/' } - - let(:sentry_api_response) { projects_sample_response } - - let!(:sentry_api_request) { stub_sentry_request(sentry_list_projects_url, body: sentry_api_response) } - - subject { client.list_projects } - - it_behaves_like 'calls sentry api' - - it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project - it_behaves_like 'has correct length', 2 - - context 'essential keys missing in API response' do - let(:sentry_api_response) do - projects_sample_response[0...1].map do |project| - project.except(:slug) - end - end - - it 'raises exception' do - expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "slug"') - end - end - - context 'optional keys missing in sentry response' do - let(:sentry_api_response) do - projects_sample_response[0...1].map do |project| - project[:organization].delete(:id) - project.delete(:id) - project.except(:status) - end - end - - it_behaves_like 'calls sentry api' - - it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project - it_behaves_like 'has correct length', 1 - end - - context 'error object created from sentry response' do - using RSpec::Parameterized::TableSyntax - - where(:sentry_project_object, :sentry_response) do - :id | :id - :name | :name - :status | :status - :slug | :slug - :organization_name | [:organization, :name] - :organization_id | [:organization, :id] - :organization_slug | [:organization, :slug] - end - - with_them do - it do - expect(subject[0].public_send(sentry_project_object)).to( - eq(sentry_api_response[0].dig(*sentry_response)) - ) - end - end - end - - context 'redirects' do - let(:sentry_api_url) { sentry_list_projects_url } - - it_behaves_like 'no redirects' - end - - # Sentry API returns 404 if there are extra slashes in the URL! - context 'extra slashes in URL' do - let(:sentry_url) { 'https://sentrytest.gitlab.com/api//0/projects//' } - let(:client) { described_class.new(sentry_url, token) } - - let!(:valid_req_stub) do - stub_sentry_request(sentry_list_projects_url) - end - - it 'removes extra slashes in api url' do - expect(Gitlab::HTTP).to receive(:get).with( - URI(sentry_list_projects_url), - anything - ).and_call_original - - subject - - expect(valid_req_stub).to have_been_requested - end - end - - context 'when exception is raised' do - let(:sentry_request_url) { sentry_list_projects_url } - - it_behaves_like 'maps exceptions' - end - end - - private - - def stub_sentry_request(url, body: {}, status: 200, headers: {}) - stub_request(:get, url) - .to_return( - status: status, - headers: { 'Content-Type' => 'application/json' }.merge(headers), - body: body.to_json - ) - end end diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb index 6bb09205a7b..ef426661066 100644 --- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb +++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb @@ -193,7 +193,7 @@ describe ErrorTracking::ProjectErrorTrackingSetting do it 'calls sentry client' do expect(subject).to receive(:sentry_client).and_return(sentry_client) - expect(sentry_client).to receive(:list_projects).and_return(projects) + expect(sentry_client).to receive(:projects).and_return(projects) result = subject.list_sentry_projects diff --git a/spec/support/helpers/sentry_client_helpers.rb b/spec/support/helpers/sentry_client_helpers.rb new file mode 100644 index 00000000000..7476b5fb249 --- /dev/null +++ b/spec/support/helpers/sentry_client_helpers.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module SentryClientHelpers + private + + def stub_sentry_request(url, body: {}, status: 200, headers: {}) + stub_request(:get, url) + .to_return( + status: status, + headers: { 'Content-Type' => 'application/json' }.merge(headers), + body: body.to_json + ) + end +end diff --git a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb new file mode 100644 index 00000000000..76b71ebd3c5 --- /dev/null +++ b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Requires sentry_api_request and subject to be defined +RSpec.shared_examples 'calls sentry api' do + it 'calls sentry api' do + subject + + expect(sentry_api_request).to have_been_requested + end +end + +# Requires sentry_api_url and subject to be defined +RSpec.shared_examples 'no Sentry redirects' do + let(:redirect_to) { 'https://redirected.example.com' } + let(:other_url) { 'https://other.example.org' } + + let!(:redirected_req_stub) { stub_sentry_request(other_url) } + + let!(:redirect_req_stub) do + stub_sentry_request( + sentry_api_url, + status: 302, + headers: { location: redirect_to } + ) + end + + it 'does not follow redirects' do + expect { subject }.to raise_exception(Sentry::Client::Error, 'Sentry response status code: 302') + expect(redirect_req_stub).to have_been_requested + expect(redirected_req_stub).not_to have_been_requested + end +end + +RSpec.shared_examples 'maps Sentry exceptions' do + exceptions = { + Gitlab::HTTP::Error => 'Error when connecting to Sentry', + Net::OpenTimeout => 'Connection to Sentry timed out', + SocketError => 'Received SocketError when trying to connect to Sentry', + OpenSSL::SSL::SSLError => 'Sentry returned invalid SSL data', + Errno::ECONNREFUSED => 'Connection refused', + StandardError => 'Sentry request failed due to StandardError' + } + + exceptions.each do |exception, message| + context "#{exception}" do + before do + stub_request(:get, sentry_request_url).to_raise(exception) + end + + it do + expect { subject } + .to raise_exception(Sentry::Client::Error, message) + end + end + end +end |