diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-12 18:09:30 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-12 18:09:30 +0300 |
commit | 3df6bfc24c8877b9442d567378b8ebd8816cd443 (patch) | |
tree | 2f6cf2e38866e10dc179c1892d37ae971af8d44f /spec | |
parent | d7fd035dc387e9c2e5c31bbb53d867239689cfbf (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
22 files changed, 333 insertions, 75 deletions
diff --git a/spec/controllers/dashboard/snippets_controller_spec.rb b/spec/controllers/dashboard/snippets_controller_spec.rb index 016a9f53129..180369447b4 100644 --- a/spec/controllers/dashboard/snippets_controller_spec.rb +++ b/spec/controllers/dashboard/snippets_controller_spec.rb @@ -29,23 +29,6 @@ RSpec.describe Dashboard::SnippetsController do it_behaves_like 'snippets sort order' - context 'when views are rendered' do - render_views - - it 'avoids N+1 database queries' do - # Warming call to load everything non snippet related - get(:index) - - project = create(:project, namespace: user.namespace) - create(:project_snippet, project: project, author: user) - - control_count = ActiveRecord::QueryRecorder.new { get(:index) }.count - - project = create(:project, namespace: user.namespace) - create(:project_snippet, project: project, author: user) - - expect { get(:index) }.not_to exceed_query_limit(control_count) - end - end + it_behaves_like 'snippets views' end end diff --git a/spec/controllers/explore/snippets_controller_spec.rb b/spec/controllers/explore/snippets_controller_spec.rb index f7bd2ba917e..e93e8502dfc 100644 --- a/spec/controllers/explore/snippets_controller_spec.rb +++ b/spec/controllers/explore/snippets_controller_spec.rb @@ -32,5 +32,9 @@ RSpec.describe Explore::SnippetsController do expect(assigns(:snippets)).to all(be_a(PersonalSnippet)) expect(response).to have_gitlab_http_status(:ok) end + + it_behaves_like 'snippets views' do + let_it_be(:user) { create(:user) } + end end end diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index 091a44130a1..df2023b7356 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -213,6 +213,38 @@ RSpec.describe Projects::MergeRequests::CreationsController do expect(assigns(:commit)).to be_nil expect(response).to have_gitlab_http_status(:ok) end + + context 'no target_project_id provided' do + before do + project.add_maintainer(user) + end + + it 'selects itself as a target project' do + get :branch_to, + params: { + namespace_id: project.namespace, + project_id: project, + ref: 'master' + } + + expect(assigns(:target_project)).to eq(project) + expect(response).to have_gitlab_http_status(:ok) + end + + context 'project is a fork' do + it 'calls to project defaults to selects a correct target project' do + get :branch_to, + params: { + namespace_id: fork_project.namespace, + project_id: fork_project, + ref: 'master' + } + + expect(assigns(:target_project)).to eq(project) + expect(response).to have_gitlab_http_status(:ok) + end + end + end end describe 'POST create' do diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 793ffbbfad9..1a6c0974f08 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -46,6 +46,10 @@ RSpec.describe Projects::SnippetsController do let(:params) { base_params } end + it_behaves_like 'snippets views' do + let(:params) { base_params } + end + context 'when the project snippet is private' do let_it_be(:project_snippet) { create(:project_snippet, :private, project: project, author: user) } diff --git a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb index 397c334a2b8..ebda5c9ff59 100644 --- a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb @@ -2,6 +2,8 @@ require 'spec_helper' RSpec.describe 'Projects > Settings > User manages merge request settings' do + include ProjectForksHelper + let(:user) { create(:user) } let(:project) { create(:project, :public, namespace: user.namespace, path: 'gitlab', name: 'sample') } @@ -198,4 +200,36 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do expect(project.reload.project_setting.squash_option).to eq('never') end end + + describe 'target project settings' do + context 'when project is a fork' do + let_it_be(:upstream) { create(:project, :public) } + + let(:project) { fork_project(upstream, user) } + + it 'allows to change merge request target project behavior' do + expect(page).to have_content 'The default target project for merge requests' + + radio = find_field('project_project_setting_attributes_mr_default_target_self_false') + expect(radio).to be_checked + + choose('project_project_setting_attributes_mr_default_target_self_true') + + within('.merge-request-settings-form') do + find('.rspec-save-merge-request-changes') + click_on('Save changes') + end + + find('.flash-notice') + radio = find_field('project_project_setting_attributes_mr_default_target_self_true') + + expect(radio).to be_checked + expect(project.reload.project_setting.mr_default_target_self).to be_truthy + end + end + + it 'does not show target project section' do + expect(page).not_to have_content 'The default target project for merge requests' + end + end end diff --git a/spec/fixtures/api/schemas/entities/member_user.json b/spec/fixtures/api/schemas/entities/member_user.json index ebd26bfaaaa..41a1e510de5 100644 --- a/spec/fixtures/api/schemas/entities/member_user.json +++ b/spec/fixtures/api/schemas/entities/member_user.json @@ -18,6 +18,5 @@ }, "additionalProperties": false } - }, - "additionalProperties": false + } } diff --git a/spec/frontend/projects/commit/components/branches_dropdown_spec.js b/spec/frontend/projects/commit/components/branches_dropdown_spec.js index 7686c28c7fc..ab84c3768d0 100644 --- a/spec/frontend/projects/commit/components/branches_dropdown_spec.js +++ b/spec/frontend/projects/commit/components/branches_dropdown_spec.js @@ -15,7 +15,7 @@ describe('BranchesDropdown', () => { const createComponent = (term, state = { isFetching: false }) => { store = new Vuex.Store({ getters: { - joinedBranches: () => ['_master_', '_branch_1_', '_branch_2_'], + joinedBranches: () => ['_main_', '_branch_1_', '_branch_2_'], }, actions: { fetchBranches: spyFetchBranches, @@ -94,13 +94,13 @@ describe('BranchesDropdown', () => { it('renders all branches when search term is empty', () => { expect(findAllDropdownItems()).toHaveLength(3); - expect(findDropdownItemByIndex(0).text()).toBe('_master_'); + expect(findDropdownItemByIndex(0).text()).toBe('_main_'); expect(findDropdownItemByIndex(1).text()).toBe('_branch_1_'); expect(findDropdownItemByIndex(2).text()).toBe('_branch_2_'); }); it('should not be selected on the inactive branch', () => { - expect(wrapper.vm.isSelected('_master_')).toBe(false); + expect(wrapper.vm.isSelected('_main_')).toBe(false); }); }); diff --git a/spec/frontend/projects/commit/mock_data.js b/spec/frontend/projects/commit/mock_data.js index e4dcb24c4c0..34e9c400af4 100644 --- a/spec/frontend/projects/commit/mock_data.js +++ b/spec/frontend/projects/commit/mock_data.js @@ -23,6 +23,6 @@ export default { modalId: '_modal_id_', openModal: '_open_modal_', }, - mockBranches: ['_branch_1', '_abc_', '_master_'], + mockBranches: ['_branch_1', '_abc_', '_main_'], mockProjects: ['_project_1', '_abc_', '_project_'], }; diff --git a/spec/frontend/projects/commit/store/mutations_spec.js b/spec/frontend/projects/commit/store/mutations_spec.js index 8989e769772..60abf0fddad 100644 --- a/spec/frontend/projects/commit/store/mutations_spec.js +++ b/spec/frontend/projects/commit/store/mutations_spec.js @@ -27,7 +27,7 @@ describe('Commit form modal mutations', () => { describe('CLEAR_MODAL', () => { it('should clear modal state ', () => { - stateCopy = { branch: '_master_', defaultBranch: '_default_branch_' }; + stateCopy = { branch: '_main_', defaultBranch: '_default_branch_' }; mutations[types.CLEAR_MODAL](stateCopy); @@ -47,7 +47,7 @@ describe('Commit form modal mutations', () => { describe('SET_BRANCH', () => { it('should set branch', () => { - stateCopy = { branch: '_master_' }; + stateCopy = { branch: '_main_' }; mutations[types.SET_BRANCH](stateCopy, '_changed_branch_'); @@ -57,7 +57,7 @@ describe('Commit form modal mutations', () => { describe('SET_SELECTED_BRANCH', () => { it('should set selectedBranch', () => { - stateCopy = { selectedBranch: '_master_' }; + stateCopy = { selectedBranch: '_main_' }; mutations[types.SET_SELECTED_BRANCH](stateCopy, '_changed_branch_'); diff --git a/spec/frontend/projects/commit_box/info/load_branches_spec.js b/spec/frontend/projects/commit_box/info/load_branches_spec.js index 184be09383c..9456e6ef5f5 100644 --- a/spec/frontend/projects/commit_box/info/load_branches_spec.js +++ b/spec/frontend/projects/commit_box/info/load_branches_spec.js @@ -6,7 +6,7 @@ import { loadBranches } from '~/projects/commit_box/info/load_branches'; const mockCommitPath = '/commit/abcd/branches'; const mockBranchesRes = - '<a href="/-/commits/master">master</a><span><a href="/-/commits/my-branch">my-branch</a></span>'; + '<a href="/-/commits/main">main</a><span><a href="/-/commits/my-branch">my-branch</a></span>'; describe('~/projects/commit_box/info/load_branches', () => { let mock; @@ -45,7 +45,7 @@ describe('~/projects/commit_box/info/load_branches', () => { beforeEach(() => { mock .onGet(mockCommitPath) - .reply(200, '<a onload="alert(\'xss!\');" href="/-/commits/master">master</a>'); + .reply(200, '<a onload="alert(\'xss!\');" href="/-/commits/main">main</a>'); }); it('displays sanitized html', async () => { @@ -53,7 +53,7 @@ describe('~/projects/commit_box/info/load_branches', () => { await waitForPromises(); expect(getElInnerHtml()).toMatchInterpolatedText( - '<div class="commit-info branches"><a href="/-/commits/master">master</a></div>', + '<div class="commit-info branches"><a href="/-/commits/main">main</a></div>', ); }); }); diff --git a/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb b/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb index e0d2eff8a21..d1c2b4044c1 100644 --- a/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb +++ b/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb @@ -11,6 +11,7 @@ RSpec.describe GitlabSchema.types['UsageTrendsMeasurement'] do describe 'authorization' do let_it_be(:measurement) { create(:usage_trends_measurement, :project_count) } + let(:user) { create(:user) } let(:query) do diff --git a/spec/graphql/types/global_id_type_spec.rb b/spec/graphql/types/global_id_type_spec.rb index 8eb023ad2a3..4df51dc8d1b 100644 --- a/spec/graphql/types/global_id_type_spec.rb +++ b/spec/graphql/types/global_id_type_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe Types::GlobalIDType do let_it_be(:project) { create(:project) } + let(:gid) { project.to_global_id } it 'is has the correct name' do diff --git a/spec/graphql/types/snippet_type_spec.rb b/spec/graphql/types/snippet_type_spec.rb index 4d827186a9b..b87770ebe8d 100644 --- a/spec/graphql/types/snippet_type_spec.rb +++ b/spec/graphql/types/snippet_type_spec.rb @@ -161,6 +161,7 @@ RSpec.describe GitlabSchema.types['Snippet'] do describe '#blobs' do let_it_be(:snippet) { create(:personal_snippet, :public, author: user) } + let(:query_blobs) { subject.dig('data', 'snippets', 'nodes')[0].dig('blobs', 'nodes') } let(:paths) { [] } let(:query) do @@ -201,6 +202,7 @@ RSpec.describe GitlabSchema.types['Snippet'] do context 'when snippet has repository' do let_it_be(:snippet) { create(:personal_snippet, :repository, :public, author: user) } + let(:blobs) { snippet.blobs } it_behaves_like 'an array' diff --git a/spec/lib/gitlab/middleware/rack_multipart_tempfile_factory_spec.rb b/spec/lib/gitlab/middleware/rack_multipart_tempfile_factory_spec.rb new file mode 100644 index 00000000000..b9d00b556c5 --- /dev/null +++ b/spec/lib/gitlab/middleware/rack_multipart_tempfile_factory_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'rack' + +RSpec.describe Gitlab::Middleware::RackMultipartTempfileFactory do + let(:app) do + lambda do |env| + params = Rack::Request.new(env).params + + if params['file'] + [200, { 'Content-Type' => params['file'][:type] }, [params['file'][:tempfile].read]] + else + [204, {}, []] + end + end + end + + let(:file_contents) { '/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg' } + + let(:multipart_fixture) do + boundary = 'AaB03x' + data = <<~DATA + --#{boundary}\r + Content-Disposition: form-data; name="file"; filename="dj.jpg"\r + Content-Type: image/jpeg\r + Content-Transfer-Encoding: base64\r + \r + #{file_contents}\r + --#{boundary}--\r + DATA + + { + 'CONTENT_TYPE' => "multipart/form-data; boundary=#{boundary}", + 'CONTENT_LENGTH' => data.bytesize.to_s, + input: StringIO.new(data) + } + end + + subject { described_class.new(app) } + + context 'for a multipart request' do + let(:env) { Rack::MockRequest.env_for('/', multipart_fixture) } + + context 'when the environment variable is enabled' do + before do + stub_env('GITLAB_TEMPFILE_IMMEDIATE_UNLINK', '1') + end + + it 'immediately unlinks the temporary file' do + tempfile = Tempfile.new('foo') + + expect(tempfile.path).not_to be(nil) + expect(Rack::Multipart::Parser::TEMPFILE_FACTORY).to receive(:call).and_return(tempfile) + expect(tempfile).to receive(:unlink).and_call_original + + subject.call(env) + + expect(tempfile.path).to be(nil) + end + + it 'processes the request as normal' do + expect(subject.call(env)).to eq([200, { 'Content-Type' => 'image/jpeg' }, [file_contents]]) + end + end + + context 'when the environment variable is disabled' do + it 'does not immediately unlink the temporary file' do + tempfile = Tempfile.new('foo') + + expect(tempfile.path).not_to be(nil) + expect(Rack::Multipart::Parser::TEMPFILE_FACTORY).to receive(:call).and_return(tempfile) + expect(tempfile).not_to receive(:unlink).and_call_original + + subject.call(env) + + expect(tempfile.path).not_to be(nil) + end + + it 'processes the request as normal' do + expect(subject.call(env)).to eq([200, { 'Content-Type' => 'image/jpeg' }, [file_contents]]) + end + end + end + + context 'for a regular request' do + let(:env) { Rack::MockRequest.env_for('/', params: { 'foo' => 'bar' }) } + + it 'does nothing' do + expect(Rack::Multipart::Parser::TEMPFILE_FACTORY).not_to receive(:call) + expect(subject.call(env)).to eq([204, {}, []]) + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 991691a408a..098c88147c3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3803,49 +3803,74 @@ RSpec.describe Project, factory_default: :keep do end describe '#default_merge_request_target' do + let_it_be(:project) { create(:project, :public) } + + let!(:forked) { fork_project(project) } + + context 'when mr_default_target_self is set to true' do + it 'returns the current project' do + expect(forked.project_setting).to receive(:mr_default_target_self) + .and_return(true) + + expect(forked.default_merge_request_target).to eq(forked) + end + end + + context 'when merge request can not target upstream' do + it 'returns the current project' do + expect(forked).to receive(:mr_can_target_upstream?).and_return(false) + + expect(forked.default_merge_request_target).to eq(forked) + end + end + + context 'when merge request can target upstream' do + it 'returns the source project' do + expect(forked).to receive(:mr_can_target_upstream?).and_return(true) + + expect(forked.default_merge_request_target).to eq(project) + end + end + end + + describe '#mr_can_target_upstream?' do + let_it_be(:project) { create(:project, :public) } + + let!(:forked) { fork_project(project) } + context 'when forked from a more visible project' do - it 'returns the more restrictive project' do - project = create(:project, :public) - forked = fork_project(project) + it 'can not target the upstream project' do forked.visibility = Gitlab::VisibilityLevel::PRIVATE forked.save! expect(project.visibility).to eq 'public' expect(forked.visibility).to eq 'private' - expect(forked.default_merge_request_target).to eq(forked) + expect(forked.mr_can_target_upstream?).to be_falsey end end context 'when forked from a project with disabled merge requests' do - it 'returns the current project' do - project = create(:project, :merge_requests_disabled) - forked = fork_project(project) + it 'can not target the upstream project' do + project.project_feature + .update!(merge_requests_access_level: ProjectFeature::DISABLED) expect(forked.forked_from_project).to receive(:merge_requests_enabled?) .and_call_original - expect(forked.default_merge_request_target).to eq(forked) + expect(forked.mr_can_target_upstream?).to be_falsey end end context 'when forked from a project with enabled merge requests' do - it 'returns the source project' do - project = create(:project, :public) - forked = fork_project(project) - - expect(project.visibility).to eq 'public' - expect(forked.visibility).to eq 'public' - - expect(forked.default_merge_request_target).to eq(project) + it 'can target the upstream project' do + expect(forked.mr_can_target_upstream?).to be_truthy end end context 'when not forked' do - it 'returns the current project' do - project = build_stubbed(:project) - - expect(project.default_merge_request_target).to eq(project) + it 'can not target the upstream project' do + expect(project.mr_can_target_upstream?).to be_falsey end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 520f616bfa0..7c01ef5e53e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1804,7 +1804,7 @@ RSpec.describe User do it 'aborts all running pipelines and related jobs' do expect(user).to receive(:pipelines).and_return(pipelines) expect(Ci::AbortPipelinesService).to receive(:new).and_return(service) - expect(service).to receive(:execute).with(pipelines) + expect(service).to receive(:execute).with(pipelines, :user_blocked) user.block end diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml index 6c9a845b217..f9eb9de94db 100644 --- a/spec/requests/api/project_attributes.yml +++ b/spec/requests/api/project_attributes.yml @@ -140,6 +140,7 @@ project_setting: - squash_option - updated_at - cve_id_request_enabled + - mr_default_target_self build_service_desk_setting: # service_desk_setting unexposed_attributes: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 00b732b4a36..d4fb49a8f50 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1584,7 +1584,6 @@ RSpec.describe API::Projects do expect(json_response['alt']).to eq("dk") expect(json_response['url']).to start_with("/uploads/") expect(json_response['url']).to end_with("/dk.png") - expect(json_response['full_path']).to start_with("/#{project.namespace.path}/#{project.path}/uploads") end @@ -1596,6 +1595,24 @@ RSpec.describe API::Projects do post api("/projects/#{project.id}/uploads", user), params: { file: file } end + it "does not leave the temporary file in place after uploading, even when the tempfile reaper does not run" do + stub_env('GITLAB_TEMPFILE_IMMEDIATE_UNLINK', '1') + tempfile = Tempfile.new('foo') + path = tempfile.path + + allow_any_instance_of(Rack::TempfileReaper).to receive(:call) do |instance, env| + instance.instance_variable_get(:@app).call(env) + end + + expect(path).not_to be(nil) + expect(Rack::Multipart::Parser::TEMPFILE_FACTORY).to receive(:call).and_return(tempfile) + + post api("/projects/#{project.id}/uploads", user), params: { file: fixture_file_upload("spec/fixtures/dk.png", "image/png") } + + expect(tempfile.path).to be(nil) + expect(File.exist?(path)).to be(false) + end + shared_examples 'capped upload attachments' do it "limits the upload to 1 GB" do expect_next_instance_of(UploadService) do |instance| diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb index 1bb260b5ea1..972caec6eb3 100644 --- a/spec/requests/rack_attack_global_spec.rb +++ b/spec/requests/rack_attack_global_spec.rb @@ -143,6 +143,31 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac end end + context 'when the request is to a container registry notification endpoint' do + let(:secret_token) { 'secret_token' } + let(:events) { [{ action: 'push' }] } + let(:registry_endpoint) { '/api/v4/container_registry_event/events' } + let(:registry_headers) { { 'Content-Type' => ::API::ContainerRegistryEvent::DOCKER_DISTRIBUTION_EVENTS_V1_JSON } } + + before do + allow(Gitlab.config.registry).to receive(:notification_secret) { secret_token } + + event = spy(:event) + allow(::ContainerRegistry::Event).to receive(:new).and_return(event) + allow(event).to receive(:supported?).and_return(true) + end + + it 'does not throttle the requests' do + (1 + requests_per_period).times do + post registry_endpoint, + params: { events: events }.to_json, + headers: registry_headers.merge('Authorization' => secret_token) + + expect(response).to have_gitlab_http_status(:ok) + end + end + end + it 'logs RackAttack info into structured logs' do requests_per_period.times do get url_that_does_not_require_authentication diff --git a/spec/services/ci/abort_pipelines_service_spec.rb b/spec/services/ci/abort_pipelines_service_spec.rb index b0f98e1266d..e31a45cb123 100644 --- a/spec/services/ci/abort_pipelines_service_spec.rb +++ b/spec/services/ci/abort_pipelines_service_spec.rb @@ -17,33 +17,38 @@ RSpec.describe Ci::AbortPipelinesService do describe '#execute' do def expect_correct_cancellations expect(cancelable_pipeline.finished_at).not_to be_nil - expect(cancelable_pipeline).to be_canceled - expect(cancelable_pipeline.stages - [non_cancelable_stage]).to all(be_canceled) - expect(cancelable_build).to be_canceled - - expect(manual_pipeline).not_to be_canceled - expect(non_cancelable_stage).not_to be_canceled - expect(non_cancelable_build).not_to be_canceled + expect(cancelable_pipeline.status).to eq('failed') + expect((cancelable_pipeline.stages - [non_cancelable_stage]).map(&:status)).to all(eq('failed')) + expect(cancelable_build.status).to eq('failed') + expect(cancelable_build.finished_at).not_to be_nil + + expect(manual_pipeline.status).not_to eq('failed') + expect(non_cancelable_stage.status).not_to eq('failed') + expect(non_cancelable_build.status).not_to eq('failed') end context 'with project pipelines' do - it 'cancels all running pipelines and related jobs' do - expect(described_class.new.execute(project.all_pipelines)).to be_success + def abort_project_pipelines + described_class.new.execute(project.all_pipelines, :project_deleted) + end + + it 'fails all running pipelines and related jobs' do + expect(abort_project_pipelines).to be_success expect_correct_cancellations - expect(other_users_pipeline).to be_canceled - expect(other_users_pipeline.stages).to all(be_canceled) + expect(other_users_pipeline.status).to eq('failed') + expect(other_users_pipeline.failure_reason).to eq('project_deleted') + expect(other_users_pipeline.stages.map(&:status)).to all(eq('failed')) end it 'avoids N+1 queries' do - project_pipelines = project.all_pipelines - control_count = ActiveRecord::QueryRecorder.new { described_class.new.execute(project_pipelines) }.count + control_count = ActiveRecord::QueryRecorder.new { abort_project_pipelines }.count pipelines = create_list(:ci_pipeline, 5, :running, project: project) create_list(:ci_build, 5, :running, pipeline: pipelines.first) - expect { described_class.new.execute(project_pipelines) }.not_to exceed_query_limit(control_count) + expect { abort_project_pipelines }.not_to exceed_query_limit(control_count) end context 'with live build logs' do @@ -51,11 +56,11 @@ RSpec.describe Ci::AbortPipelinesService do create(:ci_build_trace_chunk, build: cancelable_build) end - it 'makes canceled builds with stale trace visible' do + it 'makes failed builds with stale trace visible' do expect(Ci::Build.with_stale_live_trace.count).to eq 0 travel_to(2.days.ago) do - described_class.new.execute(project.all_pipelines) + abort_project_pipelines end expect(Ci::Build.with_stale_live_trace.count).to eq 1 @@ -64,22 +69,25 @@ RSpec.describe Ci::AbortPipelinesService do end context 'with user pipelines' do - it 'cancels all running pipelines and related jobs' do - expect(described_class.new.execute(user.pipelines)).to be_success + def abort_user_pipelines + described_class.new.execute(user.pipelines, :user_blocked) + end + + it 'fails all running pipelines and related jobs' do + expect(abort_user_pipelines).to be_success expect_correct_cancellations - expect(other_users_pipeline).not_to be_canceled + expect(other_users_pipeline.status).not_to eq('failed') end it 'avoids N+1 queries' do - user_pipelines = user.pipelines - control_count = ActiveRecord::QueryRecorder.new { described_class.new.execute(user_pipelines) }.count + control_count = ActiveRecord::QueryRecorder.new { abort_user_pipelines }.count pipelines = create_list(:ci_pipeline, 5, :running, project: project, user: user) create_list(:ci_build, 5, :running, pipeline: pipelines.first) - expect { described_class.new.execute(user_pipelines) }.not_to exceed_query_limit(control_count) + expect { abort_user_pipelines }.not_to exceed_query_limit(control_count) end end end diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 6debef81659..b2a68bbd0aa 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -109,7 +109,7 @@ RSpec.describe Projects::DestroyService, :aggregate_failures do pipelines = build_list(:ci_pipeline, 3, :running) allow(project).to receive(:all_pipelines).and_return(pipelines) - expect(::Ci::AbortPipelinesService).to receive_message_chain(:new, :execute).with(pipelines) + expect(::Ci::AbortPipelinesService).to receive_message_chain(:new, :execute).with(pipelines, :project_deleted) destroy_project(project, user, {}) end diff --git a/spec/support/shared_examples/controllers/snippet_shared_examples.rb b/spec/support/shared_examples/controllers/snippet_shared_examples.rb new file mode 100644 index 00000000000..f49cc979368 --- /dev/null +++ b/spec/support/shared_examples/controllers/snippet_shared_examples.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'snippets views' do + let(:params) { {} } + + before do + sign_in(user) + end + + context 'when rendered' do + render_views + + it 'avoids N+1 database queries' do + # Warming call to load everything non snippet related + get(:index, params: params) + + project = create(:project, namespace: user.namespace) + create(:project_snippet, project: project, author: user) + + control_count = ActiveRecord::QueryRecorder.new { get(:index, params: params) }.count + + project = create(:project, namespace: user.namespace) + create(:project_snippet, project: project, author: user) + + expect { get(:index, params: params) }.not_to exceed_query_limit(control_count) + end + end +end |