projects_spec.rb 29.8 KB
Newer Older
1
# -*- coding: utf-8 -*-
Nihad Abbasov's avatar
Nihad Abbasov committed
2 3
require 'spec_helper'

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
4
describe API::API, api: true  do
5
  include ApiHelpers
6
  include Gitlab::CurrentSettings
7 8 9
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
  let(:user3) { create(:user) }
Angus MacArthur's avatar
Angus MacArthur committed
10
  let(:admin) { create(:admin) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
11
  let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
12 13
  let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) }
  let(:project3) { create(:project, path: 'project3', creator_id: user.id, namespace: user.namespace) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
14
  let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
15 16
  let(:project_member) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) }
  let(:project_member2) { create(:project_member, user: user3, project: project, access_level: ProjectMember::DEVELOPER) }
17
  let(:user4) { create(:user) }
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
  let(:project3) do
    create(:project,
    name: 'second_project',
    path: 'second_project',
    creator_id: user.id,
    namespace: user.namespace,
    merge_requests_enabled: false,
    issues_enabled: false, wiki_enabled: false,
    snippets_enabled: false, visibility_level: 0)
  end
  let(:project_member3) do
    create(:project_member,
    user: user4,
    project: project3,
    access_level: ProjectMember::MASTER)
  end
  let(:project4) do
    create(:project,
    name: 'third_project',
    path: 'third_project',
    creator_id: user4.id,
    namespace: user4.namespace)
  end

  describe 'GET /projects' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
43 44
    before { project }

45 46 47
    context 'when unauthenticated' do
      it 'should return authentication error' do
        get api('/projects')
48
        expect(response.status).to eq(401)
49
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
50 51
    end

52 53 54
    context 'when authenticated' do
      it 'should return an array of projects' do
        get api('/projects', user)
55 56 57 58
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
        expect(json_response.first['name']).to eq(project.name)
        expect(json_response.first['owner']['username']).to eq(user.username)
Nihad Abbasov's avatar
Nihad Abbasov committed
59
      end
60 61 62 63 64 65 66 67
      
      it 'should include the project labels as the tag_list' do
        get api('/projects', user)
        response.status.should == 200
        json_response.should be_an Array
        json_response.first.keys.should include('tag_list')
      end
      
68 69 70
      context 'and using search' do
        it 'should return searched project' do
          get api('/projects', user), { search: project.name }
71 72 73
          expect(response.status).to eq(200)
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
74 75 76
        end
      end

77
      context 'and using sorting' do
78 79 80 81 82
        before do
          project2
          project3
        end

83 84
        it 'should return the correct order when sorted by id' do
          get api('/projects', user), { order_by: 'id', sort: 'desc'}
85 86 87
          expect(response.status).to eq(200)
          expect(json_response).to be_an Array
          expect(json_response.first['id']).to eq(project3.id)
88
        end
89 90 91 92 93 94 95 96 97

        it 'returns projects in the correct order when ci_enabled_first parameter is passed' do
          [project, project2, project3].each{ |project| project.build_missing_services }
          project2.gitlab_ci_service.update(active: true, token: "token", project_url: "url")
          get api('/projects', user), { ci_enabled_first: 'true'}
          expect(response.status).to eq(200)
          expect(json_response).to be_an Array
          expect(json_response.first['id']).to eq(project2.id)
        end
98
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
99 100 101
    end
  end

102
  describe 'GET /projects/all' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
103 104
    before { project }

105 106 107
    context 'when unauthenticated' do
      it 'should return authentication error' do
        get api('/projects/all')
108
        expect(response.status).to eq(401)
109 110 111
      end
    end

112 113 114
    context 'when authenticated as regular user' do
      it 'should return authentication error' do
        get api('/projects/all', user)
115
        expect(response.status).to eq(403)
116 117 118
      end
    end

119 120 121
    context 'when authenticated as admin' do
      it 'should return an array of all projects' do
        get api('/projects/all', admin)
122 123
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
Marin Jankovski's avatar
Marin Jankovski committed
124 125
        project_name = project.name

