projects_spec.rb 21.8 KB
Newer Older
N
Nihad Abbasov 已提交
1 2
require 'spec_helper'

J
Jeroen van Baarsen 已提交
3
describe API::API, api: true  do
4
  include ApiHelpers
5 6 7
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
  let(:user3) { create(:user) }
A
Angus MacArthur 已提交
8
  let(:admin) { create(:admin) }
D
Dmitriy Zaporozhets 已提交
9 10 11 12
  let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
  let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
  let(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
  let(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) }
N
Nihad Abbasov 已提交
13 14

  describe "GET /projects" do
D
Dmitriy Zaporozhets 已提交
15 16
    before { project }

17 18 19 20 21
    context "when unauthenticated" do
      it "should return authentication error" do
        get api("/projects")
        response.status.should == 401
      end
N
Nihad Abbasov 已提交
22 23
    end

24
    context "when authenticated" do
N
Nihad Abbasov 已提交
25
      it "should return an array of projects" do
R
Robert Speicher 已提交
26
        get api("/projects", user)
N
Nihad Abbasov 已提交
27
        response.status.should == 200
N
Nihad Abbasov 已提交
28 29
        json_response.should be_an Array
        json_response.first['name'].should == project.name
D
Dmitriy Zaporozhets 已提交
30
        json_response.first['owner']['username'].should == user.username
N
Nihad Abbasov 已提交
31 32 33 34
      end
    end
  end

D
Dmitriy Zaporozhets 已提交
35
  describe "GET /projects/all" do
D
Dmitriy Zaporozhets 已提交
36 37
    before { project }

D
Dmitriy Zaporozhets 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
    context "when unauthenticated" do
      it "should return authentication error" do
        get api("/projects/all")
        response.status.should == 401
      end
    end

    context "when authenticated as regular user" do
      it "should return authentication error" do
        get api("/projects/all", user)
        response.status.should == 403
      end
    end

    context "when authenticated as admin" do
      it "should return an array of all projects" do
        get api("/projects/all", admin)
        response.status.should == 200
        json_response.should be_an Array
        json_response.first['name'].should == project.name
D
Dmitriy Zaporozhets 已提交
58
        json_response.first['owner']['username'].should == user.username
D
Dmitriy Zaporozhets 已提交
59 60 61 62
      end
    end
  end

63
  describe "POST /projects" do
64 65 66 67 68 69 70 71 72 73
    context "maximum number of projects reached" do
      before do
        (1..user2.projects_limit).each do |project|
          post api("/projects", user2), name: "foo#{project}"
        end
      end

      it "should not create new project" do
        expect {
          post api("/projects", user2), name: 'foo'
74
        }.to change {Project.count}.by(0)
75 76 77
      end
    end

78
    it "should create new project without path" do
79
      expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
80
    end
A
Alex Denisov 已提交
81 82

    it "should not create new project without name" do
83
      expect { post api("/projects", user) }.to_not change {Project.count}
A
Alex Denisov 已提交
84 85
    end

86 87 88 89 90
    it "should return a 400 error if name not given" do
      post api("/projects", user)
      response.status.should == 400
    end

