projects_spec.rb 30.5 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
      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
        it 'should return the correct order when sorted by id' do
84
          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 89
        end
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
90 91 92
    end
  end

93
  describe 'GET /projects/all' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
94 95
    before { project }

96 97 98
    context 'when unauthenticated' do
      it 'should return authentication error' do
        get api('/projects/all')
99
        expect(response.status).to eq(401)
100 101 102
      end
    end

103 104 105
    context 'when authenticated as regular user' do
      it 'should return authentication error' do
        get api('/projects/all', user)
106
        expect(response.status).to eq(403)
107 108 109
      end
    end

110 111 112
    context 'when authenticated as admin' do
      it 'should return an array of all projects' do
        get api('/projects/all', admin)
113 114
        expect(response.status).to eq(200)
        expect(json_response).to be_an Array
Marin Jankovski's avatar
Marin Jankovski committed
115

116 117 118
        expect(json_response).to satisfy do |response|
          response.one? do |entry|
            entry['name'] == project.name &&
119
              entry['owner']['username'] == user.username
120 121
          end
        end
122 123 124 125
      end
    end
  end

126 127
  describe 'POST /projects' do
    context 'maximum number of projects reached' do
128
      it 'should not create new project and respond with 403' do
129
        allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
130 131
        expect { post api('/projects', user2), name: 'foo' }.
          to change {Project.count}.by(0)
132
        expect(response.status).to eq(403)
133 134 135
      end
    end

136 137 138
    it 'should create new project without path and return 201' do
      expect { post api('/projects', user), name: 'foo' }.
        to change { Project.count }.by(1)
139
      expect(response.status).to eq(201)
140 141
    end

142
    it 'should create last project before reaching project limit' do
143
      allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1)
144
      post api('/projects', user2), name: 'foo'
145
      expect(response.status).to eq(201)
146 147
    end

148
    it 'should not create new project without name and return 400' do
149
      expect { post api('/projects', user) }.not_to change { Project.count }
150
      expect(response.status).to eq(400)
151
    end
Alex Denisov's avatar
Alex Denisov committed
152

153
    it "should assign attributes to project" do
154
      project = attributes_for(:project, {
155
        path: 'camelCasePath',
Robert Speicher's avatar
Robert Speicher committed
156
        description: FFaker::Lorem.sentence,
157 158 159
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Alex Denisov's avatar
Alex Denisov committed
160 161
      })

162
      post api('/projects', user), project
Alex Denisov's avatar
Alex Denisov committed
163

164
      project.each_pair do |k,v|
165
        expect(json_response[k.to_s]).to eq(v)
Alex Denisov's avatar
Alex Denisov committed
166
      end
167
    end
168

169
    it 'should set a project as public' do
170
      project = attributes_for(:project, :public)
171
      post api('/projects', user), project
172 173
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
174 175
    end

176
    it 'should set a project as public using :public' do
177
      project = attributes_for(:project, { public: true })
178
      post api('/projects', user), project
179 180
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
181 182
    end

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

190
    it 'should set a project as internal overriding :public' do
191
      project = attributes_for(:project, :internal, { public: true })
192
      post api('/projects', user), project
193 194
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
195 196
    end

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

204
    it 'should set a project as private using :public' do
205
      project = attributes_for(:project, { public: false })
206
      post api('/projects', user), project
207 208
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
209
    end
210 211 212 213

    context 'when a visibility level is restricted' do
      before do
        @project = attributes_for(:project, { public: true })
214
        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
      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
233 234
  end

235
  describe 'POST /projects/user/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
236
    before { project }
Angus MacArthur's avatar
Angus MacArthur committed
237 238
    before { admin }

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

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

248 249
      expect(response.status).to eq(400)
      expect(json_response['message']['name']).to eq([
250 251
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
252
        Gitlab::Regex.project_name_regex_message
253 254
      ])
      expect(json_response['message']['path']).to eq([
255 256
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
257
        Gitlab::Regex.send(:project_path_regex_message)
258
      ])