126
        expect(json_response.detect {
Marin Jankovski's avatar
Marin Jankovski committed
127
          |project| project['name'] == project_name
128
        }['name']).to eq(project_name)
Marin Jankovski's avatar
Marin Jankovski committed
129

130
        expect(json_response.detect {
Marin Jankovski's avatar
Marin Jankovski committed
131
          |project| project['owner']['username'] == user.username
132
        }['owner']['username']).to eq(user.username)
133 134 135 136
      end
    end
  end

137 138
  describe 'POST /projects' do
    context 'maximum number of projects reached' do
139
      it 'should not create new project and respond with 403' do
140
        allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
141
        expect {
142
          post api('/projects', user2), name: 'foo'
143
        }.to change {Project.count}.by(0)
144
        expect(response.status).to eq(403)
145 146 147
      end
    end

148 149 150
    it 'should create new project without path and return 201' do
      expect { post api('/projects', user), name: 'foo' }.
        to change { Project.count }.by(1)
151
      expect(response.status).to eq(201)
152 153
    end

154
    it 'should create last project before reaching project limit' do
155
      allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1)
156
      post api('/projects', user2), name: 'foo'
157
      expect(response.status).to eq(201)
158 159
    end

160 161
    it 'should not create new project without name and return 400' do
      expect { post api('/projects', user) }.to_not change { Project.count }
162
      expect(response.status).to eq(400)
163
    end
Alex Denisov's avatar
Alex Denisov committed
164

165
    it "should assign attributes to project" do
166
      project = attributes_for(:project, {
167
        path: 'camelCasePath',
Robert Speicher's avatar
Robert Speicher committed
168
        description: FFaker::Lorem.sentence,
169 170 171
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Alex Denisov's avatar
Alex Denisov committed
172 173
      })

174
      post api('/projects', user), project
Alex Denisov's avatar
Alex Denisov committed
175

176
      project.each_pair do |k,v|
177
        expect(json_response[k.to_s]).to eq(v)
Alex Denisov's avatar
Alex Denisov committed
178
      end
179
    end
180

181
    it 'should set a project as public' do
182
      project = attributes_for(:project, :public)
183
      post api('/projects', user), project
184 185
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
186 187
    end

188
    it 'should set a project as public using :public' do
189
      project = attributes_for(:project, { public: true })
190
      post api('/projects', user), project
191 192
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
193 194
    end

195
    it 'should set a project as internal' do
196
      project = attributes_for(:project, :internal)
197
      post api('/projects', user), project
198 199
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
200 201
    end

202
    it 'should set a project as internal overriding :public' do
203
      project = attributes_for(:project, :internal, { public: true })
204
      post api('/projects', user), project
205 206
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
207 208
    end

209
    it 'should set a project as private' do
210
      project = attributes_for(:project, :private)
211
      post api('/projects', user), project
212 213
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
214 215
    end

216
    it 'should set a project as private using :public' do
217
      project = attributes_for(:project, { public: false })
218
      post api('/projects', user), project
219 220
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
221
    end
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

    context 'when a visibility level is restricted' do
      before do
        @project = attributes_for(:project, { public: true })
        allow_any_instance_of(ApplicationSetting).to(
          receive(:restricted_visibility_levels).and_return([20])
        )
      end

      it 'should not allow a non-admin to use a restricted visibility level' do
        post api('/projects', user), @project
        expect(response.status).to eq(400)
        expect(json_response['message']['visibility_level'].first).to(
          match('restricted by your GitLab administrator')
        )
      end

      it 'should allow an admin to override restricted visibility settings' do
        post api('/projects', admin), @project
        expect(json_response['public']).to be_truthy
        expect(json_response['visibility_level']).to(
          eq(Gitlab::VisibilityLevel::PUBLIC)
        )
      end
    end
247 248
  end

249
  describe 'POST /projects/user/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
250
    before { project }
Angus MacArthur's avatar
Angus MacArthur committed
251 252
    before { admin }

253
    it 'should create new project without path and return 201' do
