diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-17 21:08:29 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-17 21:08:29 +0000 |
commit | 40254b9ace2a74a3c9f1cc51a1b1d5e3e78c1ae9 (patch) | |
tree | 9b735ef933178be36d35088f3acab2d9b75dbbad /spec | |
parent | 22a0d312ae82e7dda3073d5d1a5a766d7641738d (diff) | |
download | gitlab-ce-40254b9ace2a74a3c9f1cc51a1b1d5e3e78c1ae9.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
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 |