projects_spec.rb 28.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 7 8
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
  let(:user3) { create(:user) }
Angus MacArthur's avatar
Angus MacArthur committed
9
  let(:admin) { create(:admin) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
10
  let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
11 12
  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
13
  let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
14 15
  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) }
16
  let(:user4) { create(:user) }
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
  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
42 43
    before { project }

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

51 52 53
    context 'when authenticated' do
      it 'should return an array of projects' do
        get api('/projects', user)
Nihad Abbasov's avatar
Nihad Abbasov committed
54
        response.status.should == 200
Nihad Abbasov's avatar
Nihad Abbasov committed
55 56
        json_response.should be_an Array
        json_response.first['name'].should == project.name
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
57
        json_response.first['owner']['username'].should == user.username
Nihad Abbasov's avatar
Nihad Abbasov committed
58
      end
59

60 61 62
      context 'and using search' do
        it 'should return searched project' do
          get api('/projects', user), { search: project.name }
63 64 65 66 67 68
          response.status.should eq(200)
          json_response.should be_an Array
          json_response.length.should eq(1)
        end
      end

69
      context 'and using sorting' do
70 71 72 73 74
        before do
          project2
          project3
        end

75 76
        it 'should return the correct order when sorted by id' do
          get api('/projects', user), { order_by: 'id', sort: 'desc'}
77 78
          response.status.should eq(200)
          json_response.should be_an Array
79
          json_response.first['id'].should eq(project3.id)
80 81
        end
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
82 83 84
    end
  end

85
  describe 'GET /projects/all' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
86 87
    before { project }

88 89 90
    context 'when unauthenticated' do
      it 'should return authentication error' do
        get api('/projects/all')
91 92 93 94
        response.status.should == 401
      end
    end

95 96 97
    context 'when authenticated as regular user' do
      it 'should return authentication error' do
        get api('/projects/all', user)
98 99 100 101
        response.status.should == 403
      end
    end

102 103 104
    context 'when authenticated as admin' do
      it 'should return an array of all projects' do
        get api('/projects/all', admin)
105 106
        response.status.should == 200
        json_response.should be_an Array
Marin Jankovski's avatar
Marin Jankovski committed
107 108 109 110 111 112 113 114 115
        project_name = project.name

        json_response.detect {
          |project| project['name'] == project_name
        }['name'].should == project_name

        json_response.detect {
          |project| project['owner']['username'] == user.username
        }['owner']['username'].should == user.username
116 117 118 119
      end
    end
  end

120 121
  describe 'POST /projects' do
    context 'maximum number of projects reached' do
122 123
      before do
        (1..user2.projects_limit).each do |project|
124
          post api('/projects', user2), name: "foo#{project}"
125 126 127
        end
      end

128
      it 'should not create new project' do
129
        expect {
130
          post api('/projects', user2), name: 'foo'
131
        }.to change {Project.count}.by(0)
132 133 134
      end
    end

135 136
    it 'should create new project without path' do
      expect { post api('/projects', user), name: 'foo' }.to change {Project.count}.by(1)
137
    end
Alex Denisov's avatar
Alex Denisov committed
138

139 140
    it 'should not create new project without name' do
      expect { post api('/projects', user) }.to_not change {Project.count}
Alex Denisov's avatar
Alex Denisov committed
141 142
    end

143 144
    it 'should return a 400 error if name not given' do
      post api('/projects', user)
145 146 147
      response.status.should == 400
    end

148 149 150
    it 'should create last project before reaching project limit' do
      (1..user2.projects_limit-1).each { |p| post api('/projects', user2), name: "foo#{p}" }
      post api('/projects', user2), name: 'foo'
151 152 153
      response.status.should == 201
    end

154 155
    it 'should respond with 201 on success' do
      post api('/projects', user), name: 'foo'
156
      response.status.should == 201
157
    end
Alex Denisov's avatar
Alex Denisov committed
158

159 160
    it 'should respond with 400 if name is not given' do
      post api('/projects', user)
161
      response.status.should == 400
162
    end
Alex Denisov's avatar
Alex Denisov committed
163

164
    it 'should return a 403 error if project limit reached' do
165
      (1..user.projects_limit).each do |p|
166
        post api('/projects', user), name: "foo#{p}"
167
      end
168
      post api('/projects', user), name: 'bar'
169 170 171
      response.status.should == 403
    end

172
    it 'should assign attributes to project' do
173
      project = attributes_for(:project, {
174
        path: 'camelCasePath',
175 176 177 178
        description: Faker::Lorem.sentence,
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
Alex Denisov's avatar
Alex Denisov committed
179 180
      })

181
      post api('/projects', user), project
