projects_spec.rb 32 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
      it 'should include the project labels as the tag_list' do
        get api('/projects', user)
63 64 65
        expect(response.status).to eq 200
        expect(json_response).to be_an Array
        expect(json_response.first.keys).to include('tag_list')
66
      end
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
      it 'should include open_issues_count' do
        get api('/projects', user)
        expect(response.status).to eq 200
        expect(json_response).to be_an Array
        expect(json_response.first.keys).to include('open_issues_count')
      end

      it 'should not include open_issues_count' do
        project.update_attributes( { issues_enabled: false } )

        get api('/projects', user)
        expect(response.status).to eq 200
        expect(json_response).to be_an Array
        expect(json_response.first.keys).not_to include('open_issues_count')
      end

84 85 86
      context 'and using search' do
        it 'should return searched project' do
          get api('/projects', user), { search: project.name }
87 88 89
          expect(response.status).to eq(200)
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
90 91 92
        end
      end

93
      context 'and using sorting' do
94 95 96 97 98
        before do
          project2
          project3
        end

99
        it 'should return the correct order when sorted by id' do
100
          get api('/projects', user), { order_by: 'id', sort: 'desc' }
101 102 103
          expect(response.status).to eq(200)
          expect(json_response).to be_an Array
          expect(json_response.first['id']).to eq(project3.id)
104 105
        end
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
106 107 108
    end
  end

109
  describe 'GET /projects/all' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
110 111
    before { project }

112 113 114
    context 'when unauthenticated' do
      it 'should return authentication error' do
        get api('/projects/all')
115
        expect(response.status).to eq(401)
116 117 118
      end
    end

119 120 121
    context 'when authenticated as regular user' do
      it 'should return authentication error' do
        get api('/projects/all', user)
122
        expect(response.status).to eq(403)
123 124 125
      end
    end

126 127 128
    context 'when authenticated as admin' do
      it 'should return an array of all projects' do
        get api('/projects/all', admin)
129 130
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
Marin Jankovski's avatar
Marin Jankovski committed
131

132 133
        expect(json_response).to satisfy do |response|
          response.one? do |entry|
134
            entry.has_key?('permissions') &&
135
            entry['name'] == project.name &&
136
              entry['owner']['username'] == user.username
137 138
          end
        end
139 140 141 142
      end
    end
  end

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
  describe 'GET /projects/starred' do
    before do
      admin.starred_projects << project
      admin.save!
    end

    it 'should return the starred projects' do
      get api('/projects/all', admin)
      expect(response.status).to eq(200)
      expect(json_response).to be_an Array

      expect(json_response).to satisfy do |response|
        response.one? do |entry|
          entry['name'] == project.name
        end
      end
    end
  end

162 163
  describe 'POST /projects' do
    context 'maximum number of projects reached' do
164
      it 'should not create new project and respond with 403' do
165
        allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
166 167
        expect { post api('/projects', user2), name: 'foo' }.
          to change {Project.count}.by(0)
168
        expect(response.status).to eq(403)
169 170 171
      end
    end

172 173 174
    it 'should create new project without path and return 201' do
      expect { post api('/projects', user), name: 'foo' }.
        to change { Project.count }.by(1)
175
      expect(response.status).to eq(201)
176 177
    end

178
    it 'should create last project before reaching project limit' do
179
      allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1)
180
      post api('/projects', user2), name: 'foo'
181
      expect(response.status).to eq(201)
182 183
    end

184
    it 'should not create new project without name and return 400' do
185
      expect { post api('/projects', user) }.not_to change { Project.count }
186
      expect(response.status).to eq(400)
187
    end
Alex Denisov's avatar
Alex Denisov committed
188

189
    it "should assign attributes to project" do
190
      project = attributes_for(:project, {
191
        path: 'camelCasePath',
Robert Speicher's avatar
Robert Speicher committed
192
        description: FFaker::Lorem.sentence,
193 194 195
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Alex Denisov's avatar
Alex Denisov committed
196 197
      })

198
      post api('/projects', user), project
Alex Denisov's avatar
Alex Denisov committed
199

200
      project.each_pair do |k,v|
201
        expect(json_response[k.to_s]).to eq(v)
Alex Denisov's avatar
Alex Denisov committed
202
      end
203
    end
204

205
    it 'should set a project as public' do
206
      project = attributes_for(:project, :public)
207
      post api('/projects', user), project
208 209
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
210 211
    end

212
    it 'should set a project as public using :public' do
213
      project = attributes_for(:project, { public: true })
214
      post api('/projects', user), project
215 216
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
217 218
    end

219
    it 'should set a project as internal' do
