projects_spec.rb 41.0 KB
Newer Older
1
# -*- coding: utf-8 -*-
N
Nihad Abbasov 已提交
2 3
require 'spec_helper'

J
Jeroen van Baarsen 已提交
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) }
A
Angus MacArthur 已提交
10
  let(:admin) { create(:admin) }
D
Dmitriy Zaporozhets 已提交
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
D
Dmitriy Zaporozhets 已提交
43 44
    before { project }

45
    context 'when unauthenticated' do
46
      it 'returns authentication error' do
47
        get api('/projects')
Z
Z.J. van de Weg 已提交
48
        expect(response).to have_http_status(401)
49
      end
N
Nihad Abbasov 已提交
50 51
    end

52
    context 'when authenticated' do
53
      it 'returns an array of projects' do
54
        get api('/projects', user)
Z
Z.J. van de Weg 已提交
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)
N
Nihad Abbasov 已提交
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
S
Stan Hu 已提交
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
F
Felipe Artur 已提交
76
        project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
S
Stan Hu 已提交
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
T
tiagonbotelho 已提交
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)
T
tiagonbotelho 已提交
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 }
Z
Z.J. van de Weg 已提交
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

J
Josh Frye 已提交
105
      context 'and using the visibility filter' do
106
        it 'filters based on private visibility param' do
J
Josh Frye 已提交
107
          get api('/projects', user), { visibility: 'private' }
Z
Z.J. van de Weg 已提交
108
          expect(response).to have_http_status(200)
J
Josh Frye 已提交
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
J
Josh Frye 已提交
114
          get api('/projects', user), { visibility: 'internal' }
Z
Z.J. van de Weg 已提交
115
          expect(response).to have_http_status(200)
J
Josh Frye 已提交
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
J
Josh Frye 已提交
121
          get api('/projects', user), { visibility: 'public' }
Z
Z.J. van de Weg 已提交
122
          expect(response).to have_http_status(200)
J
Josh Frye 已提交
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' }
Z
Z.J. van de Weg 已提交
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
N
Nihad Abbasov 已提交
141 142 143
    end
  end

144
  describe 'GET /projects/all' do
D
Dmitriy Zaporozhets 已提交
145 146
    before { project }

147
    context 'when unauthenticated' do
148
      it 'returns authentication error' do
149
        get api('/projects/all')
Z
Z.J. van de Weg 已提交
150
        expect(response).to have_http_status(401)
D
Dmitriy Zaporozhets 已提交
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)
Z
Z.J. van de Weg 已提交
157
        expect(response).to have_http_status(403)
D
Dmitriy Zaporozhets 已提交
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)
Z
Z.J. van de Weg 已提交
164
        expect(response).to have_http_status(200)
165
        expect(json_response).to be_an Array
M
Marin Jankovski 已提交
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
D
Dmitriy Zaporozhets 已提交
174 175 176 177
      end
    end
  end

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

181
    before do
182 183
      project_member2
      user3.update_attributes(starred_projects: [project, project2, project3, public_project])
184 185
    end

186
    it 'returns the starred projects viewable by the user' do
187
      get api('/projects/starred', user3)
Z
Z.J. van de Weg 已提交
188
      expect(response).to have_http_status(200)
189
      expect(json_response).to be_an Array
190
      expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, public_project.id)
191 192 193
    end
  end

194 195
  describe 'POST /projects' do
    context 'maximum number of projects reached' do
196
      it 'does not create new project and respond with 403' do
197
        allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
198 199
        expect { post api('/projects', user2), name: 'foo' }.
          to change {Project.count}.by(0)
Z
Z.J. van de Weg 已提交
200
        expect(response).to have_http_status(403)
201 202 203
      end
    end

204
    it 'creates new project without path and return 201' do
205 206
      expect { post api('/projects', user), name: 'foo' }.
        to change { Project.count }.by(1)
Z
Z.J. van de Weg 已提交
207
      expect(response).to have_http_status(201)
208 209
    end

210
    it 'creates last project before reaching project limit' do
211
      allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1)
212
      post api('/projects', user2), name: 'foo'
