gitlab-org--gitlab-foss/spec/services/projects/destroy_service_spec.rb
Stan Hu fea80aa12d Fix project deletion when feature visibility is set to private
Projects that are destroyed are put in the pending_delete state.
The ProjectDestroyWorker checks whether the current user has
access, but since the ProjectFeature class uses the default scope
of the Project, it will not be able to find the right project.

This was a regression in 8.12 that caused the following stack trace:

```
NoMethodError: undefined method `team' for nil:NilClass
  from app/models/project_feature.rb:62:in `get_permission'
  from app/models/project_feature.rb:34:in `feature_available?'
  from app/models/project.rb:21:in `feature_available?'
  from app/policies/project_policy.rb:170:in `disabled_features!'
  from app/policies/project_policy.rb:29:in `rules'
  from app/policies/base_policy.rb:82:in `block in abilities'
  from app/policies/base_policy.rb:113:in `collect_rules'
  from app/policies/base_policy.rb:82:in `abilities'
  from app/policies/base_policy.rb:50:in `abilities'
  from app/models/ability.rb:64:in `uncached_allowed'
  from app/models/ability.rb:58:in `allowed'
  from app/models/ability.rb:49:in `allowed?'
  from app/services/base_service.rb:11:in `can?'
  from lib/gitlab/metrics/instrumentation.rb:155:in `block in can?'
  from lib/gitlab/metrics/method_call.rb:23:in `measure'
  from lib/gitlab/metrics/instrumentation.rb:155:in `can?'
  from app/services/projects/destroy_service.rb:18:in `execute'
```

Closes #22948
2016-10-04 20:53:15 -07:00

78 lines
2.4 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
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 { expect(Project.all).not_to include(project) }
it { expect(Dir.exist?(path)).to be_falsey }
it { expect(Dir.exist?(remove_path)).to be_falsey }
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 'async delete of project with private issue visibility' do
let!(:async) { true }
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 'deletes the project' do
expect(Project.all).not_to include(project)
expect(Dir.exist?(path)).to be_falsey
expect(Dir.exist?(remove_path)).to be_falsey
end
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