220
      project = attributes_for(:project, :internal)
221
      post api('/projects', user), project
222 223
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
224 225
    end

226
    it 'should set a project as internal overriding :public' do
227
      project = attributes_for(:project, :internal, { public: true })
228
      post api('/projects', user), project
229 230
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
231 232
    end

233
    it 'should set a project as private' do
234
      project = attributes_for(:project, :private)
235
      post api('/projects', user), project
236 237
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
238 239
    end

240
    it 'should set a project as private using :public' do
241
      project = attributes_for(:project, { public: false })
242
      post api('/projects', user), project
243 244
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
245
    end
246 247 248 249

    context 'when a visibility level is restricted' do
      before do
        @project = attributes_for(:project, { public: true })
250
        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
      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
269 270
  end

271
  describe 'POST /projects/user/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
272
    before { project }
Angus MacArthur's avatar
Angus MacArthur committed
273 274
    before { admin }

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

280 281
    it 'should respond with 400 on failure and not project' do
      expect { post api("/projects/user/#{user.id}", admin) }.
282
        not_to change { Project.count }
283

284 285
      expect(response.status).to eq(400)
      expect(json_response['message']['name']).to eq([
286 287
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
288
        Gitlab::Regex.project_name_regex_message
289 290
      ])
      expect(json_response['message']['path']).to eq([
291 292
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
293
        Gitlab::Regex.send(:project_path_regex_message)
294
      ])
Angus MacArthur's avatar
Angus MacArthur committed
295 296
    end

297
    it 'should assign attributes to project' do
Angus MacArthur's avatar
Angus MacArthur committed
298
      project = attributes_for(:project, {
Robert Speicher's avatar
Robert Speicher committed
299
        description: FFaker::Lorem.sentence,
300 301 302
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Angus MacArthur's avatar
Angus MacArthur committed
303 304 305 306
      })

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

307
      project.each_pair do |k,v|
Angus MacArthur's avatar
Angus MacArthur committed
308
        next if k == :path
309
        expect(json_response[k.to_s]).to eq(v)
Angus MacArthur's avatar
Angus MacArthur committed
310 311
      end
    end
312

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

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

327
    it 'should set a project as internal' do
328
      project = attributes_for(:project, :internal)
329
      post api("/projects/user/#{user.id}", admin), project
330 331
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
332 333
    end

334
    it 'should set a project as internal overriding :public' do
335
      project = attributes_for(:project, :internal, { public: true })
336
      post api("/projects/user/#{user.id}", admin), project
337 338
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
339
    end
340

341
    it 'should set a project as private' do
342
      project = attributes_for(:project, :private)
343
      post api("/projects/user/#{user.id}", admin), project
344 345
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
346 347
    end

348
    it 'should set a project as private using :public' do
349 350
      project = attributes_for(:project, { public: false })
      post api("/projects/user/#{user.id}", admin), project
351 352
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
353
    end
Angus MacArthur's avatar
Angus MacArthur committed
354 355
  end

356
  describe 'GET /projects/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
357
    before { project }
358
    before { project_member }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
359

360
    it 'should return a project by id' do
Robert Speicher's avatar
Robert Speicher committed
361
      get api("/projects/#{project.id}", user)
362 363 364
      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
365
    end
366

367
    it 'should return a project by path name' do
368
      get api("/projects/#{project.id}", user)
369 370
      expect(response.status).to eq(200)
      expect(json_response['name']).to eq(project.name)
371
    end
372

373 374
    it 'should return a 404 error if not found' do
      get api('/projects/42', user)
375 376
      expect(response.status).to eq(404)
      expect(json_response['message']).to eq('404 Project Not Found')
377
    end
378

379
    it 'should return a 404 error if user is not a member' do
380 381
      other_user = create(:user)
      get api("/projects/#{project.id}", other_user)
382
      expect(response.status).to eq(404)
383
    end
384 385

    describe 'permissions' do
386 387 388 389 390 391 392 393 394 395 396 397
      context 'all projects' do
        it 'Contains permission information' do
          project.team << [user, :master]
          get api("/projects", user)

          expect(response.status).to eq(200)
          expect(json_response.first['permissions']['project_access']['access_level']).
              to eq(Gitlab::Access::MASTER)
          expect(json_response.first['permissions']['group_access']).to be_nil
        end
      end

398
      context 'personal project' do
399
        it 'Sets project access and returns 200' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
400 401
          project.team << [user, :master]
          get api("/projects/#{project.id}", user)
402

403 404 405 406 407
          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
408 409 410
      end

      context 'group project' do
411
        it 'should set the owner and return 200' do
