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>2021-03-03 15:11:16 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-03 15:11:16 +0300
commitb5820a6bcd083c878a085aa288757e8dc2d35fec (patch)
tree7ce498ba4cc77c160a04eae2b8fba7474d1196d7 /spec
parent74780f24f2005d24a0e0a8fa1b3ae5391ae2928f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/environments/environments_app_spec.js12
-rw-r--r--spec/frontend/environments/folder/environments_folder_view_spec.js14
-rw-r--r--spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb176
-rw-r--r--spec/lib/gitlab/error_tracking/log_formatter_spec.rb71
-rw-r--r--spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb45
-rw-r--r--spec/lib/gitlab/error_tracking_spec.rb219
-rw-r--r--spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb16
-rw-r--r--spec/models/upload_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb137
-rw-r--r--spec/requests/api/helpers_spec.rb20
-rw-r--r--spec/requests/api/project_attributes.yml1
-rw-r--r--spec/requests/api/projects_spec.rb11
-rw-r--r--spec/services/merge_requests/update_service_spec.rb54
13 files changed, 559 insertions, 219 deletions
diff --git a/spec/frontend/environments/environments_app_spec.js b/spec/frontend/environments/environments_app_spec.js
index 50d84b19ce8..542cf58b079 100644
--- a/spec/frontend/environments/environments_app_spec.js
+++ b/spec/frontend/environments/environments_app_spec.js
@@ -97,13 +97,21 @@ describe('Environment', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
wrapper.find('.gl-pagination li:nth-child(3) .page-link').trigger('click');
- expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'available', page: '2' });
+ expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
+ scope: 'available',
+ page: '2',
+ nested: true,
+ });
});
it('should make an API request when using tabs', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
findEnvironmentsTabStopped().trigger('click');
- expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' });
+ expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
+ scope: 'stopped',
+ page: '1',
+ nested: true,
+ });
});
it('should not make the same API request when clicking on the current scope tab', () => {
diff --git a/spec/frontend/environments/folder/environments_folder_view_spec.js b/spec/frontend/environments/folder/environments_folder_view_spec.js
index 3943e89c6cf..d02ed8688c6 100644
--- a/spec/frontend/environments/folder/environments_folder_view_spec.js
+++ b/spec/frontend/environments/folder/environments_folder_view_spec.js
@@ -103,13 +103,18 @@ describe('Environments Folder View', () => {
expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
scope: wrapper.vm.scope,
page: '10',
+ nested: true,
});
});
it('should make an API request when using tabs', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
findEnvironmentsTabStopped().trigger('click');
- expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' });
+ expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
+ scope: 'stopped',
+ page: '1',
+ nested: true,
+ });
});
});
});
@@ -161,7 +166,11 @@ describe('Environments Folder View', () => {
it('should set page to 1', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
wrapper.vm.onChangeTab('stopped');
- expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' });
+ expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
+ scope: 'stopped',
+ page: '1',
+ nested: true,
+ });
});
});
@@ -172,6 +181,7 @@ describe('Environments Folder View', () => {
expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
scope: wrapper.vm.scope,
page: '4',
+ nested: true,
});
});
});
diff --git a/spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb b/spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb
new file mode 100644
index 00000000000..0e72dd7ec5e
--- /dev/null
+++ b/spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb
@@ -0,0 +1,176 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+RSpec.describe Gitlab::ErrorTracking::ContextPayloadGenerator do
+ subject(:generator) { described_class.new }
+
+ let(:extra) do
+ {
+ some_other_info: 'info',
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-foss/-/issues/1'
+ }
+ end
+
+ let(:exception) { StandardError.new("Dummy exception") }
+
+ before do
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('cid')
+ allow(I18n).to receive(:locale).and_return('en')
+ end
+
+ context 'user metadata' do
+ let(:user) { create(:user) }
+
+ it 'appends user metadata to the payload' do
+ payload = {}
+
+ Gitlab::ApplicationContext.with_context(user: user) do
+ payload = generator.generate(exception, extra)
+ end
+
+ expect(payload[:user]).to eql(
+ username: user.username
+ )
+ end
+ end
+
+ context 'tags metadata' do
+ context 'when the GITLAB_SENTRY_EXTRA_TAGS env is not set' do
+ before do
+ stub_env('GITLAB_SENTRY_EXTRA_TAGS', nil)
+ end
+
+ it 'does not log into AppLogger' do
+ expect(Gitlab::AppLogger).not_to receive(:debug)
+
+ generator.generate(exception, extra)
+ end
+
+ it 'does not send any extra tags' do
+ payload = {}
+
+ Gitlab::ApplicationContext.with_context(feature_category: 'feature_a') do
+ payload = generator.generate(exception, extra)
+ end
+
+ expect(payload[:tags]).to eql(
+ correlation_id: 'cid',
+ locale: 'en',
+ program: 'test',
+ feature_category: 'feature_a'
+ )
+ end
+ end
+
+ context 'when the GITLAB_SENTRY_EXTRA_TAGS env is a JSON hash' do
+ it 'includes those tags in all events' do
+ stub_env('GITLAB_SENTRY_EXTRA_TAGS', { foo: 'bar', baz: 'quux' }.to_json)
+ payload = {}
+
+ Gitlab::ApplicationContext.with_context(feature_category: 'feature_a') do
+ payload = generator.generate(exception, extra)
+ end
+
+ expect(payload[:tags]).to eql(
+ correlation_id: 'cid',
+ locale: 'en',
+ program: 'test',
+ feature_category: 'feature_a',
+ 'foo' => 'bar',
+ 'baz' => 'quux'
+ )
+ end
+
+ it 'does not log into AppLogger' do
+ expect(Gitlab::AppLogger).not_to receive(:debug)
+
+ generator.generate(exception, extra)
+ end
+ end
+
+ context 'when the GITLAB_SENTRY_EXTRA_TAGS env is not a JSON hash' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:env_var, :error) do
+ { foo: 'bar', baz: 'quux' }.inspect | 'JSON::ParserError'
+ [].to_json | 'NoMethodError'
+ [%w[foo bar]].to_json | 'NoMethodError'
+ %w[foo bar].to_json | 'NoMethodError'
+ '"string"' | 'NoMethodError'
+ end
+
+ with_them do
+ before do
+ stub_env('GITLAB_SENTRY_EXTRA_TAGS', env_var)
+ end
+
+ it 'logs into AppLogger' do
+ expect(Gitlab::AppLogger).to receive(:debug).with(a_string_matching(error))
+
+ generator.generate({})
+ end
+
+ it 'does not include any extra tags' do
+ payload = {}
+
+ Gitlab::ApplicationContext.with_context(feature_category: 'feature_a') do
+ payload = generator.generate(exception, extra)
+ end
+
+ expect(payload[:tags]).to eql(
+ correlation_id: 'cid',
+ locale: 'en',
+ program: 'test',
+ feature_category: 'feature_a'
+ )
+ end
+ end
+ end
+ end
+
+ context 'extra metadata' do
+ it 'appends extra metadata to the payload' do
+ payload = generator.generate(exception, extra)
+
+ expect(payload[:extra]).to eql(
+ some_other_info: 'info',
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-foss/-/issues/1'
+ )
+ end
+
+ it 'appends exception embedded extra metadata to the payload' do
+ allow(exception).to receive(:sentry_extra_data).and_return(
+ some_other_info: 'another_info',
+ mr_url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/1'
+ )
+
+ payload = generator.generate(exception, extra)
+
+ expect(payload[:extra]).to eql(
+ some_other_info: 'another_info',
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-foss/-/issues/1',
+ mr_url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/1'
+ )
+ end
+
+ it 'filters sensitive extra info' do
+ extra[:my_token] = '456'
+ allow(exception).to receive(:sentry_extra_data).and_return(
+ mr_url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/1',
+ another_token: '1234'
+ )
+
+ payload = generator.generate(exception, extra)
+
+ expect(payload[:extra]).to eql(
+ some_other_info: 'info',
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-foss/-/issues/1',
+ mr_url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/1',
+ my_token: '[FILTERED]',
+ another_token: '[FILTERED]'
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/error_tracking/log_formatter_spec.rb b/spec/lib/gitlab/error_tracking/log_formatter_spec.rb
new file mode 100644
index 00000000000..188ccd000a1
--- /dev/null
+++ b/spec/lib/gitlab/error_tracking/log_formatter_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::ErrorTracking::LogFormatter do
+ let(:exception) { StandardError.new('boom') }
+ let(:context_payload) do
+ {
+ server: 'local-hostname-of-the-server',
+ user: {
+ ip_address: '127.0.0.1',
+ username: 'root'
+ },
+ tags: {
+ locale: 'en',
+ feature_category: 'category_a'
+ },
+ extra: {
+ some_other_info: 'other_info',
+ sidekiq: {
+ 'class' => 'HelloWorker',
+ 'args' => ['senstive string', 1, 2],
+ 'another_field' => 'field'
+ }
+ }
+ }
+ end
+
+ before do
+ Raven.context.user[:user_flag] = 'flag'
+ Raven.context.tags[:shard] = 'catchall'
+ Raven.context.extra[:some_info] = 'info'
+
+ allow(exception).to receive(:backtrace).and_return(
+ [
+ 'lib/gitlab/file_a.rb:1',
+ 'lib/gitlab/file_b.rb:2'
+ ]
+ )
+ end
+
+ after do
+ ::Raven::Context.clear!
+ end
+
+ it 'appends error-related log fields and filters sensitive Sidekiq arguments' do
+ payload = described_class.new.generate_log(exception, context_payload)
+
+ expect(payload).to eql(
+ 'exception.class' => 'StandardError',
+ 'exception.message' => 'boom',
+ 'exception.backtrace' => [
+ 'lib/gitlab/file_a.rb:1',
+ 'lib/gitlab/file_b.rb:2'
+ ],
+ 'user.ip_address' => '127.0.0.1',
+ 'user.username' => 'root',
+ 'user.user_flag' => 'flag',
+ 'tags.locale' => 'en',
+ 'tags.feature_category' => 'category_a',
+ 'tags.shard' => 'catchall',
+ 'extra.some_other_info' => 'other_info',
+ 'extra.some_info' => 'info',
+ "extra.sidekiq" => {
+ "another_field" => "field",
+ "args" => ["[FILTERED]", "1", "2"],
+ "class" => "HelloWorker"
+ }
+ )
+ end
+end
diff --git a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb
new file mode 100644
index 00000000000..0db40eca989
--- /dev/null
+++ b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::ErrorTracking::Processor::ContextPayloadProcessor do
+ subject(:processor) { described_class.new }
+
+ before do
+ allow_next_instance_of(Gitlab::ErrorTracking::ContextPayloadGenerator) do |generator|
+ allow(generator).to receive(:generate).and_return(
+ user: { username: 'root' },
+ tags: { locale: 'en', program: 'test', feature_category: 'feature_a', correlation_id: 'cid' },
+ extra: { some_info: 'info' }
+ )
+ end
+ end
+
+ it 'merges the context payload into event payload' do
+ payload = {
+ user: { ip_address: '127.0.0.1' },
+ tags: { priority: 'high' },
+ extra: { sidekiq: { class: 'SomeWorker', args: ['[FILTERED]', 1, 2] } }
+ }
+
+ processor.process(payload)
+
+ expect(payload).to eql(
+ user: {
+ ip_address: '127.0.0.1',
+ username: 'root'
+ },
+ tags: {
+ priority: 'high',
+ locale: 'en',
+ program: 'test',
+ feature_category: 'feature_a',
+ correlation_id: 'cid'
+ },
+ extra: {
+ some_info: 'info',
+ sidekiq: { class: 'SomeWorker', args: ['[FILTERED]', 1, 2] }
+ }
+ )
+ end
+end
diff --git a/spec/lib/gitlab/error_tracking_spec.rb b/spec/lib/gitlab/error_tracking_spec.rb
index 764478ad1d7..a905b9f8d40 100644
--- a/spec/lib/gitlab/error_tracking_spec.rb
+++ b/spec/lib/gitlab/error_tracking_spec.rb
@@ -8,116 +8,55 @@ RSpec.describe Gitlab::ErrorTracking do
let(:exception) { RuntimeError.new('boom') }
let(:issue_url) { 'http://gitlab.com/gitlab-org/gitlab-foss/issues/1' }
- let(:expected_payload_includes) do
- [
- { 'exception.class' => 'RuntimeError' },
- { 'exception.message' => 'boom' },
- { 'tags.correlation_id' => 'cid' },
- { 'extra.some_other_info' => 'info' },
- { 'extra.issue_url' => 'http://gitlab.com/gitlab-org/gitlab-foss/issues/1' }
- ]
+ let(:user) { create(:user) }
+
+ let(:sentry_payload) do
+ {
+ tags: {
+ program: 'test',
+ locale: 'en',
+ feature_category: 'feature_a',
+ correlation_id: 'cid'
+ },
+ user: {
+ username: user.username
+ },
+ extra: {
+ some_other_info: 'info',
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-foss/issues/1'
+ }
+ }
end
- let(:sentry_event) { Gitlab::Json.parse(Raven.client.transport.events.last[1]) }
+ let(:logger_payload) do
+ {
+ 'exception.class' => 'RuntimeError',
+ 'exception.message' => 'boom',
+ 'tags.program' => 'test',
+ 'tags.locale' => 'en',
+ 'tags.feature_category' => 'feature_a',
+ 'tags.correlation_id' => 'cid',
+ 'user.username' => user.username,
+ 'extra.some_other_info' => 'info',
+ 'extra.issue_url' => 'http://gitlab.com/gitlab-org/gitlab-foss/issues/1'
+ }
+ end
before do
stub_sentry_settings
allow(described_class).to receive(:sentry_dsn).and_return(Gitlab.config.sentry.dsn)
allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('cid')
+ allow(I18n).to receive(:locale).and_return('en')
described_class.configure do |config|
config.encoding = 'json'
end
end
- describe '.configure' do
- context 'default tags from GITLAB_SENTRY_EXTRA_TAGS' do
- context 'when the value is a JSON hash' do
- it 'includes those tags in all events' do
- stub_env('GITLAB_SENTRY_EXTRA_TAGS', { foo: 'bar', baz: 'quux' }.to_json)
-
- described_class.configure do |config|
- config.encoding = 'json'
- end
-
- described_class.track_exception(StandardError.new)
-
- expect(sentry_event['tags'].except('correlation_id', 'locale', 'program'))
- .to eq('foo' => 'bar', 'baz' => 'quux')
- end
- end
-
- context 'when the value is not set' do
- before do
- stub_env('GITLAB_SENTRY_EXTRA_TAGS', nil)
- end
-
- it 'does not log an error' do
- expect(Gitlab::AppLogger).not_to receive(:debug)
-
- described_class.configure do |config|
- config.encoding = 'json'
- end
- end
-
- it 'does not send any extra tags' do
- described_class.configure do |config|
- config.encoding = 'json'
- end
-
- described_class.track_exception(StandardError.new)
-
- expect(sentry_event['tags'].keys).to contain_exactly('correlation_id', 'locale', 'program')
- end
- end
-
- context 'when the value is not a JSON hash' do
- using RSpec::Parameterized::TableSyntax
-
- where(:env_var, :error) do
- { foo: 'bar', baz: 'quux' }.inspect | 'JSON::ParserError'
- [].to_json | 'NoMethodError'
- [%w[foo bar]].to_json | 'NoMethodError'
- %w[foo bar].to_json | 'NoMethodError'
- '"string"' | 'NoMethodError'
- end
-
- with_them do
- before do
- stub_env('GITLAB_SENTRY_EXTRA_TAGS', env_var)
- end
-
- it 'does not include any extra tags' do
- described_class.configure do |config|
- config.encoding = 'json'
- end
-
- described_class.track_exception(StandardError.new)
-
- expect(sentry_event['tags'].except('correlation_id', 'locale', 'program'))
- .to be_empty
- end
-
- it 'logs the error class' do
- expect(Gitlab::AppLogger).to receive(:debug).with(a_string_matching(error))
-
- described_class.configure do |config|
- config.encoding = 'json'
- end
- end
- end
- end
- end
- end
-
- describe '.with_context' do
- it 'adds the expected tags' do
- described_class.with_context {}
-
- expect(Raven.tags_context[:locale].to_s).to eq(I18n.locale.to_s)
- expect(Raven.tags_context[Labkit::Correlation::CorrelationId::LOG_KEY.to_sym].to_s)
- .to eq('cid')
+ around do |example|
+ Gitlab::ApplicationContext.with_context(user: user, feature_category: 'feature_a') do
+ example.run
end
end
@@ -128,10 +67,15 @@ RSpec.describe Gitlab::ErrorTracking do
end
it 'raises the exception' do
- expect(Raven).to receive(:capture_exception)
-
- expect { described_class.track_and_raise_for_dev_exception(exception) }
- .to raise_error(RuntimeError)
+ expect(Raven).to receive(:capture_exception).with(exception, sentry_payload)
+
+ expect do
+ described_class.track_and_raise_for_dev_exception(
+ exception,
+ issue_url: issue_url,
+ some_other_info: 'info'
+ )
+ end.to raise_error(RuntimeError, /boom/)
end
end
@@ -141,19 +85,7 @@ RSpec.describe Gitlab::ErrorTracking do
end
it 'logs the exception with all attributes passed' do
- expected_extras = {
- some_other_info: 'info',
- issue_url: 'http://gitlab.com/gitlab-org/gitlab-foss/issues/1'
- }
-
- expected_tags = {
- correlation_id: 'cid'
- }
-
- expect(Raven).to receive(:capture_exception)
- .with(exception,
- tags: a_hash_including(expected_tags),
- extra: a_hash_including(expected_extras))
+ expect(Raven).to receive(:capture_exception).with(exception, sentry_payload)
described_class.track_and_raise_for_dev_exception(
exception,
@@ -163,8 +95,7 @@ RSpec.describe Gitlab::ErrorTracking do
end
it 'calls Gitlab::ErrorTracking::Logger.error with formatted payload' do
- expect(Gitlab::ErrorTracking::Logger).to receive(:error)
- .with(a_hash_including(*expected_payload_includes))
+ expect(Gitlab::ErrorTracking::Logger).to receive(:error).with(logger_payload)
described_class.track_and_raise_for_dev_exception(
exception,
@@ -177,15 +108,19 @@ RSpec.describe Gitlab::ErrorTracking do
describe '.track_and_raise_exception' do
it 'always raises the exception' do
- expect(Raven).to receive(:capture_exception)
+ expect(Raven).to receive(:capture_exception).with(exception, sentry_payload)
- expect { described_class.track_and_raise_exception(exception) }
- .to raise_error(RuntimeError)
+ expect do
+ described_class.track_and_raise_for_dev_exception(
+ exception,
+ issue_url: issue_url,
+ some_other_info: 'info'
+ )
+ end.to raise_error(RuntimeError, /boom/)
end
it 'calls Gitlab::ErrorTracking::Logger.error with formatted payload' do
- expect(Gitlab::ErrorTracking::Logger).to receive(:error)
- .with(a_hash_including(*expected_payload_includes))
+ expect(Gitlab::ErrorTracking::Logger).to receive(:error).with(logger_payload)
expect do
described_class.track_and_raise_exception(
@@ -210,17 +145,16 @@ RSpec.describe Gitlab::ErrorTracking do
it 'calls Raven.capture_exception' do
track_exception
- expect(Raven).to have_received(:capture_exception)
- .with(exception,
- tags: a_hash_including(correlation_id: 'cid'),
- extra: a_hash_including(some_other_info: 'info', issue_url: issue_url))
+ expect(Raven).to have_received(:capture_exception).with(
+ exception,
+ sentry_payload
+ )
end
it 'calls Gitlab::ErrorTracking::Logger.error with formatted payload' do
track_exception
- expect(Gitlab::ErrorTracking::Logger).to have_received(:error)
- .with(a_hash_including(*expected_payload_includes))
+ expect(Gitlab::ErrorTracking::Logger).to have_received(:error).with(logger_payload)
end
context 'with filterable parameters' do
@@ -229,8 +163,9 @@ RSpec.describe Gitlab::ErrorTracking do
it 'filters parameters' do
track_exception
- expect(Gitlab::ErrorTracking::Logger).to have_received(:error)
- .with(hash_including({ 'extra.test' => 1, 'extra.my_token' => '[FILTERED]' }))
+ expect(Gitlab::ErrorTracking::Logger).to have_received(:error).with(
+ hash_including({ 'extra.test' => 1, 'extra.my_token' => '[FILTERED]' })
+ )
end
end
@@ -241,8 +176,9 @@ RSpec.describe Gitlab::ErrorTracking do
it 'includes the extra data from the exception in the tracking information' do
track_exception
- expect(Raven).to have_received(:capture_exception)
- .with(exception, a_hash_including(extra: a_hash_including(extra_info)))
+ expect(Raven).to have_received(:capture_exception).with(
+ exception, a_hash_including(extra: a_hash_including(extra_info))
+ )
end
end
@@ -253,8 +189,9 @@ RSpec.describe Gitlab::ErrorTracking do
it 'just includes the other extra info' do
track_exception
- expect(Raven).to have_received(:capture_exception)
- .with(exception, a_hash_including(extra: a_hash_including(extra)))
+ expect(Raven).to have_received(:capture_exception).with(
+ exception, a_hash_including(extra: a_hash_including(extra))
+ )
end
end
@@ -266,7 +203,13 @@ RSpec.describe Gitlab::ErrorTracking do
track_exception
expect(Gitlab::ErrorTracking::Logger).to have_received(:error).with(
- hash_including({ 'extra.sidekiq' => { 'class' => 'PostReceive', 'args' => ['1', '{"id"=>2, "name"=>"hello"}', 'some-value', 'another-value'] } }))
+ hash_including(
+ 'extra.sidekiq' => {
+ 'class' => 'PostReceive',
+ 'args' => ['1', '{"id"=>2, "name"=>"hello"}', 'some-value', 'another-value']
+ }
+ )
+ )
end
end
@@ -276,9 +219,17 @@ RSpec.describe Gitlab::ErrorTracking do
it 'filters sensitive arguments before sending' do
track_exception
+ sentry_event = Gitlab::Json.parse(Raven.client.transport.events.last[1])
+
expect(sentry_event.dig('extra', 'sidekiq', 'args')).to eq(['[FILTERED]', 1, 2])
expect(Gitlab::ErrorTracking::Logger).to have_received(:error).with(
- hash_including('extra.sidekiq' => { 'class' => 'UnknownWorker', 'args' => ['[FILTERED]', '1', '2'] }))
+ hash_including(
+ 'extra.sidekiq' => {
+ 'class' => 'UnknownWorker',
+ 'args' => ['[FILTERED]', '1', '2']
+ }
+ )
+ )
end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
index a604de4a61f..6bc42430889 100644
--- a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
@@ -284,4 +284,20 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let(:action) { described_class::MR_CREATE_FROM_ISSUE_ACTION }
end
end
+
+ describe '.track_discussion_locked_action' do
+ subject { described_class.track_discussion_locked_action(user: user) }
+
+ it_behaves_like 'a tracked merge request unique event' do
+ let(:action) { described_class::MR_DISCUSSION_LOCKED_ACTION }
+ end
+ end
+
+ describe '.track_discussion_unlocked_action' do
+ subject { described_class.track_discussion_unlocked_action(user: user) }
+
+ it_behaves_like 'a tracked merge request unique event' do
+ let(:action) { described_class::MR_DISCUSSION_UNLOCKED_ACTION }
+ end
+ end
end
diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb
index 18388b4cd83..6bac5e31435 100644
--- a/spec/models/upload_spec.rb
+++ b/spec/models/upload_spec.rb
@@ -221,7 +221,7 @@ RSpec.describe Upload do
it 'does not send a message to Sentry' do
upload = described_class.new(path: "#{__FILE__}-nope", store: ObjectStorage::Store::LOCAL)
- expect(Raven).not_to receive(:capture_message)
+ expect(Gitlab::ErrorTracking).not_to receive(:track_exception)
upload.exist?
end
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index d684be91dc9..12060eb51e9 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -7,13 +7,27 @@ RSpec.describe 'getting merge request listings nested in a project' do
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:current_user) { create(:user) }
-
let_it_be(:label) { create(:label, project: project) }
- let_it_be(:merge_request_a) { create(:labeled_merge_request, :unique_branches, source_project: project, labels: [label]) }
- let_it_be(:merge_request_b) { create(:merge_request, :closed, :unique_branches, source_project: project) }
- let_it_be(:merge_request_c) { create(:labeled_merge_request, :closed, :unique_branches, source_project: project, labels: [label]) }
- let_it_be(:merge_request_d) { create(:merge_request, :locked, :unique_branches, source_project: project) }
- let_it_be(:merge_request_e) { create(:merge_request, :unique_branches, source_project: project) }
+
+ let_it_be(:merge_request_a) do
+ create(:labeled_merge_request, :unique_branches, source_project: project, labels: [label])
+ end
+
+ let_it_be(:merge_request_b) do
+ create(:merge_request, :closed, :unique_branches, source_project: project)
+ end
+
+ let_it_be(:merge_request_c) do
+ create(:labeled_merge_request, :closed, :unique_branches, source_project: project, labels: [label])
+ end
+
+ let_it_be(:merge_request_d) do
+ create(:merge_request, :locked, :unique_branches, source_project: project)
+ end
+
+ let_it_be(:merge_request_e) do
+ create(:merge_request, :unique_branches, source_project: project)
+ end
let(:results) { graphql_data.dig('project', 'mergeRequests', 'nodes') }
@@ -27,32 +41,38 @@ RSpec.describe 'getting merge request listings nested in a project' do
)
end
- let(:query) do
- query_merge_requests(all_graphql_fields_for('MergeRequest', max_depth: 1))
- end
-
it_behaves_like 'a working graphql query' do
+ let(:query) do
+ query_merge_requests(all_graphql_fields_for('MergeRequest', max_depth: 2))
+ end
+
before do
- post_graphql(query, current_user: current_user)
+ # We cannot call the whitelist here, since the transaction does not
+ # begin until we enter the controller.
+ headers = {
+ 'X-GITLAB-QUERY-WHITELIST-ISSUE' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/322979'
+ }
+
+ post_graphql(query, current_user: current_user, headers: headers)
end
end
# The following tests are needed to guarantee that we have correctly annotated
# all the gitaly calls. Selecting combinations of fields may mask this due to
# memoization.
- context 'requesting a single field' do
+ context 'when requesting a single field' do
let_it_be(:fresh_mr) { create(:merge_request, :unique_branches, source_project: project) }
+
let(:search_params) { { iids: [fresh_mr.iid.to_s] } }
+ let(:graphql_data) do
+ GitlabSchema.execute(query, context: { current_user: current_user }).to_h['data']
+ end
before do
project.repository.expire_branches_cache
end
- let(:graphql_data) do
- GitlabSchema.execute(query, context: { current_user: current_user }).to_h['data']
- end
-
- context 'selecting any single scalar field' do
+ context 'when selecting any single scalar field' do
where(:field) do
scalar_fields_of('MergeRequest').map { |name| [name] }
end
@@ -68,7 +88,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
end
end
- context 'selecting any single nested field' do
+ context 'when selecting any single nested field' do
where(:field, :subfield, :is_connection) do
nested_fields_of('MergeRequest').flat_map do |name, field|
type = field_type(field)
@@ -95,7 +115,11 @@ RSpec.describe 'getting merge request listings nested in a project' do
end
end
- shared_examples 'searching with parameters' do
+ shared_examples 'when searching with parameters' do
+ let(:query) do
+ query_merge_requests('iid title')
+ end
+
let(:expected) do
mrs.map { |mr| a_hash_including('iid' => mr.iid.to_s, 'title' => mr.title) }
end
@@ -107,60 +131,60 @@ RSpec.describe 'getting merge request listings nested in a project' do
end
end
- context 'there are no search params' do
+ context 'when there are no search params' do
let(:search_params) { nil }
let(:mrs) { [merge_request_a, merge_request_b, merge_request_c, merge_request_d, merge_request_e] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'the search params do not match anything' do
- let(:search_params) { { iids: %w(foo bar baz) } }
+ context 'when the search params do not match anything' do
+ let(:search_params) { { iids: %w[foo bar baz] } }
let(:mrs) { [] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'searching by iids' do
+ context 'when searching by iids' do
let(:search_params) { { iids: mrs.map(&:iid).map(&:to_s) } }
let(:mrs) { [merge_request_a, merge_request_c] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'searching by state' do
+ context 'when searching by state' do
let(:search_params) { { state: :closed } }
let(:mrs) { [merge_request_b, merge_request_c] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'searching by source_branch' do
+ context 'when searching by source_branch' do
let(:search_params) { { source_branches: mrs.map(&:source_branch) } }
let(:mrs) { [merge_request_b, merge_request_c] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'searching by target_branch' do
+ context 'when searching by target_branch' do
let(:search_params) { { target_branches: mrs.map(&:target_branch) } }
let(:mrs) { [merge_request_a, merge_request_d] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'searching by label' do
+ context 'when searching by label' do
let(:search_params) { { labels: [label.title] } }
let(:mrs) { [merge_request_a, merge_request_c] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
- context 'searching by combination' do
+ context 'when searching by combination' do
let(:search_params) { { state: :closed, labels: [label.title] } }
let(:mrs) { [merge_request_c] }
- it_behaves_like 'searching with parameters'
+ it_behaves_like 'when searching with parameters'
end
context 'when requesting `approved_by`' do
@@ -203,10 +227,10 @@ RSpec.describe 'getting merge request listings nested in a project' do
it 'exposes `commit_count`' do
execute_query
- expect(results).to match_array([
+ expect(results).to match_array [
{ "iid" => merge_request_a.iid.to_s, "commitCount" => 0 },
{ "iid" => merge_request_with_commits.iid.to_s, "commitCount" => 29 }
- ])
+ ]
end
end
@@ -216,8 +240,8 @@ RSpec.describe 'getting merge request listings nested in a project' do
before do
# make the MRs "merged"
[merge_request_a, merge_request_b, merge_request_c].each do |mr|
- mr.update_column(:state_id, MergeRequest.available_states[:merged])
- mr.metrics.update_column(:merged_at, Time.now)
+ mr.update!(state_id: MergeRequest.available_states[:merged])
+ mr.metrics.update!(merged_at: Time.now)
end
end
@@ -256,13 +280,12 @@ RSpec.describe 'getting merge request listings nested in a project' do
end
it 'returns the reviewers' do
+ nodes = merge_request_a.reviewers.map { |r| { 'username' => r.username } }
+ reviewers = { 'nodes' => match_array(nodes) }
+
execute_query
- expect(results).to include a_hash_including('reviewers' => {
- 'nodes' => match_array(merge_request_a.reviewers.map do |r|
- a_hash_including('username' => r.username)
- end)
- })
+ expect(results).to include a_hash_including('reviewers' => match(reviewers))
end
include_examples 'N+1 query check'
@@ -309,12 +332,14 @@ RSpec.describe 'getting merge request listings nested in a project' do
allow(Gitlab::Database).to receive(:read_only?).and_return(false)
end
+ def query_context
+ { current_user: current_user }
+ end
+
def run_query(number)
# Ensure that we have a fresh request store and batch-context between runs
- result = run_with_clean_state(query,
- context: { current_user: current_user },
- variables: { first: number }
- )
+ vars = { first: number }
+ result = run_with_clean_state(query, context: query_context, variables: vars)
graphql_dig_at(result.to_h, :data, :project, :merge_requests, :nodes)
end
@@ -348,13 +373,11 @@ RSpec.describe 'getting merge request listings nested in a project' do
let(:data_path) { [:project, :mergeRequests] }
def pagination_query(params)
- graphql_query_for(:project, { full_path: project.full_path },
- <<~QUERY
+ graphql_query_for(:project, { full_path: project.full_path }, <<~QUERY)
mergeRequests(#{params}) {
#{page_info} nodes { id }
}
- QUERY
- )
+ QUERY
end
context 'when sorting by merged_at DESC' do
@@ -396,14 +419,12 @@ RSpec.describe 'getting merge request listings nested in a project' do
let(:query) do
# Note: __typename meta field is always requested by the FE
- graphql_query_for(:project, { full_path: project.full_path },
- <<~QUERY
+ graphql_query_for(:project, { full_path: project.full_path }, <<~QUERY)
mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0, sourceBranches: null, labels: null) {
count
__typename
}
QUERY
- )
end
shared_examples 'count examples' do
@@ -430,14 +451,12 @@ RSpec.describe 'getting merge request listings nested in a project' do
context 'when total_time_to_merge and count is queried' do
let(:query) do
- graphql_query_for(:project, { full_path: project.full_path },
- <<~QUERY
+ graphql_query_for(:project, { full_path: project.full_path }, <<~QUERY)
mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0) {
totalTimeToMerge
count
}
QUERY
- )
end
it 'does not query the merge requests table for the total_time_to_merge' do
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 91d10791541..8160a94aef2 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -314,14 +314,13 @@ RSpec.describe API::Helpers do
expect(Gitlab::ErrorTracking).to receive(:sentry_dsn).and_return(Gitlab.config.sentry.dsn)
Gitlab::ErrorTracking.configure
- Raven.client.configuration.encoding = 'json'
end
it 'does not report a MethodNotAllowed exception to Sentry' do
exception = Grape::Exceptions::MethodNotAllowed.new({ 'X-GitLab-Test' => '1' })
allow(exception).to receive(:backtrace).and_return(caller)
- expect(Raven).not_to receive(:capture_exception).with(exception)
+ expect(Gitlab::ErrorTracking).not_to receive(:track_exception).with(exception)
handle_api_exception(exception)
end
@@ -330,8 +329,7 @@ RSpec.describe API::Helpers do
exception = RuntimeError.new('test error')
allow(exception).to receive(:backtrace).and_return(caller)
- expect(Raven).to receive(:capture_exception).with(exception, tags:
- a_hash_including(correlation_id: 'new-correlation-id'), extra: {})
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(exception)
Labkit::Correlation::CorrelationId.use_id('new-correlation-id') do
handle_api_exception(exception)
@@ -357,20 +355,6 @@ RSpec.describe API::Helpers do
expect(json_response['message']).to start_with("\nRuntimeError (Runtime Error!):")
end
end
-
- context 'extra information' do
- # Sentry events are an array of the form [auth_header, data, options]
- let(:event_data) { Raven.client.transport.events.first[1] }
-
- it 'sends the params, excluding confidential values' do
- expect(ProjectsFinder).to receive(:new).and_raise('Runtime Error!')
-
- get api('/projects', user), params: { password: 'dont_send_this', other_param: 'send_this' }
-
- expect(event_data).to include('other_param=send_this')
- expect(event_data).to include('password=********')
- end
- end
end
describe '.authenticate_non_get!' do
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index 181fcafd577..104918810f8 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -56,6 +56,7 @@ itself: # project
- can_create_merge_request_in
- compliance_frameworks
- container_expiration_policy
+ - container_registry_image_prefix
- default_branch
- empty_repo
- forks_count
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 8a68db6ae4b..19cab51ef34 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1540,6 +1540,10 @@ RSpec.describe API::Projects do
end
context 'when authenticated as an admin' do
+ before do
+ stub_container_registry_config(enabled: true, host_port: 'registry.example.org:5000')
+ end
+
let(:project_attributes_file) { 'spec/requests/api/project_attributes.yml' }
let(:project_attributes) { YAML.load_file(project_attributes_file) }
@@ -1569,7 +1573,7 @@ RSpec.describe API::Projects do
keys
end
- it 'returns a project by id' do
+ it 'returns a project by id', :aggregate_failures do
project
project_member
group = create(:group)
@@ -1587,6 +1591,7 @@ RSpec.describe API::Projects do
expect(json_response['ssh_url_to_repo']).to be_present
expect(json_response['http_url_to_repo']).to be_present
expect(json_response['web_url']).to be_present
+ expect(json_response['container_registry_image_prefix']).to eq("registry.example.org:5000/#{project.full_path}")
expect(json_response['owner']).to be_a Hash
expect(json_response['name']).to eq(project.name)
expect(json_response['path']).to be_present
@@ -1644,9 +1649,10 @@ RSpec.describe API::Projects do
before do
project
project_member
+ stub_container_registry_config(enabled: true, host_port: 'registry.example.org:5000')
end
- it 'returns a project by id' do
+ it 'returns a project by id', :aggregate_failures do
group = create(:group)
link = create(:project_group_link, project: project, group: group)
@@ -1662,6 +1668,7 @@ RSpec.describe API::Projects do
expect(json_response['ssh_url_to_repo']).to be_present
expect(json_response['http_url_to_repo']).to be_present
expect(json_response['web_url']).to be_present
+ expect(json_response['container_registry_image_prefix']).to eq("registry.example.org:5000/#{project.full_path}")
expect(json_response['owner']).to be_a Hash
expect(json_response['name']).to eq(project.name)
expect(json_response['path']).to be_present
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index a6bd8416e58..e9ec3bccda3 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -48,6 +48,8 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
context 'valid params' do
+ let(:locked) { true }
+
let(:opts) do
{
title: 'New title',
@@ -58,7 +60,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
label_ids: [label.id],
target_branch: 'target',
force_remove_source_branch: '1',
- discussion_locked: true
+ discussion_locked: locked
}
end
@@ -117,6 +119,56 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
MergeRequests::UpdateService.new(project, user, opts).execute(draft_merge_request)
end
+
+ context 'when MR is locked' do
+ context 'when locked again' do
+ it 'does not track discussion locking' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .not_to receive(:track_discussion_locked_action)
+
+ opts[:discussion_locked] = true
+
+ MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ end
+ end
+
+ context 'when unlocked' do
+ it 'tracks dicussion unlocking' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_discussion_unlocked_action).once.with(user: user)
+
+ opts[:discussion_locked] = false
+
+ MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ end
+ end
+ end
+
+ context 'when MR is unlocked' do
+ let(:locked) { false }
+
+ context 'when unlocked again' do
+ it 'does not track discussion unlocking' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .not_to receive(:track_discussion_unlocked_action)
+
+ opts[:discussion_locked] = false
+
+ MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ end
+ end
+
+ context 'when locked' do
+ it 'tracks dicussion locking' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_discussion_locked_action).once.with(user: user)
+
+ opts[:discussion_locked] = true
+
+ MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ end
+ end
+ end
end
context 'updating milestone' do