Z
Z.J. van de Weg 已提交
213
      expect(response).to have_http_status(201)
214 215
    end

216
    it 'does not create new project without name and return 400' do
217
      expect { post api('/projects', user) }.not_to change { Project.count }
Z
Z.J. van de Weg 已提交
218
      expect(response).to have_http_status(400)
219
    end
A
Alex Denisov 已提交
220

221
    it "assigns attributes to project" do
222
      project = attributes_for(:project, {
223
        path: 'camelCasePath',
R
Robert Speicher 已提交
224
        description: FFaker::Lorem.sentence,
225 226
        issues_enabled: false,
        merge_requests_enabled: false,
227
        wiki_enabled: false,
228 229
        only_allow_merge_if_build_succeeds: false,
        request_access_enabled: true
A
Alex Denisov 已提交
230 231
      })

232
      post api('/projects', user), project
A
Alex Denisov 已提交
233

234
      project.each_pair do |k, v|
F
Felipe Artur 已提交
235
        next if %i{ issues_enabled merge_requests_enabled wiki_enabled }.include?(k)
236
        expect(json_response[k.to_s]).to eq(v)
A
Alex Denisov 已提交
237
      end
F
Felipe Artur 已提交
238 239 240 241 242 243

      # 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)
244
    end
245

246
    it 'sets a project as public' do
247
      project = attributes_for(:project, :public)
248
      post api('/projects', user), project
249 250
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
251 252
    end

253
    it 'sets a project as public using :public' do
254
      project = attributes_for(:project, { public: true })
255
      post api('/projects', user), project
256 257
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
258 259
    end

260
    it 'sets a project as internal' do
261
      project = attributes_for(:project, :internal)
262
      post api('/projects', user), project
263 264
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
265 266
    end

267
    it 'sets a project as internal overriding :public' do
268
      project = attributes_for(:project, :internal, { public: true })
269
      post api('/projects', user), project
270 271
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
272 273
    end

274
    it 'sets a project as private' do
275
      project = attributes_for(:project, :private)
276
      post api('/projects', user), project
277 278
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
279 280
    end

281
    it 'sets a project as private using :public' do
282
      project = attributes_for(:project, { public: false })
283
      post api('/projects', user), project
284 285
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
286
    end
287

288 289 290 291 292 293 294 295 296 297 298 299
    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

300 301 302
    context 'when a visibility level is restricted' do
      before do
        @project = attributes_for(:project, { public: true })
303
        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
304 305
      end

306
      it 'does not allow a non-admin to use a restricted visibility level' do
307
        post api('/projects', user), @project
F
Felipe Artur 已提交
308

Z
Z.J. van de Weg 已提交
309
        expect(response).to have_http_status(400)
310 311 312 313 314
        expect(json_response['message']['visibility_level'].first).to(
          match('restricted by your GitLab administrator')
        )
      end

315
      it 'allows an admin to override restricted visibility settings' do
316 317 318 319 320 321 322
        post api('/projects', admin), @project
        expect(json_response['public']).to be_truthy
        expect(json_response['visibility_level']).to(
          eq(Gitlab::VisibilityLevel::PUBLIC)
        )
      end
    end
323 324
  end

325
  describe 'POST /projects/user/:id' do
D
Dmitriy Zaporozhets 已提交
326
    before { project }
A
Angus MacArthur 已提交
327 328
    before { admin }

329
    it 'should create new project without path and return 201' do
330
      expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
Z
Z.J. van de Weg 已提交
331
      expect(response).to have_http_status(201)
A
Angus MacArthur 已提交
332 333
    end

334
    it 'responds with 400 on failure and not project' do
335
      expect { post api("/projects/user/#{user.id}", admin) }.
336
        not_to change { Project.count }
337

Z
Z.J. van de Weg 已提交
338
      expect(response).to have_http_status(400)
339
      expect(json_response['message']['name']).to eq([
J
jubianchi 已提交
340 341
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
D
Douwe Maan 已提交
342
        Gitlab::Regex.project_name_regex_message
343 344
      ])
      expect(json_response['message']['path']).to eq([
J
jubianchi 已提交
345 346
        'can\'t be blank',
        'is too short (minimum is 0 characters)',
D
Douwe Maan 已提交
347
        Gitlab::Regex.send(:project_path_regex_message)
348
      ])
