Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-01 00:08:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-01 00:08:52 +0300
commitd5d3c03598df712550acf0c6463a61c6e7dcc19e (patch)
treed0fdf0f9cd6df46aea6ed16b6556f44055efb642 /spec
parent0434f38ef1dce4fe640fe1e4542235746ceb943c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/config/mail_room_spec.rb48
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb2
-rw-r--r--spec/fixtures/config/mail_room_disabled.yml11
-rw-r--r--spec/fixtures/config/mail_room_enabled.yml11
-rw-r--r--spec/frontend/error_tracking/components/error_details_spec.js99
-rw-r--r--spec/frontend/error_tracking/store/actions_spec.js64
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb1
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb19
-rw-r--r--spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb19
-rw-r--r--spec/helpers/projects/error_tracking_helper_spec.rb5
-rw-r--r--spec/lib/gitlab/mail_room/mail_room_spec.rb134
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb91
-rw-r--r--spec/support/shared_examples/error_tracking_shared_examples.rb33
13 files changed, 377 insertions, 160 deletions
diff --git a/spec/config/mail_room_spec.rb b/spec/config/mail_room_spec.rb
index 94b29b89f24..fcef4e7a9b0 100644
--- a/spec/config/mail_room_spec.rb
+++ b/spec/config/mail_room_spec.rb
@@ -39,39 +39,31 @@ describe 'mail_room.yml' do
end
end
- context 'when incoming email is enabled' do
+ context 'when both incoming email and service desk email are enabled' do
let(:gitlab_config_path) { 'spec/fixtures/config/mail_room_enabled.yml' }
let(:queues_config_path) { 'spec/fixtures/config/redis_queues_new_format_host.yml' }
-
let(:gitlab_redis_queues) { Gitlab::Redis::Queues.new(Rails.env) }
it 'contains the intended configuration' do
- expect(configuration[:mailboxes].length).to eq(1)
- mailbox = configuration[:mailboxes].first
-
- expect(mailbox[:host]).to eq('imap.gmail.com')
- expect(mailbox[:port]).to eq(993)
- expect(mailbox[:ssl]).to eq(true)
- expect(mailbox[:start_tls]).to eq(false)
- expect(mailbox[:email]).to eq('gitlab-incoming@gmail.com')
- expect(mailbox[:password]).to eq('[REDACTED]')
- expect(mailbox[:name]).to eq('inbox')
- expect(mailbox[:idle_timeout]).to eq(60)
-
- redis_url = gitlab_redis_queues.url
- sentinels = gitlab_redis_queues.sentinels
-
- expect(mailbox[:delivery_options][:redis_url]).to be_present
- expect(mailbox[:delivery_options][:redis_url]).to eq(redis_url)
-
- expect(mailbox[:delivery_options][:sentinels]).to be_present
- expect(mailbox[:delivery_options][:sentinels]).to eq(sentinels)
-
- expect(mailbox[:arbitration_options][:redis_url]).to be_present
- expect(mailbox[:arbitration_options][:redis_url]).to eq(redis_url)
-
- expect(mailbox[:arbitration_options][:sentinels]).to be_present
- expect(mailbox[:arbitration_options][:sentinels]).to eq(sentinels)
+ expected_mailbox = {
+ host: 'imap.gmail.com',
+ port: 993,
+ ssl: true,
+ start_tls: false,
+ email: 'gitlab-incoming@gmail.com',
+ password: '[REDACTED]',
+ name: 'inbox',
+ idle_timeout: 60
+ }
+ expected_options = {
+ redis_url: gitlab_redis_queues.url,
+ sentinels: gitlab_redis_queues.sentinels
+ }
+
+ expect(configuration[:mailboxes].length).to eq(2)
+ expect(configuration[:mailboxes]).to all(include(expected_mailbox))
+ expect(configuration[:mailboxes].map { |m| m[:delivery_options] }).to all(include(expected_options))
+ expect(configuration[:mailboxes].map { |m| m[:arbitration_options] }).to all(include(expected_options))
end
end
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 3a47475da2b..cf74b2cc8ce 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -51,7 +51,7 @@ describe 'Dashboard shortcuts', :js do
find('body').send_keys([:shift, 'P'])
find('.nothing-here-block')
- expect(page).to have_content('Explore public groups to find projects to contribute to.')
+ expect(page).to have_content("This user doesn't have any personal projects")
end
end
diff --git a/spec/fixtures/config/mail_room_disabled.yml b/spec/fixtures/config/mail_room_disabled.yml
index 97f8cff051f..538f2a35f81 100644
--- a/spec/fixtures/config/mail_room_disabled.yml
+++ b/spec/fixtures/config/mail_room_disabled.yml
@@ -9,3 +9,14 @@ test:
ssl: true
start_tls: false
mailbox: "inbox"
+
+ service_desk_email:
+ enabled: false
+ address: "gitlab-incoming+%{key}@gmail.com"
+ user: "gitlab-incoming@gmail.com"
+ password: "[REDACTED]"
+ host: "imap.gmail.com"
+ port: 993
+ ssl: true
+ start_tls: false
+ mailbox: "inbox"
diff --git a/spec/fixtures/config/mail_room_enabled.yml b/spec/fixtures/config/mail_room_enabled.yml
index 9c94649244d..e1f4c2f44de 100644
--- a/spec/fixtures/config/mail_room_enabled.yml
+++ b/spec/fixtures/config/mail_room_enabled.yml
@@ -9,3 +9,14 @@ test:
ssl: true
start_tls: false
mailbox: "inbox"
+
+ service_desk_email:
+ enabled: true
+ address: "gitlab-incoming+%{key}@gmail.com"
+ user: "gitlab-incoming@gmail.com"
+ password: "[REDACTED]"
+ host: "imap.gmail.com"
+ port: 993
+ ssl: true
+ start_tls: false
+ mailbox: "inbox"
diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js
index f0578b52922..1e1d20800da 100644
--- a/spec/frontend/error_tracking/components/error_details_spec.js
+++ b/spec/frontend/error_tracking/components/error_details_spec.js
@@ -1,10 +1,15 @@
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
+import { __ } from '~/locale';
import { GlLoadingIcon, GlLink, GlBadge, GlFormInput } from '@gitlab/ui';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import Stacktrace from '~/error_tracking/components/stacktrace.vue';
import ErrorDetails from '~/error_tracking/components/error_details.vue';
-import { severityLevel, severityLevelVariant } from '~/error_tracking/components/constants';
+import {
+ severityLevel,
+ severityLevelVariant,
+ errorStatus,
+} from '~/error_tracking/components/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
@@ -56,6 +61,8 @@ describe('ErrorDetails', () => {
actions = {
startPollingDetails: () => {},
startPollingStacktrace: () => {},
+ updateIgnoreStatus: jest.fn(),
+ updateResolveStatus: jest.fn(),
};
getters = {
@@ -219,6 +226,96 @@ describe('ErrorDetails', () => {
});
});
+ describe('Status update', () => {
+ const findUpdateIgnoreStatusButton = () =>
+ wrapper.find('[data-qa-selector="update_ignore_status_button"]');
+ const findUpdateResolveStatusButton = () =>
+ wrapper.find('[data-qa-selector="update_resolve_status_button"]');
+
+ afterEach(() => {
+ actions.updateIgnoreStatus.mockClear();
+ actions.updateResolveStatus.mockClear();
+ });
+
+ describe('when error is unresolved', () => {
+ beforeEach(() => {
+ store.state.details.errorStatus = errorStatus.UNRESOLVED;
+ mountComponent();
+ });
+
+ it('displays Ignore and Resolve buttons', () => {
+ expect(findUpdateIgnoreStatusButton().text()).toBe(__('Ignore'));
+ expect(findUpdateResolveStatusButton().text()).toBe(__('Resolve'));
+ });
+
+ it('marks error as ignored when ignore button is clicked', () => {
+ findUpdateIgnoreStatusButton().trigger('click');
+ expect(actions.updateIgnoreStatus.mock.calls[0][1]).toEqual(
+ expect.objectContaining({ status: errorStatus.IGNORED }),
+ );
+ });
+
+ it('marks error as resolved when resolve button is clicked', () => {
+ findUpdateResolveStatusButton().trigger('click');
+ expect(actions.updateResolveStatus.mock.calls[0][1]).toEqual(
+ expect.objectContaining({ status: errorStatus.RESOLVED }),
+ );
+ });
+ });
+
+ describe('when error is ignored', () => {
+ beforeEach(() => {
+ store.state.details.errorStatus = errorStatus.IGNORED;
+ mountComponent();
+ });
+
+ it('displays Undo Ignore and Resolve buttons', () => {
+ expect(findUpdateIgnoreStatusButton().text()).toBe(__('Undo ignore'));
+ expect(findUpdateResolveStatusButton().text()).toBe(__('Resolve'));
+ });
+
+ it('marks error as unresolved when ignore button is clicked', () => {
+ findUpdateIgnoreStatusButton().trigger('click');
+ expect(actions.updateIgnoreStatus.mock.calls[0][1]).toEqual(
+ expect.objectContaining({ status: errorStatus.UNRESOLVED }),
+ );
+ });
+
+ it('marks error as resolved when resolve button is clicked', () => {
+ findUpdateResolveStatusButton().trigger('click');
+ expect(actions.updateResolveStatus.mock.calls[0][1]).toEqual(
+ expect.objectContaining({ status: errorStatus.RESOLVED }),
+ );
+ });
+ });
+
+ describe('when error is resolved', () => {
+ beforeEach(() => {
+ store.state.details.errorStatus = errorStatus.RESOLVED;
+ mountComponent();
+ });
+
+ it('displays Ignore and Unresolve buttons', () => {
+ expect(findUpdateIgnoreStatusButton().text()).toBe(__('Ignore'));
+ expect(findUpdateResolveStatusButton().text()).toBe(__('Unresolve'));
+ });
+
+ it('marks error as ignored when ignore button is clicked', () => {
+ findUpdateIgnoreStatusButton().trigger('click');
+ expect(actions.updateIgnoreStatus.mock.calls[0][1]).toEqual(
+ expect.objectContaining({ status: errorStatus.IGNORED }),
+ );
+ });
+
+ it('marks error as unresolved when unresolve button is clicked', () => {
+ findUpdateResolveStatusButton().trigger('click');
+ expect(actions.updateResolveStatus.mock.calls[0][1]).toEqual(
+ expect.objectContaining({ status: errorStatus.UNRESOLVED }),
+ );
+ });
+ });
+ });
+
describe('GitLab issue link', () => {
const gitlabIssue = 'https://gitlab.example.com/issues/1';
const findGitLabLink = () => wrapper.find(`[href="${gitlabIssue}"]`);
diff --git a/spec/frontend/error_tracking/store/actions_spec.js b/spec/frontend/error_tracking/store/actions_spec.js
index 8bc53d94345..e4a895902b3 100644
--- a/spec/frontend/error_tracking/store/actions_spec.js
+++ b/spec/frontend/error_tracking/store/actions_spec.js
@@ -10,6 +10,8 @@ jest.mock('~/flash.js');
jest.mock('~/lib/utils/url_utility');
let mock;
+const commit = jest.fn();
+const dispatch = jest.fn().mockResolvedValue();
describe('Sentry common store actions', () => {
beforeEach(() => {
@@ -20,26 +22,22 @@ describe('Sentry common store actions', () => {
mock.restore();
createFlash.mockClear();
});
+ const endpoint = '123/stacktrace';
+ const redirectUrl = '/list';
+ const status = 'resolved';
+ const params = { endpoint, redirectUrl, status };
describe('updateStatus', () => {
- const endpoint = '123/stacktrace';
- const redirectUrl = '/list';
- const status = 'resolved';
-
it('should handle successful status update', done => {
mock.onPut().reply(200, {});
testAction(
actions.updateStatus,
- { endpoint, redirectUrl, status },
+ params,
{},
[
{
- payload: true,
- type: types.SET_UPDATING_RESOLVE_STATUS,
- },
- {
- payload: false,
- type: 'SET_UPDATING_RESOLVE_STATUS',
+ payload: 'resolved',
+ type: types.SET_ERROR_STATUS,
},
],
[],
@@ -52,27 +50,29 @@ describe('Sentry common store actions', () => {
it('should handle unsuccessful status update', done => {
mock.onPut().reply(400, {});
- testAction(
- actions.updateStatus,
- { endpoint, redirectUrl, status },
- {},
- [
- {
- payload: true,
- type: types.SET_UPDATING_RESOLVE_STATUS,
- },
- {
- payload: false,
- type: types.SET_UPDATING_RESOLVE_STATUS,
- },
- ],
- [],
- () => {
- expect(visitUrl).not.toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalledTimes(1);
- done();
- },
- );
+ testAction(actions.updateStatus, params, {}, [], [], () => {
+ expect(visitUrl).not.toHaveBeenCalled();
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ done();
+ });
});
});
+
+ describe('updateResolveStatus', () => {
+ it('handles status update', () =>
+ actions.updateResolveStatus({ commit, dispatch }, params).then(() => {
+ expect(commit).toHaveBeenCalledWith(types.SET_UPDATING_RESOLVE_STATUS, true);
+ expect(commit).toHaveBeenCalledWith(types.SET_UPDATING_RESOLVE_STATUS, false);
+ expect(dispatch).toHaveBeenCalledWith('updateStatus', params);
+ }));
+ });
+
+ describe('updateIgnoreStatus', () => {
+ it('handles status update', () =>
+ actions.updateIgnoreStatus({ commit, dispatch }, params).then(() => {
+ expect(commit).toHaveBeenCalledWith(types.SET_UPDATING_IGNORE_STATUS, true);
+ expect(commit).toHaveBeenCalledWith(types.SET_UPDATING_IGNORE_STATUS, false);
+ expect(dispatch).toHaveBeenCalledWith('updateStatus', params);
+ }));
+ });
});
diff --git a/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb
index 1e6b7f89c08..3de0a359c15 100644
--- a/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb
+++ b/spec/graphql/types/error_tracking/sentry_error_collection_type_spec.rb
@@ -12,6 +12,7 @@ describe GitlabSchema.types['SentryErrorCollection'] do
errors
detailed_error
external_url
+ error_stack_trace
]
is_expected.to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb
new file mode 100644
index 00000000000..ce5fade6fcc
--- /dev/null
+++ b/spec/graphql/types/error_tracking/sentry_error_stack_trace_entry_type_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['SentryErrorStackTraceEntry'] do
+ it { expect(described_class.graphql_name).to eq('SentryErrorStackTraceEntry') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ function
+ col
+ line
+ file_name
+ trace_context
+ ]
+
+ is_expected.to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb b/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb
new file mode 100644
index 00000000000..ac41e6903e5
--- /dev/null
+++ b/spec/graphql/types/error_tracking/sentry_error_stack_trace_type_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['SentryErrorStackTrace'] do
+ it { expect(described_class.graphql_name).to eq('SentryErrorStackTrace') }
+
+ it { expect(described_class).to require_graphql_authorizations(:read_sentry_issue) }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ issue_id
+ date_received
+ stack_trace_entries
+ ]
+
+ is_expected.to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/helpers/projects/error_tracking_helper_spec.rb b/spec/helpers/projects/error_tracking_helper_spec.rb
index 325ff32dd89..d4dcd7eb54e 100644
--- a/spec/helpers/projects/error_tracking_helper_spec.rb
+++ b/spec/helpers/projects/error_tracking_helper_spec.rb
@@ -83,7 +83,6 @@ describe Projects::ErrorTrackingHelper do
describe '#error_details_data' do
let(:issue_id) { 1234 }
let(:route_params) { [project.owner, project, issue_id, { format: :json }] }
- let(:list_path) { project_error_tracking_index_path(project) }
let(:details_path) { details_namespace_project_error_tracking_index_path(*route_params) }
let(:project_path) { project.full_path }
let(:stack_trace_path) { stack_trace_namespace_project_error_tracking_index_path(*route_params) }
@@ -91,10 +90,6 @@ describe Projects::ErrorTrackingHelper do
let(:result) { helper.error_details_data(project, issue_id) }
- it 'returns the correct list path' do
- expect(result['list-path']).to eq list_path
- end
-
it 'returns the correct issue id' do
expect(result['issue-id']).to eq issue_id
end
diff --git a/spec/lib/gitlab/mail_room/mail_room_spec.rb b/spec/lib/gitlab/mail_room/mail_room_spec.rb
index 43218fc6e0d..5d41ee06263 100644
--- a/spec/lib/gitlab/mail_room/mail_room_spec.rb
+++ b/spec/lib/gitlab/mail_room/mail_room_spec.rb
@@ -4,9 +4,10 @@ require 'spec_helper'
describe Gitlab::MailRoom do
let(:default_port) { 143 }
- let(:default_config) do
+ let(:yml_config) do
{
- enabled: false,
+ enabled: true,
+ address: 'address@example.com',
port: default_port,
ssl: false,
start_tls: false,
@@ -16,71 +17,73 @@ describe Gitlab::MailRoom do
}
end
- shared_examples_for 'only truthy if both enabled and address are truthy' do |target_proc|
- context 'with both enabled and address as truthy values' do
- it 'is truthy' do
- stub_config(enabled: true, address: 'localhost')
+ let(:custom_config) { {} }
+ let(:incoming_email_config) { yml_config.merge(custom_config) }
+ let(:service_desk_email_config) { yml_config.merge(custom_config) }
- expect(target_proc.call).to be_truthy
- end
- end
-
- context 'with address only as truthy' do
- it 'is falsey' do
- stub_config(enabled: false, address: 'localhost')
-
- expect(target_proc.call).to be_falsey
- end
- end
+ let(:configs) do
+ {
+ incoming_email: incoming_email_config,
+ service_desk_email: service_desk_email_config
+ }
+ end
- context 'with enabled only as truthy' do
- it 'is falsey' do
- stub_config(enabled: true, address: nil)
+ before do
+ described_class.instance_variable_set(:@enabled_configs, nil)
+ end
- expect(target_proc.call).to be_falsey
- end
+ describe '#enabled_configs' do
+ before do
+ allow(described_class).to receive(:load_yaml).and_return(configs)
end
- context 'with neither address nor enabled as truthy' do
- it 'is falsey' do
- stub_config(enabled: false, address: nil)
-
- expect(target_proc.call).to be_falsey
+ context 'when both email and address is set' do
+ it 'returns email configs' do
+ expect(described_class.enabled_configs.size).to eq(2)
end
end
- end
-
- before do
- described_class.reset_config!
- allow(File).to receive(:exist?).and_return true
- end
- describe '#config' do
- context 'if the yml file cannot be found' do
+ context 'when the yml file cannot be found' do
before do
- allow(File).to receive(:exist?).and_return false
+ allow(described_class).to receive(:config_file).and_return('not_existing_file')
end
- it 'returns an empty hash' do
- expect(described_class.config).to be_empty
+ it 'returns an empty list' do
+ expect(described_class.enabled_configs).to be_empty
end
end
- before do
- allow(described_class).to receive(:load_from_yaml).and_return(default_config)
+ context 'when email is disabled' do
+ let(:custom_config) { { enabled: false } }
+
+ it 'returns an empty list' do
+ expect(described_class.enabled_configs).to be_empty
+ end
end
- it 'sets up config properly' do
- expected_result = default_config
+ context 'when email is enabled but address is not set' do
+ let(:custom_config) { { enabled: true, address: '' } }
- expect(described_class.config).to match expected_result
+ it 'returns an empty list' do
+ expect(described_class.enabled_configs).to be_empty
+ end
end
context 'when a config value is missing from the yml file' do
+ let(:yml_config) { {} }
+ let(:custom_config) { { enabled: true, address: 'address@example.com' } }
+
it 'overwrites missing values with the default' do
- stub_config(port: nil)
+ expect(described_class.enabled_configs.first[:port]).to eq(Gitlab::MailRoom::DEFAULT_CONFIG[:port])
+ end
+ end
+
+ context 'when only incoming_email config is present' do
+ let(:configs) { { incoming_email: incoming_email_config } }
- expect(described_class.config[:port]).to eq default_port
+ it 'returns only encoming_email' do
+ expect(described_class.enabled_configs.size).to eq(1)
+ expect(described_class.enabled_configs.first[:worker]).to eq('EmailReceiverWorker')
end
end
@@ -91,50 +94,31 @@ describe Gitlab::MailRoom do
allow(Gitlab::Redis::Queues).to receive(:new).and_return(fake_redis_queues)
end
- target_proc = proc { described_class.config[:redis_url] }
+ it 'sets redis config' do
+ config = described_class.enabled_configs.first
- it_behaves_like 'only truthy if both enabled and address are truthy', target_proc
+ expect(config[:redis_url]).to eq('localhost')
+ expect(config[:sentinels]).to eq('yes, them')
+ end
end
describe 'setting up the log path' do
context 'if the log path is a relative path' do
- it 'expands the log path to an absolute value' do
- stub_config(log_path: 'tiny_log.log')
+ let(:custom_config) { { log_path: 'tiny_log.log' } }
- new_path = Pathname.new(described_class.config[:log_path])
+ it 'expands the log path to an absolute value' do
+ new_path = Pathname.new(described_class.enabled_configs.first[:log_path])
expect(new_path.absolute?).to be_truthy
end
end
context 'if the log path is absolute path' do
- it 'leaves the path as-is' do
- new_path = '/dev/null'
- stub_config(log_path: new_path)
+ let(:custom_config) { { log_path: '/dev/null' } }
- expect(described_class.config[:log_path]).to eq new_path
+ it 'leaves the path as-is' do
+ expect(described_class.enabled_configs.first[:log_path]).to eq '/dev/null'
end
end
end
end
-
- describe '#enabled?' do
- target_proc = proc { described_class.enabled? }
-
- it_behaves_like 'only truthy if both enabled and address are truthy', target_proc
- end
-
- describe '#reset_config?' do
- it 'resets config' do
- described_class.instance_variable_set(:@config, { some_stuff: 'hooray' })
-
- described_class.reset_config!
-
- expect(described_class.instance_variable_get(:@config)).to be_nil
- end
- end
-
- def stub_config(override_values)
- modified_config = default_config.merge(override_values)
- allow(described_class).to receive(:load_from_yaml).and_return(modified_config)
- end
end
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
index e68025bf01b..06a0bfc0d32 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
@@ -40,8 +40,8 @@ describe 'sentry errors requests' do
post_graphql(query, current_user: current_user)
end
- it "is expected to return an empty error" do
- expect(error_data).to eq nil
+ it 'is expected to return an empty error' do
+ expect(error_data).to be_nil
end
end
@@ -49,7 +49,7 @@ describe 'sentry errors requests' do
before do
allow_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
.to receive(:issue_details)
- .and_return({ issue: sentry_detailed_error })
+ .and_return(issue: sentry_detailed_error)
post_graphql(query, current_user: current_user)
end
@@ -72,8 +72,8 @@ describe 'sentry errors requests' do
context 'user does not have permission' do
let(:current_user) { create(:user) }
- it "is expected to return an empty error" do
- expect(error_data).to eq nil
+ it 'is expected to return an empty error' do
+ expect(error_data).to be_nil
end
end
end
@@ -82,13 +82,13 @@ describe 'sentry errors requests' do
before do
expect_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
.to receive(:issue_details)
- .and_return({ error: 'error message' })
+ .and_return(error: 'error message')
post_graphql(query, current_user: current_user)
end
it 'is expected to handle the error and return nil' do
- expect(error_data).to eq nil
+ expect(error_data).to be_nil
end
end
end
@@ -132,8 +132,8 @@ describe 'sentry errors requests' do
post_graphql(query, current_user: current_user)
end
- it "is expected to return nil" do
- expect(error_data).to eq nil
+ it 'is expected to return nil' do
+ expect(error_data).to be_nil
end
end
@@ -141,7 +141,7 @@ describe 'sentry errors requests' do
before do
expect_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
.to receive(:list_sentry_issues)
- .and_return({ issues: [sentry_error], pagination: pagination })
+ .and_return(issues: [sentry_error], pagination: pagination)
post_graphql(query, current_user: current_user)
end
@@ -174,17 +174,82 @@ describe 'sentry errors requests' do
end
end
- context "sentry api itself errors out" do
+ context 'sentry api itself errors out' do
before do
expect_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
.to receive(:list_sentry_issues)
- .and_return({ error: 'error message' })
+ .and_return(error: 'error message')
post_graphql(query, current_user: current_user)
end
it 'is expected to handle the error and return nil' do
- expect(error_data).to eq nil
+ expect(error_data).to be_nil
+ end
+ end
+ end
+
+ describe 'getting a stack trace' do
+ let_it_be(:sentry_stack_trace) { build(:error_tracking_error_event) }
+ let(:sentry_gid) { Gitlab::ErrorTracking::DetailedError.new(id: 1).to_global_id.to_s }
+
+ let(:stack_trace_fields) do
+ all_graphql_fields_for('SentryErrorStackTrace'.classify)
+ end
+
+ let(:fields) do
+ query_graphql_field('errorStackTrace', { id: sentry_gid }, stack_trace_fields)
+ end
+
+ let(:stack_trace_data) { graphql_data.dig('project', 'sentryErrors', 'errorStackTrace') }
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ context 'when data is loading via reactive cache' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'is expected to return an empty error' do
+ expect(stack_trace_data).to be_nil
+ end
+ end
+
+ context 'reactive cache returns data' do
+ before do
+ allow_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
+ .to receive(:issue_latest_event)
+ .and_return(latest_event: sentry_stack_trace)
+
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'setting stack trace error'
+
+ context 'user does not have permission' do
+ let(:current_user) { create(:user) }
+
+ it 'is expected to return an empty error' do
+ expect(stack_trace_data).to be_nil
+ end
+ end
+ end
+
+ context 'sentry api returns an error' do
+ before do
+ expect_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
+ .to receive(:issue_latest_event)
+ .and_return(error: 'error message')
+
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'is expected to handle the error and return nil' do
+ expect(stack_trace_data).to be_nil
end
end
end
diff --git a/spec/support/shared_examples/error_tracking_shared_examples.rb b/spec/support/shared_examples/error_tracking_shared_examples.rb
index 86134fa7fd1..8e7a63b69c7 100644
--- a/spec/support/shared_examples/error_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/error_tracking_shared_examples.rb
@@ -3,11 +3,34 @@
RSpec.shared_examples 'setting sentry error data' do
it 'sets the sentry error data correctly' do
aggregate_failures 'testing the sentry error is correct' do
- expect(error['id']).to eql sentry_error.to_global_id.to_s
- expect(error['sentryId']).to eql sentry_error.id.to_s
- expect(error['status']).to eql sentry_error.status.upcase
- expect(error['firstSeen']).to eql sentry_error.first_seen
- expect(error['lastSeen']).to eql sentry_error.last_seen
+ expect(error['id']).to eq sentry_error.to_global_id.to_s
+ expect(error['sentryId']).to eq sentry_error.id.to_s
+ expect(error['status']).to eq sentry_error.status.upcase
+ expect(error['firstSeen']).to eq sentry_error.first_seen
+ expect(error['lastSeen']).to eq sentry_error.last_seen
+ end
+ end
+end
+
+RSpec.shared_examples 'setting stack trace error' do
+ it 'sets the stack trace data correctly' do
+ aggregate_failures 'testing the stack trace is correct' do
+ expect(stack_trace_data['dateReceived']).to eq(sentry_stack_trace.date_received)
+ expect(stack_trace_data['issueId']).to eq(sentry_stack_trace.issue_id)
+ expect(stack_trace_data['stackTraceEntries']).to be_an_instance_of(Array)
+ expect(stack_trace_data['stackTraceEntries'].size).to eq(sentry_stack_trace.stack_trace_entries.size)
+ end
+ end
+
+ it 'sets the stack trace entry data correctly' do
+ aggregate_failures 'testing the stack trace entry is correct' do
+ stack_trace_entry = stack_trace_data['stackTraceEntries'].first
+ model_entry = sentry_stack_trace.stack_trace_entries.first
+
+ expect(stack_trace_entry['function']).to eq model_entry['function']
+ expect(stack_trace_entry['col']).to eq model_entry['colNo']
+ expect(stack_trace_entry['line']).to eq model_entry['lineNo'].to_s
+ expect(stack_trace_entry['fileName']).to eq model_entry['filename']
end
end
end