BigW Consortium Gitlab

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

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 committed
10
  let(:admin) { create(:admin) }
11
  let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
12
  let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) }
13
  let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') }
14 15
  let(:project_member) { create(:project_member, :master, user: user, project: project) }
  let(:project_member2) { create(:project_member, :developer, user: user3, project: project) }
16
  let(:user4) { create(:user) }
17 18
  let(:project3) do
    create(:project,
19
    :private,
20 21 22 23 24 25
    name: 'second_project',
    path: 'second_project',
    creator_id: user.id,
    namespace: user.namespace,
    merge_requests_enabled: false,
    issues_enabled: false, wiki_enabled: false,
26
    snippets_enabled: false)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
  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
43 44
    before { project }

45
    context 'when unauthenticated' do
46
      it 'returns authentication error' do
47
        get api('/projects')
48
        expect(response).to have_http_status(401)
49
      end
Nihad Abbasov committed
50 51
    end

52
    context 'when authenticated' do
53
      it 'returns an array of projects' do
54
        get api('/projects', user)
55
        expect(response).to have_http_status(200)
56 57 58
        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 committed
59
      end
60

61
      it 'includes the project labels as the tag_list' do
62
        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
      it 'includes open_issues_count' do
69 70 71 72 73 74
        get api('/projects', user)
        expect(response.status).to eq 200
        expect(json_response).to be_an Array
        expect(json_response.first.keys).to include('open_issues_count')
      end

75
      it 'does not include open_issues_count' do
76
        project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
77 78 79 80 81 82 83

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

84
      context 'GET /projects?simple=true' do
85
        it 'returns a simplified version of all the projects' do
86
          expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"]
87

88
          get api('/projects?simple=true', user)
89

90 91
          expect(response).to have_http_status(200)
          expect(json_response).to be_an Array
92
          expect(json_response.first.keys).to match_array expected_keys
93 94 95
        end
      end

96
      context 'and using search' do
97
        it 'returns searched project' do
98
          get api('/projects', user), { search: project.name }
99
          expect(response).to have_http_status(200)
100 101
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
102 103 104
        end
      end

Josh Frye committed
105
      context 'and using the visibility filter' do
106
        it 'filters based on private visibility param' do
Josh Frye committed
107
          get api('/projects', user), { visibility: 'private' }
108
          expect(response).to have_http_status(200)
Josh Frye committed
109 110 111 112
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).count)
        end

113
        it 'filters based on internal visibility param' do
Josh Frye committed
114
          get api('/projects', user), { visibility: 'internal' }
115
          expect(response).to have_http_status(200)
Josh Frye committed
116 117 118 119
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).count)
        end

120
        it 'filters based on public visibility param' do
Josh Frye committed
121
          get api('/projects', user), { visibility: 'public' }
122
          expect(response).to have_http_status(200)
Josh Frye committed
123 124 125 126 127
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).count)
        end
      end

128
      context 'and using sorting' do
129 130 131 132 133
        before do
          project2
          project3
        end

134
        it 'returns the correct order when sorted by id' do
135
          get api('/projects', user), { order_by: 'id', sort: 'desc' }
136
          expect(response).to have_http_status(200)
137 138
          expect(json_response).to be_an Array
          expect(json_response.first['id']).to eq(project3.id)
139 140
        end
      end
Nihad Abbasov committed
141 142 143
    end
  end

144
  describe 'GET /projects/all' do
145 146
    before { project }

147
    context 'when unauthenticated' do
148
      it 'returns authentication error' do
149
        get api('/projects/all')
150
        expect(response).to have_http_status(401)
151 152 153
      end
    end

154
    context 'when authenticated as regular user' do
155
      it 'returns authentication error' do
156
        get api('/projects/all', user)
157
        expect(response).to have_http_status(403)
158 159 160
      end
    end

161
    context 'when authenticated as admin' do
162
      it 'returns an array of all projects' do
163
        get api('/projects/all', admin)
164
        expect(response).to have_http_status(200)
165
        expect(json_response).to be_an Array
Marin Jankovski committed
166

167 168
        expect(json_response).to satisfy do |response|
          response.one? do |entry|
169
            entry.has_key?('permissions') &&
170
            entry['name'] == project.name &&
171
              entry['owner']['username'] == user.username
172 173
          end
        end
174 175 176 177
      end
    end
  end

178 179 180
  describe 'GET /projects/visible' do
    let(:public_project) { create(:project, :public) }