254
      expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
255
      expect(response.status).to eq(201)
Angus MacArthur's avatar
Angus MacArthur committed
256 257
    end

258 259 260 261
    it 'should respond with 400 on failure and not project' do
      expect { post api("/projects/user/#{user.id}", admin) }.
        to_not change { Project.count }

262 263
      expect(response.status).to eq(400)
      expect(json_response['message']['name']).to eq([
264 265
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
266
        Gitlab::Regex.project_name_regex_message
267 268
      ])
      expect(json_response['message']['path']).to eq([
269 270
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
271
        Gitlab::Regex.send(:project_path_regex_message)
272
      ])
Angus MacArthur's avatar
Angus MacArthur committed
273 274
    end

275
    it 'should assign attributes to project' do
Angus MacArthur's avatar
Angus MacArthur committed
276
      project = attributes_for(:project, {
Robert Speicher's avatar
Robert Speicher committed
277
        description: FFaker::Lorem.sentence,
278 279 280
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Angus MacArthur's avatar
Angus MacArthur committed
281 282 283 284
      })

      post api("/projects/user/#{user.id}", admin), project

285
      project.each_pair do |k,v|
Angus MacArthur's avatar
Angus MacArthur committed
286
        next if k == :path
287
        expect(json_response[k.to_s]).to eq(v)
Angus MacArthur's avatar
Angus MacArthur committed
288 289
      end
    end
290

291
    it 'should set a project as public' do
292
      project = attributes_for(:project, :public)
293
      post api("/projects/user/#{user.id}", admin), project
294 295
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
296 297
    end

298
    it 'should set a project as public using :public' do
299 300
      project = attributes_for(:project, { public: true })
      post api("/projects/user/#{user.id}", admin), project
301 302
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
303
    end
304

305
    it 'should set a project as internal' do
306
      project = attributes_for(:project, :internal)
307
      post api("/projects/user/#{user.id}", admin), project
308 309
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
310 311
    end

312
    it 'should set a project as internal overriding :public' do
313
      project = attributes_for(:project, :internal, { public: true })
314
      post api("/projects/user/#{user.id}", admin), project
315 316
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
317
    end
318

319
    it 'should set a project as private' do
320
      project = attributes_for(:project, :private)
321
      post api("/projects/user/#{user.id}", admin), project
322 323
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
324 325
    end

326
    it 'should set a project as private using :public' do
327 328
      project = attributes_for(:project, { public: false })
      post api("/projects/user/#{user.id}", admin), project
329 330
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
331
    end
Angus MacArthur's avatar
Angus MacArthur committed
332 333
  end

334
  describe 'GET /projects/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
335
    before { project }
336
    before { project_member }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
337

338
    it 'should return a project by id' do
Robert Speicher's avatar
Robert Speicher committed
339
      get api("/projects/#{project.id}", user)
340 341 342
      expect(response.status).to eq(200)
      expect(json_response['name']).to eq(project.name)
      expect(json_response['owner']['username']).to eq(user.username)
Nihad Abbasov's avatar
Nihad Abbasov committed
343
    end
344

345
    it 'should return a project by path name' do
346
      get api("/projects/#{project.id}", user)
347 348
      expect(response.status).to eq(200)
      expect(json_response['name']).to eq(project.name)
349
    end
350

351 352
    it 'should return a 404 error if not found' do
      get api('/projects/42', user)
353 354
      expect(response.status).to eq(404)
      expect(json_response['message']).to eq('404 Project Not Found')
355
    end
356

357
    it 'should return a 404 error if user is not a member' do
358 359
      other_user = create(:user)
      get api("/projects/#{project.id}", other_user)
360
      expect(response.status).to eq(404)
361
    end
362 363 364

    describe 'permissions' do
      context 'personal project' do
365
        it 'Sets project access and returns 200' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
366 367
          project.team << [user, :master]
          get api("/projects/#{project.id}", user)
368

