create_service_spec.rb 11.9 KB
Newer Older
1 2
# frozen_string_literal: true

3 4
require 'spec_helper'

5
describe Projects::CreateService, '#execute' do
6
  include ExternalAuthorizationServiceHelpers
7 8
  include GitHelpers

9
  let(:gitlab_shell) { Gitlab::Shell.new }
S
Semyon Pupkov 已提交
10 11 12
  let(:user) { create :user }
  let(:opts) do
    {
13 14
      name: 'GitLab',
      namespace_id: user.namespace.id
S
Semyon Pupkov 已提交
15 16
    }
  end
17

S
Semyon Pupkov 已提交
18 19 20
  it 'creates labels on Project creation if there are templates' do
    Label.create(title: "bug", template: true)
    project = create_project(user, opts)
V
Valery Sizov 已提交
21

F
Felipe Artur 已提交
22 23 24 25 26
    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')
S
Semyon Pupkov 已提交
27
  end
V
Valery Sizov 已提交
28

S
Semyon Pupkov 已提交
29 30 31
  context 'user namespace' do
    it do
      project = create_project(user, opts)
32

S
Semyon Pupkov 已提交
33 34
      expect(project).to be_valid
      expect(project.owner).to eq(user)
35
      expect(project.team.maintainers).to include(user)
S
Semyon Pupkov 已提交
36
      expect(project.namespace).to eq(user.namespace)
37
    end
S
Semyon Pupkov 已提交
38
  end
39

A
Andreas Brandl 已提交
40 41 42 43 44 45 46 47
  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

48 49 50 51 52 53 54 55 56 57 58
  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)
59
      expect(project.team.maintainers).to contain_exactly(user)
60 61 62 63
      expect(project.namespace).to eq(user.namespace)
    end
  end

S
Semyon Pupkov 已提交
64 65 66 67 68 69
  context 'group namespace' do
    let(:group) do
      create(:group).tap do |group|
        group.add_owner(user)
      end
    end
70

S
Semyon Pupkov 已提交
71 72 73
    before do
      user.refresh_authorized_projects # Ensure cache is warm
    end
74

S
Semyon Pupkov 已提交
75 76
    it do
      project = create_project(user, opts.merge!(namespace_id: group.id))
77

S
Semyon Pupkov 已提交
78 79 80 81
      expect(project).to be_valid
      expect(project.owner).to eq(group)
      expect(project.namespace).to eq(group)
      expect(user.authorized_projects).to include(project)
82
    end
S
Semyon Pupkov 已提交
83
  end
84

S
Semyon Pupkov 已提交
85 86
  context 'error handling' do
    it 'handles invalid options' do
D
Douwe Maan 已提交
87
      opts[:default_branch] = 'master'
S
Semyon Pupkov 已提交
88
      expect(create_project(user, opts)).to eq(nil)
89
    end
90

91
    it 'sets invalid service as inactive' do
92 93 94
      create(:service, type: 'JiraService', project: nil, template: true, active: true)

      project = create_project(user, opts)
95
      service = project.services.first
96

97 98
      expect(project).to be_persisted
      expect(service.active).to be false
99
    end
S
Semyon Pupkov 已提交
100
  end
101

S
Semyon Pupkov 已提交
102 103 104 105
  context 'wiki_enabled creates repository directory' do
    context 'wiki_enabled true creates wiki repository directory' do
      it do
        project = create_project(user, opts)
D
Dmitriy Zaporozhets 已提交
106

107
        expect(wiki_repo(project).exists?).to be_truthy
D
Dmitriy Zaporozhets 已提交
108
      end
S
Semyon Pupkov 已提交
109
    end
D
Dmitriy Zaporozhets 已提交
110

S
Semyon Pupkov 已提交
111 112
    context 'wiki_enabled false does not create wiki repository directory' do
      it do
D
Douwe Maan 已提交
113
        opts[:wiki_enabled] = false
S
Semyon Pupkov 已提交
114
        project = create_project(user, opts)
D
Dmitriy Zaporozhets 已提交
115

116
        expect(wiki_repo(project).exists?).to be_falsey
D
Dmitriy Zaporozhets 已提交
117 118
      end
    end
119 120 121

    def wiki_repo(project)
      relative_path = ProjectWiki.new(project).disk_path + '.git'
122
      Gitlab::Git::Repository.new(project.repository_storage, relative_path, 'foobar', project.full_path)
123
    end
S
Semyon Pupkov 已提交
124
  end
125

126 127 128 129 130 131 132 133 134 135 136
  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

S
Semyon Pupkov 已提交
137 138
  context 'builds_enabled global setting' do
    let(:project) { create_project(user, opts) }