181 182 183 184 185 186 187 188
    before do
      public_project
      project
      project2
      project3
      project4
    end

189
    it 'returns the projects viewable by the user' do
190 191 192 193 194 195 196 197 198 199 200
      get api('/projects/visible', user)

      expect(response).to have_http_status(200)
      expect(json_response).to be_an Array
      expect(json_response.map { |project| project['id'] }).
        to contain_exactly(public_project.id, project.id, project2.id, project3.id)
    end

    it 'shows only public projects when the user only has access to those' do
      get api('/projects/visible', user2)

201 202
      expect(response).to have_http_status(200)
      expect(json_response).to be_an Array
203 204
      expect(json_response.map { |project| project['id'] }).
        to contain_exactly(public_project.id)
205 206 207
    end
  end

208
  describe 'GET /projects/starred' do
209 210
    let(:public_project) { create(:project, :public) }

211
    before do
212 213
      project_member2
      user3.update_attributes(starred_projects: [project, project2, project3, public_project])
214 215
    end

216
    it 'returns the starred projects viewable by the user' do
217
      get api('/projects/starred', user3)
218
      expect(response).to have_http_status(200)
219
      expect(json_response).to be_an Array
220
      expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, public_project.id)
221 222 223
    end
  end

224 225
  describe 'POST /projects' do
    context 'maximum number of projects reached' do
226
      it 'does not create new project and respond with 403' do
227
        allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
228 229
        expect { post api('/projects', user2), name: 'foo' }.
          to change {Project.count}.by(0)
230
        expect(response).to have_http_status(403)
231 232 233
      end
    end

234
    it 'creates new project without path and return 201' do
235 236
      expect { post api('/projects', user), name: 'foo' }.
        to change { Project.count }.by(1)
237
      expect(response).to have_http_status(201)
238 239
    end

240
    it 'creates last project before reaching project limit' do
241
      allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1)
242
      post api('/projects', user2), name: 'foo'
243
      expect(response).to have_http_status(201)
244 245
    end

246
    it 'does not create new project without name and return 400' do
247
      expect { post api('/projects', user) }.not_to change { Project.count }
248
      expect(response).to have_http_status(400)
249
    end
Alex Denisov committed
250

251
    it "assigns attributes to project" do
252
      project = attributes_for(:project, {
253
        path: 'camelCasePath',
Robert Speicher committed
254
        description: FFaker::Lorem.sentence,
255 256
        issues_enabled: false,
        merge_requests_enabled: false,
257
        wiki_enabled: false,
258 259
        only_allow_merge_if_build_succeeds: false,
        request_access_enabled: true
Alex Denisov committed
260 261
      })

262
      post api('/projects', user), project
Alex Denisov committed
263

264
      project.each_pair do |k, v|
265
        next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k)
266
        expect(json_response[k.to_s]).to eq(v)
Alex Denisov committed
267
      end
268 269 270 271 272 273

      # Check feature permissions attributes
      project = Project.find_by_path(project[:path])
      expect(project.project_feature.issues_access_level).to eq(ProjectFeature::DISABLED)
      expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::DISABLED)
      expect(project.project_feature.wiki_access_level).to eq(ProjectFeature::DISABLED)
274
    end
275

276
    it 'sets a project as public' do
277
      project = attributes_for(:project, :public)
278
      post api('/projects', user), project
279 280
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
281 282
    end

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

290
    it 'sets a project as internal' do
291
      project = attributes_for(:project, :internal)
292
      post api('/projects', user), project
293 294
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
295 296
    end

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

304
    it 'sets a project as private' do
305
      project = attributes_for(:project, :private)
306
      post api('/projects', user), project
307 308
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
309 310
    end

311
    it 'sets a project as private using :public' do
312
      project = attributes_for(:project, { public: false })
313
      post api('/projects', user), project
314 315
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
316
    end
317

318 319 320 321 322 323 324 325 326 327 328 329
    it 'sets a project as allowing merge even if build fails' do
      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false })
      post api('/projects', user), project
      expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey
    end

    it 'sets a project as allowing merge only if build succeeds' do
      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true })
      post api('/projects', user), project
      expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy
    end

330 331 332
    context 'when a visibility level is restricted' do
      before do
        @project = attributes_for(:project, { public: true })
333
        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
334 335
      end

336
      it 'does not allow a non-admin to use a restricted visibility level' do