369 370 371 372 373
          expect(response.status).to eq(200)
          expect(json_response['permissions']['project_access']['access_level']).
            to eq(Gitlab::Access::MASTER)
          expect(json_response['permissions']['group_access']).to be_nil
        end
374 375 376
      end

      context 'group project' do
377
        it 'should set the owner and return 200' do
378 379 380 381
          project2 = create(:project, group: create(:group))
          project2.group.add_owner(user)
          get api("/projects/#{project2.id}", user)

382 383 384 385 386
          expect(response.status).to eq(200)
          expect(json_response['permissions']['project_access']).to be_nil
          expect(json_response['permissions']['group_access']['access_level']).
            to eq(Gitlab::Access::OWNER)
        end
387 388
      end
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
389 390
  end

391
  describe 'GET /projects/:id/events' do
Douwe Maan's avatar
Douwe Maan committed
392
    before { project_member2 }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
393

394
    it 'should return a project events' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
395
      get api("/projects/#{project.id}/events", user)
396
      expect(response.status).to eq(200)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
397 398
      json_event = json_response.first

399 400
      expect(json_event['action_name']).to eq('joined')
      expect(json_event['project_id'].to_i).to eq(project.id)
Douwe Maan's avatar
Douwe Maan committed
401
      expect(json_event['author_username']).to eq(user3.username)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
402 403
    end

404 405
    it 'should return a 404 error if not found' do
      get api('/projects/42/events', user)
406 407
      expect(response.status).to eq(404)
      expect(json_response['message']).to eq('404 Project Not Found')
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
408 409
    end

410
    it 'should return a 404 error if user is not a member' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
411 412
      other_user = create(:user)
      get api("/projects/#{project.id}/events", other_user)
413
      expect(response.status).to eq(404)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
414 415 416
    end
  end

417
  describe 'GET /projects/:id/snippets' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
418 419
    before { snippet }

420
    it 'should return an array of project snippets' do
421
      get api("/projects/#{project.id}/snippets", user)
422 423 424
      expect(response.status).to eq(200)
      expect(json_response).to be_an Array
      expect(json_response.first['title']).to eq(snippet.title)
425 426 427
    end
  end

428 429
  describe 'GET /projects/:id/snippets/:snippet_id' do
    it 'should return a project snippet' do
430
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
431 432
      expect(response.status).to eq(200)
      expect(json_response['title']).to eq(snippet.title)
Nihad Abbasov's avatar
Nihad Abbasov committed
433
    end
434

435
    it 'should return a 404 error if snippet id not found' do
436
      get api("/projects/#{project.id}/snippets/1234", user)
437
      expect(response.status).to eq(404)
438
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
439 440
  end

441 442
  describe 'POST /projects/:id/snippets' do
    it 'should create a new project snippet' do
443
      post api("/projects/#{project.id}/snippets", user),
444 445
        title: 'api test', file_name: 'sample.rb', code: 'test',
        visibility_level: '0'
446 447
      expect(response.status).to eq(201)
      expect(json_response['title']).to eq('api test')
Nihad Abbasov's avatar
Nihad Abbasov committed
448
    end
449

450 451 452
    it 'should return a 400 error if invalid snippet is given' do
      post api("/projects/#{project.id}/snippets", user)
      expect(status).to eq(400)
453
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
454 455
  end

456 457
  describe 'PUT /projects/:id/snippets/:shippet_id' do
    it 'should update an existing project snippet' do
458
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
459
        code: 'updated code'
460 461 462
      expect(response.status).to eq(200)
      expect(json_response['title']).to eq('example')
      expect(snippet.reload.content).to eq('updated code')
463
    end
464

465
    it 'should update an existing project snippet with new title' do
466
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
467
        title: 'other api test'
468 469
      expect(response.status).to eq(200)
      expect(json_response['title']).to eq('other api test')
470
    end
471 472
  end

473
  describe 'DELETE /projects/:id/snippets/:snippet_id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
474 475
    before { snippet }

476
    it 'should delete existing project snippet' do
Nihad Abbasov's avatar
Nihad Abbasov committed
477
      expect {
478
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
479
      }.to change { Snippet.count }.by(-1)
