projects_spec.rb 29.4 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
        end
89 90 91

        it 'returns projects in the correct order when ci_enabled_first parameter is passed' do
          [project, project2, project3].each{ |project| project.build_missing_services }
Kamil Trzcinski's avatar
Kamil Trzcinski committed
92
          project2.gitlab_ci_service.update(active: true)
93
          get api('/projects', user), { ci_enabled_first: 'true' }
94 95 96 97
          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 126 127
        expect(json_response).to satisfy do |response|
          response.one? do |entry|
            entry['name'] == project.name &&
128
              entry['owner']['username'] == user.username
129 130
          end
        end
131 132 133 134
      end
    end
  end

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

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

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

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

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

171
      post api('/projects', user), project
Alex Denisov's avatar
Alex Denisov committed
172

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

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

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

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

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

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

213
    it 'should set a project as private using :public' do
214
      project = attributes_for(:project, { public: false })
215
      post api('/projects', user), project
216 217
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
218
    end
219 220 221 222

    context 'when a visibility level is restricted' do
      before do
        @project = attributes_for(:project, { public: true })
223
        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
      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
242 243
  end

244
  describe 'POST /projects/user/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
245
    before { project }
Angus MacArthur's avatar
Angus MacArthur committed
246 247
    before { admin }

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

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

257 258
      expect(response.status).to eq(400)
      expect(json_response['message']['name']).to eq([
259 260
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan's avatar
Douwe Maan committed
261
        Gitlab::Regex.project_name_regex_message
262 263
      ])
      expect(json_response['message']['path']).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.send(:project_path_regex_message)
267
      ])
Angus MacArthur's avatar
Angus MacArthur committed
268 269
    end

270
    it 'should assign attributes to project' do
Angus MacArthur's avatar
Angus MacArthur committed
271
      project = attributes_for(:project, {
Robert Speicher's avatar
Robert Speicher committed
272
        description: FFaker::Lorem.sentence,
273 274 275
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Angus MacArthur's avatar
Angus MacArthur committed
276 277 278 279
      })

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

280
      project.each_pair do |k,v|
Angus MacArthur's avatar
Angus MacArthur committed
281
        next if k == :path
282
        expect(json_response[k.to_s]).to eq(v)
Angus MacArthur's avatar
Angus MacArthur committed
283 284
      end
    end
285

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

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

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

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

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

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

329
  describe 'GET /projects/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
330
    before { project }
331
    before { project_member }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
332

333
    it 'should return a project by id' do
Robert Speicher's avatar
Robert Speicher committed
334
      get api("/projects/#{project.id}", user)
335 336 337
      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
338
    end
339

340
    it 'should return a project by path name' do
341
      get api("/projects/#{project.id}", user)
342 343
      expect(response.status).to eq(200)
      expect(json_response['name']).to eq(project.name)
344
    end
345

346 347
    it 'should return a 404 error if not found' do
      get api('/projects/42', user)
348 349
      expect(response.status).to eq(404)
      expect(json_response['message']).to eq('404 Project Not Found')
350
    end
351

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

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

364 365 366 367 368
          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
369 370 371
      end

      context 'group project' do
372
        it 'should set the owner and return 200' do
373 374 375 376
          project2 = create(:project, group: create(:group))
          project2.group.add_owner(user)
          get api("/projects/#{project2.id}", user)

377 378 379 380 381
          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
382 383
      end
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
384 385
  end

386
  describe 'GET /projects/:id/events' do
Douwe Maan's avatar
Douwe Maan committed
387
    before { project_member2 }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
388

389
    it 'should return a project events' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
390
      get api("/projects/#{project.id}/events", user)
391
      expect(response.status).to eq(200)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
392 393
      json_event = json_response.first

394 395
      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
396
      expect(json_event['author_username']).to eq(user3.username)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
397 398
    end

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

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

412
  describe 'GET /projects/:id/snippets' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
413 414
    before { snippet }

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

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

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

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

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

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

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

468
  describe 'DELETE /projects/:id/snippets/:snippet_id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
469 470
    before { snippet }

471
    it 'should delete existing project snippet' do
472
      expect do
473
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
474
      end.to change { Snippet.count }.by(-1)
475
      expect(response.status).to eq(200)
476 477
    end

478
    it 'should return 404 when deleting unknown snippet id' do
479
      delete api("/projects/#{project.id}/snippets/1234", user)
480
      expect(response.status).to eq(404)
Nihad Abbasov's avatar
Nihad Abbasov committed
481 482
    end
  end
483

484 485
  describe 'GET /projects/:id/snippets/:snippet_id/raw' do
    it 'should get a raw project snippet' do
486
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
487
      expect(response.status).to eq(200)
488
    end
489

490
    it 'should return a 404 error if raw project snippet not found' do
491
      get api("/projects/#{project.id}/snippets/5555/raw", user)
492
      expect(response.status).to eq(404)
493
    end
494
  end
495

496 497 498
  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
499

500
    describe 'GET /projects/:id/keys' do
501
      before { deploy_key }
Matt Humphrey's avatar
Matt Humphrey committed
502

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

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

518
      it 'should return 404 Not Found with invalid ID' do
519
        get api("/projects/#{project.id}/keys/404", user)