337
        post api('/projects', user), @project
Felipe Artur committed
338

339
        expect(response).to have_http_status(400)
340 341 342 343 344
        expect(json_response['message']['visibility_level'].first).to(
          match('restricted by your GitLab administrator')
        )
      end

345
      it 'allows an admin to override restricted visibility settings' do
346 347 348 349 350 351 352
        post api('/projects', admin), @project
        expect(json_response['public']).to be_truthy
        expect(json_response['visibility_level']).to(
          eq(Gitlab::VisibilityLevel::PUBLIC)
        )
      end
    end
353 354
  end

355
  describe 'POST /projects/user/:id' do
356
    before { project }
Angus MacArthur committed
357 358
    before { admin }

359
    it 'should create new project without path and return 201' do
360
      expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
361
      expect(response).to have_http_status(201)
Angus MacArthur committed
362 363
    end

364
    it 'responds with 400 on failure and not project' do
365
      expect { post api("/projects/user/#{user.id}", admin) }.
366
        not_to change { Project.count }
367

368
      expect(response).to have_http_status(400)
369
      expect(json_response['message']['name']).to eq([
370 371
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
372
        Gitlab::Regex.project_name_regex_message
373 374
      ])
      expect(json_response['message']['path']).to eq([
375 376
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
Douwe Maan committed
377
        Gitlab::Regex.send(:project_path_regex_message)
378
      ])
Angus MacArthur committed
379 380
    end

381
    it 'assigns attributes to project' do
Angus MacArthur committed
382
      project = attributes_for(:project, {
Robert Speicher committed
383
        description: FFaker::Lorem.sentence,
384 385
        issues_enabled: false,
        merge_requests_enabled: false,
386 387
        wiki_enabled: false,
        request_access_enabled: true
Angus MacArthur committed
388 389 390 391
      })

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

392
      project.each_pair do |k, v|
393
        next if %i[has_external_issue_tracker path].include?(k)
394
        expect(json_response[k.to_s]).to eq(v)
Angus MacArthur committed
395 396
      end
    end
397

398
    it 'sets a project as public' do
399
      project = attributes_for(:project, :public)
400
      post api("/projects/user/#{user.id}", admin), project
401 402
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
403 404
    end

405
    it 'sets a project as public using :public' do
406 407
      project = attributes_for(:project, { public: true })
      post api("/projects/user/#{user.id}", admin), project
408 409
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
410
    end
411

412
    it 'sets a project as internal' do
413
      project = attributes_for(:project, :internal)
414
      post api("/projects/user/#{user.id}", admin), project
415 416
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
417 418
    end

419
    it 'sets a project as internal overriding :public' do
420
      project = attributes_for(:project, :internal, { public: true })
421
      post api("/projects/user/#{user.id}", admin), project
422 423
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
424
    end
425

426
    it 'sets a project as private' do
427
      project = attributes_for(:project, :private)
428
      post api("/projects/user/#{user.id}", admin), project
429 430
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
431 432
    end

433
    it 'sets a project as private using :public' do
434 435
      project = attributes_for(:project, { public: false })
      post api("/projects/user/#{user.id}", admin), project
436 437
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
438
    end
439 440 441 442 443 444 445 446 447 448 449 450

    it 'sets a project as allowing merge even if build fails' do
      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false })
      post api("/projects/user/#{user.id}", admin), project
      expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey
    end

    it 'sets a project as allowing merge only if build succeeds' do
      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true })
      post api("/projects/user/#{user.id}", admin), project
      expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy
    end
Angus MacArthur committed
451 452
  end

453 454 455 456 457 458
  describe "POST /projects/:id/uploads" do
    before { project }

    it "uploads the file and returns its info" do
      post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")

459
      expect(response).to have_http_status(201)
460 461 462 463 464 465
      expect(json_response['alt']).to eq("dk")
      expect(json_response['url']).to start_with("/uploads/")
      expect(json_response['url']).to end_with("/dk.png")
    end
  end

466
  describe 'GET /projects/:id' do
467
    before { project }
468
    before { project_member }
469

470 471 472 473
    it 'returns a project by id' do
      group = create(:group)
      link = create(:project_group_link, project: project, group: group)

Robert Speicher committed
474
      get api("/projects/#{project.id}", user)
475

476
      expect(response).to have_http_status(200)