139

S
Semyon Pupkov 已提交
140
    subject { project.builds_enabled? }
141

S
Semyon Pupkov 已提交
142 143 144
    context 'global builds_enabled false does not enable CI by default' do
      before do
        project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
145 146
      end

S
Semyon Pupkov 已提交
147 148
      it { is_expected.to be_falsey }
    end
149

S
Semyon Pupkov 已提交
150 151
    context 'global builds_enabled true does enable CI by default' do
      it { is_expected.to be_truthy }
152
    end
S
Semyon Pupkov 已提交
153
  end
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
  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

S
Semyon Pupkov 已提交
182 183 184
  context 'restricted visibility level' do
    before do
      stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
185

S
Semyon Pupkov 已提交
186
      opts.merge!(
187
        visibility_level: Gitlab::VisibilityLevel::PUBLIC
S
Semyon Pupkov 已提交
188 189
      )
    end
190

S
Semyon Pupkov 已提交
191 192 193 194 195 196 197 198
    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
199

S
Semyon Pupkov 已提交
200 201 202
    it 'allows a restricted visibility level for admins' do
      admin = create(:admin)
      project = create_project(admin, opts)
203

S
Semyon Pupkov 已提交
204 205
      expect(project.errors.any?).to be(false)
      expect(project.saved?).to be(true)
206
    end
S
Semyon Pupkov 已提交
207
  end
208

S
Semyon Pupkov 已提交
209 210 211
  context 'repository creation' do
    it 'synchronously creates the repository' do
      expect_any_instance_of(Project).to receive(:create_repository)
212

S
Semyon Pupkov 已提交
213 214 215 216
      project = create_project(user, opts)
      expect(project).to be_valid
      expect(project.owner).to eq(user)
      expect(project.namespace).to eq(user.namespace)
217
    end
218 219

    context 'when another repository already exists on disk' do
220 221
      let(:repository_storage) { 'default' }

222 223 224 225 226 227 228
      let(:opts) do
        {
          name: 'Existing',
          namespace_id: user.namespace.id
        }
      end

229 230
      context 'with legacy storage' do
        before do
231
          stub_application_setting(hashed_storage_enabled: false)
232
          gitlab_shell.create_repository(repository_storage, "#{user.namespace.full_path}/existing", 'group/project')
233
        end
234

235
        after do
236
          gitlab_shell.remove_repository(repository_storage, "#{user.namespace.full_path}/existing")
237
        end
238

239 240
        it 'does not allow to create a project when path matches existing repository on disk' do
          project = create_project(user, opts)
241

242 243 244 245 246
          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
247

248 249 250 251 252 253 254 255
        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
256 257
      end

258 259 260 261 262 263 264 265 266
      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
267
          gitlab_shell.create_repository(repository_storage, hashed_path, 'group/project')
268 269 270
        end

        after do
271
          gitlab_shell.remove_repository(repository_storage, hashed_path)
272 273 274 275
        end

        it 'does not allow to create a project when path matches existing repository on disk' do
          project = create_project(user, opts)
276

277 278 279 280 281
          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
282 283
      end
    end
S
Semyon Pupkov 已提交
284
  end
285

286 287 288 289 290 291 292 293 294 295 296 297
  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

S
Semyon Pupkov 已提交
298 299 300 301
  context 'when there is an active service template' do
    before do
      create(:service, project: nil, template: true, active: true)
    end
302

S
Semyon Pupkov 已提交
303 304
    it 'creates a service from this template' do
      project = create_project(user, opts)
305

S
Semyon Pupkov 已提交
306
      expect(project.services.count).to eq 1
307
    end
308 309
  end

310
  context 'when a bad service template is created' do
311
    it 'sets service to be inactive' do
312
      opts[:import_url] = 'http://www.gitlab.com/gitlab-org/gitlab-ce'
313 314
      create(:service, type: 'DroneCiService', project: nil, template: true, active: true)

315
      project = create_project(user, opts)
316
      service = project.services.first
317

318 319
      expect(project).to be_persisted
      expect(service.active).to be false
320 321 322
    end
  end

S
Stan Hu 已提交
323 324 325 326 327 328 329 330 331
  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

332 333 334 335 336 337 338 339 340 341 342
  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

343 344
  it 'writes project full path to .git/config' do
    project = create_project(user, opts)
345
    rugged = rugged_repo(project.repository)
346

347
    expect(rugged.config['gitlab.fullpath']).to eq project.full_path
348 349
  end

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
  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

386
  def create_project(user, opts)
387
    Projects::CreateService.new(user, opts).execute
388 389
  end
end