A
Angus MacArthur 已提交
349 350
    end

351
    it 'assigns attributes to project' do
A
Angus MacArthur 已提交
352
      project = attributes_for(:project, {
R
Robert Speicher 已提交
353
        description: FFaker::Lorem.sentence,
354 355
        issues_enabled: false,
        merge_requests_enabled: false,
356 357
        wiki_enabled: false,
        request_access_enabled: true
A
Angus MacArthur 已提交
358 359 360 361
      })

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

362
      project.each_pair do |k, v|
A
Angus MacArthur 已提交
363
        next if k == :path
364
        expect(json_response[k.to_s]).to eq(v)
A
Angus MacArthur 已提交
365 366
      end
    end
367

368
    it 'sets a project as public' do
369
      project = attributes_for(:project, :public)
370
      post api("/projects/user/#{user.id}", admin), project
371 372
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
373 374
    end

375
    it 'sets a project as public using :public' do
376 377
      project = attributes_for(:project, { public: true })
      post api("/projects/user/#{user.id}", admin), project
378 379
      expect(json_response['public']).to be_truthy
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
380
    end
381

382
    it 'sets a project as internal' do
383
      project = attributes_for(:project, :internal)
384
      post api("/projects/user/#{user.id}", admin), project
385 386
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
387 388
    end

389
    it 'sets a project as internal overriding :public' do
390
      project = attributes_for(:project, :internal, { public: true })
391
      post api("/projects/user/#{user.id}", admin), project
392 393
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
394
    end
395

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

403
    it 'sets a project as private using :public' do
404 405
      project = attributes_for(:project, { public: false })
      post api("/projects/user/#{user.id}", admin), project
406 407
      expect(json_response['public']).to be_falsey
      expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
408
    end
409 410 411 412 413 414 415 416 417 418 419 420

    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
A
Angus MacArthur 已提交
421 422
  end

D
Douwe Maan 已提交
423 424 425 426 427 428
  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")

Z
Z.J. van de Weg 已提交
429
      expect(response).to have_http_status(201)
D
Douwe Maan 已提交
430 431 432 433 434 435
      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

436
  describe 'GET /projects/:id' do
D
Dmitriy Zaporozhets 已提交
437
    before { project }
438
    before { project_member }
D
Dmitriy Zaporozhets 已提交
439

440 441 442 443
    it 'returns a project by id' do
      group = create(:group)
      link = create(:project_group_link, project: project, group: group)

R
Robert Speicher 已提交
444
      get api("/projects/#{project.id}", user)
445

Z
Z.J. van de Weg 已提交
446
      expect(response).to have_http_status(200)
447 448 449 450 451 452 453 454 455 456 457 458
      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
459
      expect(json_response['name']).to eq(project.name)
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
      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)
481
      expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds)
N
Nihad Abbasov 已提交
482
    end
483

484
    it 'returns a project by path name' do
485
      get api("/projects/#{project.id}", user)
Z
Z.J. van de Weg 已提交
486
      expect(response).to have_http_status(200)
487
      expect(json_response['name']).to eq(project.name)
488
    end
N
Nihad Abbasov 已提交
489

490
    it 'returns a 404 error if not found' do
491
      get api('/projects/42', user)
Z
Z.J. van de Weg 已提交
492
      expect(response).to have_http_status(404)
493
      expect(json_response['message']).to eq('404 Project Not Found')
N
Nihad Abbasov 已提交
494
    end
495

496
    it 'returns a 404 error if user is not a member' do
497 498
      other_user = create(:user)
      get api("/projects/#{project.id}", other_user)
Z
Z.J. van de Weg 已提交
499
      expect(response).to have_http_status(404)
500
    end
501

502
    it 'handles users with dots' do
503 504 505 506
      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)
Z
Z.J. van de Weg 已提交
507
      expect(response).to have_http_status(200)
508 509 510
      expect(json_response['name']).to eq(project.name)
    end

511
    describe 'permissions' do
512
      context 'all projects' do