477 478 479 480 481 482 483 484 485 486 487 488
      expect(json_response['id']).to eq(project.id)
      expect(json_response['description']).to eq(project.description)
      expect(json_response['default_branch']).to eq(project.default_branch)
      expect(json_response['tag_list']).to be_an Array
      expect(json_response['public']).to be_falsey
      expect(json_response['archived']).to be_falsey
      expect(json_response['visibility_level']).to be_present
      expect(json_response['ssh_url_to_repo']).to be_present
      expect(json_response['http_url_to_repo']).to be_present
      expect(json_response['web_url']).to be_present
      expect(json_response['owner']).to be_a Hash
      expect(json_response['owner']).to be_a Hash
489
      expect(json_response['name']).to eq(project.name)
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
      expect(json_response['path']).to be_present
      expect(json_response['issues_enabled']).to be_present
      expect(json_response['merge_requests_enabled']).to be_present
      expect(json_response['wiki_enabled']).to be_present
      expect(json_response['builds_enabled']).to be_present
      expect(json_response['snippets_enabled']).to be_present
      expect(json_response['container_registry_enabled']).to be_present
      expect(json_response['created_at']).to be_present
      expect(json_response['last_activity_at']).to be_present
      expect(json_response['shared_runners_enabled']).to be_present
      expect(json_response['creator_id']).to be_present
      expect(json_response['namespace']).to be_present
      expect(json_response['avatar_url']).to be_nil
      expect(json_response['star_count']).to be_present
      expect(json_response['forks_count']).to be_present
      expect(json_response['public_builds']).to be_present
      expect(json_response['shared_with_groups']).to be_an Array
      expect(json_response['shared_with_groups'].length).to eq(1)
      expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id)
      expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name)
      expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access)
511
      expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds)
Nihad Abbasov committed
512
    end
513

514
    it 'returns a project by path name' do
515
      get api("/projects/#{project.id}", user)
516
      expect(response).to have_http_status(200)
517
      expect(json_response['name']).to eq(project.name)
518
    end
519

520
    it 'returns a 404 error if not found' do
521
      get api('/projects/42', user)
522
      expect(response).to have_http_status(404)
523
      expect(json_response['message']).to eq('404 Project Not Found')
524
    end
525

526
    it 'returns a 404 error if user is not a member' do
527 528
      other_user = create(:user)
      get api("/projects/#{project.id}", other_user)
529
      expect(response).to have_http_status(404)
530
    end
531

532
    it 'handles users with dots' do
533 534 535 536
      dot_user = create(:user, username: 'dot.user')
      project = create(:project, creator_id: dot_user.id, namespace: dot_user.namespace)

      get api("/projects/#{dot_user.namespace.name}%2F#{project.path}", dot_user)
537
      expect(response).to have_http_status(200)
538 539 540
      expect(json_response['name']).to eq(project.name)
    end

541
    describe 'permissions' do
542
      context 'all projects' do
543 544 545
        before { project.team << [user, :master] }

        it 'contains permission information' do
546 547
          get api("/projects", user)

548
          expect(response).to have_http_status(200)
549 550 551 552 553 554
          expect(json_response.first['permissions']['project_access']['access_level']).
              to eq(Gitlab::Access::MASTER)
          expect(json_response.first['permissions']['group_access']).to be_nil
        end
      end

555
      context 'personal project' do
556
        it 'sets project access and returns 200' do
557 558
          project.team << [user, :master]
          get api("/projects/#{project.id}", user)
559

560
          expect(response).to have_http_status(200)
561 562 563 564
          expect(json_response['permissions']['project_access']['access_level']).
            to eq(Gitlab::Access::MASTER)
          expect(json_response['permissions']['group_access']).to be_nil
        end
565 566 567
      end

      context 'group project' do
568 569 570 571
        let(:project2) { create(:project, group: create(:group)) }

        before { project2.group.add_owner(user) }

572
        it 'sets the owner and return 200' do
573 574
          get api("/projects/#{project2.id}", user)

575
          expect(response).to have_http_status(200)
576 577 578 579
          expect(json_response['permissions']['project_access']).to be_nil
          expect(json_response['permissions']['group_access']['access_level']).
            to eq(Gitlab::Access::OWNER)
        end
580 581
      end
    end
Nihad Abbasov committed
582 583
  end

584
  describe 'GET /projects/:id/events' do
Douwe Maan committed
585
    before { project_member2 }
586

587 588 589 590 591 592
    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)
      end

