summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-17 21:08:29 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-17 21:08:29 +0000
commit40254b9ace2a74a3c9f1cc51a1b1d5e3e78c1ae9 (patch)
tree9b735ef933178be36d35088f3acab2d9b75dbbad /spec
parent22a0d312ae82e7dda3073d5d1a5a766d7641738d (diff)
downloadgitlab-ce-40254b9ace2a74a3c9f1cc51a1b1d5e3e78c1ae9.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/finders/deployments_finder_spec.rb36
-rw-r--r--spec/frontend/error_tracking/components/error_tracking_list_spec.js41
-rw-r--r--spec/frontend/lib/utils/text_utility_spec.js19
-rw-r--r--spec/frontend/monitoring/store/mutations_spec.js4
-rw-r--r--spec/frontend/releases/list/components/release_block_spec.js2
-rw-r--r--spec/javascripts/projects/project_import_gitlab_project_spec.js46
-rw-r--r--spec/javascripts/projects/project_new_spec.js30
-rw-r--r--spec/lib/banzai/filter/abstract_reference_filter_spec.rb24
-rw-r--r--spec/lib/gitlab/application_context_spec.rb24
-rw-r--r--spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb320
-rw-r--r--spec/lib/gitlab/import_export/import_failure_service_spec.rb107
-rw-r--r--spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb56
-rw-r--r--spec/models/import_failure_spec.rb28
-rw-r--r--spec/requests/api/deployments_spec.rb12
-rw-r--r--spec/services/merge_requests/conflicts/list_service_spec.rb4
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb4
-rw-r--r--spec/services/merge_requests/push_options_handler_service_spec.rb12
-rw-r--r--spec/services/milestones/promote_service_spec.rb4
-rw-r--r--spec/services/milestones/transfer_service_spec.rb4
-rw-r--r--spec/services/namespaces/statistics_refresher_service_spec.rb9
-rw-r--r--spec/services/notes/resolve_service_spec.rb4
-rw-r--r--spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb6
-rw-r--r--spec/services/projects/create_service_spec.rb4
-rw-r--r--spec/services/projects/import_export/export_service_spec.rb8
-rw-r--r--spec/services/projects/lfs_pointers/lfs_import_service_spec.rb12
-rw-r--r--spec/services/projects/update_pages_service_spec.rb12
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb8
-rw-r--r--spec/support/helpers/filter_spec_helper.rb11
-rw-r--r--spec/support/import_export/common_util.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb32
-rw-r--r--spec/workers/ci/archive_traces_cron_worker_spec.rb9
-rw-r--r--spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb6
-rw-r--r--spec/workers/delete_merged_branches_worker_spec.rb4
-rw-r--r--spec/workers/expire_build_artifacts_worker_spec.rb4
-rw-r--r--spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb12
-rw-r--r--spec/workers/gitlab_shell_worker_spec.rb4
-rw-r--r--spec/workers/gitlab_usage_ping_worker_spec.rb4
-rw-r--r--spec/workers/hashed_storage/migrator_worker_spec.rb4
-rw-r--r--spec/workers/hashed_storage/rollbacker_worker_spec.rb4
-rw-r--r--spec/workers/import_issues_csv_worker_spec.rb4
-rw-r--r--spec/workers/new_release_worker_spec.rb4
-rw-r--r--spec/workers/repository_import_worker_spec.rb23
42 files changed, 878 insertions, 91 deletions
diff --git a/spec/finders/deployments_finder_spec.rb b/spec/finders/deployments_finder_spec.rb
index 2dcbd5ba8ea..b20c7e5a8a5 100644
--- a/spec/finders/deployments_finder_spec.rb
+++ b/spec/finders/deployments_finder_spec.rb
@@ -25,6 +25,42 @@ describe DeploymentsFinder do
is_expected.to match_array([deployment_1])
end
end
+
+ context 'when the environment name is specified' do
+ let!(:environment1) { create(:environment, project: project) }
+ let!(:environment2) { create(:environment, project: project) }
+ let!(:deployment1) do
+ create(:deployment, project: project, environment: environment1)
+ end
+
+ let!(:deployment2) do
+ create(:deployment, project: project, environment: environment2)
+ end
+
+ let(:params) { { environment: environment1.name } }
+
+ it 'returns deployments for the given environment' do
+ is_expected.to match_array([deployment1])
+ end
+ end
+
+ context 'when the deployment status is specified' do
+ let!(:deployment1) { create(:deployment, :success, project: project) }
+ let!(:deployment2) { create(:deployment, :failed, project: project) }
+ let(:params) { { status: 'success' } }
+
+ it 'returns deployments for the given environment' do
+ is_expected.to match_array([deployment1])
+ end
+ end
+
+ context 'when using an invalid deployment status' do
+ let(:params) { { status: 'kittens' } }
+
+ it 'raises ArgumentError' do
+ expect { subject }.to raise_error(ArgumentError)
+ end
+ end
end
describe 'ordering' do
diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
index 10b24cf04d3..310cd676ca1 100644
--- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js
+++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
@@ -143,10 +143,14 @@ describe('ErrorTrackingList', () => {
});
it('each error in the list should have an ignore button', () => {
- const error = wrapper.findAll('tbody tr');
+ findErrorListRows().wrappers.forEach(row => {
+ expect(row.contains('glicon-stub[name="eye-slash"]')).toBe(true);
+ });
+ });
- error.wrappers.forEach((_, index) => {
- expect(error.at(index).exists('glicon-stub[name="eye-slash"]')).toBe(true);
+ it('each error in the list should have a resolve button', () => {
+ findErrorListRows().wrappers.forEach(row => {
+ expect(row.contains('glicon-stub[name="check-circle"]')).toBe(true);
});
});
@@ -231,8 +235,7 @@ describe('ErrorTrackingList', () => {
});
it('sends the "ignored" status and error ID', () => {
- const ignoreButton = wrapper.find({ ref: 'ignoreError' });
- ignoreButton.trigger('click');
+ wrapper.find({ ref: 'ignoreError' }).trigger('click');
expect(actions.updateStatus).toHaveBeenCalledWith(
expect.anything(),
{
@@ -245,6 +248,34 @@ describe('ErrorTrackingList', () => {
});
});
+ describe('When the resolve button on an error is clicked', () => {
+ beforeEach(() => {
+ store.state.list.loading = false;
+ store.state.list.errors = errorsList;
+
+ mountComponent({
+ stubs: {
+ GlTable: false,
+ GlLink: false,
+ GlButton: false,
+ },
+ });
+ });
+
+ it('sends "resolved" status and error ID', () => {
+ wrapper.find({ ref: 'resolveError' }).trigger('click');
+ expect(actions.updateStatus).toHaveBeenCalledWith(
+ expect.anything(),
+ {
+ endpoint: '/project/test/-/error_tracking/3.json',
+ redirectUrl: '/error_tracking',
+ status: 'resolved',
+ },
+ undefined,
+ );
+ });
+ });
+
describe('When error tracking is disabled and user is not allowed to enable it', () => {
beforeEach(() => {
mountComponent({
diff --git a/spec/frontend/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js
index deb6dab772e..803b3629524 100644
--- a/spec/frontend/lib/utils/text_utility_spec.js
+++ b/spec/frontend/lib/utils/text_utility_spec.js
@@ -27,6 +27,9 @@ describe('text_utility', () => {
it('should remove underscores and uppercase the first letter', () => {
expect(textUtils.humanize('foo_bar')).toEqual('Foo bar');
});
+ it('should remove underscores and dashes and uppercase the first letter', () => {
+ expect(textUtils.humanize('foo_bar-foo', '[_-]')).toEqual('Foo bar foo');
+ });
});
describe('dasherize', () => {
@@ -52,14 +55,20 @@ describe('text_utility', () => {
expect(textUtils.slugify(' a new project ')).toEqual('a-new-project');
});
it('should only remove non-allowed special characters', () => {
- expect(textUtils.slugify('test!_pro-ject~')).toEqual('test-_pro-ject-');
+ expect(textUtils.slugify('test!_pro-ject~')).toEqual('test-_pro-ject');
});
it('should squash multiple hypens', () => {
- expect(textUtils.slugify('test!!!!_pro-ject~')).toEqual('test-_pro-ject-');
+ expect(textUtils.slugify('test!!!!_pro-ject~')).toEqual('test-_pro-ject');
});
it('should return empty string if only non-allowed characters', () => {
expect(textUtils.slugify('здрасти')).toEqual('');
});
+ it('should squash multiple separators', () => {
+ expect(textUtils.slugify('Test:-)')).toEqual('test');
+ });
+ it('should trim any separators from the beginning and end of the slug', () => {
+ expect(textUtils.slugify('-Test:-)-')).toEqual('test');
+ });
});
describe('stripHtml', () => {
@@ -109,6 +118,12 @@ describe('text_utility', () => {
});
});
+ describe('convertToTitleCase', () => {
+ it('converts sentence case to Sentence Case', () => {
+ expect(textUtils.convertToTitleCase('hello world')).toBe('Hello World');
+ });
+ });
+
describe('truncateSha', () => {
it('shortens SHAs to 8 characters', () => {
expect(textUtils.truncateSha('verylongsha')).toBe('verylong');
diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js
index e89c22268d4..cb53ab60bdb 100644
--- a/spec/frontend/monitoring/store/mutations_spec.js
+++ b/spec/frontend/monitoring/store/mutations_spec.js
@@ -29,8 +29,8 @@ describe('Monitoring mutations', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, payload);
const groups = getGroups();
- expect(groups[0].key).toBe('response-metrics-nginx-ingress-vts--0');
- expect(groups[1].key).toBe('system-metrics-kubernetes--1');
+ expect(groups[0].key).toBe('response-metrics-nginx-ingress-vts-0');
+ expect(groups[1].key).toBe('system-metrics-kubernetes-1');
});
it('normalizes values', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, payload);
diff --git a/spec/frontend/releases/list/components/release_block_spec.js b/spec/frontend/releases/list/components/release_block_spec.js
index e3d6af13417..20c25a4aac2 100644
--- a/spec/frontend/releases/list/components/release_block_spec.js
+++ b/spec/frontend/releases/list/components/release_block_spec.js
@@ -169,7 +169,7 @@ describe('Release block', () => {
releaseClone.tag_name = 'a dangerous tag name <script>alert("hello")</script>';
return factory(releaseClone).then(() => {
- expect(wrapper.attributes().id).toBe('a-dangerous-tag-name-script-alert-hello-script-');
+ expect(wrapper.attributes().id).toBe('a-dangerous-tag-name-script-alert-hello-script');
});
});
diff --git a/spec/javascripts/projects/project_import_gitlab_project_spec.js b/spec/javascripts/projects/project_import_gitlab_project_spec.js
index 126f73103e0..3c94934699d 100644
--- a/spec/javascripts/projects/project_import_gitlab_project_spec.js
+++ b/spec/javascripts/projects/project_import_gitlab_project_spec.js
@@ -1,25 +1,59 @@
import projectImportGitlab from '~/projects/project_import_gitlab_project';
describe('Import Gitlab project', () => {
- let projectName;
- beforeEach(() => {
- projectName = 'project';
- window.history.pushState({}, null, `?path=${projectName}`);
+ const pathName = 'my-project';
+ const projectName = 'My Project';
+
+ const setTestFixtures = url => {
+ window.history.pushState({}, null, url);
setFixtures(`
<input class="js-path-name" />
+ <input class="js-project-name" />
`);
projectImportGitlab();
+ };
+
+ beforeEach(() => {
+ setTestFixtures(`?name=${projectName}&path=${pathName}`);
});
afterEach(() => {
window.history.pushState({}, null, '');
});
- describe('path name', () => {
+ describe('project name', () => {
it('should fill in the project name derived from the previously filled project name', () => {
- expect(document.querySelector('.js-path-name').value).toEqual(projectName);
+ expect(document.querySelector('.js-project-name').value).toEqual(projectName);
+ });
+
+ describe('empty path name', () => {
+ it('derives the path name from the previously filled project name', () => {
+ const alternateProjectName = 'My Alt Project';
+ const alternatePathName = 'my-alt-project';
+
+ setTestFixtures(`?name=${alternateProjectName}`);
+
+ expect(document.querySelector('.js-path-name').value).toEqual(alternatePathName);
+ });
+ });
+ });
+
+ describe('path name', () => {
+ it('should fill in the path name derived from the previously filled path name', () => {
+ expect(document.querySelector('.js-path-name').value).toEqual(pathName);
+ });
+
+ describe('empty project name', () => {
+ it('derives the project name from the previously filled path name', () => {
+ const alternateProjectName = 'My Alt Project';
+ const alternatePathName = 'my-alt-project';
+
+ setTestFixtures(`?path=${alternatePathName}`);
+
+ expect(document.querySelector('.js-project-name').value).toEqual(alternateProjectName);
+ });
});
});
});
diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js
index 106a3ba94e4..7c6ff90aff6 100644
--- a/spec/javascripts/projects/project_new_spec.js
+++ b/spec/javascripts/projects/project_new_spec.js
@@ -172,4 +172,34 @@ describe('New Project', () => {
expect($projectPath.val()).toEqual('my-dash-delimited-awesome-project');
});
});
+
+ describe('derivesProjectNameFromSlug', () => {
+ const dummyProjectPath = 'my-awesome-project';
+ const dummyProjectName = 'Original Awesome Project';
+
+ beforeEach(() => {
+ projectNew.bindEvents();
+ $projectPath.val('').change();
+ });
+
+ it('converts slug to humanized project name', () => {
+ $projectPath.val(dummyProjectPath);
+
+ projectNew.onProjectPathChange($projectName, $projectPath);
+
+ expect($projectName.val()).toEqual('My Awesome Project');
+ });
+
+ it('does not convert slug to humanized project name if a project name already exists', () => {
+ $projectName.val(dummyProjectName);
+ $projectPath.val(dummyProjectPath);
+ projectNew.onProjectPathChange(
+ $projectName,
+ $projectPath,
+ $projectName.val().trim().length > 0,
+ );
+
+ expect($projectName.val()).toEqual(dummyProjectName);
+ });
+ });
});
diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
index 3e8b0ea113f..798112d0f53 100644
--- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
@@ -3,30 +3,27 @@
require 'spec_helper'
describe Banzai::Filter::AbstractReferenceFilter do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
+
+ let(:doc) { Nokogiri::HTML.fragment('') }
+ let(:filter) { described_class.new(doc, project: project) }
describe '#references_per_parent' do
- it 'returns a Hash containing references grouped per parent paths' do
- doc = Nokogiri::HTML.fragment("#1 #{project.full_path}#2")
- filter = described_class.new(doc, project: project)
+ let(:doc) { Nokogiri::HTML.fragment("#1 #{project.full_path}#2 #2") }
- expect(filter).to receive(:object_class).exactly(4).times.and_return(Issue)
- expect(filter).to receive(:object_sym).twice.and_return(:issue)
+ it 'returns a Hash containing references grouped per parent paths' do
+ expect(described_class).to receive(:object_class).exactly(6).times.and_return(Issue)
refs = filter.references_per_parent
- expect(refs).to be_an_instance_of(Hash)
- expect(refs[project.full_path]).to eq(Set.new(%w[1 2]))
+ expect(refs).to match(a_hash_including(project.full_path => contain_exactly(1, 2)))
end
end
describe '#parent_per_reference' do
it 'returns a Hash containing projects grouped per parent paths' do
- doc = Nokogiri::HTML.fragment('')
- filter = described_class.new(doc, project: project)
-
expect(filter).to receive(:references_per_parent)
- .and_return({ project.full_path => Set.new(%w[1]) })
+ .and_return({ project.full_path => Set.new([1]) })
expect(filter.parent_per_reference)
.to eq({ project.full_path => project })
@@ -34,9 +31,6 @@ describe Banzai::Filter::AbstractReferenceFilter do
end
describe '#find_for_paths' do
- let(:doc) { Nokogiri::HTML.fragment('') }
- let(:filter) { described_class.new(doc, project: project) }
-
context 'with RequestStore disabled' do
it 'returns a list of Projects for a list of paths' do
expect(filter.find_for_paths([project.full_path]))
diff --git a/spec/lib/gitlab/application_context_spec.rb b/spec/lib/gitlab/application_context_spec.rb
index 1c8fcb8d737..482bf0dc192 100644
--- a/spec/lib/gitlab/application_context_spec.rb
+++ b/spec/lib/gitlab/application_context_spec.rb
@@ -28,7 +28,7 @@ describe Gitlab::ApplicationContext do
describe '.push' do
it 'passes the expected context on to labkit' do
fake_proc = duck_type(:call)
- expected_context = hash_including(user: fake_proc, project: fake_proc, root_namespace: fake_proc)
+ expected_context = { user: fake_proc }
expect(Labkit::Context).to receive(:push).with(expected_context)
@@ -78,5 +78,27 @@ describe Gitlab::ApplicationContext do
expect(result(context))
.to include(project: project.full_path, root_namespace: project.full_path_components.first)
end
+
+ context 'only include values for which an option was specified' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:provided_options, :expected_context_keys) do
+ [:user, :namespace, :project] | [:user, :project, :root_namespace]
+ [:user, :project] | [:user, :project, :root_namespace]
+ [:user, :namespace] | [:user, :root_namespace]
+ [:user] | [:user]
+ [] | []
+ end
+
+ with_them do
+ it do
+ # Build a hash that has all `provided_options` as keys, and `nil` as value
+ provided_values = provided_options.map { |key| [key, nil] }.to_h
+ context = described_class.new(provided_values)
+
+ expect(context.to_lazy_hash.keys).to contain_exactly(*expected_context_keys)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb b/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb
new file mode 100644
index 00000000000..664e3810fc9
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb
@@ -0,0 +1,320 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::MigrateIssueTrackersSensitiveData, :migration, schema: 20190924152703 do
+ let(:services) { table(:services) }
+
+ # we need to define the classes due to encryption
+ class IssueTrackerData < ApplicationRecord
+ self.table_name = 'issue_tracker_data'
+
+ def self.encryption_options
+ {
+ key: Settings.attr_encrypted_db_key_base_32,
+ encode: true,
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm'
+ }
+ end
+
+ attr_encrypted :project_url, encryption_options
+ attr_encrypted :issues_url, encryption_options
+ attr_encrypted :new_issue_url, encryption_options
+ end
+
+ class JiraTrackerData < ApplicationRecord
+ self.table_name = 'jira_tracker_data'
+
+ def self.encryption_options
+ {
+ key: Settings.attr_encrypted_db_key_base_32,
+ encode: true,
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm'
+ }
+ end
+
+ attr_encrypted :url, encryption_options
+ attr_encrypted :api_url, encryption_options
+ attr_encrypted :username, encryption_options
+ attr_encrypted :password, encryption_options
+ end
+
+ let(:url) { 'http://base-url.tracker.com' }
+ let(:new_issue_url) { 'http://base-url.tracker.com/new_issue' }
+ let(:issues_url) { 'http://base-url.tracker.com/issues' }
+ let(:api_url) { 'http://api.tracker.com' }
+ let(:password) { 'passw1234' }
+ let(:username) { 'user9' }
+ let(:title) { 'Issue tracker' }
+ let(:description) { 'Issue tracker description' }
+
+ let(:jira_properties) do
+ {
+ 'api_url' => api_url,
+ 'jira_issue_transition_id' => '5',
+ 'password' => password,
+ 'url' => url,
+ 'username' => username,
+ 'title' => title,
+ 'description' => description,
+ 'other_field' => 'something'
+ }
+ end
+
+ let(:tracker_properties) do
+ {
+ 'project_url' => url,
+ 'new_issue_url' => new_issue_url,
+ 'issues_url' => issues_url,
+ 'title' => title,
+ 'description' => description,
+ 'other_field' => 'something'
+ }
+ end
+
+ let(:tracker_properties_no_url) do
+ {
+ 'new_issue_url' => new_issue_url,
+ 'issues_url' => issues_url,
+ 'title' => title,
+ 'description' => description
+ }
+ end
+
+ subject { described_class.new.perform(1, 100) }
+
+ shared_examples 'handle properties' do
+ it 'does not clear the properties' do
+ expect { subject }.not_to change { service.reload.properties}
+ end
+ end
+
+ context 'with jira service' do
+ let!(:service) do
+ services.create(id: 10, type: 'JiraService', title: nil, properties: jira_properties.to_json, category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'migrates data' do
+ expect { subject }.to change { JiraTrackerData.count }.by(1)
+
+ service.reload
+ data = JiraTrackerData.find_by(service_id: service.id)
+
+ expect(data.url).to eq(url)
+ expect(data.api_url).to eq(api_url)
+ expect(data.username).to eq(username)
+ expect(data.password).to eq(password)
+ expect(service.title).to eq(title)
+ expect(service.description).to eq(description)
+ end
+ end
+
+ context 'with bugzilla service' do
+ let!(:service) do
+ services.create(id: 11, type: 'BugzillaService', title: nil, properties: tracker_properties.to_json, category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'migrates data' do
+ expect { subject }.to change { IssueTrackerData.count }.by(1)
+
+ service.reload
+ data = IssueTrackerData.find_by(service_id: service.id)
+
+ expect(data.project_url).to eq(url)
+ expect(data.issues_url).to eq(issues_url)
+ expect(data.new_issue_url).to eq(new_issue_url)
+ expect(service.title).to eq(title)
+ expect(service.description).to eq(description)
+ end
+ end
+
+ context 'with youtrack service' do
+ let!(:service) do
+ services.create(id: 12, type: 'YoutrackService', title: nil, properties: tracker_properties_no_url.to_json, category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'migrates data' do
+ expect { subject }.to change { IssueTrackerData.count }.by(1)
+
+ service.reload
+ data = IssueTrackerData.find_by(service_id: service.id)
+
+ expect(data.project_url).to be_nil
+ expect(data.issues_url).to eq(issues_url)
+ expect(data.new_issue_url).to eq(new_issue_url)
+ expect(service.title).to eq(title)
+ expect(service.description).to eq(description)
+ end
+ end
+
+ context 'with gitlab service with no properties' do
+ let!(:service) do
+ services.create(id: 13, type: 'GitlabIssueTrackerService', title: nil, properties: {}, category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not migrate data' do
+ expect { subject }.not_to change { IssueTrackerData.count }
+ end
+ end
+
+ context 'with redmine service already with data fields' do
+ let!(:service) do
+ services.create(id: 14, type: 'RedmineService', title: nil, properties: tracker_properties_no_url.to_json, category: 'issue_tracker').tap do |service|
+ IssueTrackerData.create!(service_id: service.id, project_url: url, new_issue_url: new_issue_url, issues_url: issues_url)
+ end
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not create new data fields record' do
+ expect { subject }.not_to change { IssueTrackerData.count }
+ end
+ end
+
+ context 'with custom issue tracker which has data fields record inconsistent with properties field' do
+ let!(:service) do
+ services.create(id: 15, type: 'CustomIssueTrackerService', title: 'Existing title', properties: jira_properties.to_json, category: 'issue_tracker').tap do |service|
+ IssueTrackerData.create!(service_id: service.id, project_url: 'http://other_url', new_issue_url: 'http://other_url/new_issue', issues_url: 'http://other_url/issues')
+ end
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not update the data fields record' do
+ expect { subject }.not_to change { IssueTrackerData.count }
+
+ service.reload
+ data = IssueTrackerData.find_by(service_id: service.id)
+
+ expect(data.project_url).to eq('http://other_url')
+ expect(data.issues_url).to eq('http://other_url/issues')
+ expect(data.new_issue_url).to eq('http://other_url/new_issue')
+ expect(service.title).to eq('Existing title')
+ end
+ end
+
+ context 'with jira service which has data fields record inconsistent with properties field' do
+ let!(:service) do
+ services.create(id: 16, type: 'CustomIssueTrackerService', description: 'Existing description', properties: jira_properties.to_json, category: 'issue_tracker').tap do |service|
+ JiraTrackerData.create!(service_id: service.id, url: 'http://other_jira_url')
+ end
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not update the data fields record' do
+ expect { subject }.not_to change { JiraTrackerData.count }
+
+ service.reload
+ data = JiraTrackerData.find_by(service_id: service.id)
+
+ expect(data.url).to eq('http://other_jira_url')
+ expect(data.password).to be_nil
+ expect(data.username).to be_nil
+ expect(data.api_url).to be_nil
+ expect(service.description).to eq('Existing description')
+ end
+ end
+
+ context 'non issue tracker service' do
+ let!(:service) do
+ services.create(id: 17, title: nil, description: nil, type: 'OtherService', properties: tracker_properties.to_json)
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not migrate any data' do
+ expect { subject }.not_to change { IssueTrackerData.count }
+
+ service.reload
+ expect(service.title).to be_nil
+ expect(service.description).to be_nil
+ end
+ end
+
+ context 'jira service with empty properties' do
+ let!(:service) do
+ services.create(id: 18, type: 'JiraService', properties: '', category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not migrate any data' do
+ expect { subject }.not_to change { JiraTrackerData.count }
+ end
+ end
+
+ context 'jira service with nil properties' do
+ let!(:service) do
+ services.create(id: 18, type: 'JiraService', properties: nil, category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not migrate any data' do
+ expect { subject }.not_to change { JiraTrackerData.count }
+ end
+ end
+
+ context 'jira service with invalid properties' do
+ let!(:service) do
+ services.create(id: 18, type: 'JiraService', properties: 'invalid data', category: 'issue_tracker')
+ end
+
+ it_behaves_like 'handle properties'
+
+ it 'does not migrate any data' do
+ expect { subject }.not_to change { JiraTrackerData.count }
+ end
+ end
+
+ context 'with jira service with invalid properties, valid jira service and valid bugzilla service' do
+ let!(:jira_service_invalid) do
+ services.create(id: 19, title: 'invalid - title', description: 'invalid - description', type: 'JiraService', properties: 'invalid data', category: 'issue_tracker')
+ end
+ let!(:jira_service_valid) do
+ services.create(id: 20, type: 'JiraService', properties: jira_properties.to_json, category: 'issue_tracker')
+ end
+ let!(:bugzilla_service_valid) do
+ services.create(id: 11, type: 'BugzillaService', title: nil, properties: tracker_properties.to_json, category: 'issue_tracker')
+ end
+
+ it 'migrates data for the valid service' do
+ subject
+
+ jira_service_invalid.reload
+ expect(JiraTrackerData.find_by(service_id: jira_service_invalid.id)).to be_nil
+ expect(jira_service_invalid.title).to eq('invalid - title')
+ expect(jira_service_invalid.description).to eq('invalid - description')
+ expect(jira_service_invalid.properties).to eq('invalid data')
+
+ jira_service_valid.reload
+ data = JiraTrackerData.find_by(service_id: jira_service_valid.id)
+
+ expect(data.url).to eq(url)
+ expect(data.api_url).to eq(api_url)
+ expect(data.username).to eq(username)
+ expect(data.password).to eq(password)
+ expect(jira_service_valid.title).to eq(title)
+ expect(jira_service_valid.description).to eq(description)
+
+ bugzilla_service_valid.reload
+ data = IssueTrackerData.find_by(service_id: bugzilla_service_valid.id)
+
+ expect(data.project_url).to eq(url)
+ expect(data.issues_url).to eq(issues_url)
+ expect(data.new_issue_url).to eq(new_issue_url)
+ expect(bugzilla_service_valid.title).to eq(title)
+ expect(bugzilla_service_valid.description).to eq(description)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/import_failure_service_spec.rb b/spec/lib/gitlab/import_export/import_failure_service_spec.rb
new file mode 100644
index 00000000000..0351f88afdb
--- /dev/null
+++ b/spec/lib/gitlab/import_export/import_failure_service_spec.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::ImportExport::ImportFailureService do
+ let(:importable) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') }
+ let(:label) { create(:label) }
+ let(:subject) { described_class.new(importable) }
+ let(:relation_key) { "labels" }
+ let(:relation_index) { 0 }
+
+ describe '#log_import_failure' do
+ let(:standard_error_message) { "StandardError message" }
+ let(:exception) { StandardError.new(standard_error_message) }
+ let(:correlation_id) { 'my-correlation-id' }
+ let(:retry_count) { 2 }
+ let(:log_import_failure) do
+ subject.log_import_failure(relation_key, relation_index, exception, retry_count)
+ end
+
+ before do
+ # Import is running from the rake task, `correlation_id` is not assigned
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_or_new_id).and_return(correlation_id)
+ end
+
+ context 'when importable is a group' do
+ let(:importable) { create(:group) }
+
+ it_behaves_like 'log import failure', :group_id
+ end
+
+ context 'when importable is a project' do
+ it_behaves_like 'log import failure', :project_id
+ end
+
+ context 'when ImportFailure does not support importable class' do
+ let(:importable) { create(:merge_request) }
+
+ it 'raise exception' do
+ expect { subject }.to raise_exception(ActiveRecord::AssociationNotFoundError, "Association named 'import_failures' was not found on MergeRequest; perhaps you misspelled it?")
+ end
+ end
+ end
+
+ describe '#with_retry' do
+ let(:perform_retry) do
+ subject.with_retry(relation_key, relation_index) do
+ label.save!
+ end
+ end
+
+ context 'when exceptions are retriable' do
+ where(:exception) { Gitlab::ImportExport::ImportFailureService::RETRIABLE_EXCEPTIONS }
+
+ with_them do
+ context 'when retry succeeds' do
+ before do
+ expect(label).to receive(:save!).and_raise(exception.new)
+ expect(label).to receive(:save!).and_return(true)
+ end
+
+ it 'retries and logs import failure once with correct params' do
+ expect(subject).to receive(:log_import_failure).with(relation_key, relation_index, instance_of(exception), 1).once
+
+ perform_retry
+ end
+ end
+
+ context 'when retry continues to fail with intermittent errors' do
+ let(:maximum_retry_count) do
+ Retriable.config.tries
+ end
+
+ before do
+ expect(label).to receive(:save!)
+ .exactly(maximum_retry_count).times
+ .and_raise(exception.new)
+ end
+
+ it 'retries the number of times allowed and raise exception', :aggregate_failures do
+ expect { perform_retry }.to raise_exception(exception)
+ end
+
+ it 'logs import failure each time and raise exception', :aggregate_failures do
+ maximum_retry_count.times do |index|
+ retry_count = index + 1
+
+ expect(subject).to receive(:log_import_failure).with(relation_key, relation_index, instance_of(exception), retry_count)
+ end
+
+ expect { perform_retry }.to raise_exception(exception)
+ end
+ end
+ end
+ end
+
+ context 'when exception is not retriable' do
+ let(:exception) { StandardError.new }
+
+ it 'raise the exception', :aggregate_failures do
+ expect(label).to receive(:save!).once.and_raise(exception)
+ expect(subject).not_to receive(:log_import_failure)
+ expect { perform_retry }.to raise_exception(exception)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb b/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb
new file mode 100644
index 00000000000..0453ac87436
--- /dev/null
+++ b/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20190924152703_migrate_issue_trackers_data.rb')
+
+describe MigrateIssueTrackersData, :migration do
+ let(:services) { table(:services) }
+ let(:migration_class) { Gitlab::BackgroundMigration::MigrateIssueTrackersSensitiveData }
+ let(:migration_name) { migration_class.to_s.demodulize }
+
+ let(:properties) do
+ {
+ 'url' => 'http://example.com'
+ }
+ end
+ let!(:jira_service) do
+ services.create(id: 10, type: 'JiraService', properties: properties, category: 'issue_tracker')
+ end
+ let!(:jira_service_nil) do
+ services.create(id: 11, type: 'JiraService', properties: nil, category: 'issue_tracker')
+ end
+ let!(:bugzilla_service) do
+ services.create(id: 12, type: 'BugzillaService', properties: properties, category: 'issue_tracker')
+ end
+ let!(:youtrack_service) do
+ services.create(id: 13, type: 'YoutrackService', properties: properties, category: 'issue_tracker')
+ end
+ let!(:youtrack_service_empty) do
+ services.create(id: 14, type: 'YoutrackService', properties: '', category: 'issue_tracker')
+ end
+ let!(:gitlab_service) do
+ services.create(id: 15, type: 'GitlabIssueTrackerService', properties: properties, category: 'issue_tracker')
+ end
+ let!(:gitlab_service_empty) do
+ services.create(id: 16, type: 'GitlabIssueTrackerService', properties: {}, category: 'issue_tracker')
+ end
+ let!(:other_service) do
+ services.create(id: 17, type: 'OtherService', properties: properties, category: 'other_category')
+ end
+
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 2)
+ end
+
+ it 'schedules background migrations at correct time' do
+ Sidekiq::Testing.fake! do
+ Timecop.freeze do
+ migrate!
+
+ expect(migration_name).to be_scheduled_delayed_migration(3.minutes, jira_service.id, bugzilla_service.id)
+ expect(migration_name).to be_scheduled_delayed_migration(6.minutes, youtrack_service.id, gitlab_service.id)
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/models/import_failure_spec.rb b/spec/models/import_failure_spec.rb
new file mode 100644
index 00000000000..d6574791a65
--- /dev/null
+++ b/spec/models/import_failure_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ImportFailure do
+ describe "Associations" do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:group) }
+ end
+
+ describe 'Validations' do
+ context 'has no group' do
+ before do
+ allow(subject).to receive(:group).and_return(nil)
+ end
+
+ it { is_expected.to validate_presence_of(:project) }
+ end
+
+ context 'has no project' do
+ before do
+ allow(subject).to receive(:project).and_return(nil)
+ end
+
+ it { is_expected.to validate_presence_of(:group) }
+ end
+ end
+end
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index 9add328f6a8..d8fc234cbae 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -40,6 +40,18 @@ describe API::Deployments do
end
end
+ context 'with the environment filter specifed' do
+ it 'returns deployments for the environment' do
+ get(
+ api("/projects/#{project.id}/deployments", user),
+ params: { environment: deployment_1.environment.name }
+ )
+
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['iid']).to eq(deployment_1.iid)
+ end
+ end
+
describe 'ordering' do
let(:order_by) { 'iid' }
let(:sort) { 'desc' }
diff --git a/spec/services/merge_requests/conflicts/list_service_spec.rb b/spec/services/merge_requests/conflicts/list_service_spec.rb
index 68a9c0a8b86..13d69307084 100644
--- a/spec/services/merge_requests/conflicts/list_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/list_service_spec.rb
@@ -74,7 +74,9 @@ describe MergeRequests::Conflicts::ListService do
it 'returns a falsey value when the MR has a missing ref after a force push' do
merge_request = create_merge_request('conflict-resolvable')
service = conflicts_service(merge_request)
- allow_any_instance_of(Gitlab::GitalyClient::ConflictsService).to receive(:list_conflict_files).and_raise(GRPC::Unknown)
+ allow_next_instance_of(Gitlab::GitalyClient::ConflictsService) do |instance|
+ allow(instance).to receive(:list_conflict_files).and_raise(GRPC::Unknown)
+ end
expect(service.can_be_resolved_in_ui?).to be_falsey
end
diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb
index 7145cfe7897..3d58ecdd8cd 100644
--- a/spec/services/merge_requests/create_from_issue_service_spec.rb
+++ b/spec/services/merge_requests/create_from_issue_service_spec.rb
@@ -55,7 +55,9 @@ describe MergeRequests::CreateFromIssueService do
end
it 'creates the new_issue_branch system note when the branch could be created but the merge_request cannot be created', :sidekiq_might_not_need_inline do
- expect_any_instance_of(MergeRequest).to receive(:valid?).at_least(:once).and_return(false)
+ expect_next_instance_of(MergeRequest) do |instance|
+ expect(instance).to receive(:valid?).at_least(:once).and_return(false)
+ end
expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, issue.to_branch_name, branch_project: target_project)
diff --git a/spec/services/merge_requests/push_options_handler_service_spec.rb b/spec/services/merge_requests/push_options_handler_service_spec.rb
index 7f9c47d8670..420c8513c72 100644
--- a/spec/services/merge_requests/push_options_handler_service_spec.rb
+++ b/spec/services/merge_requests/push_options_handler_service_spec.rb
@@ -714,9 +714,9 @@ describe MergeRequests::PushOptionsHandlerService do
let(:exception) { StandardError.new('My standard error') }
def run_service_with_exception
- allow_any_instance_of(
- MergeRequests::BuildService
- ).to receive(:execute).and_raise(exception)
+ allow_next_instance_of(MergeRequests::BuildService) do |instance|
+ allow(instance).to receive(:execute).and_raise(exception)
+ end
service.execute
end
@@ -766,9 +766,9 @@ describe MergeRequests::PushOptionsHandlerService do
invalid_merge_request = MergeRequest.new
invalid_merge_request.errors.add(:base, 'my error')
- expect_any_instance_of(
- MergeRequests::CreateService
- ).to receive(:execute).and_return(invalid_merge_request)
+ expect_next_instance_of(MergeRequests::CreateService) do |instance|
+ expect(instance).to receive(:execute).and_return(invalid_merge_request)
+ end
service.execute
diff --git a/spec/services/milestones/promote_service_spec.rb b/spec/services/milestones/promote_service_spec.rb
index 22c7e9dde30..fa893b86cdb 100644
--- a/spec/services/milestones/promote_service_spec.rb
+++ b/spec/services/milestones/promote_service_spec.rb
@@ -31,7 +31,9 @@ describe Milestones::PromoteService do
it 'does not promote milestone and update issuables if promoted milestone is not valid' do
issue = create(:issue, milestone: milestone, project: project)
merge_request = create(:merge_request, milestone: milestone, source_project: project)
- allow_any_instance_of(Milestone).to receive(:valid?).and_return(false)
+ allow_next_instance_of(Milestone) do |instance|
+ allow(instance).to receive(:valid?).and_return(false)
+ end
expect { service.execute(milestone) }.to raise_error(described_class::PromoteMilestoneError)
diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb
index b3d41eb0763..711969ce504 100644
--- a/spec/services/milestones/transfer_service_spec.rb
+++ b/spec/services/milestones/transfer_service_spec.rb
@@ -71,7 +71,9 @@ describe Milestones::TransferService do
context 'when find_or_create_milestone returns nil' do
before do
- allow_any_instance_of(Milestones::FindOrCreateService).to receive(:execute).and_return(nil)
+ allow_next_instance_of(Milestones::FindOrCreateService) do |instance|
+ allow(instance).to receive(:execute).and_return(nil)
+ end
end
it 'removes issues group milestone' do
diff --git a/spec/services/namespaces/statistics_refresher_service_spec.rb b/spec/services/namespaces/statistics_refresher_service_spec.rb
index 9d42e917efe..1fa0a794edd 100644
--- a/spec/services/namespaces/statistics_refresher_service_spec.rb
+++ b/spec/services/namespaces/statistics_refresher_service_spec.rb
@@ -17,7 +17,9 @@ describe Namespaces::StatisticsRefresherService, '#execute' do
end
it 'recalculate the namespace statistics' do
- expect_any_instance_of(Namespace::RootStorageStatistics).to receive(:recalculate!).once
+ expect_next_instance_of(Namespace::RootStorageStatistics) do |instance|
+ expect(instance).to receive(:recalculate!).once
+ end
service.execute(group)
end
@@ -45,8 +47,9 @@ describe Namespaces::StatisticsRefresherService, '#execute' do
context 'when something goes wrong' do
before do
- allow_any_instance_of(Namespace::RootStorageStatistics)
- .to receive(:recalculate!).and_raise(ActiveRecord::ActiveRecordError)
+ allow_next_instance_of(Namespace::RootStorageStatistics) do |instance|
+ allow(instance).to receive(:recalculate!).and_raise(ActiveRecord::ActiveRecordError)
+ end
end
it 'raises RefreshError' do
diff --git a/spec/services/notes/resolve_service_spec.rb b/spec/services/notes/resolve_service_spec.rb
index 3f82e1dbdc0..c98384c226e 100644
--- a/spec/services/notes/resolve_service_spec.rb
+++ b/spec/services/notes/resolve_service_spec.rb
@@ -17,7 +17,9 @@ describe Notes::ResolveService do
end
it "sends notifications if all discussions are resolved" do
- expect_any_instance_of(MergeRequests::ResolvedDiscussionNotificationService).to receive(:execute).with(merge_request)
+ expect_next_instance_of(MergeRequests::ResolvedDiscussionNotificationService) do |instance|
+ expect(instance).to receive(:execute).with(merge_request)
+ end
described_class.new(merge_request.project, user).execute(note)
end
diff --git a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
index af79a42b611..9832ba95524 100644
--- a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
+++ b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
@@ -32,9 +32,9 @@ describe PagesDomains::ObtainLetsEncryptCertificateService do
def stub_lets_encrypt_order(url, status)
order = ::Gitlab::LetsEncrypt::Order.new(acme_order_double(status: status))
- allow_any_instance_of(::Gitlab::LetsEncrypt::Client).to(
- receive(:load_order).with(url).and_return(order)
- )
+ allow_next_instance_of(::Gitlab::LetsEncrypt::Client) do |instance|
+ allow(instance).to receive(:load_order).with(url).and_return(order)
+ end
order
end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 814bf912c8c..bce3f72a287 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -247,7 +247,9 @@ describe Projects::CreateService, '#execute' do
context 'repository creation' do
it 'synchronously creates the repository' do
- expect_any_instance_of(Project).to receive(:create_repository)
+ expect_next_instance_of(Project) do |instance|
+ expect(instance).to receive(:create_repository)
+ end
project = create_project(user, opts)
expect(project).to be_valid
diff --git a/spec/services/projects/import_export/export_service_spec.rb b/spec/services/projects/import_export/export_service_spec.rb
index a557e61da78..c7ac07fc524 100644
--- a/spec/services/projects/import_export/export_service_spec.rb
+++ b/spec/services/projects/import_export/export_service_spec.rb
@@ -94,7 +94,9 @@ describe Projects::ImportExport::ExportService do
end
it 'notifies the user' do
- expect_any_instance_of(NotificationService).to receive(:project_not_exported)
+ expect_next_instance_of(NotificationService) do |instance|
+ expect(instance).to receive(:project_not_exported)
+ end
end
it 'notifies logger' do
@@ -122,7 +124,9 @@ describe Projects::ImportExport::ExportService do
end
it 'notifies the user' do
- expect_any_instance_of(NotificationService).to receive(:project_not_exported)
+ expect_next_instance_of(NotificationService) do |instance|
+ expect(instance).to receive(:project_not_exported)
+ end
end
it 'notifies logger' do
diff --git a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb
index 7ca20a6d751..016028a96bf 100644
--- a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb
@@ -16,7 +16,9 @@ describe Projects::LfsPointers::LfsImportService do
it 'downloads lfs objects' do
service = double
- expect_any_instance_of(Projects::LfsPointers::LfsObjectDownloadListService).to receive(:execute).and_return(oid_download_links)
+ expect_next_instance_of(Projects::LfsPointers::LfsObjectDownloadListService) do |instance|
+ expect(instance).to receive(:execute).and_return(oid_download_links)
+ end
expect(Projects::LfsPointers::LfsDownloadService).to receive(:new).and_return(service).twice
expect(service).to receive(:execute).twice
@@ -27,7 +29,9 @@ describe Projects::LfsPointers::LfsImportService do
context 'when no downloadable lfs object links' do
it 'does not call LfsDownloadService' do
- expect_any_instance_of(Projects::LfsPointers::LfsObjectDownloadListService).to receive(:execute).and_return({})
+ expect_next_instance_of(Projects::LfsPointers::LfsObjectDownloadListService) do |instance|
+ expect(instance).to receive(:execute).and_return({})
+ end
expect(Projects::LfsPointers::LfsDownloadService).not_to receive(:new)
result = subject.execute
@@ -39,7 +43,9 @@ describe Projects::LfsPointers::LfsImportService do
context 'when an exception is raised' do
it 'returns error' do
error_message = "error message"
- expect_any_instance_of(Projects::LfsPointers::LfsObjectDownloadListService).to receive(:execute).and_raise(StandardError, error_message)
+ expect_next_instance_of(Projects::LfsPointers::LfsObjectDownloadListService) do |instance|
+ expect(instance).to receive(:execute).and_raise(StandardError, error_message)
+ end
result = subject.execute
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index 001c6670f4b..714256d9b08 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -110,8 +110,9 @@ describe Projects::UpdatePagesService do
context 'when timeout happens by DNS error' do
before do
- allow_any_instance_of(described_class)
- .to receive(:extract_zip_archive!).and_raise(SocketError)
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:extract_zip_archive!).and_raise(SocketError)
+ end
end
it 'raises an error' do
@@ -125,9 +126,10 @@ describe Projects::UpdatePagesService do
context 'when failed to extract zip artifacts' do
before do
- expect_any_instance_of(described_class)
- .to receive(:extract_zip_archive!)
- .and_raise(Projects::UpdatePagesService::FailedToExtractError)
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:extract_zip_archive!)
+ .and_raise(Projects::UpdatePagesService::FailedToExtractError)
+ end
end
it 'raises an error' do
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index c2f627c681b..56ef0039b63 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -265,7 +265,9 @@ describe ::SystemNotes::IssuablesService do
context 'when cross-reference disallowed' do
before do
- expect_any_instance_of(described_class).to receive(:cross_reference_disallowed?).and_return(true)
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:cross_reference_disallowed?).and_return(true)
+ end
end
it 'returns nil' do
@@ -279,7 +281,9 @@ describe ::SystemNotes::IssuablesService do
context 'when cross-reference allowed' do
before do
- expect_any_instance_of(described_class).to receive(:cross_reference_disallowed?).and_return(false)
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:cross_reference_disallowed?).and_return(false)
+ end
end
it_behaves_like 'a system note' do
diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb
index 95c24d76dcd..45d49696e06 100644
--- a/spec/support/helpers/filter_spec_helper.rb
+++ b/spec/support/helpers/filter_spec_helper.rb
@@ -28,6 +28,17 @@ module FilterSpecHelper
described_class.call(html, context)
end
+ # Get an instance of the Filter class
+ #
+ # Use this for testing instance methods, but remember to test the result of
+ # the full pipeline by calling #call using the other methods in this helper.
+ def filter_instance
+ render_context = Banzai::RenderContext.new(project, current_user)
+ context = { project: project, current_user: current_user, render_context: render_context }
+
+ described_class.new(input_text, context)
+ end
+
# Run text through HTML::Pipeline with the current filter and return the
# result Hash
#
diff --git a/spec/support/import_export/common_util.rb b/spec/support/import_export/common_util.rb
index 4e149c9fa54..72baec7bfcb 100644
--- a/spec/support/import_export/common_util.rb
+++ b/spec/support/import_export/common_util.rb
@@ -3,7 +3,9 @@
module ImportExport
module CommonUtil
def setup_symlink(tmpdir, symlink_name)
- allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(tmpdir)
+ allow_next_instance_of(Gitlab::ImportExport) do |instance|
+ allow(instance).to receive(:storage_path).and_return(tmpdir)
+ end
File.open("#{tmpdir}/test", 'w') { |file| file.write("test") }
FileUtils.ln_s("#{tmpdir}/test", "#{tmpdir}/#{symlink_name}")
diff --git a/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
new file mode 100644
index 00000000000..691564120cc
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+shared_examples 'log import failure' do |importable_column|
+ it 'tracks error' do
+ extra = {
+ relation_key: relation_key,
+ relation_index: relation_index,
+ retry_count: retry_count
+ }
+ extra[importable_column] = importable.id
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(exception, extra)
+
+ subject.log_import_failure(relation_key, relation_index, exception, retry_count)
+ end
+
+ it 'saves data to ImportFailure' do
+ log_import_failure
+
+ import_failure = ImportFailure.last
+
+ aggregate_failures do
+ expect(import_failure[importable_column]).to eq(importable.id)
+ expect(import_failure.relation_key).to eq(relation_key)
+ expect(import_failure.relation_index).to eq(relation_index)
+ expect(import_failure.exception_class).to eq('StandardError')
+ expect(import_failure.exception_message).to eq(standard_error_message)
+ expect(import_failure.correlation_id_value).to eq(correlation_id)
+ expect(import_failure.retry_count).to eq(retry_count)
+ end
+ end
+end
diff --git a/spec/workers/ci/archive_traces_cron_worker_spec.rb b/spec/workers/ci/archive_traces_cron_worker_spec.rb
index fc700c15b10..789e83783bb 100644
--- a/spec/workers/ci/archive_traces_cron_worker_spec.rb
+++ b/spec/workers/ci/archive_traces_cron_worker_spec.rb
@@ -35,8 +35,9 @@ describe Ci::ArchiveTracesCronWorker do
it_behaves_like 'archives trace'
it 'executes service' do
- expect_any_instance_of(Ci::ArchiveTraceService)
- .to receive(:execute).with(build, anything)
+ expect_next_instance_of(Ci::ArchiveTraceService) do |instance|
+ expect(instance).to receive(:execute).with(build, anything)
+ end
subject
end
@@ -64,7 +65,9 @@ describe Ci::ArchiveTracesCronWorker do
before do
allow(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- allow_any_instance_of(Gitlab::Ci::Trace).to receive(:archive!).and_raise('Unexpected error')
+ allow_next_instance_of(Gitlab::Ci::Trace) do |instance|
+ allow(instance).to receive(:archive!).and_raise('Unexpected error')
+ end
end
it 'puts a log' do
diff --git a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
index 294eacf09ab..c4f6ddf9aca 100644
--- a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
@@ -57,9 +57,9 @@ describe Gitlab::GithubImport::ReschedulingMethods do
expect(worker)
.not_to receive(:notify_waiter)
- expect_any_instance_of(Gitlab::GithubImport::Client)
- .to receive(:rate_limit_resets_in)
- .and_return(14)
+ expect_next_instance_of(Gitlab::GithubImport::Client) do |instance|
+ expect(instance).to receive(:rate_limit_resets_in).and_return(14)
+ end
expect(worker.class)
.to receive(:perform_in)
diff --git a/spec/workers/delete_merged_branches_worker_spec.rb b/spec/workers/delete_merged_branches_worker_spec.rb
index 8c983859e36..3eaeb7e0797 100644
--- a/spec/workers/delete_merged_branches_worker_spec.rb
+++ b/spec/workers/delete_merged_branches_worker_spec.rb
@@ -9,7 +9,9 @@ describe DeleteMergedBranchesWorker do
describe "#perform" do
it "delegates to Branches::DeleteMergedService" do
- expect_any_instance_of(::Branches::DeleteMergedService).to receive(:execute).and_return(true)
+ expect_next_instance_of(::Branches::DeleteMergedService) do |instance|
+ expect(instance).to receive(:execute).and_return(true)
+ end
worker.perform(project.id, project.owner.id)
end
diff --git a/spec/workers/expire_build_artifacts_worker_spec.rb b/spec/workers/expire_build_artifacts_worker_spec.rb
index 0a0aea838d2..06561e94fb7 100644
--- a/spec/workers/expire_build_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_artifacts_worker_spec.rb
@@ -7,7 +7,9 @@ describe ExpireBuildArtifactsWorker do
describe '#perform' do
it 'executes a service' do
- expect_any_instance_of(Ci::DestroyExpiredJobArtifactsService).to receive(:execute)
+ expect_next_instance_of(Ci::DestroyExpiredJobArtifactsService) do |instance|
+ expect(instance).to receive(:execute)
+ end
worker.perform
end
diff --git a/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
index 6d47d73b92e..3a8fe73622a 100644
--- a/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
@@ -21,9 +21,9 @@ describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
it 'schedules the importing of the base data' do
client = double(:client)
- expect_any_instance_of(Gitlab::GithubImport::Importer::RepositoryImporter)
- .to receive(:execute)
- .and_return(true)
+ expect_next_instance_of(Gitlab::GithubImport::Importer::RepositoryImporter) do |instance|
+ expect(instance).to receive(:execute).and_return(true)
+ end
expect(Gitlab::GithubImport::Stage::ImportBaseDataWorker)
.to receive(:perform_async)
@@ -37,9 +37,9 @@ describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
it 'does not schedule the importing of the base data' do
client = double(:client)
- expect_any_instance_of(Gitlab::GithubImport::Importer::RepositoryImporter)
- .to receive(:execute)
- .and_return(false)
+ expect_next_instance_of(Gitlab::GithubImport::Importer::RepositoryImporter) do |instance|
+ expect(instance).to receive(:execute).and_return(false)
+ end
expect(Gitlab::GithubImport::Stage::ImportBaseDataWorker)
.not_to receive(:perform_async)
diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb
index 0758cfc4ee2..5dedf5be9fa 100644
--- a/spec/workers/gitlab_shell_worker_spec.rb
+++ b/spec/workers/gitlab_shell_worker_spec.rb
@@ -7,7 +7,9 @@ describe GitlabShellWorker do
describe '#perform with add_key' do
it 'calls add_key on Gitlab::Shell' do
- expect_any_instance_of(Gitlab::Shell).to receive(:add_key).with('foo', 'bar')
+ expect_next_instance_of(Gitlab::Shell) do |instance|
+ expect(instance).to receive(:add_key).with('foo', 'bar')
+ end
worker.perform(:add_key, 'foo', 'bar')
end
end
diff --git a/spec/workers/gitlab_usage_ping_worker_spec.rb b/spec/workers/gitlab_usage_ping_worker_spec.rb
index aff5d112cdd..198daf40493 100644
--- a/spec/workers/gitlab_usage_ping_worker_spec.rb
+++ b/spec/workers/gitlab_usage_ping_worker_spec.rb
@@ -8,7 +8,9 @@ describe GitlabUsagePingWorker do
it 'delegates to SubmitUsagePingService' do
allow(subject).to receive(:try_obtain_lease).and_return(true)
- expect_any_instance_of(SubmitUsagePingService).to receive(:execute)
+ expect_next_instance_of(SubmitUsagePingService) do |instance|
+ expect(instance).to receive(:execute)
+ end
subject.perform
end
diff --git a/spec/workers/hashed_storage/migrator_worker_spec.rb b/spec/workers/hashed_storage/migrator_worker_spec.rb
index 9180da87058..ac76a306f43 100644
--- a/spec/workers/hashed_storage/migrator_worker_spec.rb
+++ b/spec/workers/hashed_storage/migrator_worker_spec.rb
@@ -10,7 +10,9 @@ describe HashedStorage::MigratorWorker do
describe '#perform' do
it 'delegates to MigratorService' do
- expect_any_instance_of(Gitlab::HashedStorage::Migrator).to receive(:bulk_migrate).with(start: 5, finish: 10)
+ expect_next_instance_of(Gitlab::HashedStorage::Migrator) do |instance|
+ expect(instance).to receive(:bulk_migrate).with(start: 5, finish: 10)
+ end
worker.perform(5, 10)
end
diff --git a/spec/workers/hashed_storage/rollbacker_worker_spec.rb b/spec/workers/hashed_storage/rollbacker_worker_spec.rb
index 3ca2601df0f..55fc4fb0fe1 100644
--- a/spec/workers/hashed_storage/rollbacker_worker_spec.rb
+++ b/spec/workers/hashed_storage/rollbacker_worker_spec.rb
@@ -10,7 +10,9 @@ describe HashedStorage::RollbackerWorker do
describe '#perform' do
it 'delegates to MigratorService' do
- expect_any_instance_of(Gitlab::HashedStorage::Migrator).to receive(:bulk_rollback).with(start: 5, finish: 10)
+ expect_next_instance_of(Gitlab::HashedStorage::Migrator) do |instance|
+ expect(instance).to receive(:bulk_rollback).with(start: 5, finish: 10)
+ end
worker.perform(5, 10)
end
diff --git a/spec/workers/import_issues_csv_worker_spec.rb b/spec/workers/import_issues_csv_worker_spec.rb
index 89370c4890d..03944cfb05d 100644
--- a/spec/workers/import_issues_csv_worker_spec.rb
+++ b/spec/workers/import_issues_csv_worker_spec.rb
@@ -11,7 +11,9 @@ describe ImportIssuesCsvWorker do
describe '#perform' do
it 'calls #execute on Issues::ImportCsvService and destroys upload' do
- expect_any_instance_of(Issues::ImportCsvService).to receive(:execute).and_return({ success: 5, errors: [], valid_file: true })
+ expect_next_instance_of(Issues::ImportCsvService) do |instance|
+ expect(instance).to receive(:execute).and_return({ success: 5, errors: [], valid_file: true })
+ end
worker.perform(user.id, project.id, upload.id)
diff --git a/spec/workers/new_release_worker_spec.rb b/spec/workers/new_release_worker_spec.rb
index 9010c36f795..9d8c5bbf919 100644
--- a/spec/workers/new_release_worker_spec.rb
+++ b/spec/workers/new_release_worker_spec.rb
@@ -6,7 +6,9 @@ describe NewReleaseWorker do
let(:release) { create(:release) }
it 'sends a new release notification' do
- expect_any_instance_of(NotificationService).to receive(:send_new_release_notifications).with(release)
+ expect_next_instance_of(NotificationService) do |instance|
+ expect(instance).to receive(:send_new_release_notifications).with(release)
+ end
described_class.new.perform(release.id)
end
diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb
index b8767af8eee..507098582c9 100644
--- a/spec/workers/repository_import_worker_spec.rb
+++ b/spec/workers/repository_import_worker_spec.rb
@@ -21,8 +21,9 @@ describe RepositoryImportWorker do
allow(subject).to receive(:jid).and_return(jid)
- expect_any_instance_of(Projects::ImportService).to receive(:execute)
- .and_return({ status: :ok })
+ expect_next_instance_of(Projects::ImportService) do |instance|
+ expect(instance).to receive(:execute).and_return({ status: :ok })
+ end
# Works around https://github.com/rspec/rspec-mocks/issues/910
expect(Project).to receive(:find).with(started_project.id).and_return(started_project)
@@ -36,8 +37,9 @@ describe RepositoryImportWorker do
context 'when the import was successful' do
it 'imports a project' do
- expect_any_instance_of(Projects::ImportService).to receive(:execute)
- .and_return({ status: :ok })
+ expect_next_instance_of(Projects::ImportService) do |instance|
+ expect(instance).to receive(:execute).and_return({ status: :ok })
+ end
# Works around https://github.com/rspec/rspec-mocks/issues/910
expect(Project).to receive(:find).with(project.id).and_return(project)
@@ -54,7 +56,9 @@ describe RepositoryImportWorker do
error = %q{remote: Not Found fatal: repository 'https://user:pass@test.com/root/repoC.git/' not found }
import_state.update(jid: '123')
- expect_any_instance_of(Projects::ImportService).to receive(:execute).and_return({ status: :error, message: error })
+ expect_next_instance_of(Projects::ImportService) do |instance|
+ expect(instance).to receive(:execute).and_return({ status: :error, message: error })
+ end
expect do
subject.perform(project.id)
@@ -67,7 +71,9 @@ describe RepositoryImportWorker do
project.update(import_type: 'gitlab_project')
import_state.update(jid: '123')
- expect_any_instance_of(Projects::ImportService).to receive(:execute).and_return({ status: :error, message: error })
+ expect_next_instance_of(Projects::ImportService) do |instance|
+ expect(instance).to receive(:execute).and_return({ status: :error, message: error })
+ end
expect do
subject.perform(project.id)
@@ -93,8 +99,9 @@ describe RepositoryImportWorker do
.to receive(:async?)
.and_return(true)
- expect_any_instance_of(ProjectImportState)
- .not_to receive(:finish)
+ expect_next_instance_of(ProjectImportState) do |instance|
+ expect(instance).not_to receive(:finish)
+ end
subject.perform(project.id)
end