480
      expect(response.status).to eq(200)
481 482
    end

483
    it 'should return 404 when deleting unknown snippet id' do
484
      delete api("/projects/#{project.id}/snippets/1234", user)
485
      expect(response.status).to eq(404)
Nihad Abbasov's avatar
Nihad Abbasov committed
486 487
    end
  end
488

489 490
  describe 'GET /projects/:id/snippets/:snippet_id/raw' do
    it 'should get a raw project snippet' do
491
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
492
      expect(response.status).to eq(200)
493
    end
494

495
    it 'should return a 404 error if raw project snippet not found' do
496
      get api("/projects/#{project.id}/snippets/5555/raw", user)
497
      expect(response.status).to eq(404)
498
    end
499
  end
500

501 502 503
  describe :deploy_keys do
    let(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
    let(:deploy_key) { deploy_keys_project.deploy_key }
Matt Humphrey's avatar
Matt Humphrey committed
504

505
    describe 'GET /projects/:id/keys' do
506
      before { deploy_key }
Matt Humphrey's avatar
Matt Humphrey committed
507

508
      it 'should return array of ssh keys' do
509
        get api("/projects/#{project.id}/keys", user)
510 511 512
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
        expect(json_response.first['title']).to eq(deploy_key.title)
513
      end
Matt Humphrey's avatar
Matt Humphrey committed
514 515
    end

516 517
    describe 'GET /projects/:id/keys/:key_id' do
      it 'should return a single key' do
518
        get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
519 520
        expect(response.status).to eq(200)
        expect(json_response['title']).to eq(deploy_key.title)
521
      end
Matt Humphrey's avatar
Matt Humphrey committed
522

523
      it 'should return 404 Not Found with invalid ID' do
524
        get api("/projects/#{project.id}/keys/404", user)
525
        expect(response.status).to eq(404)
526
      end
Matt Humphrey's avatar
Matt Humphrey committed
527 528
    end

529 530 531
    describe 'POST /projects/:id/keys' do
      it 'should not create an invalid ssh key' do
        post api("/projects/#{project.id}/keys", user), { title: 'invalid key' }
532 533
        expect(response.status).to eq(400)
        expect(json_response['message']['key']).to eq([
534 535 536
          'can\'t be blank',
          'is too short (minimum is 0 characters)',
          'is invalid'
537
        ])
538 539 540 541
      end

      it 'should not create a key without title' do
        post api("/projects/#{project.id}/keys", user), key: 'some key'
542 543
        expect(response.status).to eq(400)
        expect(json_response['message']['title']).to eq([
544 545
          'can\'t be blank',
          'is too short (minimum is 0 characters)'
546
        ])
547 548
      end

549
      it 'should create new ssh key' do
550 551 552
        key_attrs = attributes_for :key
        expect {
          post api("/projects/#{project.id}/keys", user), key_attrs
553
        }.to change{ project.deploy_keys.count }.by(1)
554
      end
Matt Humphrey's avatar
Matt Humphrey committed
555 556
    end

557
    describe 'DELETE /projects/:id/keys/:key_id' do
558 559
      before { deploy_key }

560
      it 'should delete existing key' do
561 562
        expect {
          delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
563
        }.to change{ project.deploy_keys.count }.by(-1)
564 565
      end

566
      it 'should return 404 Not Found with invalid ID' do
567
        delete api("/projects/#{project.id}/keys/404", user)
568
        expect(response.status).to eq(404)
569
      end
Matt Humphrey's avatar
Matt Humphrey committed
570 571
    end
  end
572 573 574

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
575
    let(:project_fork_source) { create(:project, :public) }
576

577
    describe 'POST /projects/:id/fork/:forked_from_id' do
578
      let(:new_project_fork_source) { create(:project, :public) }
579 580 581

      it "shouldn't available for non admin users" do
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
582
        expect(response.status).to eq(403)
583 584
      end

585
      it 'should allow project to be forked from an existing project' do
586
        expect(project_fork_target.forked?).not_to be_truthy
587
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
588
        expect(response.status).to eq(201)
589
        project_fork_target.reload
590 591 592
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
        expect(project_fork_target.forked_project_link).not_to be_nil
        expect(project_fork_target.forked?).to be_truthy
593 594
      end

595
      it 'should fail if forked_from project which does not exist' do
596
        post api("/projects/#{project_fork_target.id}/fork/9999", admin)
597
        expect(response.status).to eq(404)
598 599
      end

600
      it 'should fail with 409 if already forked' do
601 602
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
603
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
604
        post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
605
        expect(response.status).to eq(409)
606
        project_fork_target.reload
607 608
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
        expect(project_fork_target.forked?).to be_truthy
609 610 611
      end
    end

612
    describe 'DELETE /projects/:id/fork' do
613 614 615

      it "shouldn't available for non admin users" do
        delete api("/projects/#{project_fork_target.id}/fork", user)
616
        expect(response.status).to eq(403)
617 618
      end

619
      it 'should make forked project unforked' do
620 621
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
622 623
        expect(project_fork_target.forked_from_project).not_to be_nil
        expect(project_fork_target.forked?).to be_truthy
624
        delete api("/projects/#{project_fork_target.id}/fork", admin)
625
        expect(response.status).to eq(200)
626
        project_fork_target.reload
627 628
        expect(project_fork_target.forked_from_project).to be_nil
        expect(project_fork_target.forked?).not_to be_truthy
629 630
      end

631
      it 'should be idempotent if not forked' do
632
        expect(project_fork_target.forked_from_project).to be_nil
633
        delete api("/projects/#{project_fork_target.id}/fork", admin)
634 635
        expect(response.status).to eq(200)
        expect(project_fork_target.reload.forked_from_project).to be_nil
636 637 638
      end
    end
  end
639

640
  describe 'GET /projects/search/:query' do
641
    let!(:query) { 'query'}
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
642 643 644 645 646
    let!(:search)           { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) }
    let!(:pre)              { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) }
    let!(:post)             { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) }
    let!(:pre_post)         { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) }
    let!(:unfound)          { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) }