593 594
      it 'returns all events' do
        get api("/projects/#{project.id}/events", user)
595

596
        expect(response).to have_http_status(200)
597

598
        first_event = json_response.first
599

600 601
        expect(first_event['action_name']).to eq('commented on')
        expect(first_event['note']['body']).to eq('What an awesome day!')
602

603 604 605 606 607 608
        last_event = json_response.last

        expect(last_event['action_name']).to eq('joined')
        expect(last_event['project_id'].to_i).to eq(project.id)
        expect(last_event['author_username']).to eq(user3.username)
        expect(last_event['author']['name']).to eq(user3.name)
609
      end
610 611
    end

612
    it 'returns a 404 error if not found' do
613
      get api('/projects/42/events', user)
614

615
      expect(response).to have_http_status(404)
616
      expect(json_response['message']).to eq('404 Project Not Found')
617 618
    end

619
    it 'returns a 404 error if user is not a member' do
620
      other_user = create(:user)
621

622
      get api("/projects/#{project.id}/events", other_user)
623

624
      expect(response).to have_http_status(404)
625 626 627
    end
  end

628
  describe 'GET /projects/:id/snippets' do
629 630
    before { snippet }

631
    it 'returns an array of project snippets' do
632
      get api("/projects/#{project.id}/snippets", user)
633
      expect(response).to have_http_status(200)
634 635
      expect(json_response).to be_an Array
      expect(json_response.first['title']).to eq(snippet.title)
636 637 638
    end
  end

639
  describe 'GET /projects/:id/snippets/:snippet_id' do
640
    it 'returns a project snippet' do
641
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
642
      expect(response).to have_http_status(200)
643
      expect(json_response['title']).to eq(snippet.title)
Nihad Abbasov committed
644
    end
645

646
    it 'returns a 404 error if snippet id not found' do
647
      get api("/projects/#{project.id}/snippets/1234", user)
648
      expect(response).to have_http_status(404)
649
    end
Nihad Abbasov committed
650 651
  end

652
  describe 'POST /projects/:id/snippets' do
653
    it 'creates a new project snippet' do
654
      post api("/projects/#{project.id}/snippets", user),
655 656
        title: 'api test', file_name: 'sample.rb', code: 'test',
        visibility_level: '0'
657
      expect(response).to have_http_status(201)
658
      expect(json_response['title']).to eq('api test')
Nihad Abbasov committed
659
    end
660

661
    it 'returns a 400 error if invalid snippet is given' do
662 663
      post api("/projects/#{project.id}/snippets", user)
      expect(status).to eq(400)
664
    end
Nihad Abbasov committed
665 666
  end

667
  describe 'PUT /projects/:id/snippets/:snippet_id' do
668
    it 'updates an existing project snippet' do
669
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
670
        code: 'updated code'
671
      expect(response).to have_http_status(200)
672 673
      expect(json_response['title']).to eq('example')
      expect(snippet.reload.content).to eq('updated code')
674
    end
675

676
    it 'updates an existing project snippet with new title' do
677
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
678
        title: 'other api test'
679
      expect(response).to have_http_status(200)
680
      expect(json_response['title']).to eq('other api test')
681
    end
682 683
  end

684
  describe 'DELETE /projects/:id/snippets/:snippet_id' do
685 686
    before { snippet }

687
    it 'deletes existing project snippet' do
688
      expect do
689
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
690
      end.to change { Snippet.count }.by(-1)
691
      expect(response).to have_http_status(200)
692 693
    end

694
    it 'returns 404 when deleting unknown snippet id' do
695
      delete api("/projects/#{project.id}/snippets/1234", user)
696
      expect(response).to have_http_status(404)
Nihad Abbasov committed
697 698
    end
  end
699

700
  describe 'GET /projects/:id/snippets/:snippet_id/raw' do
701
    it 'gets a raw project snippet' do
702
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
703
      expect(response).to have_http_status(200)
704
    end
705

706
    it 'returns a 404 error if raw project snippet not found' do
707
      get api("/projects/#{project.id}/snippets/5555/raw", user)
708
      expect(response).to have_http_status(404)
709
    end
710
  end
711

712 713
  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
714
    let(:project_fork_source) { create(:project, :public) }
715

716
    describe 'POST /projects/:id/fork/:forked_from_id' do
717
      let(:new_project_fork_source) { create(:project, :public) }
718

719
      it "is not available for non admin users" do