91 92 93 94 95 96
    it "should create last project before reaching project limit" do
      (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" }
      post api("/projects", user2), name: "foo"
      response.status.should == 201
    end

A
Alex Denisov 已提交
97 98
    it "should respond with 201 on success" do
      post api("/projects", user), name: 'foo'
99
      response.status.should == 201
100
    end
A
Alex Denisov 已提交
101

102
    it "should respond with 400 if name is not given" do
A
Alex Denisov 已提交
103
      post api("/projects", user)
104
      response.status.should == 400
105
    end
A
Alex Denisov 已提交
106

107 108 109 110 111 112 113 114
    it "should return a 403 error if project limit reached" do
      (1..user.projects_limit).each do |p|
        post api("/projects", user), name: "foo#{p}"
      end
      post api("/projects", user), name: 'bar'
      response.status.should == 403
    end

A
Alex Denisov 已提交
115
    it "should assign attributes to project" do
116
      project = attributes_for(:project, {
117 118 119 120
        description: Faker::Lorem.sentence,
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
A
Alex Denisov 已提交
121 122 123 124
      })

      post api("/projects", user), project

125
      project.each_pair do |k,v|
126
        next if k == :path
A
Alex Denisov 已提交
127 128
        json_response[k.to_s].should == v
      end
129
    end
130 131

    it "should set a project as public" do
132
      project = attributes_for(:project, :public)
133 134 135 136 137 138
      post api("/projects", user), project
      json_response['public'].should be_true
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end

    it "should set a project as public using :public" do
139 140 141
      project = attributes_for(:project, { public: true })
      post api("/projects", user), project
      json_response['public'].should be_true
142 143 144 145
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end

    it "should set a project as internal" do
146
      project = attributes_for(:project, :internal)
147 148 149 150 151 152
      post api("/projects", user), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
    end

    it "should set a project as internal overriding :public" do
153
      project = attributes_for(:project, :internal, { public: true })
154 155 156
      post api("/projects", user), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
157 158 159
    end

    it "should set a project as private" do
160
      project = attributes_for(:project, :private)
161 162 163 164 165 166
      post api("/projects", user), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
    end

    it "should set a project as private using :public" do
167 168 169
      project = attributes_for(:project, { public: false })
      post api("/projects", user), project
      json_response['public'].should be_false
170
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
171
    end
172 173
  end

A
Angus MacArthur 已提交
174
  describe "POST /projects/user/:id" do
D
Dmitriy Zaporozhets 已提交
175
    before { project }
A
Angus MacArthur 已提交
176 177 178
    before { admin }

    it "should create new project without path" do
179
      expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
A
Angus MacArthur 已提交
180 181 182
    end

    it "should not create new project without name" do
183
      expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
A
Angus MacArthur 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197
    end

    it "should respond with 201 on success" do
      post api("/projects/user/#{user.id}", admin), name: 'foo'
      response.status.should == 201
    end

    it "should respond with 404 on failure" do
      post api("/projects/user/#{user.id}", admin)
      response.status.should == 404
    end

    it "should assign attributes to project" do
      project = attributes_for(:project, {
198 199 200 201
        description: Faker::Lorem.sentence,
        issues_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
A
Angus MacArthur 已提交
202 203 204 205
      })

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

206
      project.each_pair do |k,v|
A
Angus MacArthur 已提交
207 208 209 210
        next if k == :path
        json_response[k.to_s].should == v
      end
    end
211 212

    it "should set a project as public" do
213
      project = attributes_for(:project, :public)
214 215 216 217 218 219
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_true
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end

    it "should set a project as public using :public" do
220 221 222
      project = attributes_for(:project, { public: true })
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_true
223 224
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end
225

226
    it "should set a project as internal" do
227
      project = attributes_for(:project, :internal)
228 229 230
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
231 232
    end

233
    it "should set a project as internal overriding :public" do
234
      project = attributes_for(:project, :internal, { public: true })
235 236
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
237 238
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
    end
239

240
    it "should set a project as private" do
241
      project = attributes_for(:project, :private)
242 243 244
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
245 246
    end

247 248 249 250 251 252
    it "should set a project as private using :public" do
      project = attributes_for(:project, { public: false })
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
    end
A
Angus MacArthur 已提交
253 254
  end

N
Nihad Abbasov 已提交
255
  describe "GET /projects/:id" do
D
Dmitriy Zaporozhets 已提交
256
    before { project }
257
    before { users_project }
D
Dmitriy Zaporozhets 已提交
258

N
Nihad Abbasov 已提交
259
    it "should return a project by id" do
R
Robert Speicher 已提交
260
      get api("/projects/#{project.id}", user)
N
Nihad Abbasov 已提交
261
      response.status.should == 200
N
Nihad Abbasov 已提交
262
      json_response['name'].should == project.name
D
Dmitriy Zaporozhets 已提交
263
      json_response['owner']['username'].should == user.username
N
Nihad Abbasov 已提交
264
    end
265

266
    it "should return a project by path name" do
267
      get api("/projects/#{project.id}", user)
268 269 270
      response.status.should == 200
      json_response['name'].should == project.name
    end
N
Nihad Abbasov 已提交
271 272

    it "should return a 404 error if not found" do
R
Robert Speicher 已提交
273
      get api("/projects/42", user)
N
Nihad Abbasov 已提交
274
      response.status.should == 404
A
Alex Denisov 已提交
275
      json_response['message'].should == '404 Not Found'
N
Nihad Abbasov 已提交
276
    end
277 278 279 280 281 282

    it "should return a 404 error if user is not a member" do
      other_user = create(:user)
      get api("/projects/#{project.id}", other_user)
      response.status.should == 404
    end
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

    describe 'permissions' do
      context 'personal project' do
        before { get api("/projects/#{project.id}", user) }

        it { response.status.should == 200 }
        it { json_response['permissions']["project_access"]["access_level"].should == Gitlab::Access::MASTER }
        it { json_response['permissions']["group_access"].should be_nil }
      end

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

        it { response.status.should == 200 }
        it { json_response['permissions']["project_access"].should be_nil }
        it { json_response['permissions']["group_access"]["access_level"].should == Gitlab::Access::OWNER }
      end
    end
N
Nihad Abbasov 已提交
305 306
  end

D
Dmitriy Zaporozhets 已提交
307
  describe "GET /projects/:id/events" do
D
Dmitriy Zaporozhets 已提交
308 309
    before { users_project }

D
Dmitriy Zaporozhets 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    it "should return a project events" do
      get api("/projects/#{project.id}/events", user)
      response.status.should == 200
      json_event = json_response.first

      json_event['action_name'].should == 'joined'
      json_event['project_id'].to_i.should == project.id
    end

    it "should return a 404 error if not found" do
      get api("/projects/42/events", user)
      response.status.should == 404
      json_response['message'].should == '404 Not Found'
    end

    it "should return a 404 error if user is not a member" do
      other_user = create(:user)
      get api("/projects/#{project.id}/events", other_user)
      response.status.should == 404
    end
  end

N
Nihad Abbasov 已提交
332
  describe "GET /projects/:id/snippets" do
D
Dmitriy Zaporozhets 已提交
333 334
    before { snippet }

N
Nihad Abbasov 已提交
335
    it "should return an array of project snippets" do
336
      get api("/projects/#{project.id}/snippets", user)
N
Nihad Abbasov 已提交
337 338 339 340 341 342
      response.status.should == 200
      json_response.should be_an Array
      json_response.first['title'].should == snippet.title
    end
  end

N
Nihad Abbasov 已提交
343 344
  describe "GET /projects/:id/snippets/:snippet_id" do
    it "should return a project snippet" do
345
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
N
Nihad Abbasov 已提交
346
      response.status.should == 200
N
Nihad Abbasov 已提交
347
      json_response['title'].should == snippet.title
N
Nihad Abbasov 已提交
348
    end
349 350 351 352 353

    it "should return a 404 error if snippet id not found" do
      get api("/projects/#{project.id}/snippets/1234", user)
      response.status.should == 404
    end
N
Nihad Abbasov 已提交
354 355 356 357
  end

  describe "POST /projects/:id/snippets" do
    it "should create a new project snippet" do
358
      post api("/projects/#{project.id}/snippets", user),
359
        title: 'api test', file_name: 'sample.rb', code: 'test'
N
Nihad Abbasov 已提交
360
      response.status.should == 201
N
Nihad Abbasov 已提交
361
      json_response['title'].should == 'api test'
N
Nihad Abbasov 已提交
362
    end
363 364 365

    it "should return a 400 error if title is not given" do
      post api("/projects/#{project.id}/snippets", user),
366
        file_name: 'sample.rb', code: 'test'
367 368
      response.status.should == 400
    end
369 370 371

    it "should return a 400 error if file_name not given" do
      post api("/projects/#{project.id}/snippets", user),
372
        title: 'api test', code: 'test'
373 374 375 376 377
      response.status.should == 400
    end

    it "should return a 400 error if code not given" do
      post api("/projects/#{project.id}/snippets", user),
378
        title: 'api test', file_name: 'sample.rb'
379 380
      response.status.should == 400
    end
N
Nihad Abbasov 已提交
381 382
  end

383
  describe "PUT /projects/:id/snippets/:shippet_id" do
384
    it "should update an existing project snippet" do
385
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
386
        code: 'updated code'
387 388
      response.status.should == 200
      json_response['title'].should == 'example'
389
      snippet.reload.content.should == 'updated code'
390
    end
391 392 393

    it "should update an existing project snippet with new title" do
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
394
        title: 'other api test'
395 396 397
      response.status.should == 200
      json_response['title'].should == 'other api test'
    end
398 399
  end

N
Nihad Abbasov 已提交
400
  describe "DELETE /projects/:id/snippets/:snippet_id" do
D
Dmitriy Zaporozhets 已提交
401 402
    before { snippet }

M
m16a1 已提交
403
    it "should delete existing project snippet" do
N
Nihad Abbasov 已提交
404
      expect {
405
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
406
      }.to change { Snippet.count }.by(-1)
407 408 409 410 411 412
      response.status.should == 200
    end

    it "should return success when deleting unknown snippet id" do
      delete api("/projects/#{project.id}/snippets/1234", user)
      response.status.should == 200
N
Nihad Abbasov 已提交
413 414
    end
  end
415 416 417

  describe "GET /projects/:id/snippets/:snippet_id/raw" do
    it "should get a raw project snippet" do
418
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
419 420
      response.status.should == 200
    end
421 422 423 424 425

    it "should return a 404 error if raw project snippet not found" do
      get api("/projects/#{project.id}/snippets/5555/raw", user)
      response.status.should == 404
    end
426
  end
427

428 429 430
  describe :deploy_keys do
    let(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
    let(:deploy_key) { deploy_keys_project.deploy_key }
M
Matt Humphrey 已提交
431

432 433
    describe "GET /projects/:id/keys" do
      before { deploy_key }
M
Matt Humphrey 已提交
434

435 436 437 438 439 440
      it "should return array of ssh keys" do
        get api("/projects/#{project.id}/keys", user)
        response.status.should == 200
        json_response.should be_an Array
        json_response.first['title'].should == deploy_key.title
      end
M
Matt Humphrey 已提交
441 442
    end

443 444 445 446 447 448
    describe "GET /projects/:id/keys/:key_id" do
      it "should return a single key" do
        get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
        response.status.should == 200
        json_response['title'].should == deploy_key.title
      end
M
Matt Humphrey 已提交
449

450 451 452 453
      it "should return 404 Not Found with invalid ID" do
        get api("/projects/#{project.id}/keys/404", user)
        response.status.should == 404
      end
M
Matt Humphrey 已提交
454 455
    end

456 457
    describe "POST /projects/:id/keys" do
      it "should not create an invalid ssh key" do
458
        post api("/projects/#{project.id}/keys", user), { title: "invalid key" }
459 460 461 462 463 464 465
        response.status.should == 404
      end

      it "should create new ssh key" do
        key_attrs = attributes_for :key
        expect {
          post api("/projects/#{project.id}/keys", user), key_attrs
466
        }.to change{ project.deploy_keys.count }.by(1)
467
      end
M
Matt Humphrey 已提交
468 469
    end

470 471 472 473 474 475
    describe "DELETE /projects/:id/keys/:key_id" do
      before { deploy_key }

      it "should delete existing key" do
        expect {
          delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
476
        }.to change{ project.deploy_keys.count }.by(-1)
477 478 479 480 481 482
      end

      it "should return 404 Not Found with invalid ID" do
        delete api("/projects/#{project.id}/keys/404", user)
        response.status.should == 404
      end
M
Matt Humphrey 已提交
483 484
    end
  end
485 486 487

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
488
    let(:project_fork_source) { create(:project, :public) }
489 490

    describe "POST /projects/:id/fork/:forked_from_id" do
491
      let(:new_project_fork_source) { create(:project, :public) }
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

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

      it "should allow project to be forked from an existing project" do
        project_fork_target.forked?.should_not be_true
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        response.status.should == 201
        project_fork_target.reload
        project_fork_target.forked_from_project.id.should == project_fork_source.id
        project_fork_target.forked_project_link.should_not be_nil
        project_fork_target.forked?.should be_true
      end

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

      it "should fail with 409 if already forked" do
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
        project_fork_target.forked_from_project.id.should == project_fork_source.id
        post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
        response.status.should == 409
        project_fork_target.reload
        project_fork_target.forked_from_project.id.should == project_fork_source.id
        project_fork_target.forked?.should be_true
      end
    end

    describe "DELETE /projects/:id/fork" do

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

      it "should make forked project unforked" do
        post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
        project_fork_target.reload
        project_fork_target.forked_from_project.should_not be_nil
        project_fork_target.forked?.should be_true
        delete api("/projects/#{project_fork_target.id}/fork", admin)
        response.status.should == 200
        project_fork_target.reload
        project_fork_target.forked_from_project.should be_nil
        project_fork_target.forked?.should_not be_true
      end

      it "should be idempotent if not forked" do
        project_fork_target.forked_from_project.should be_nil
        delete api("/projects/#{project_fork_target.id}/fork", admin)
        response.status.should == 200
        project_fork_target.reload.forked_from_project.should be_nil
      end
    end
  end
552 553 554

  describe "GET /projects/search/:query" do
    let!(:query) { 'query'}
D
Dmitriy Zaporozhets 已提交
555 556 557 558 559
    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) }