513 514 515
        before { project.team << [user, :master] }

        it 'contains permission information' do
516 517
          get api("/projects", user)

Z
Z.J. van de Weg 已提交
518
          expect(response).to have_http_status(200)
519 520 521 522 523 524
          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

525
      context 'personal project' do
526
        it 'sets project access and returns 200' do
D
Dmitriy Zaporozhets 已提交
527 528
          project.team << [user, :master]
          get api("/projects/#{project.id}", user)
529

Z
Z.J. van de Weg 已提交
530
          expect(response).to have_http_status(200)
531 532 533 534
          expect(json_response['permissions']['project_access']['access_level']).
            to eq(Gitlab::Access::MASTER)
          expect(json_response['permissions']['group_access']).to be_nil
        end
535 536 537
      end

      context 'group project' do
538 539 540 541
        let(:project2) { create(:project, group: create(:group)) }

        before { project2.group.add_owner(user) }

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

Z
Z.J. van de Weg 已提交
545
          expect(response).to have_http_status(200)
546 547 548 549
          expect(json_response['permissions']['project_access']).to be_nil
          expect(json_response['permissions']['group_access']['access_level']).
            to eq(Gitlab::Access::OWNER)
        end
550 551
      end
    end
N
Nihad Abbasov 已提交
552 553
  end

554
  describe 'GET /projects/:id/events' do
D
Douwe Maan 已提交
555
    before { project_member2 }
D
Dmitriy Zaporozhets 已提交
556

D
Dmitriy Zaporozhets 已提交
557 558 559 560 561 562 563
    context 'valid request' do
      before do
        note = create(:note_on_issue, note: 'What an awesome day!', project: project)
        EventCreateService.new.leave_note(note, note.author)
        get api("/projects/#{project.id}/events", user)
      end

Z
Z.J. van de Weg 已提交
564
      it { expect(response).to have_http_status(200) }
D
Dmitriy Zaporozhets 已提交
565 566 567

      context 'joined event' do
        let(:json_event) { json_response[1] }
D
Dmitriy Zaporozhets 已提交
568

D
Dmitriy Zaporozhets 已提交
569 570 571 572 573 574 575 576 577 578 579 580
        it { expect(json_event['action_name']).to eq('joined') }
        it { expect(json_event['project_id'].to_i).to eq(project.id) }
        it { expect(json_event['author_username']).to eq(user3.username) }
        it { expect(json_event['author']['name']).to eq(user3.name) }
      end

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

        it { expect(json_event['action_name']).to eq('commented on') }
        it { expect(json_event['note']['body']).to eq('What an awesome day!') }
      end
D
Dmitriy Zaporozhets 已提交
581 582
    end

583
    it 'returns a 404 error if not found' do
584
      get api('/projects/42/events', user)
Z
Z.J. van de Weg 已提交
585
      expect(response).to have_http_status(404)
586
      expect(json_response['message']).to eq('404 Project Not Found')
D
Dmitriy Zaporozhets 已提交
587 588
    end

589
    it 'returns a 404 error if user is not a member' do
D
Dmitriy Zaporozhets 已提交
590 591
      other_user = create(:user)
      get api("/projects/#{project.id}/events", other_user)
Z
Z.J. van de Weg 已提交
592
      expect(response).to have_http_status(404)
D
Dmitriy Zaporozhets 已提交
593 594 595
    end
  end

596
  describe 'GET /projects/:id/snippets' do
D
Dmitriy Zaporozhets 已提交
597 598
    before { snippet }

599
    it 'returns an array of project snippets' do
600
      get api("/projects/#{project.id}/snippets", user)
Z
Z.J. van de Weg 已提交
601
      expect(response).to have_http_status(200)
602 603
      expect(json_response).to be_an Array
      expect(json_response.first['title']).to eq(snippet.title)
N
Nihad Abbasov 已提交
604 605 606
    end
  end

607
  describe 'GET /projects/:id/snippets/:snippet_id' do
608
    it 'returns a project snippet' do
609
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
Z
Z.J. van de Weg 已提交
610
      expect(response).to have_http_status(200)
611
      expect(json_response['title']).to eq(snippet.title)