412 413 414 415
          project2 = create(:project, group: create(:group))
          project2.group.add_owner(user)
          get api("/projects/#{project2.id}", user)

416 417 418 419 420
          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
421 422
      end
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
423 424
  end

425
  describe 'GET /projects/:id/events' do
Douwe Maan's avatar
Douwe Maan committed
426
    before { project_member2 }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
427

428 429 430 431 432 433 434 435 436 437 438
    context 'valid request' do
      before do
        note = create(:note_on_issue, note: 'What an awesome day!', project: project)
        EventCreateService.new.leave_note(note, note.author)
        get api("/projects/#{project.id}/events", user)
      end

      it { expect(response.status).to eq(200) }

      context 'joined event' do
        let(:json_event) { json_response[1] }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
439

440 441 442 443 444 445 446 447 448 449 450 451
        it { expect(json_event['action_name']).to eq('joined') }
        it { expect(json_event['project_id'].to_i).to eq(project.id) }
        it { expect(json_event['author_username']).to eq(user3.username) }
        it { expect(json_event['author']['name']).to eq(user3.name) }
      end

      context 'comment event' do
        let(:json_event) { json_response.first }

        it { expect(json_event['action_name']).to eq('commented on') }
        it { expect(json_event['note']['body']).to eq('What an awesome day!') }
      end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
452 453
    end

454 455
    it 'should return a 404 error if not found' do
      get api('/projects/42/events', user)
456 457
      expect(response.status).to eq(404)
      expect(json_response['message']).to eq('404 Project Not Found')
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
458 459
    end

460
    it 'should return a 404 error if user is not a member' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
461 462
      other_user = create(:user)
      get api("/projects/#{project.id}/events", other_user)
463
      expect(response.status).to eq(404)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
464 465 466
    end
  end

467
  describe 'GET /projects/:id/snippets' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
468 469
    before { snippet }

470
    it 'should return an array of project snippets' do
471
      get api("/projects/#{project.id}/snippets", user)
472 473 474
      expect(response.status).to eq(200)
      expect(json_response).to be_an Array
      expect(json_response.first['title']).to eq(snippet.title)
475 476 477
    end
  end

478 479
  describe 'GET /projects/:id/snippets/:snippet_id' do
    it 'should return a project snippet' do
480
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
481 482
      expect(response.status).to eq(200)
      expect(json_response['title']).to eq(snippet.title)
Nihad Abbasov's avatar
Nihad Abbasov committed
483
    end
484

485
    it 'should return a 404 error if snippet id not found' do
486
      get api("/projects/#{project.id}/snippets/1234", user)
487
      expect(response.status).to eq(404)
488
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
489 490
  end

491 492
  describe 'POST /projects/:id/snippets' do
    it 'should create a new project snippet' do
493
      post api("/projects/#{project.id}/snippets", user),
494 495
        title: 'api test', file_name: 'sample.rb', code: 'test',
        visibility_level: '0'
496 497
      expect(response.status).to eq(201)
      expect(json_response['title']).to eq('api test')
Nihad Abbasov's avatar
Nihad Abbasov committed
498
    end
499

500 501 502
    it 'should return a 400 error if invalid snippet is given' do
      post api("/projects/#{project.id}/snippets", user)
      expect(status).to eq(400)
503
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
504 505
  end

506
  describe 'PUT /projects/:id/snippets/:snippet_id' do
507
    it 'should update an existing project snippet' do
508
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
509
        code: 'updated code'
510 511 512
      expect(response.status).to eq(200)
      expect(json_response['title']).to eq('example')
      expect(snippet.reload.content).to eq('updated code')
513
    end
514

515
    it 'should update an existing project snippet with new title' do
516
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
517
        title: 'other api test'
518 519
      expect(response.status).to eq(200)
      expect(json_response['title']).to eq('other api test')
520
    end
521 522
  end

523
  describe 'DELETE /projects/:id/snippets/:snippet_id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
524 525
    before { snippet }

526
    it 'should delete existing project snippet' do
527
      expect do
528
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
529
      end.to change { Snippet.count }.by(-1)
530
      expect(response.status).to eq(200)
531 532
    end

533
    it 'should return 404 when deleting unknown snippet id' do
534
      delete api("/projects/#{project.id}/snippets/1234", user)
535
      expect(response.status).to eq(404)
Nihad Abbasov's avatar
Nihad Abbasov committed
536 537
    end
  end
538

539 540
  describe 'GET /projects/:id/snippets/:snippet_id/raw' do
    it 'should get a raw project snippet' do
541
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
542
      expect(response.status).to eq(200)
543
    end
544

545
    it 'should return a 404 error if raw project snippet not found' do