647 648 649 650
    let!(:internal)         { create(:empty_project, :internal, name: "internal #{query}") }
    let!(:unfound_internal) { create(:empty_project, :internal, name: 'unfound internal') }
    let!(:public)           { create(:empty_project, :public, name: "public #{query}") }
    let!(:unfound_public)   { create(:empty_project, :public, name: 'unfound public') }
651

652 653
    context 'when unauthenticated' do
      it 'should return authentication error' do
654
        get api("/projects/search/#{query}")
655
        expect(response.status).to eq(401)
656 657 658
      end
    end

659 660
    context 'when authenticated' do
      it 'should return an array of projects' do
661
        get api("/projects/search/#{query}",user)
662 663 664 665
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
        expect(json_response.size).to eq(6)
        json_response.each {|project| expect(project['name']).to match(/.*query.*/)}
666 667 668
      end
    end

669 670
    context 'when authenticated as a different user' do
      it 'should return matching public projects' do
671
        get api("/projects/search/#{query}", user2)
672 673 674 675
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
        expect(json_response.size).to eq(2)
        json_response.each {|project| expect(project['name']).to match(/(internal|public) query/)}
676 677 678
      end
    end
  end
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693
  describe 'PUT /projects/:id̈́' do
    before { project }
    before { user }
    before { user3 }
    before { user4 }
    before { project3 }
    before { project4 }
    before { project_member3 }
    before { project_member2 }

    context 'when unauthenticated' do
      it 'should return authentication error' do
        project_param = { name: 'bar' }
        put api("/projects/#{project.id}"), project_param
694
        expect(response.status).to eq(401)
695 696 697 698 699 700 701
      end
    end

    context 'when authenticated as project owner' do
      it 'should update name' do
        project_param = { name: 'bar' }
        put api("/projects/#{project.id}", user), project_param
702
        expect(response.status).to eq(200)