N
Nihad Abbasov 已提交
612
    end
613

614
    it 'returns a 404 error if snippet id not found' do
615
      get api("/projects/#{project.id}/snippets/1234", user)
Z
Z.J. van de Weg 已提交
616
      expect(response).to have_http_status(404)
617
    end
N
Nihad Abbasov 已提交
618 619
  end

620
  describe 'POST /projects/:id/snippets' do
621
    it 'creates a new project snippet' do
622
      post api("/projects/#{project.id}/snippets", user),
623 624
        title: 'api test', file_name: 'sample.rb', code: 'test',
        visibility_level: '0'
Z
Z.J. van de Weg 已提交
625
      expect(response).to have_http_status(201)
626
      expect(json_response['title']).to eq('api test')
N
Nihad Abbasov 已提交
627
    end
628

629
    it 'returns a 400 error if invalid snippet is given' do
630 631
      post api("/projects/#{project.id}/snippets", user)
      expect(status).to eq(400)
632
    end
N
Nihad Abbasov 已提交
633 634
  end

635
  describe 'PUT /projects/:id/snippets/:snippet_id' do
636
    it 'updates an existing project snippet' do
637
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
638
        code: 'updated code'
Z
Z.J. van de Weg 已提交
639
      expect(response).to have_http_status(200)
640 641
      expect(json_response['title']).to eq('example')
      expect(snippet.reload.content).to eq('updated code')
642
    end
643

644
    it 'updates an existing project snippet with new title' do
645
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
646
        title: 'other api test'
Z
Z.J. van de Weg 已提交
647
      expect(response).to have_http_status(200)
648
      expect(json_response['title']).to eq('other api test')
649
    end
650 651
  end

652
  describe 'DELETE /projects/:id/snippets/:snippet_id' do
D
Dmitriy Zaporozhets 已提交
653 654
    before { snippet }

655
    it 'deletes existing project snippet' do
656
      expect do
657
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
658
      end.to change { Snippet.count }.by(-1)
Z
Z.J. van de Weg 已提交
659
      expect(response).to have_http_status(200)
660 661
    end

662
    it 'returns 404 when deleting unknown snippet id' do
663
      delete api("/projects/#{project.id}/snippets/1234", user)
Z
Z.J. van de Weg 已提交
664
      expect(response).to have_http_status(404)
N
Nihad Abbasov 已提交
665 666
    end
  end
667

668
  describe 'GET /projects/:id/snippets/:snippet_id/raw' do
669
    it 'gets a raw project snippet' do
670
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
Z
Z.J. van de Weg 已提交
671
      expect(response).to have_http_status(200)
672
    end
673

674
    it 'returns a 404 error if raw project snippet not found' do
675
      get api("/projects/#{project.id}/snippets/5555/raw", user)
Z
Z.J. van de Weg 已提交
676
      expect(response).to have_http_status(404)
677
    end
678
  end
679

680 681
  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
682
    let(:project_fork_source) { create(:project, :public) }
683

684
    describe 'POST /projects/:id/fork/:forked_from_id' do
685
      let(:new_project_fork_source) { create(:project, :public) }
686

687
      it "is not available for non admin users" do
688
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
Z
Z.J. van de Weg 已提交
689
        expect(response).to have_http_status(403)
690 691
      end

692
      it 'allows project to be forked from an existing project' do
693
        expect(project_fork_target.forked?).not_to be_truthy
694
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
Z
Z.J. van de Weg 已提交
695
        expect(response).to have_http_status(201)
696
        project_fork_target.reload
697 698 699
        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
700 701
      end

702
      it 'fails if forked_from project which does not exist' do
703
        post api("/projects/#{project_fork_target.id}/fork/9999", admin)
Z
Z.J. van de Weg 已提交
704
        expect(response).to have_http_status(404)
705 706
      end

707
      it 'fails with 409 if already forked' do
708 709
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
710
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
711
        post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
Z
Z.J. van de Weg 已提交
712
        expect(response).to have_http_status(409)
713
        project_fork_target.reload
714 715
        expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
        expect(project_fork_target.forked?).to be_truthy
716 717 718
      end
    end