Angus MacArthur's avatar
Angus MacArthur committed
259 260
    end

261
    it 'should assign attributes to project' do
Angus MacArthur's avatar
Angus MacArthur committed
262
      project = attributes_for(:project, {
Robert Speicher's avatar
Robert Speicher committed
263
        description: FFaker::Lorem.sentence,
264 265 266
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Angus MacArthur's avatar
Angus MacArthur committed
267 268 269 270
      })

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

271
      project.each_pair do |k,v|
Angus MacArthur's avatar
Angus MacArthur committed
272
        next if k == :path
273
        expect(json_response[k.to_s]).to eq(v)
Angus MacArthur's avatar
Angus MacArthur committed
274 275
      end
    end
276

277
    it 'should set a project as public' do
278
      project = attributes_for(:project, :public)
279
      post api("/projects/user/#{user.id}", admin), project
280 281
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
282 283
    end

284
    it 'should set a project as public using :public' do
285 286
      project = attributes_for(:project, { public: true })
      post api("/projects/user/#{user.id}", admin), project
287 288
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
289
    end
290

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

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

305
    it 'should set a project as private' do
306
      project = attributes_for(:project, :private)
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::PRIVATE)
310 311
    end

312
    it 'should set a project as private using :public' do
313 314
      project = attributes_for(:project, { public: false })
      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::PRIVATE)
317
    end
Angus MacArthur's avatar
Angus MacArthur committed
318 319
  end

320
  describe 'GET /projects/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
321
    before { project }
322
    before { project_member }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
323

324
    it 'should return a project by id' do
Robert Speicher's avatar
Robert Speicher committed
325
      get api("/projects/#{project.id}", user)
326 327 328
      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
329
    end
330

331
    it 'should return a project by path name' do
332
      get api("/projects/#{project.id}", user)
333 334
      expect(response.status).to eq(200)
      expect(json_response['name']).to eq(project.name)
335
    end
336

337 338
    it 'should return a 404 error if not found' do
      get api('/projects/42', user)
339 340
      expect(response.status).to eq(404)
      expect(json_response['message']).to eq('404 Project Not Found')
341
    end
342

343
    it 'should return a 404 error if user is not a member' do
344 345
      other_user = create(:user)
      get api("/projects/#{project.id}", other_user)
346
      expect(response.status).to eq(404)
347
    end
348 349 350

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

355 356 357 358 359
          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
360 361 362
      end

      context 'group project' do
363
        it 'should set the owner and return 200' do
364 365 366 367
          project2 = create(:project, group: create(:group))
          project2.group.add_owner(user)
          get api("/projects/#{project2.id}", user)

368 369 370 371 372
          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
373 374
      end
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
375 376
  end

377
  describe 'GET /projects/:id/events' do
Douwe Maan's avatar
Douwe Maan committed
378
    before { project_member2 }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
379

380 381 382 383 384 385 386 387 388 389 390
    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
391

392 393 394 395 396 397 398 399 400 401 402 403
        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
404 405
    end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

503 504 505
  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
506

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

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

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

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

531 532 533
    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' }
534 535
        expect(response.status).to eq(400)
        expect(json_response['message']['key']).to eq([
536 537 538
          'can\'t be blank',
          'is too short (minimum is 0 characters)',
          'is invalid'
539
        ])
540 541 542 543
      end

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

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

559
    describe 'DELETE /projects/:id/keys/:key_id' do
560 561
      before { deploy_key }

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

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

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
577
    let(:project_fork_source) { create(:project, :public) }
578

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

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

587
      it 'should allow project to be forked from an existing project' do
588
        expect(project_fork_target.forked?).not_to be_truthy
589
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
590
        expect(response.status).to eq(201)
591
        project_fork_target.reload
592 593 594
        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
595 596
      end

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

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

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

616
      it "shouldn't be visible to users outside group" do
617
        delete api("/projects/#{project_fork_target.id}/fork", user)
