gitlab-org--gitlab-foss/spec/services/projects/create_service_spec.rb
Luke Duncalfe 37b17fa61a Add service classes for mutating AwardEmoji
Adding, destroying and toggling emoji previously lacked services and
instead were performed through methods called on Awardable models.

This led to inconsistencies where relevant todos would be marked as done
only when emoji were awarded through our controllers, but not through
the API. Todos could also be marked as done when an emoji was being
removed.

Behaviour changes

- Awarding emoji through the API will now mark a relevant Todo as done
- Toggling an emoji off (destroying it) through our controllers will no
  longer mark a relevant Todo as done

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/63372
2019-08-21 11:39:41 +12:00

390 lines
12 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
describe Projects::CreateService, '#execute' do
include ExternalAuthorizationServiceHelpers
include GitHelpers
let(:gitlab_shell) { Gitlab::Shell.new }
let(:user) { create :user }
let(:opts) do
{
name: 'GitLab',
namespace_id: user.namespace.id
}
end
it 'creates labels on Project creation if there are templates' do
Label.create(title: "bug", template: true)
project = create_project(user, opts)
created_label = project.reload.labels.last
expect(created_label.type).to eq('ProjectLabel')
expect(created_label.project_id).to eq(project.id)
expect(created_label.title).to eq('bug')
end
context 'user namespace' do
it do
project = create_project(user, opts)
expect(project).to be_valid
expect(project.owner).to eq(user)
expect(project.team.maintainers).to include(user)
expect(project.namespace).to eq(user.namespace)
end
end
describe 'after create actions' do
it 'invalidate personal_projects_count caches' do
expect(user).to receive(:invalidate_personal_projects_count)
create_project(user, opts)
end
end
context "admin creates project with other user's namespace_id" do
it 'sets the correct permissions' do
admin = create(:admin)
opts = {
name: 'GitLab',
namespace_id: user.namespace.id
}
project = create_project(admin, opts)
expect(project).to be_persisted
expect(project.owner).to eq(user)
expect(project.team.maintainers).to contain_exactly(user)
expect(project.namespace).to eq(user.namespace)
end
end
context 'group namespace' do
let(:group) do
create(:group).tap do |group|
group.add_owner(user)
end
end
before do
user.refresh_authorized_projects # Ensure cache is warm
end
it do
project = create_project(user, opts.merge!(namespace_id: group.id))
expect(project).to be_valid
expect(project.owner).to eq(group)
expect(project.namespace).to eq(group)
expect(project.team.owners).to include(user)
expect(user.authorized_projects).to include(project)
end
end
context 'error handling' do
it 'handles invalid options' do
opts[:default_branch] = 'master'
expect(create_project(user, opts)).to eq(nil)
end
it 'sets invalid service as inactive' do
create(:service, type: 'JiraService', project: nil, template: true, active: true)
project = create_project(user, opts)
service = project.services.first
expect(project).to be_persisted
expect(service.active).to be false
end
end
context 'wiki_enabled creates repository directory' do
context 'wiki_enabled true creates wiki repository directory' do
it do
project = create_project(user, opts)
expect(wiki_repo(project).exists?).to be_truthy
end
end
context 'wiki_enabled false does not create wiki repository directory' do
it do
opts[:wiki_enabled] = false
project = create_project(user, opts)
expect(wiki_repo(project).exists?).to be_falsey
end
end
def wiki_repo(project)
relative_path = ProjectWiki.new(project).disk_path + '.git'
Gitlab::Git::Repository.new(project.repository_storage, relative_path, 'foobar', project.full_path)
end
end
context 'import data' do
it 'stores import data and URL' do
import_data = { data: { 'test' => 'some data' } }
project = create_project(user, { name: 'test', import_url: 'http://import-url', import_data: import_data })
expect(project.import_data).to be_persisted
expect(project.import_data.data).to eq(import_data[:data])
expect(project.import_url).to eq('http://import-url')
end
end
context 'builds_enabled global setting' do
let(:project) { create_project(user, opts) }
subject { project.builds_enabled? }
context 'global builds_enabled false does not enable CI by default' do
before do
project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
end
it { is_expected.to be_falsey }
end
context 'global builds_enabled true does enable CI by default' do
it { is_expected.to be_truthy }
end
end
context 'default visibility level' do
let(:group) { create(:group, :private) }
before do
stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL)
group.add_developer(user)
opts.merge!(
visibility: 'private',
name: 'test',
namespace: group,
path: 'foo'
)
end
it 'creates a private project' do
project = create_project(user, opts)
expect(project).to respond_to(:errors)
expect(project.errors.any?).to be(false)
expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
expect(project.saved?).to be(true)
expect(project.valid?).to be(true)
end
end
context 'restricted visibility level' do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
opts.merge!(
visibility_level: Gitlab::VisibilityLevel::PUBLIC
)
end
it 'does not allow a restricted visibility level for non-admins' do
project = create_project(user, opts)
expect(project).to respond_to(:errors)
expect(project.errors.messages).to have_key(:visibility_level)
expect(project.errors.messages[:visibility_level].first).to(
match('restricted by your GitLab administrator')
)
end
it 'allows a restricted visibility level for admins' do
admin = create(:admin)
project = create_project(admin, opts)
expect(project.errors.any?).to be(false)
expect(project.saved?).to be(true)
end
end
context 'repository creation' do
it 'synchronously creates the repository' do
expect_any_instance_of(Project).to receive(:create_repository)
project = create_project(user, opts)
expect(project).to be_valid
expect(project.owner).to eq(user)
expect(project.namespace).to eq(user.namespace)
end
context 'when another repository already exists on disk' do
let(:repository_storage) { 'default' }
let(:opts) do
{
name: 'Existing',
namespace_id: user.namespace.id
}
end
context 'with legacy storage' do
before do
stub_application_setting(hashed_storage_enabled: false)
gitlab_shell.create_repository(repository_storage, "#{user.namespace.full_path}/existing", 'group/project')
end
after do
gitlab_shell.remove_repository(repository_storage, "#{user.namespace.full_path}/existing")
end
it 'does not allow to create a project when path matches existing repository on disk' do
project = create_project(user, opts)
expect(project).not_to be_persisted
expect(project).to respond_to(:errors)
expect(project.errors.messages).to have_key(:base)
expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
end
it 'does not allow to import project when path matches existing repository on disk' do
project = create_project(user, opts.merge({ import_url: 'https://gitlab.com/gitlab-org/gitlab-test.git' }))
expect(project).not_to be_persisted
expect(project).to respond_to(:errors)
expect(project.errors.messages).to have_key(:base)
expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
end
end
context 'with hashed storage' do
let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
let(:hashed_path) { '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
before do
allow(Digest::SHA2).to receive(:hexdigest) { hash }
end
before do
gitlab_shell.create_repository(repository_storage, hashed_path, 'group/project')
end
after do
gitlab_shell.remove_repository(repository_storage, hashed_path)
end
it 'does not allow to create a project when path matches existing repository on disk' do
project = create_project(user, opts)
expect(project).not_to be_persisted
expect(project).to respond_to(:errors)
expect(project.errors.messages).to have_key(:base)
expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
end
end
end
end
context 'when readme initialization is requested' do
it 'creates README.md' do
opts[:initialize_with_readme] = '1'
project = create_project(user, opts)
expect(project.repository.commit_count).to be(1)
expect(project.repository.readme.name).to eql('README.md')
expect(project.repository.readme.data).to include('# GitLab')
end
end
context 'when there is an active service template' do
before do
create(:service, project: nil, template: true, active: true)
end
it 'creates a service from this template' do
project = create_project(user, opts)
expect(project.services.count).to eq 1
end
end
context 'when a bad service template is created' do
it 'sets service to be inactive' do
opts[:import_url] = 'http://www.gitlab.com/gitlab-org/gitlab-ce'
create(:service, type: 'DroneCiService', project: nil, template: true, active: true)
project = create_project(user, opts)
service = project.services.first
expect(project).to be_persisted
expect(service.active).to be false
end
end
context 'when skip_disk_validation is used' do
it 'sets the project attribute' do
opts[:skip_disk_validation] = true
project = create_project(user, opts)
expect(project.skip_disk_validation).to be_truthy
end
end
it 'calls the passed block' do
fake_block = double('block')
opts[:relations_block] = fake_block
expect_next_instance_of(Project) do |project|
expect(fake_block).to receive(:call).with(project)
end
create_project(user, opts)
end
it 'writes project full path to .git/config' do
project = create_project(user, opts)
rugged = rugged_repo(project.repository)
expect(rugged.config['gitlab.fullpath']).to eq project.full_path
end
context 'with external authorization enabled' do
before do
enable_external_authorization_service_check
end
it 'does not save the project with an error if the service denies access' do
expect(::Gitlab::ExternalAuthorization)
.to receive(:access_allowed?).with(user, 'new-label', any_args) { false }
project = create_project(user, opts.merge({ external_authorization_classification_label: 'new-label' }))
expect(project.errors[:external_authorization_classification_label]).to be_present
expect(project).not_to be_persisted
end
it 'saves the project when the user has access to the label' do
expect(::Gitlab::ExternalAuthorization)
.to receive(:access_allowed?).with(user, 'new-label', any_args) { true }
project = create_project(user, opts.merge({ external_authorization_classification_label: 'new-label' }))
expect(project).to be_persisted
expect(project.external_authorization_classification_label).to eq('new-label')
end
it 'does not save the project when the user has no access to the default label and no label is provided' do
expect(::Gitlab::ExternalAuthorization)
.to receive(:access_allowed?).with(user, 'default_label', any_args) { false }
project = create_project(user, opts)
expect(project.errors[:external_authorization_classification_label]).to be_present
expect(project).not_to be_persisted
end
end
def create_project(user, opts)
Projects::CreateService.new(user, opts).execute
end
end