719
    describe 'DELETE /projects/:id/fork' do
720
      it "is not visible to users outside group" do
721
        delete api("/projects/#{project_fork_target.id}/fork", user)
Z
Z.J. van de Weg 已提交
722
        expect(response).to have_http_status(404)
723 724
      end

725 726
      context 'when users belong to project group' do
        let(:project_fork_target) { create(:project, group: create(:group)) }
727

728 729 730 731 732
        before do
          project_fork_target.group.add_owner user
          project_fork_target.group.add_developer user2
        end

733
        it 'is forbidden to non-owner users' do
734
          delete api("/projects/#{project_fork_target.id}/fork", user2)
Z
Z.J. van de Weg 已提交
735
          expect(response).to have_http_status(403)
736 737
        end

738
        it 'makes forked project unforked' do
739 740 741 742 743
          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)
Z
Z.J. van de Weg 已提交
744
          expect(response).to have_http_status(200)
745 746 747 748 749
          project_fork_target.reload
          expect(project_fork_target.forked_from_project).to be_nil
          expect(project_fork_target.forked?).not_to be_truthy
        end

750
        it 'is idempotent if not forked' do
751 752
          expect(project_fork_target.forked_from_project).to be_nil
          delete api("/projects/#{project_fork_target.id}/fork", admin)
Z
Z.J. van de Weg 已提交
753
          expect(response).to have_http_status(200)
754 755
          expect(project_fork_target.reload.forked_from_project).to be_nil
        end
756 757 758
      end
    end
  end
759

760 761 762
  describe "POST /projects/:id/share" do
    let(:group) { create(:group) }

763
    it "shares project with group" do
764 765
      expires_at = 10.days.from_now.to_date

766
      expect do
767
        post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at
768 769 770
      end.to change { ProjectGroupLink.count }.by(1)

      expect(response.status).to eq 201
771 772 773
      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)
774 775
    end

776
    it "returns a 400 error when group id is not given" do
777 778 779 780
      post api("/projects/#{project.id}/share", user), group_access: Gitlab::Access::DEVELOPER
      expect(response.status).to eq 400
    end

781
    it "returns a 400 error when access level is not given" do
782 783 784 785
      post api("/projects/#{project.id}/share", user), group_id: group.id
      expect(response.status).to eq 400
    end

786
    it "returns a 400 error when sharing is disabled" do
787 788 789 790 791
      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

792
    it "returns a 409 error when wrong params passed" do
793 794 795 796 797 798
      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

799
  describe 'GET /projects/search/:query' do
800
    let!(:query) { 'query'}
D
Dmitriy Zaporozhets 已提交
801 802 803 804 805
    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) }
806 807 808 809
    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') }
810

811
    context 'when unauthenticated' do
812
      it 'returns authentication error' do
813
        get api("/projects/search/#{query}")
Z
Z.J. van de Weg 已提交
814
        expect(response).to have_http_status(401)
815 816 817
      end
    end

818
    context 'when authenticated' do
819
      it 'returns an array of projects' do
820
        get api("/projects/search/#{query}", user)
Z
Z.J. van de Weg 已提交
821
        expect(response).to have_http_status(200)
822 823 824
        expect(json_response).to be_an Array
        expect(json_response.size).to eq(6)
        json_response.each {|project| expect(project['name']).to match(/.*query.*/)}
825 826 827
      end
    end

828
    context 'when authenticated as a different user' do
829
      it 'returns matching public projects' do
830
        get api("/projects/search/#{query}", user2)
Z
Z.J. van de Weg 已提交
831
        expect(response).to have_http_status(200)
832 833 834
        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/)}
835 836 837
      end
    end
  end
838

839 840 841 842 843 844 845 846 847 848 849
  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
850
      it 'returns authentication error' do
851 852
        project_param = { name: 'bar' }
        put api("/projects/#{project.id}"), project_param
Z
Z.J. van de Weg 已提交
853
        expect(response).to have_http_status(401)
854 855 856 857
      end
    end

    context 'when authenticated as project owner' do
858
      it 'updates name' do
859 860
        project_param = { name: 'bar' }
        put api("/projects/#{project.id}", user), project_param