720
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
721
        expect(response).to have_http_status(403)
722 723
      end

724
      it 'allows project to be forked from an existing project' do
725
        expect(project_fork_target.forked?).not_to be_truthy
726
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
727
        expect(response).to have_http_status(201)
728
        project_fork_target.reload
729 730 731
        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
732 733
      end

734
      it 'fails if forked_from project which does not exist' do
735
        post api("/projects/#{project_fork_target.id}/fork/9999", admin)
736
        expect(response).to have_http_status(404)
737 738
      end

739
      it 'fails with 409 if already forked' do
740 741
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
742
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
743
        post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
744
        expect(response).to have_http_status(409)
745
        project_fork_target.reload
746 747
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
        expect(project_fork_target.forked?).to be_truthy
748 749 750
      end
    end

751
    describe 'DELETE /projects/:id/fork' do
752
      it "is not visible to users outside group" do
753
        delete api("/projects/#{project_fork_target.id}/fork", user)
754
        expect(response).to have_http_status(404)
755 756
      end

757 758
      context 'when users belong to project group' do
        let(:project_fork_target) { create(:project, group: create(:group)) }
759

760 761 762 763 764
        before do
          project_fork_target.group.add_owner user
          project_fork_target.group.add_developer user2
        end

765
        it 'is forbidden to non-owner users' do
766
          delete api("/projects/#{project_fork_target.id}/fork", user2)
767
          expect(response).to have_http_status(403)
768 769
        end

770
        it 'makes forked project unforked' do
771 772 773 774 775
          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)
776
          expect(response).to have_http_status(200)
777 778 779 780 781
          project_fork_target.reload
          expect(project_fork_target.forked_from_project).to be_nil
          expect(project_fork_target.forked?).not_to be_truthy
        end

782
        it 'is idempotent if not forked' do
783 784
          expect(project_fork_target.forked_from_project).to be_nil
          delete api("/projects/#{project_fork_target.id}/fork", admin)
785
          expect(response).to have_http_status(200)
786 787
          expect(project_fork_target.reload.forked_from_project).to be_nil
        end
788 789 790
      end
    end
  end
791

792 793 794
  describe "POST /projects/:id/share" do
    let(:group) { create(:group) }

795
    it "shares project with group" do
796 797
      expires_at = 10.days.from_now.to_date

798
      expect do
799
        post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at
800 801 802
      end.to change { ProjectGroupLink.count }.by(1)

      expect(response.status).to eq 201
803 804 805
      expect(json_response['group_id']).to eq(group.id)
      expect(json_response['group_access']).to eq(Gitlab::Access::DEVELOPER)
      expect(json_response['expires_at']).to eq(expires_at.to_s)
806 807
    end

808
    it "returns a 400 error when group id is not given" do
809 810 811 812
      post api("/projects/#{project.id}/share", user), group_access: Gitlab::Access::DEVELOPER
      expect(response.status).to eq 400
    end

813
    it "returns a 400 error when access level is not given" do
814 815 816 817
      post api("/projects/#{project.id}/share", user), group_id: group.id
      expect(response.status).to eq 400
    end

818
    it "returns a 400 error when sharing is disabled" do
819 820 821 822 823
      project.namespace.update(share_with_group_lock: true)
      post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER
      expect(response.status).to eq 400
    end

824 825 826 827 828 829 830 831 832 833 834 835 836 837
    it 'returns a 404 error when user cannot read group' do
      private_group = create(:group, :private)

      post api("/projects/#{project.id}/share", user), group_id: private_group.id, group_access: Gitlab::Access::DEVELOPER

      expect(response.status).to eq 404
    end

    it 'returns a 404 error when group does not exist' do
      post api("/projects/#{project.id}/share", user), group_id: 1234, group_access: Gitlab::Access::DEVELOPER

      expect(response.status).to eq 404
    end

838
    it "returns a 409 error when wrong params passed" do
839 840 841 842 843 844
      post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234
      expect(response.status).to eq 409
      expect(json_response['message']).to eq 'Group access is not included in the list'
    end
  end

845
  describe 'GET /projects/search/:query' do
846
    let!(:query) { 'query'}
847 848 849 850 851
    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) }
852 853 854 855
    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') }
856

857
    context 'when unauthenticated' do
858
      it 'returns authentication error' do
859
        get api("/projects/search/#{query}")
860
        expect(response).to have_http_status(401)
861 862 863
      end
    end