618
        expect(response.status).to eq(404)
619 620
      end

621 622
      context 'when users belong to project group' do
        let(:project_fork_target) { create(:project, group: create(:group)) }
623

624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
        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
652 653 654
      end
    end
  end
655

656
  describe 'GET /projects/search/:query' do
657
    let!(:query) { 'query'}
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
658 659 660 661 662
    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) }
663 664 665 666
    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') }
667

668 669
    context 'when unauthenticated' do
      it 'should return authentication error' do
670
        get api("/projects/search/#{query}")
671
        expect(response.status).to eq(401)
672 673 674
      end
    end

675 676
    context 'when authenticated' do
      it 'should return an array of projects' do
677
        get api("/projects/search/#{query}",user)
678 679 680 681
        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.*/)}
682 683 684
      end
    end

685 686
    context 'when authenticated as a different user' do
      it 'should return matching public projects' do
687
        get api("/projects/search/#{query}", user2)
688 689 690 691
        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/)}
692 693 694
      end
    end
  end
695

696 697 698 699 700 701 702 703 704 705 706 707 708 709
  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
710
        expect(response.status).to eq(401)
711 712 713 714 715 716 717
      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
718
        expect(response.status).to eq(200)
719
        project_param.each_pair do |k, v|
720
          expect(json_response[k.to_s]).to eq(v)
721 722 723 724 725 726
        end
      end

      it 'should update visibility_level' do
        project_param = { visibility_level: 20 }
        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
        end
      end

733 734 735 736 737 738 739 740 741 742 743 744
      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

745 746 747
      it 'should not update name to existing name' do
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
748 749
        expect(response.status).to eq(400)
        expect(json_response['message']['name']).to eq(['has already been taken'])
750 751 752 753 754
      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
755
        expect(response.status).to eq(200)
756
        project_param.each_pair do |k, v|
757
          expect(json_response[k.to_s]).to eq(v)
758 759 760 761 762 763 764 765
        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
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 775 776 777 778 779
        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
780
        expect(response.status).to eq(200)
781
        project_param.each_pair do |k, v|
782
          expect(json_response[k.to_s]).to eq(v)
783 784 785 786 787 788
        end
      end

      it 'should not update path to existing path' do
        project_param = { path: project.path }
        put api("/projects/#{project3.id}", user4), project_param
789 790
        expect(response.status).to eq(400)
        expect(json_response['message']['path']).to eq(['has already been taken'])
791 792 793 794 795
      end

      it 'should not update name' do
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
796
        expect(response.status).to eq(403)
797 798 799 800 801
      end

      it 'should not update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
802
        expect(response.status).to eq(403)
803 804 805 806 807 808 809 810 811 812 813 814
      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
815
        expect(response.status).to eq(403)
816 817 818 819
      end
    end
  end

820 821 822
  describe 'DELETE /projects/:id' do
    context 'when authenticated as user' do
      it 'should remove project' do
823
        delete api("/projects/#{project.id}", user)
824
        expect(response.status).to eq(200)
825 826
      end

827
      it 'should not remove a project if not an owner' do
828 829 830
        user3 = create(:user)
        project.team << [user3, :developer]
        delete api("/projects/#{project.id}", user3)
831
        expect(response.status).to eq(403)
832 833
      end

834 835
      it 'should not remove a non existing project' do
        delete api('/projects/1328', user)
836
        expect(response.status).to eq(404)
837 838
      end

839
      it 'should not remove a project not attached to user' do
840
        delete api("/projects/#{project.id}", user2)
841
        expect(response.status).to eq(404)
842 843 844
      end
    end

845 846
    context 'when authenticated as admin' do
      it 'should remove any existing project' do
847
        delete api("/projects/#{project.id}", admin)
848
        expect(response.status).to eq(200)
849 850
      end

851 852
      it 'should not remove a non existing project' do
        delete api('/projects/1328', admin)
853
        expect(response.status).to eq(404)
854 855 856
      end
    end
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
857
end