Z
Z.J. van de Weg 已提交
861
        expect(response).to have_http_status(200)
862
        project_param.each_pair do |k, v|
863
          expect(json_response[k.to_s]).to eq(v)
864 865 866
        end
      end

867
      it 'updates visibility_level' do
868 869
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user), project_param
Z
Z.J. van de Weg 已提交
870
        expect(response).to have_http_status(200)
871
        project_param.each_pair do |k, v|
872
          expect(json_response[k.to_s]).to eq(v)
873 874 875
        end
      end

876
      it 'updates visibility_level from public to private' do
877 878 879 880
        project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })

        project_param = { public: false }
        put api("/projects/#{project3.id}", user), project_param
Z
Z.J. van de Weg 已提交
881
        expect(response).to have_http_status(200)
882 883 884 885 886 887
        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

888
      it 'does not update name to existing name' do
889 890
        project_param = { name: project3.name }
        put api("/projects/#{project.id}", user), project_param
Z
Z.J. van de Weg 已提交
891
        expect(response).to have_http_status(400)
892
        expect(json_response['message']['name']).to eq(['has already been taken'])
893 894
      end

895 896 897 898 899 900 901 902 903
      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

904
      it 'updates path & name to existing path & name in different namespace' do
905 906
        project_param = { path: project4.path, name: project4.name }
        put api("/projects/#{project3.id}", user), project_param
Z
Z.J. van de Weg 已提交
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 913 914
        end
      end
    end

    context 'when authenticated as project master' do
915
      it 'updates path' do