546
      get api("/projects/#{project.id}/snippets/5555/raw", user)
547
      expect(response.status).to eq(404)
548
    end
549
  end
550

551 552 553
  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
554

555
    describe 'GET /projects/:id/keys' do
556
      before { deploy_key }
Matt Humphrey's avatar
Matt Humphrey committed
557

558
      it 'should return array of ssh keys' do
559
        get api("/projects/#{project.id}/keys", user)
560 561 562
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
        expect(json_response.first['title']).to eq(deploy_key.title)
563
      end
Matt Humphrey's avatar
Matt Humphrey committed
564 565
    end

566 567
    describe 'GET /projects/:id/keys/:key_id' do
      it 'should return a single key' do
568
        get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
569 570
        expect(response.status).to eq(200)
        expect(json_response['title']).to eq(deploy_key.title)
571
      end
Matt Humphrey's avatar
Matt Humphrey committed
572

573
      it 'should return 404 Not Found with invalid ID' do
574
        get api("/projects/#{project.id}/keys/404", user)
575
        expect(response.status).to eq(404)
576
      end
Matt Humphrey's avatar
Matt Humphrey committed
577 578
    end

579 580 581
    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' }
582 583
        expect(response.status).to eq(400)
        expect(json_response['message']['key']).to eq([
584 585 586
          'can\'t be blank',
          'is too short (minimum is 0 characters)',
          'is invalid'
587
        ])
588 589 590 591
      end

      it 'should not create a key without title' do
        post api("/projects/#{project.id}/keys", user), key: 'some key'
592 593
        expect(response.status).to eq(400)
        expect(json_response['message']['title']).to eq([
594 595
          'can\'t be blank',
          'is too short (minimum is 0 characters)'
596
        ])
597 598
      end

599
      it 'should create new ssh key' do
600
        key_attrs = attributes_for :key
601
        expect do
602
          post api("/projects/#{project.id}/keys", user), key_attrs
603
        end.to change{ project.deploy_keys.count }.by(1)
604
      end
Matt Humphrey's avatar
Matt Humphrey committed
605 606
    end

607
    describe 'DELETE /projects/:id/keys/:key_id' do
608 609
      before { deploy_key }

610
      it 'should delete existing key' do
611
        expect do
612
          delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
613
        end.to change{ project.deploy_keys.count }.by(-1)
614 615
      end

616
      it 'should return 404 Not Found with invalid ID' do
617
        delete api("/projects/#{project.id}/keys/404", user)
618
        expect(response.status).to eq(404)
619
      end
Matt Humphrey's avatar
Matt Humphrey committed
620 621
    end
  end
622 623 624

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
625
    let(:project_fork_source) { create(:project, :public) }
626

627
    describe 'POST /projects/:id/fork/:forked_from_id' do
628
      let(:new_project_fork_source) { create(:project, :public) }
629 630 631

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

635
      it 'should allow project to be forked from an existing project' do
636
        expect(project_fork_target.forked?).not_to be_truthy
637
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
638
        expect(response.status).to eq(201)
639
        project_fork_target.reload
640 641 642
        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
643 644
      end

645
      it 'should fail if forked_from project which does not exist' do
646
        post api("/projects/#{project_fork_target.id}/fork/9999", admin)
647
        expect(response.status).to eq(404)
648 649
      end

650
      it 'should fail with 409 if already forked' do
651 652
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
653
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
654
        post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
655
        expect(response.status).to eq(409)
656
        project_fork_target.reload
657 658
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
        expect(project_fork_target.forked?).to be_truthy
659 660 661
      end
    end

662
    describe 'DELETE /projects/:id/fork' do
663

664
      it "shouldn't be visible to users outside group" do
665
        delete api("/projects/#{project_fork_target.id}/fork", user)
666
        expect(response.status).to eq(404)
667 668
      end

669 670
      context 'when users belong to project group' do
        let(:project_fork_target) { create(:project, group: create(:group)) }
671

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
        before do
          project_fork_target.group.add_owner user
          project_fork_target.group.add_developer user2
        end

        it 'should be forbidden to non-owner users' do
          delete api("/projects/#{project_fork_target.id}/fork", user2)
          expect(response.status).to eq(403)
        end

        it 'should make forked project unforked' do
          post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
          project_fork_target.reload
          expect(project_fork_target.forked_from_project).not_to be_nil
          expect(project_fork_target.forked?).to be_truthy
          delete api("/projects/#{project_fork_target.id}/fork", admin)
          expect(response.status).to eq(200)
          project_fork_target.reload
          expect(project_fork_target.forked_from_project).to be_nil
          expect(project_fork_target.forked?).not_to be_truthy
        end

        it 'should be idempotent if not forked' do
          expect(project_fork_target.forked_from_project).to be_nil
          delete api("/projects/#{project_fork_target.id}/fork", admin)
          expect(response.status).to eq(200)
          expect(project_fork_target.reload.forked_from_project).to be_nil
        end
