From f64a639bcfa1fc2bc89ca7db268f594306edfd7c Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 16 Mar 2021 18:18:33 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-10-stable-ee --- .../error_tracking/sentry_client/api_urls_spec.rb | 85 ++++++ .../lib/error_tracking/sentry_client/event_spec.rb | 75 +++++ .../sentry_client/issue_link_spec.rb | 65 ++++ .../lib/error_tracking/sentry_client/issue_spec.rb | 330 +++++++++++++++++++++ .../sentry_client/pagination_parser_spec.rb | 60 ++++ .../error_tracking/sentry_client/projects_spec.rb | 100 +++++++ spec/lib/error_tracking/sentry_client/repo_spec.rb | 39 +++ 7 files changed, 754 insertions(+) create mode 100644 spec/lib/error_tracking/sentry_client/api_urls_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/event_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/issue_link_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/issue_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/projects_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/repo_spec.rb (limited to 'spec/lib/error_tracking/sentry_client') diff --git a/spec/lib/error_tracking/sentry_client/api_urls_spec.rb b/spec/lib/error_tracking/sentry_client/api_urls_spec.rb new file mode 100644 index 00000000000..bd701748dc2 --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/api_urls_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ErrorTracking::SentryClient::ApiUrls do + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project/' } + let(:token) { 'test-token' } + let(:issue_id) { '123456' } + let(:issue_id_with_reserved_chars) { '123$%' } + let(:escaped_issue_id) { '123%24%25' } + let(:api_urls) { described_class.new(sentry_url) } + + # Sentry API returns 404 if there are extra slashes in the URL! + shared_examples 'correct url with extra slashes' do + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects//sentry-org/sentry-project/' } + + it_behaves_like 'correct url' + end + + shared_examples 'correctly escapes issue ID' do + context 'with param a string with reserved chars' do + let(:issue_id) { issue_id_with_reserved_chars } + + it { expect(subject.to_s).to include(escaped_issue_id) } + end + + context 'with param a symbol with reserved chars' do + let(:issue_id) { issue_id_with_reserved_chars.to_sym } + + it { expect(subject.to_s).to include(escaped_issue_id) } + end + + context 'with param an integer' do + let(:issue_id) { 12345678 } + + it { expect(subject.to_s).to include(issue_id.to_s) } + end + end + + describe '#issues_url' do + subject { api_urls.issues_url } + + shared_examples 'correct url' do + it { is_expected.to eq_uri('https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project/issues/') } + end + + it_behaves_like 'correct url' + it_behaves_like 'correct url with extra slashes' + end + + describe '#issue_url' do + subject { api_urls.issue_url(issue_id) } + + shared_examples 'correct url' do + it { is_expected.to eq_uri("https://sentrytest.gitlab.com/api/0/issues/#{issue_id}/") } + end + + it_behaves_like 'correct url' + it_behaves_like 'correct url with extra slashes' + it_behaves_like 'correctly escapes issue ID' + end + + describe '#projects_url' do + subject { api_urls.projects_url } + + shared_examples 'correct url' do + it { is_expected.to eq_uri('https://sentrytest.gitlab.com/api/0/projects/') } + end + + it_behaves_like 'correct url' + it_behaves_like 'correct url with extra slashes' + end + + describe '#issue_latest_event_url' do + subject { api_urls.issue_latest_event_url(issue_id) } + + shared_examples 'correct url' do + it { is_expected.to eq_uri("https://sentrytest.gitlab.com/api/0/issues/#{issue_id}/events/latest/") } + end + + it_behaves_like 'correct url' + it_behaves_like 'correct url with extra slashes' + it_behaves_like 'correctly escapes issue ID' + end +end diff --git a/spec/lib/error_tracking/sentry_client/event_spec.rb b/spec/lib/error_tracking/sentry_client/event_spec.rb new file mode 100644 index 00000000000..64e674f1e9b --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/event_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ErrorTracking::SentryClient 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 + { + follow_redirects: false, + headers: { "Authorization" => "Bearer test-token" } + } + end + + let(:client) { described_class.new(sentry_url, token) } + + describe '#issue_latest_event' do + let(:sample_response) do + Gitlab::Utils.deep_indifferent_access( + Gitlab::Json.parse(fixture_file('sentry/issue_latest_event_sample_response.json')) + ) + end + + let(:issue_id) { '1234' } + let(:sentry_api_response) { sample_response } + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' } + let(:sentry_request_url) { "#{sentry_url}/issues/#{issue_id}/events/latest/" } + let!(:sentry_api_request) { stub_sentry_request(sentry_request_url, body: sentry_api_response) } + + subject { client.issue_latest_event(issue_id: issue_id) } + + it_behaves_like 'calls sentry api' + + it 'has correct return type' do + expect(subject).to be_a(Gitlab::ErrorTracking::ErrorEvent) + end + + shared_examples 'assigns error tracking event correctly' do + using RSpec::Parameterized::TableSyntax + + where(:event_object, :sentry_response) do + :issue_id | :groupID + :date_received | :dateReceived + end + + with_them do + it { expect(subject.public_send(event_object)).to eq(sentry_api_response.dig(*sentry_response)) } + end + end + + context 'error object created from sentry response' do + it_behaves_like 'assigns error tracking event correctly' + + it 'parses the stack trace' do + expect(subject.stack_trace_entries).to be_a Array + expect(subject.stack_trace_entries).not_to be_empty + end + + context 'error without stack trace' do + before do + sample_response['entries'] = [] + stub_sentry_request(sentry_request_url, body: sample_response) + end + + it_behaves_like 'assigns error tracking event correctly' + + it 'returns an empty array for stack_trace_entries' do + expect(subject.stack_trace_entries).to eq [] + end + end + end + end +end diff --git a/spec/lib/error_tracking/sentry_client/issue_link_spec.rb b/spec/lib/error_tracking/sentry_client/issue_link_spec.rb new file mode 100644 index 00000000000..f86d328ef89 --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/issue_link_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ErrorTracking::SentryClient::IssueLink do + include SentryClientHelpers + + let_it_be(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } + let_it_be(:error_tracking_setting) { create(:project_error_tracking_setting, api_url: sentry_url) } + let_it_be(:issue) { create(:issue, project: error_tracking_setting.project) } + + let(:client) { error_tracking_setting.sentry_client } + let(:sentry_issue_id) { 11111111 } + + describe '#create_issue_link' do + let(:sentry_issue_link_url) { "https://sentrytest.gitlab.com/api/0/groups/#{sentry_issue_id}/integrations/#{integration_id}/" } + let(:integration_id) { 44444 } + + let(:issue_link_sample_response) { Gitlab::Json.parse(fixture_file('sentry/global_integration_link_sample_response.json')) } + let(:sentry_api_response) { issue_link_sample_response } + let!(:sentry_api_request) { stub_sentry_request(sentry_issue_link_url, :put, body: sentry_api_response, status: 201) } + + subject { client.create_issue_link(integration_id, sentry_issue_id, issue) } + + it_behaves_like 'calls sentry api' + + it { is_expected.to be_present } + + context 'redirects' do + let(:sentry_api_url) { sentry_issue_link_url } + + it_behaves_like 'no Sentry redirects', :put + end + + context 'when exception is raised' do + let(:sentry_request_url) { sentry_issue_link_url } + + it_behaves_like 'maps Sentry exceptions', :put + end + + context 'when integration_id is not provided' do + let(:sentry_issue_link_url) { "https://sentrytest.gitlab.com/api/0/issues/#{sentry_issue_id}/plugins/gitlab/link/" } + let(:integration_id) { nil } + + let(:issue_link_sample_response) { Gitlab::Json.parse(fixture_file('sentry/plugin_link_sample_response.json')) } + let!(:sentry_api_request) { stub_sentry_request(sentry_issue_link_url, :post, body: sentry_api_response) } + + it_behaves_like 'calls sentry api' + + it { is_expected.to be_present } + + context 'redirects' do + let(:sentry_api_url) { sentry_issue_link_url } + + it_behaves_like 'no Sentry redirects', :post + end + + context 'when exception is raised' do + let(:sentry_request_url) { sentry_issue_link_url } + + it_behaves_like 'maps Sentry exceptions', :post + end + end + end +end diff --git a/spec/lib/error_tracking/sentry_client/issue_spec.rb b/spec/lib/error_tracking/sentry_client/issue_spec.rb new file mode 100644 index 00000000000..e54296c58e0 --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/issue_spec.rb @@ -0,0 +1,330 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ErrorTracking::SentryClient::Issue do + include SentryClientHelpers + + let(:token) { 'test-token' } + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' } + let(:client) { ErrorTracking::SentryClient.new(sentry_url, token) } + let(:issue_id) { 11 } + + describe '#list_issues' do + shared_examples 'issues have correct return type' do |klass| + it "returns objects of type #{klass}" do + expect(subject[:issues]).to all( be_a(klass) ) + end + end + + shared_examples 'issues have correct length' do |length| + it { expect(subject[:issues].length).to eq(length) } + end + + let(:issues_sample_response) do + Gitlab::Utils.deep_indifferent_access( + Gitlab::Json.parse(fixture_file('sentry/issues_sample_response.json')) + ) + end + + let(:default_httparty_options) do + { + follow_redirects: false, + headers: { 'Content-Type' => 'application/json', 'Authorization' => "Bearer test-token" } + } + end + + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } + let(:issue_status) { 'unresolved' } + let(:limit) { 20 } + let(:search_term) { '' } + let(:cursor) { nil } + let(:sort) { 'last_seen' } + let(:sentry_api_response) { issues_sample_response } + let(:sentry_request_url) { sentry_url + '/issues/?limit=20&query=is:unresolved' } + let!(:sentry_api_request) { stub_sentry_request(sentry_request_url, body: sentry_api_response) } + + subject { client.list_issues(issue_status: issue_status, limit: limit, search_term: search_term, sort: sort, cursor: cursor) } + + it_behaves_like 'calls sentry api' + + it_behaves_like 'issues have correct return type', Gitlab::ErrorTracking::Error + it_behaves_like 'issues have correct length', 3 + + shared_examples 'has correct external_url' do + context 'external_url' do + it 'is constructed correctly' do + expect(subject[:issues][0].external_url).to eq('https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/11') + end + end + end + + context 'when response has a pagination info' do + let(:headers) do + { + link: '; rel="previous"; results="true"; cursor="1573556671000:0:1", ; rel="next"; results="true"; cursor="1572959139000:0:0"' + } + end + + let!(:sentry_api_request) { stub_sentry_request(sentry_request_url, body: sentry_api_response, headers: headers) } + + it 'parses the pagination' do + expect(subject[:pagination]).to eq( + 'previous' => { 'cursor' => '1573556671000:0:1' }, + 'next' => { 'cursor' => '1572959139000:0:0' } + ) + end + end + + context 'error object created from sentry response' do + using RSpec::Parameterized::TableSyntax + + where(:error_object, :sentry_response) do + :id | :id + :first_seen | :firstSeen + :last_seen | :lastSeen + :title | :title + :type | :type + :user_count | :userCount + :count | :count + :message | [:metadata, :value] + :culprit | :culprit + :short_id | :shortId + :status | :status + :frequency | [:stats, '24h'] + :project_id | [:project, :id] + :project_name | [:project, :name] + :project_slug | [:project, :slug] + end + + with_them do + it { expect(subject[:issues][0].public_send(error_object)).to eq(sentry_api_response[0].dig(*sentry_response)) } + end + + it_behaves_like 'has correct external_url' + end + + context 'redirects' do + let(:sentry_api_url) { sentry_url + '/issues/?limit=20&query=is:unresolved' } + + it_behaves_like 'no Sentry redirects' + end + + context 'requests with sort parameter in sentry api' do + let(:sentry_request_url) do + 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project/' \ + 'issues/?limit=20&query=is:unresolved&sort=freq' + end + + let!(:sentry_api_request) { stub_sentry_request(sentry_request_url, body: sentry_api_response) } + + subject { client.list_issues(issue_status: issue_status, limit: limit, sort: 'frequency') } + + it 'calls the sentry api with sort params' do + expect(Gitlab::HTTP).to receive(:get).with( + URI("#{sentry_url}/issues/"), + default_httparty_options.merge(query: { limit: 20, query: "is:unresolved", sort: "freq" }) + ).and_call_original + + subject + + expect(sentry_api_request).to have_been_requested + end + end + + context 'with invalid sort params' do + subject { client.list_issues(issue_status: issue_status, limit: limit, sort: 'fish') } + + it 'throws an error' do + expect { subject }.to raise_error(ErrorTracking::SentryClient::BadRequestError, 'Invalid value for sort param') + end + end + + context 'Older sentry versions where keys are not present' do + let(:sentry_api_response) do + issues_sample_response[0...1].map do |issue| + issue[:project].delete(:id) + issue + end + end + + it_behaves_like 'calls sentry api' + + it_behaves_like 'issues have correct return type', Gitlab::ErrorTracking::Error + it_behaves_like 'issues have correct length', 1 + + it_behaves_like 'has correct external_url' + end + + context 'essential keys missing in API response' do + let(:sentry_api_response) do + issues_sample_response[0...1].map do |issue| + issue.except(:id) + end + end + + it 'raises exception' do + expect { subject }.to raise_error(ErrorTracking::SentryClient::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') + end + end + + context 'sentry api response too large' do + it 'raises exception' do + deep_size = double('Gitlab::Utils::DeepSize', valid?: false) + allow(Gitlab::Utils::DeepSize).to receive(:new).with(sentry_api_response).and_return(deep_size) + + expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError, 'Sentry API response is too big. Limit is 1 MB.') + end + end + + it_behaves_like 'maps Sentry exceptions' + + context 'when search term is present' do + let(:search_term) { 'NoMethodError' } + let(:sentry_request_url) { "#{sentry_url}/issues/?limit=20&query=is:unresolved NoMethodError" } + + it_behaves_like 'calls sentry api' + + it_behaves_like 'issues have correct return type', Gitlab::ErrorTracking::Error + it_behaves_like 'issues have correct length', 3 + end + + context 'when cursor is present' do + let(:cursor) { '1572959139000:0:0' } + let(:sentry_request_url) { "#{sentry_url}/issues/?limit=20&cursor=#{cursor}&query=is:unresolved" } + + it_behaves_like 'calls sentry api' + + it_behaves_like 'issues have correct return type', Gitlab::ErrorTracking::Error + it_behaves_like 'issues have correct length', 3 + end + end + + describe '#issue_details' do + let(:issue_sample_response) do + Gitlab::Utils.deep_indifferent_access( + Gitlab::Json.parse(fixture_file('sentry/issue_sample_response.json')) + ) + end + + let(:sentry_request_url) { "#{sentry_url}/issues/#{issue_id}/" } + let!(:sentry_api_request) { stub_sentry_request(sentry_request_url, body: issue_sample_response) } + + subject { client.issue_details(issue_id: issue_id) } + + context 'error object created from sentry response' do + using RSpec::Parameterized::TableSyntax + + where(:error_object, :sentry_response) do + :id | :id + :first_seen | :firstSeen + :last_seen | :lastSeen + :title | :title + :type | :type + :user_count | :userCount + :count | :count + :message | [:metadata, :value] + :culprit | :culprit + :short_id | :shortId + :status | :status + :frequency | [:stats, '24h'] + :project_id | [:project, :id] + :project_name | [:project, :name] + :project_slug | [:project, :slug] + :first_release_last_commit | [:firstRelease, :lastCommit] + :last_release_last_commit | [:lastRelease, :lastCommit] + :first_release_short_version | [:firstRelease, :shortVersion] + :last_release_short_version | [:lastRelease, :shortVersion] + :first_release_version | [:firstRelease, :version] + :last_release_version | [:lastRelease, :version] + end + + with_them do + it do + expect(subject.public_send(error_object)).to eq(issue_sample_response.dig(*sentry_response)) + end + end + + it 'has a correct external URL' do + expect(subject.external_url).to eq('https://sentrytest.gitlab.com/api/0/issues/11') + end + + it 'issue has a correct external base url' do + expect(subject.external_base_url).to eq('https://sentrytest.gitlab.com/api/0') + end + + it 'has a correct GitLab issue url' do + expect(subject.gitlab_issue).to eq('https://gitlab.com/gitlab-org/gitlab/issues/1') + end + + context 'when issue annotations exist' do + before do + issue_sample_response['annotations'] = [ + nil, + '', + "github-issue-6", + "
annotation", + "gitlab-org/gitlab#2" + ] + stub_sentry_request(sentry_request_url, body: issue_sample_response) + end + + it 'has a correct GitLab issue url' do + expect(subject.gitlab_issue).to eq('http://localhost/gitlab-org/gitlab/issues/2') + end + end + + context 'when no GitLab issue is linked' do + before do + issue_sample_response['pluginIssues'] = [] + stub_sentry_request(sentry_request_url, body: issue_sample_response) + end + + it 'does not find a GitLab issue' do + expect(subject.gitlab_issue).to be_nil + end + end + + it 'has the correct tags' do + expect(subject.tags).to eq({ level: issue_sample_response['level'], logger: issue_sample_response['logger'] }) + end + end + end + + describe '#update_issue' do + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' } + let(:sentry_request_url) { "#{sentry_url}/issues/#{issue_id}/" } + + before do + stub_sentry_request(sentry_request_url, :put) + end + + let(:params) do + { + status: 'resolved' + } + end + + subject { client.update_issue(issue_id: issue_id, params: params) } + + it_behaves_like 'calls sentry api' do + let(:sentry_api_request) { stub_sentry_request(sentry_request_url, :put) } + end + + it 'returns a truthy result' do + expect(subject).to be_truthy + end + + context 'error encountered' do + let(:error) { StandardError.new('error') } + + before do + allow(client).to receive(:update_issue).and_raise(error) + end + + it 'raises the error' do + expect { subject }.to raise_error(error) + end + end + end +end diff --git a/spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb b/spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb new file mode 100644 index 00000000000..c4b771d5b93 --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +RSpec.describe ErrorTracking::SentryClient::PaginationParser do + describe '.parse' do + subject { described_class.parse(headers) } + + context 'when headers do not have "link" param' do + let(:headers) { {} } + + it 'returns empty hash' do + is_expected.to eq({}) + end + end + + context 'when headers.link has previous and next pages' do + let(:headers) do + { + 'link' => '; rel="previous"; results="true"; cursor="1573556671000:0:1", ; rel="next"; results="true"; cursor="1572959139000:0:0"' + } + end + + it 'returns info about both pages' do + is_expected.to eq( + 'previous' => { 'cursor' => '1573556671000:0:1' }, + 'next' => { 'cursor' => '1572959139000:0:0' } + ) + end + end + + context 'when headers.link has only next page' do + let(:headers) do + { + 'link' => '; rel="previous"; results="false"; cursor="1573556671000:0:1", ; rel="next"; results="true"; cursor="1572959139000:0:0"' + } + end + + it 'returns only info about the next page' do + is_expected.to eq( + 'next' => { 'cursor' => '1572959139000:0:0' } + ) + end + end + + context 'when headers.link has only previous page' do + let(:headers) do + { + 'link' => '; rel="previous"; results="true"; cursor="1573556671000:0:1", ; rel="next"; results="false"; cursor="1572959139000:0:0"' + } + end + + it 'returns only info about the previous page' do + is_expected.to eq( + 'previous' => { 'cursor' => '1573556671000:0:1' } + ) + end + end + end +end diff --git a/spec/lib/error_tracking/sentry_client/projects_spec.rb b/spec/lib/error_tracking/sentry_client/projects_spec.rb new file mode 100644 index 00000000000..247f9c1c085 --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/projects_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ErrorTracking::SentryClient::Projects do + include SentryClientHelpers + + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } + let(:token) { 'test-token' } + let(:client) { ErrorTracking::SentryClient.new(sentry_url, token) } + let(:projects_sample_response) do + Gitlab::Utils.deep_indifferent_access( + Gitlab::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(ErrorTracking::SentryClient::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 + + 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/error_tracking/sentry_client/repo_spec.rb b/spec/lib/error_tracking/sentry_client/repo_spec.rb new file mode 100644 index 00000000000..9a1c7a69c3d --- /dev/null +++ b/spec/lib/error_tracking/sentry_client/repo_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ErrorTracking::SentryClient::Repo do + include SentryClientHelpers + + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } + let(:token) { 'test-token' } + let(:client) { ErrorTracking::SentryClient.new(sentry_url, token) } + let(:repos_sample_response) { Gitlab::Json.parse(fixture_file('sentry/repos_sample_response.json')) } + + describe '#repos' do + let(:organization_slug) { 'gitlab' } + let(:sentry_repos_url) { "https://sentrytest.gitlab.com/api/0/organizations/#{organization_slug}/repos/" } + let(:sentry_api_response) { repos_sample_response } + let!(:sentry_api_request) { stub_sentry_request(sentry_repos_url, body: sentry_api_response) } + + subject { client.repos(organization_slug) } + + it_behaves_like 'calls sentry api' + + it { is_expected.to all( be_a(Gitlab::ErrorTracking::Repo)) } + + it { expect(subject.length).to eq(1) } + + context 'redirects' do + let(:sentry_api_url) { sentry_repos_url } + + it_behaves_like 'no Sentry redirects' + end + + context 'when exception is raised' do + let(:sentry_request_url) { sentry_repos_url } + + it_behaves_like 'maps Sentry exceptions' + end + end +end -- cgit v1.2.1