916 917
        project_param = { path: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
Z
Z.J. van de Weg 已提交
918
        expect(response).to have_http_status(200)
919
        project_param.each_pair do |k, v|
920
          expect(json_response[k.to_s]).to eq(v)
921 922 923
        end
      end

924
      it 'updates other attributes' do
925 926 927 928 929 930 931
        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
Z
Z.J. van de Weg 已提交
932
        expect(response).to have_http_status(200)
933
        project_param.each_pair do |k, v|
934
          expect(json_response[k.to_s]).to eq(v)
935 936 937
        end
      end

938
      it 'does not update path to existing path' do
939 940
        project_param = { path: project.path }
        put api("/projects/#{project3.id}", user4), project_param
Z
Z.J. van de Weg 已提交
941
        expect(response).to have_http_status(400)
942
        expect(json_response['message']['path']).to eq(['has already been taken'])
943 944
      end

945
      it 'does not update name' do
946 947
        project_param = { name: 'bar' }
        put api("/projects/#{project3.id}", user4), project_param
Z
Z.J. van de Weg 已提交
948
        expect(response).to have_http_status(403)
949 950
      end

951
      it 'does not update visibility_level' do
952 953
        project_param = { visibility_level: 20 }
        put api("/projects/#{project3.id}", user4), project_param
Z
Z.J. van de Weg 已提交
954
        expect(response).to have_http_status(403)
955 956 957 958
      end
    end

    context 'when authenticated as project developer' do
959
      it 'does not update other attributes' do
960 961 962 963 964
        project_param = { path: 'bar',
                          issues_enabled: true,
                          wiki_enabled: true,
                          snippets_enabled: true,
                          merge_requests_enabled: true,
965 966
                          description: 'new description',
                          request_access_enabled: true }
967
        put api("/projects/#{project.id}", user3), project_param
Z
Z.J. van de Weg 已提交
968
        expect(response).to have_http_status(403)
969 970 971 972
      end
    end
  end

973
  describe 'POST /projects/:id/archive' do
974 975
    context 'on an unarchived project' do
      it 'archives the project' do
976
        post api("/projects/#{project.id}/archive", user)
977

Z
Z.J. van de Weg 已提交
978
        expect(response).to have_http_status(201)
979 980 981 982 983 984 985 986 987 988
        expect(json_response['archived']).to be_truthy
      end
    end

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

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

Z
Z.J. van de Weg 已提交
991
        expect(response).to have_http_status(201)
992 993
        expect(json_response['archived']).to be_truthy
      end
994
    end
995

996 997 998 999
    context 'user without archiving rights to the project' do
      before do
        project.team << [user3, :developer]
      end
1000

1001 1002 1003
      it 'rejects the action' do
        post api("/projects/#{project.id}/archive", user3)

Z
Z.J. van de Weg 已提交
1004
        expect(response).to have_http_status(403)
1005 1006 1007 1008
      end
    end
  end

1009
  describe 'POST /projects/:id/unarchive' do
1010 1011
    context 'on an unarchived project' do
      it 'remains unarchived' do
1012
        post api("/projects/#{project.id}/unarchive", user)
1013

Z
Z.J. van de Weg 已提交
1014
        expect(response).to have_http_status(201)
1015 1016 1017 1018 1019 1020 1021 1022 1023
        expect(json_response['archived']).to be_falsey
      end
    end

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

1024 1025
      it 'unarchives the project' do
        post api("/projects/#{project.id}/unarchive", user)
1026

Z
Z.J. van de Weg 已提交
1027
        expect(response).to have_http_status(201)
1028 1029
        expect(json_response['archived']).to be_falsey
      end
1030
    end
1031

1032 1033 1034 1035
    context 'user without archiving rights to the project' do
      before do
        project.team << [user3, :developer]
      end
1036

1037 1038 1039
      it 'rejects the action' do
        post api("/projects/#{project.id}/unarchive", user3)

Z
Z.J. van de Weg 已提交
1040
        expect(response).to have_http_status(403)
1041 1042 1043 1044
      end
    end
  end

1045 1046 1047
  describe 'POST /projects/:id/star' do
    context 'on an unstarred project' do
      it 'stars the project' do
1048
        expect { post api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(1)
1049

Z
Z.J. van de Weg 已提交
1050
        expect(response).to have_http_status(201)
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
        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
1062
        expect { post api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count }
1063

Z
Z.J. van de Weg 已提交
1064
        expect(response).to have_http_status(304)
1065 1066 1067 1068
      end
    end
  end

R
Robert Schilling 已提交
1069
  describe 'DELETE /projects/:id/star' do
1070 1071 1072 1073 1074 1075 1076
    context 'on a starred project' do
      before do
        user.toggle_star(project)
        project.reload
      end

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

Z
Z.J. van de Weg 已提交
1079
        expect(response).to have_http_status(200)
1080 1081 1082 1083 1084 1085
        expect(json_response['star_count']).to eq(0)
      end
    end

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

Z
Z.J. van de Weg 已提交
1088
        expect(response).to have_http_status(304)
1089 1090 1091 1092
      end
    end
  end

1093 1094
  describe 'DELETE /projects/:id' do
    context 'when authenticated as user' do
1095
      it 'removes project' do
1096
        delete api("/projects/#{project.id}", user)
Z
Z.J. van de Weg 已提交
1097
        expect(response).to have_http_status(200)
1098 1099
      end

1100
      it 'does not remove a project if not an owner' do
1101 1102 1103
        user3 = create(:user)
        project.team << [user3, :developer]
        delete api("/projects/#{project.id}", user3)
Z
Z.J. van de Weg 已提交
1104
        expect(response).to have_http_status(403)
1105 1106
      end

1107
      it 'does not remove a non existing project' do
1108
        delete api('/projects/1328', user)
Z
Z.J. van de Weg 已提交
1109
        expect(response).to have_http_status(404)
1110 1111
      end

1112
      it 'does not remove a project not attached to user' do
1113
        delete api("/projects/#{project.id}", user2)
Z
Z.J. van de Weg 已提交
1114
        expect(response).to have_http_status(404)
1115 1116 1117
      end
    end

1118
    context 'when authenticated as admin' do
1119
      it 'removes any existing project' do
1120
        delete api("/projects/#{project.id}", admin)
Z
Z.J. van de Weg 已提交
1121
        expect(response).to have_http_status(200)
1122 1123
      end

1124
      it 'does not remove a non existing project' do
1125
        delete api('/projects/1328', admin)
Z
Z.J. van de Weg 已提交
1126
        expect(response).to have_http_status(404)
1127 1128 1129
      end
    end
  end
N
Nihad Abbasov 已提交
1130
end