520
        expect(response.status).to eq(404)
521
      end
Matt Humphrey's avatar
Matt Humphrey committed
522 523
    end

524 525 526
    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' }
527 528
        expect(response.status).to eq(400)
        expect(json_response['message']['key']).to eq([
529 530 531
          'can\'t be blank',
          'is too short (minimum is 0 characters)',
          'is invalid'
532
        ])
533 534 535 536
      end

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

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

552
    describe 'DELETE /projects/:id/keys/:key_id' do
553 554
      before { deploy_key }

555
      it 'should delete existing key' do
556
        expect do
557
          delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
558
        end.to change{ project.deploy_keys.count }.by(-1)
559 560
      end

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

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
570
    let(:project_fork_source) { create(:project, :public) }
571

572
    describe 'POST /projects/:id/fork/:forked_from_id' do
573
      let(:new_project_fork_source) { create(:project, :public) }
574 575 576

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

580
      it 'should allow project to be forked from an existing project' do
581
        expect(project_fork_target.forked?).not_to be_truthy
582
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
583
        expect(response.status).to eq(201)
584
        project_fork_target.reload
585 586 587
        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
588 589
      end

590
      it 'should fail if forked_from project which does not exist' do
591
        post api("/projects/#{project_fork_target.id}/fork/9999", admin)
592
        expect(response.status).to eq(404)
593 594
      end

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

607
    describe 'DELETE /projects/:id/fork' do
608 609 610

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

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

626
      it 'should be idempotent if not forked' do
627
        expect(project_fork_target.forked_from_project).to be_nil
628
        delete api("/projects/#{project_fork_target.id}/fork", admin)
629 630
        expect(response.status).to eq(200)
        expect(project_fork_target.reload.forked_from_project).to be_nil
631 632 633
      end
    end
  end
634

635
  describe 'GET /projects/search/:query' do
636
    let!(:query) { 'query'}
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
637 638 639 640 641
    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) }
642 643 644 645
    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') }
646

647 648
    context 'when unauthenticated' do
      it 'should return authentication error' do
649
        get api("/projects/search/#{query}")
650
        expect(response.status).to eq(401)
651 652 653
      end
    end

654 655
    context 'when authenticated' do
      it 'should return an array of projects' do
656
        get api("/projects/search/#{query}",user)
657 658 659 660
        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.*/)}
661 662 663
      end
    end

664 665
    context 'when authenticated as a different user' do
      it 'should return matching public projects' do
666
        get api("/projects/search/#{query}", user2)
667 668 669 670
        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/)}
671 672 673
      end
    end
  end
674

675 676 677 678 679 680 681 682 683 684 685 686 687 688
  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
689
        expect(response.status).to eq(401)
690 691 692 693 694 695 696
      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
697
        expect(response.status).to eq(200)
698
        project_param.each_pair do |k, v|
699
          expect(json_response[k.to_s]).to eq(v)
700 701 702 703 704 705
        end
      end

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

      it 'should not update name to existing name' do
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
715 716
        expect(response.status).to eq(400)
        expect(json_response['message']['name']).to eq(['has already been taken'])
717 718 719 720 721
      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
722
        expect(response.status).to eq(200)
723
        project_param.each_pair do |k, v|
724
          expect(json_response[k.to_s]).to eq(v)
725 726 727 728 729 730 731 732
        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
733
        expect(response.status).to eq(200)
734
        project_param.each_pair do |k, v|
735
          expect(json_response[k.to_s]).to eq(v)
736 737 738 739 740 741 742 743 744 745 746
        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
747
        expect(response.status).to eq(200)
748
        project_param.each_pair do |k, v|
749
          expect(json_response[k.to_s]).to eq(v)
750 751 752 753 754 755
        end
      end

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

      it 'should not update name' do
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
763
        expect(response.status).to eq(403)
764 765 766 767 768
      end

      it 'should not update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
769
        expect(response.status).to eq(403)
770 771 772 773 774 775 776 777 778 779 780 781
      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
782
        expect(response.status).to eq(403)
783 784 785 786
      end
    end
  end

787 788 789
  describe 'DELETE /projects/:id' do
    context 'when authenticated as user' do
      it 'should remove project' do
790
        delete api("/projects/#{project.id}", user)
791
        expect(response.status).to eq(200)
792 793
      end

794
      it 'should not remove a project if not an owner' do
795 796 797
        user3 = create(:user)
        project.team << [user3, :developer]
        delete api("/projects/#{project.id}", user3)
798
        expect(response.status).to eq(403)
799 800
      end

801 802
      it 'should not remove a non existing project' do
        delete api('/projects/1328', user)
803
        expect(response.status).to eq(404)
804 805
      end

806
      it 'should not remove a project not attached to user' do
807
        delete api("/projects/#{project.id}", user2)
808
        expect(response.status).to eq(404)
809 810 811
      end
    end

812 813
    context 'when authenticated as admin' do
      it 'should remove any existing project' do
814
        delete api("/projects/#{project.id}", admin)
815
        expect(response.status).to eq(200)
816 817
      end

818 819
      it 'should not remove a non existing project' do
        delete api('/projects/1328', admin)
820
        expect(response.status).to eq(404)
821 822 823
      end
    end
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
824
end