703
        project_param.each_pair do |k, v|
704
          expect(json_response[k.to_s]).to eq(v)
705 706 707 708 709 710
        end
      end

      it 'should update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user), project_param
711
        expect(response.status).to eq(200)
712
        project_param.each_pair do |k, v|
713
          expect(json_response[k.to_s]).to eq(v)
714 715 716 717 718 719
        end
      end

      it 'should not update name to existing name' do
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
720 721
        expect(response.status).to eq(400)
        expect(json_response['message']['name']).to eq(['has already been taken'])
722 723 724 725 726
      end

      it 'should update path & name to existing path & name in different namespace' do
        project_param = { path: project4.path, name: project4.name }
        put api("/projects/#{project3.id}", user), project_param
727
        expect(response.status).to eq(200)
728
        project_param.each_pair do |k, v|
729
          expect(json_response[k.to_s]).to eq(v)
730 731 732 733 734 735 736 737
        end
      end
    end

    context 'when authenticated as project master' do
      it 'should update path' do
        project_param = { path: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
738
        expect(response.status).to eq(200)
739
        project_param.each_pair do |k, v|
740
          expect(json_response[k.to_s]).to eq(v)
741 742 743 744 745 746 747 748 749 750 751
        end
      end

      it 'should update other attributes' do
        project_param = { issues_enabled: true,
                          wiki_enabled: true,
                          snippets_enabled: true,
                          merge_requests_enabled: true,
                          description: 'new description' }

        put api("/projects/#{project3.id}", user4), project_param
752
        expect(response.status).to eq(200)
753
        project_param.each_pair do |k, v|
754
          expect(json_response[k.to_s]).to eq(v)
755 756 757 758 759 760
        end
      end

      it 'should not update path to existing path' do
        project_param = { path: project.path }
        put api("/projects/#{project3.id}", user4), project_param
761 762
        expect(response.status).to eq(400)
        expect(json_response['message']['path']).to eq(['has already been taken'])
763 764 765 766 767
      end

      it 'should not update name' do
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
768
        expect(response.status).to eq(403)
769 770 771 772 773
      end

      it 'should not update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
774
        expect(response.status).to eq(403)
775 776 777 778 779 780 781 782 783 784 785 786
      end
    end

    context 'when authenticated as project developer' do
      it 'should not update other attributes' do
        project_param = { path: 'bar',
                          issues_enabled: true,
                          wiki_enabled: true,
                          snippets_enabled: true,
                          merge_requests_enabled: true,
                          description: 'new description' }
        put api("/projects/#{project.id}", user3), project_param
787
        expect(response.status).to eq(403)
788 789 790 791
      end
    end
  end

792 793 794
  describe 'DELETE /projects/:id' do
    context 'when authenticated as user' do
      it 'should remove project' do
795 796 797 798 799
        expect(GitlabShellWorker).to(
          receive(:perform_async).with(:remove_repository,
                                       /#{project.path_with_namespace}/)
        ).twice

800
        delete api("/projects/#{project.id}", user)
801
        expect(response.status).to eq(200)
802 803
      end

804
      it 'should not remove a project if not an owner' do
805 806 807
        user3 = create(:user)
        project.team << [user3, :developer]
        delete api("/projects/#{project.id}", user3)
808
        expect(response.status).to eq(403)
809 810
      end

811 812
      it 'should not remove a non existing project' do
        delete api('/projects/1328', user)
813
        expect(response.status).to eq(404)
814 815
      end

816
      it 'should not remove a project not attached to user' do
817
        delete api("/projects/#{project.id}", user2)
818
        expect(response.status).to eq(404)
819 820 821
      end
    end

822 823
    context 'when authenticated as admin' do
      it 'should remove any existing project' do
824
        delete api("/projects/#{project.id}", admin)
825
        expect(response.status).to eq(200)
826 827
      end

828 829
      it 'should not remove a non existing project' do
        delete api('/projects/1328', admin)
830
        expect(response.status).to eq(404)
831 832 833
      end
    end
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
834
end