700 701 702
      end
    end
  end
703

704
  describe 'GET /projects/search/:query' do
705
    let!(:query) { 'query'}
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
706 707 708 709 710
    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) }
711 712 713 714
    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') }
715

716 717
    context 'when unauthenticated' do
      it 'should return authentication error' do
718
        get api("/projects/search/#{query}")
719
        expect(response.status).to eq(401)
720 721 722
      end
    end

723 724
    context 'when authenticated' do
      it 'should return an array of projects' do
725
        get api("/projects/search/#{query}",user)
726 727 728 729
        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.*/)}
730 731 732
      end
    end

733 734
    context 'when authenticated as a different user' do
      it 'should return matching public projects' do
735
        get api("/projects/search/#{query}", user2)
736 737 738 739
        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/)}
740 741 742
      end
    end
  end
743

744 745 746 747 748 749 750 751 752 753 754 755 756 757
  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
758
        expect(response.status).to eq(401)
759 760 761 762 763 764 765
      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
766
        expect(response.status).to eq(200)
767
        project_param.each_pair do |k, v|
768
          expect(json_response[k.to_s]).to eq(v)
769 770 771 772 773 774
        end
      end

      it 'should update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user), project_param
775
        expect(response.status).to eq(200)
776
        project_param.each_pair do |k, v|
777
          expect(json_response[k.to_s]).to eq(v)
778 779 780
        end
      end

781 782 783 784 785 786 787 788 789 790 791 792
      it 'should update visibility_level from public to private' do
        project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })

        project_param = { public: false }
        put api("/projects/#{project3.id}", user), project_param
        expect(response.status).to eq(200)
        project_param.each_pair do |k, v|
          expect(json_response[k.to_s]).to eq(v)
        end
        expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
      end

793 794 795
      it 'should not update name to existing name' do
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
796 797
        expect(response.status).to eq(400)
        expect(json_response['message']['name']).to eq(['has already been taken'])
798 799 800 801 802
      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
803
        expect(response.status).to eq(200)
804
        project_param.each_pair do |k, v|
805
          expect(json_response[k.to_s]).to eq(v)
806 807 808 809 810 811 812 813
        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
814
        expect(response.status).to eq(200)
815
        project_param.each_pair do |k, v|
816
          expect(json_response[k.to_s]).to eq(v)
817 818 819 820 821 822 823 824 825 826 827
        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
828
        expect(response.status).to eq(200)
829
        project_param.each_pair do |k, v|
830
          expect(json_response[k.to_s]).to eq(v)
831 832 833 834 835 836
        end
      end

      it 'should not update path to existing path' do
        project_param = { path: project.path }
        put api("/projects/#{project3.id}", user4), project_param
837 838
        expect(response.status).to eq(400)
        expect(json_response['message']['path']).to eq(['has already been taken'])
839 840 841 842 843
      end

      it 'should not update name' do
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
844
        expect(response.status).to eq(403)
845 846 847 848 849
      end

      it 'should not update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
850
        expect(response.status).to eq(403)
851 852 853 854 855 856 857 858 859 860 861 862
      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
863
        expect(response.status).to eq(403)
864 865 866 867
      end
    end
  end

868 869 870
  describe 'DELETE /projects/:id' do
    context 'when authenticated as user' do
      it 'should remove project' do
871
        delete api("/projects/#{project.id}", user)
872
        expect(response.status).to eq(200)
873 874
      end

875
      it 'should not remove a project if not an owner' do
876 877 878
        user3 = create(:user)
        project.team << [user3, :developer]
        delete api("/projects/#{project.id}", user3)
879
        expect(response.status).to eq(403)
880 881
      end

882 883
      it 'should not remove a non existing project' do
        delete api('/projects/1328', user)
884
        expect(response.status).to eq(404)
885 886
      end

887
      it 'should not remove a project not attached to user' do
888
        delete api("/projects/#{project.id}", user2)
889
        expect(response.status).to eq(404)
890 891 892
      end
    end

893 894
    context 'when authenticated as admin' do
      it 'should remove any existing project' do
895
        delete api("/projects/#{project.id}", admin)
896
        expect(response.status).to eq(200)
897 898
      end

899 900
      it 'should not remove a non existing project' do
        delete api('/projects/1328', admin)
901
        expect(response.status).to eq(404)
902 903 904
      end
    end
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
905
end