Alex Denisov's avatar
Alex Denisov committed
182

183
      project.each_pair do |k,v|
Alex Denisov's avatar
Alex Denisov committed
184 185
        json_response[k.to_s].should == v
      end
186
    end
187

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

195
    it 'should set a project as public using :public' do
196
      project = attributes_for(:project, { public: true })
197
      post api('/projects', user), project
198
      json_response['public'].should be_true
199 200 201
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end

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

209
    it 'should set a project as internal overriding :public' do
210
      project = attributes_for(:project, :internal, { public: true })
211
      post api('/projects', user), project
212 213
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
214 215
    end

216
    it 'should set a project as private' do
217
      project = attributes_for(:project, :private)
218
      post api('/projects', user), project
219 220 221 222
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
    end

223
    it 'should set a project as private using :public' do
224
      project = attributes_for(:project, { public: false })
225
      post api('/projects', user), project
226
      json_response['public'].should be_false
227
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
228
    end
229 230
  end

231
  describe 'POST /projects/user/:id' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
232
    before { project }
Angus MacArthur's avatar
Angus MacArthur committed
233 234
    before { admin }

235
    it 'should create new project without path' do
236
      expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
Angus MacArthur's avatar
Angus MacArthur committed
237 238
    end

239
    it 'should not create new project without name' do
240
      expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
Angus MacArthur's avatar
Angus MacArthur committed
241 242
    end

243
    it 'should respond with 201 on success' do
Angus MacArthur's avatar
Angus MacArthur committed
244 245 246 247
      post api("/projects/user/#{user.id}", admin), name: 'foo'
      response.status.should == 201
    end

248
    it 'should respond with 400 on failure' do
Angus MacArthur's avatar
Angus MacArthur committed
249
      post api("/projects/user/#{user.id}", admin)
250 251 252 253
      response.status.should == 400
      json_response['message']['name'].should == [
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
254
        Gitlab::Regex.project_regex_message
255 256 257 258
      ]
      json_response['message']['path'].should == [
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
259
        Gitlab::Regex.send(:default_regex_message)
260
      ]
Angus MacArthur's avatar
Angus MacArthur committed
261 262
    end

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

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

273
      project.each_pair do |k,v|
Angus MacArthur's avatar
Angus MacArthur committed
274 275 276 277
        next if k == :path
        json_response[k.to_s].should == v
      end
    end
278

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

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

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

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

307
    it 'should set a project as private' do
308
      project = attributes_for(:project, :private)
309 310 311
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
312 313
    end

314
    it 'should set a project as private using :public' do
315 316 317 318 319
      project = attributes_for(:project, { public: false })
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
    end
Angus MacArthur's avatar
Angus MacArthur committed
320 321
  end

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

326
    it 'should return a project by id' do
Robert Speicher's avatar
Robert Speicher committed
327
      get api("/projects/#{project.id}", user)
Nihad Abbasov's avatar
Nihad Abbasov committed
328
      response.status.should == 200
Nihad Abbasov's avatar
Nihad Abbasov committed
329
      json_response['name'].should == project.name
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
330
      json_response['owner']['username'].should == user.username
Nihad Abbasov's avatar
Nihad Abbasov committed
331
    end
332

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

339 340
    it 'should return a 404 error if not found' do
      get api('/projects/42', user)
341
      response.status.should == 404
Marin Jankovski's avatar
Marin Jankovski committed
342
      json_response['message'].should == '404 Project Not Found'
343
    end
344

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

    describe 'permissions' do
      context 'personal project' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
353 354 355 356
        before do
          project.team << [user, :master]
          get api("/projects/#{project.id}", user)
        end
357 358

        it { response.status.should == 200 }
359 360
        it { json_response['permissions']['project_access']['access_level'].should == Gitlab::Access::MASTER }
        it { json_response['permissions']['group_access'].should be_nil }
361 362 363 364 365 366 367 368 369 370
      end

      context 'group project' do
        before do
          project2 = create(:project, group: create(:group))
          project2.group.add_owner(user)
          get api("/projects/#{project2.id}", user)
        end

        it { response.status.should == 200 }
371 372
        it { json_response['permissions']['project_access'].should be_nil }
        it { json_response['permissions']['group_access']['access_level'].should == Gitlab::Access::OWNER }
373 374
      end
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
375 376
  end

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

380
    it 'should return a project events' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
381 382 383 384 385 386
      get api("/projects/#{project.id}/events", user)
      response.status.should == 200
      json_event = json_response.first

      json_event['action_name'].should == 'joined'
      json_event['project_id'].to_i.should == project.id
387
      json_event['author_username'].should == user.username
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
388 389
    end