560 561 562 563
    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') }
564 565 566 567 568 569 570 571 572 573 574 575 576

    context "when unauthenticated" do
      it "should return authentication error" do
        get api("/projects/search/#{query}")
        response.status.should == 401
      end
    end

    context "when authenticated" do
      it "should return an array of projects" do
        get api("/projects/search/#{query}",user)
        response.status.should == 200
        json_response.should be_an Array
577
        json_response.size.should == 6
578 579 580 581 582 583 584 585 586
        json_response.each {|project| project['name'].should =~ /.*query.*/}
      end
    end

    context "when authenticated as a different user" do
      it "should return matching public projects" do
        get api("/projects/search/#{query}", user2)
        response.status.should == 200
        json_response.should be_an Array
587 588
        json_response.size.should == 2
        json_response.each {|project| project['name'].should =~ /(internal|public) query/}
589 590 591
      end
    end
  end
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629

  describe "DELETE /projects/:id" do
    context "when authenticated as user" do
      it "should remove project" do
        delete api("/projects/#{project.id}", user)
        response.status.should == 200
      end

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

      it "should not remove a non existing project" do
        delete api("/projects/1328", user)
        response.status.should == 404
      end

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

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

      it "should not remove a non existing project" do
        delete api("/projects/1328", admin)
        response.status.should == 404
      end
    end
  end
N
Nihad Abbasov 已提交
630
end