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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-12 18:09:30 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-12 18:09:30 +0300
commit3df6bfc24c8877b9442d567378b8ebd8816cd443 (patch)
tree2f6cf2e38866e10dc179c1892d37ae971af8d44f /spec
parentd7fd035dc387e9c2e5c31bbb53d867239689cfbf (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/dashboard/snippets_controller_spec.rb19
-rw-r--r--spec/controllers/explore/snippets_controller_spec.rb4
-rw-r--r--spec/controllers/projects/merge_requests/creations_controller_spec.rb32
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb4
-rw-r--r--spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb34
-rw-r--r--spec/fixtures/api/schemas/entities/member_user.json3
-rw-r--r--spec/frontend/projects/commit/components/branches_dropdown_spec.js6
-rw-r--r--spec/frontend/projects/commit/mock_data.js2
-rw-r--r--spec/frontend/projects/commit/store/mutations_spec.js6
-rw-r--r--spec/frontend/projects/commit_box/info/load_branches_spec.js6
-rw-r--r--spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb1
-rw-r--r--spec/graphql/types/global_id_type_spec.rb1
-rw-r--r--spec/graphql/types/snippet_type_spec.rb2
-rw-r--r--spec/lib/gitlab/middleware/rack_multipart_tempfile_factory_spec.rb94
-rw-r--r--spec/models/project_spec.rb65
-rw-r--r--spec/models/user_spec.rb2
-rw-r--r--spec/requests/api/project_attributes.yml1
-rw-r--r--spec/requests/api/projects_spec.rb19
-rw-r--r--spec/requests/rack_attack_global_spec.rb25
-rw-r--r--spec/services/ci/abort_pipelines_service_spec.rb52
-rw-r--r--spec/services/projects/destroy_service_spec.rb2
-rw-r--r--spec/support/shared_examples/controllers/snippet_shared_examples.rb28
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