390 391
    it 'should return a 404 error if not found' do
      get api('/projects/42/events', user)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
392
      response.status.should == 404
Marin Jankovski's avatar
Marin Jankovski committed
393
      json_response['message'].should == '404 Project Not Found'
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
394 395
    end

396
    it 'should return a 404 error if user is not a member' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
397 398 399 400 401 402
      other_user = create(:user)
      get api("/projects/#{project.id}/events", other_user)
      response.status.should == 404
    end
  end

403
  describe 'GET /projects/:id/snippets' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
404 405
    before { snippet }

406
    it 'should return an array of project snippets' do
407
      get api("/projects/#{project.id}/snippets", user)
408 409 410 411 412 413
      response.status.should == 200
      json_response.should be_an Array
      json_response.first['title'].should == snippet.title
    end
  end

414 415
  describe 'GET /projects/:id/snippets/:snippet_id' do
    it 'should return a project snippet' do
416
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
Nihad Abbasov's avatar
Nihad Abbasov committed
417
      response.status.should == 200
Nihad Abbasov's avatar
Nihad Abbasov committed
418
      json_response['title'].should == snippet.title
Nihad Abbasov's avatar
Nihad Abbasov committed
419
    end
420

421
    it 'should return a 404 error if snippet id not found' do
422 423 424
      get api("/projects/#{project.id}/snippets/1234", user)
      response.status.should == 404
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
425 426
  end

427 428
  describe 'POST /projects/:id/snippets' do
    it 'should create a new project snippet' do
429
      post api("/projects/#{project.id}/snippets", user),
430
        title: 'api test', file_name: 'sample.rb', code: 'test'
Nihad Abbasov's avatar
Nihad Abbasov committed
431
      response.status.should == 201
Nihad Abbasov's avatar
Nihad Abbasov committed
432
      json_response['title'].should == 'api test'
Nihad Abbasov's avatar
Nihad Abbasov committed
433
    end
434

435
    it 'should return a 400 error if title is not given' do
436
      post api("/projects/#{project.id}/snippets", user),
437
        file_name: 'sample.rb', code: 'test'
438 439
      response.status.should == 400
    end
440

441
    it 'should return a 400 error if file_name not given' do
442
      post api("/projects/#{project.id}/snippets", user),
443
        title: 'api test', code: 'test'
444 445 446
      response.status.should == 400
    end

447
    it 'should return a 400 error if code not given' do
448
      post api("/projects/#{project.id}/snippets", user),
449
        title: 'api test', file_name: 'sample.rb'
450 451
      response.status.should == 400
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
452 453
  end

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

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

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

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

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

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

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

499 500 501
  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
502

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

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

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

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

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

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

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

555
    describe 'DELETE /projects/:id/keys/:key_id' do
556 557
      before { deploy_key }

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

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

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
573
    let(:project_fork_source) { create(:project, :public) }
574

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

      it "shouldn't available for non admin users" do
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
        response.status.should == 403
      end

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

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

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

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

      it "shouldn't available for non admin users" do
        delete api("/projects/#{project_fork_target.id}/fork", user)
        response.status.should == 403
      end

617
      it 'should make forked project unforked' do
618 619 620 621 622 623 624 625 626 627 628
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
        project_fork_target.forked_from_project.should_not be_nil
        project_fork_target.forked?.should be_true
        delete api("/projects/#{project_fork_target.id}/fork", admin)
        response.status.should == 200
        project_fork_target.reload
        project_fork_target.forked_from_project.should be_nil
        project_fork_target.forked?.should_not be_true
      end

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

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

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

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

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

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
  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
        response.status.should == 401
      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
        response.status.should == 200
        project_param.each_pair do |k, v|
          json_response[k.to_s].should == v
        end
      end

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

      it 'should not update name to existing name' do
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
        response.status.should == 400
        json_response['message']['name'].should == ['has already been taken']
      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
        response.status.should == 200
        project_param.each_pair do |k, v|
          json_response[k.to_s].should == v
        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
        response.status.should == 200
        project_param.each_pair do |k, v|
          json_response[k.to_s].should == v
        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
        response.status.should == 200
        project_param.each_pair do |k, v|
          json_response[k.to_s].should == v
        end
      end

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

      it 'should not update name' do
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
        response.status.should == 403
      end

      it 'should not update visibility_level' do
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
        response.status.should == 403
      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
        response.status.should == 403
      end
    end
  end

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

798 799 800 801
        delete api("/projects/#{project.id}", user)
        response.status.should == 200
      end

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

809 810
      it 'should not remove a non existing project' do
        delete api('/projects/1328', user)
811 812 813
        response.status.should == 404
      end

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

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

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