gitlab-org--gitlab-foss/spec/services/projects/destroy_service_spec.rb
Stan Hu 45f94ea78c Prevent project team from being truncated too early during project destruction
There are two issues with truncating the project team early:

1. `Projects::UnlinkForkService` may not close merge requests properly since
   permissions may be revoked early.

2. If an error is encountered during flushing of caches, then the user will
   lose all privileges, possibly causing an issue on deletion on retry.
2017-02-19 05:00:27 -08:00

122 lines
3.6 KiB
Ruby

require 'spec_helper'
describe Projects::DestroyService, services: true do
let!(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace) }
let!(:path) { project.repository.path_to_repo }
let!(:remove_path) { path.sub(/\.git\Z/, "+#{project.id}+deleted.git") }
let!(:async) { false } # execute or async_execute
shared_examples 'deleting the project' do
it 'deletes the project' do
expect(Project.unscoped.all).not_to include(project)
expect(Dir.exist?(path)).to be_falsey
expect(Dir.exist?(remove_path)).to be_falsey
end
end
shared_examples 'deleting the project with pipeline and build' do
context 'with pipeline and build' do # which has optimistic locking
let!(:pipeline) { create(:ci_pipeline, project: project) }
let!(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
before do
perform_enqueued_jobs do
destroy_project(project, user, {})
end
end
it_behaves_like 'deleting the project'
end
end
context 'Sidekiq inline' do
before do
# Run sidekiq immediatly to check that renamed repository will be removed
Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
end
it_behaves_like 'deleting the project'
end
context 'Sidekiq fake' do
before do
# Dont run sidekiq to check if renamed repository exists
Sidekiq::Testing.fake! { destroy_project(project, user, {}) }
end
it { expect(Project.all).not_to include(project) }
it { expect(Dir.exist?(path)).to be_falsey }
it { expect(Dir.exist?(remove_path)).to be_truthy }
end
context 'when flushing caches fail' do
before do
new_user = create(:user)
project.team.add_user(new_user, Gitlab::Access::DEVELOPER)
allow_any_instance_of(Projects::DestroyService).to receive(:flush_caches).and_raise(Redis::CannotConnectError)
end
it 'keeps project team intact upon an error' do
Sidekiq::Testing.inline! do
begin
destroy_project(project, user, {})
rescue Redis::CannotConnectError
end
end
expect(project.team.members.count).to eq 1
end
end
context 'with async_execute' do
let(:async) { true }
context 'async delete of project with private issue visibility' do
before do
project.project_feature.update_attribute("issues_access_level", ProjectFeature::PRIVATE)
# Run sidekiq immediately to check that renamed repository will be removed
Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
end
it_behaves_like 'deleting the project'
end
it_behaves_like 'deleting the project with pipeline and build'
end
context 'with execute' do
it_behaves_like 'deleting the project with pipeline and build'
end
context 'container registry' do
before do
stub_container_registry_config(enabled: true)
stub_container_registry_tags('tag')
end
context 'tags deletion succeeds' do
it do
expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete).and_return(true)
destroy_project(project, user, {})
end
end
context 'tags deletion fails' do
before { expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete).and_return(false) }
subject { destroy_project(project, user, {}) }
it { expect{subject}.to raise_error(Projects::DestroyService::DestroyError) }
end
end
def destroy_project(project, user, params)
if async
Projects::DestroyService.new(project, user, params).async_execute
else
Projects::DestroyService.new(project, user, params).execute
end
end
end