864
    context 'when authenticated' do
865
      it 'returns an array of projects' do
866
        get api("/projects/search/#{query}", user)
867
        expect(response).to have_http_status(200)
868 869 870
        expect(json_response).to be_an Array
        expect(json_response.size).to eq(6)
        json_response.each {|project| expect(project['name']).to match(/.*query.*/)}
871 872 873
      end
    end

874
    context 'when authenticated as a different user' do
875
      it 'returns matching public projects' do
876
        get api("/projects/search/#{query}", user2)
877
        expect(response).to have_http_status(200)
878 879 880
        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/)}
881 882 883
      end
    end
  end
884

885 886 887 888 889 890 891 892 893 894 895
  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
896
      it 'returns authentication error' do
897 898
        project_param = { name: 'bar' }
        put api("/projects/#{project.id}"), project_param
899
        expect(response).to have_http_status(401)
900 901 902 903
      end
    end

    context 'when authenticated as project owner' do
904
      it 'updates name' do
905 906
        project_param = { name: 'bar' }
        put api("/projects/#{project.id}", user), project_param
907
        expect(response).to have_http_status(200)
908
        project_param.each_pair do |k, v|
909
          expect(json_response[k.to_s]).to eq(v)
910 911 912
        end
      end

913
      it 'updates visibility_level' do
914 915
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user), project_param
916
        expect(response).to have_http_status(200)
917
        project_param.each_pair do |k, v|
918
          expect(json_response[k.to_s]).to eq(v)
919 920 921
        end
      end

922
      it 'updates visibility_level from public to private' do
923 924 925 926
        project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })

        project_param = { public: false }
        put api("/projects/#{project3.id}", user), project_param
927
        expect(response).to have_http_status(200)
928 929 930 931 932 933
        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

934
      it 'does not update name to existing name' do
935 936
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
937
        expect(response).to have_http_status(400)
938
        expect(json_response['message']['name']).to eq(['has already been taken'])
939 940
      end

941 942 943 944 945 946 947 948 949
      it 'updates request_access_enabled' do
        project_param = { request_access_enabled: false }

        put api("/projects/#{project.id}", user), project_param

        expect(response).to have_http_status(200)
        expect(json_response['request_access_enabled']).to eq(false)
      end

950
      it 'updates path & name to existing path & name in different namespace' do
951 952
        project_param = { path: project4.path, name: project4.name }
        put api("/projects/#{project3.id}", user), project_param
953
        expect(response).to have_http_status(200)
954
        project_param.each_pair do |k, v|
955
          expect(json_response[k.to_s]).to eq(v)
956 957 958 959 960
        end
      end
    end

    context 'when authenticated as project master' do
961
      it 'updates path' do
962 963
        project_param = { path: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
964
        expect(response).to have_http_status(200)
965
        project_param.each_pair do |k, v|
966
          expect(json_response[k.to_s]).to eq(v)
967 968 969
        end
      end

970
      it 'updates other attributes' do
971 972 973 974 975 976 977
        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
978
        expect(response).to have_http_status(200)
979
        project_param.each_pair do |k, v|
980
          expect(json_response[k.to_s]).to eq(v)
981 982 983
        end
      end

984
      it 'does not update path to existing path' do
985 986
        project_param = { path: project.path }
        put api("/projects/#{project3.id}", user4), project_param
987
        expect(response).to have_http_status(400)
988
        expect(json_response['message']['path']).to eq(['has already been taken'])
989 990
      end

991
      it 'does not update name' do
992 993
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
994
        expect(response).to have_http_status(403)
995 996
      end

997
      it 'does not update visibility_level' do
998 999
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
1000
        expect(response).to have_http_status(403)
1001 1002 1003 1004
      end
    end

    context 'when authenticated as project developer' do
1005
      it 'does not update other attributes' do
1006 1007 1008 1009 1010
        project_param = { path: 'bar',
                          issues_enabled: true,
                          wiki_enabled: true,
                          snippets_enabled: true,
                          merge_requests_enabled: true,
1011 1012
                          description: 'new description',
                          request_access_enabled: true }
1013
        put api("/projects/#{project.id}", user3), project_param
1014
        expect(response).to have_http_status(403)
1015 1016 1017 1018
      end
    end
  end

1019
  describe 'POST /projects/:id/archive' do
1020 1021
    context 'on an unarchived project' do
      it 'archives the project' do
1022
        post api("/projects/#{project.id}/archive", user)
1023

1024
        expect(response).to have_http_status(201)
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        expect(json_response['archived']).to be_truthy
      end
    end

    context 'on an archived project' do
      before do
        project.archive!
      end

      it 'remains archived' do
1035
        post api("/projects/#{project.id}/archive", user)
1036

1037
        expect(response).to have_http_status(201)
1038 1039
        expect(json_response['archived']).to be_truthy
      end
1040
    end
1041

1042 1043 1044 1045
    context 'user without archiving rights to the project' do
      before do
        project.team << [user3, :developer]
      end
1046

1047 1048 1049
      it 'rejects the action' do
        post api("/projects/#{project.id}/archive", user3)

1050
        expect(response).to have_http_status(403)
1051 1052 1053 1054
      end
    end
  end

1055
  describe 'POST /projects/:id/unarchive' do
1056 1057
    context 'on an unarchived project' do
      it 'remains unarchived' do
1058
        post api("/projects/#{project.id}/unarchive", user)
1059

1060
        expect(response).to have_http_status(201)
1061 1062 1063 1064 1065 1066 1067 1068 1069
        expect(json_response['archived']).to be_falsey
      end
    end

    context 'on an archived project' do
      before do
        project.archive!
      end

1070 1071
      it 'unarchives the project' do
        post api("/projects/#{project.id}/unarchive", user)
1072

1073
        expect(response).to have_http_status(201)
1074 1075
        expect(json_response['archived']).to be_falsey
      end
1076
    end
1077

1078 1079 1080 1081
    context 'user without archiving rights to the project' do
      before do
        project.team << [user3, :developer]
      end
1082

1083 1084 1085
      it 'rejects the action' do
        post api("/projects/#{project.id}/unarchive", user3)

1086
        expect(response).to have_http_status(403)
1087 1088 1089 1090
      end
    end
  end

1091 1092 1093
  describe 'POST /projects/:id/star' do
    context 'on an unstarred project' do
      it 'stars the project' do
1094
        expect { post api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(1)
1095

1096
        expect(response).to have_http_status(201)
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
        expect(json_response['star_count']).to eq(1)
      end
    end

    context 'on a starred project' do
      before do
        user.toggle_star(project)
        project.reload
      end

      it 'does not modify the star count' do
1108
        expect { post api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count }
1109

1110
        expect(response).to have_http_status(304)
1111 1112 1113 1114
      end
    end
  end

1115
  describe 'DELETE /projects/:id/star' do
1116 1117 1118 1119 1120 1121 1122
    context 'on a starred project' do
      before do
        user.toggle_star(project)
        project.reload
      end

      it 'unstars the project' do
1123
        expect { delete api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(-1)
1124

1125
        expect(response).to have_http_status(200)
1126 1127 1128 1129 1130 1131
        expect(json_response['star_count']).to eq(0)
      end
    end

    context 'on an unstarred project' do
      it 'does not modify the star count' do
1132
        expect { delete api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count }
1133

1134
        expect(response).to have_http_status(304)
1135 1136 1137 1138
      end
    end
  end

1139 1140
  describe 'DELETE /projects/:id' do
    context 'when authenticated as user' do
1141
      it 'removes project' do
1142
        delete api("/projects/#{project.id}", user)
1143
        expect(response).to have_http_status(200)
1144 1145
      end

1146
      it 'does not remove a project if not an owner' do
1147 1148 1149
        user3 = create(:user)
        project.team << [user3, :developer]
        delete api("/projects/#{project.id}", user3)
1150
        expect(response).to have_http_status(403)
1151 1152
      end

1153
      it 'does not remove a non existing project' do
1154
        delete api('/projects/1328', user)
1155
        expect(response).to have_http_status(404)
1156 1157
      end

1158
      it 'does not remove a project not attached to user' do
1159
        delete api("/projects/#{project.id}", user2)
1160
        expect(response).to have_http_status(404)
1161 1162 1163
      end
    end

1164
    context 'when authenticated as admin' do
1165
      it 'removes any existing project' do
1166
        delete api("/projects/#{project.id}", admin)
1167
        expect(response).to have_http_status(200)
1168 1169
      end

1170
      it 'does not remove a non existing project' do
1171
        delete api('/projects/1328', admin)
1172
        expect(response).to have_http_status(404)
1173 1174 1175
      end
    end
  end
Nihad Abbasov committed
1176
end