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

3
describe API::API do
4
  include ApiHelpers
5
  before(:each) { enable_observers }
I
Izaak Alpert 已提交
6
  after(:each) { disable_observers }
7

8 9 10
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
  let(:user3) { create(:user) }
A
Angus MacArthur 已提交
11
  let(:admin) { create(:admin) }
D
Dmitriy Zaporozhets 已提交
12 13 14 15
  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 已提交
16 17

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

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

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

D
Dmitriy Zaporozhets 已提交
38
  describe "GET /projects/all" do
D
Dmitriy Zaporozhets 已提交
39 40
    before { project }

D
Dmitriy Zaporozhets 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
    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
        json_response.first['owner']['email'].should == user.email
      end
    end
  end

66
  describe "POST /projects" do
67 68 69 70 71 72 73 74 75 76
    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'
77
        }.to change {Project.count}.by(0)
78 79 80
      end
    end

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

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

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

94 95 96 97 98 99
    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 已提交
100 101
    it "should respond with 201 on success" do
      post api("/projects", user), name: 'foo'
102
      response.status.should == 201
103
    end
A
Alex Denisov 已提交
104

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

110 111 112 113 114 115 116 117
    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 已提交
118
    it "should assign attributes to project" do
119
      project = attributes_for(:project, {
120 121 122 123 124
        description: Faker::Lorem.sentence,
        issues_enabled: false,
        wall_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
A
Alex Denisov 已提交
125 126 127 128
      })

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

129
      project.each_pair do |k,v|
130
        next if k == :path
A
Alex Denisov 已提交
131 132
        json_response[k.to_s].should == v
      end
133
    end
134 135

    it "should set a project as public" do
136 137 138 139 140 141 142
      project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PUBLIC })
      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
143 144 145
      project = attributes_for(:project, { public: true })
      post api("/projects", user), project
      json_response['public'].should be_true
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end

    it "should set a project as internal" do
      project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::INTERNAL })
      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
      project = attributes_for(:project, { public: true, visibility_level: Gitlab::VisibilityLevel::INTERNAL })
      post api("/projects", user), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
161 162 163
    end

    it "should set a project as private" do
164 165 166 167 168 169 170
      project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
      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
171 172 173
      project = attributes_for(:project, { public: false })
      post api("/projects", user), project
      json_response['public'].should be_false
174
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
175
    end
176 177
  end

A
Angus MacArthur 已提交
178
  describe "POST /projects/user/:id" do
D
Dmitriy Zaporozhets 已提交
179
    before { project }
A
Angus MacArthur 已提交
180 181 182
    before { admin }

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

    it "should not create new project without name" do
187
      expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
A
Angus MacArthur 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201
    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, {
202 203 204 205 206
        description: Faker::Lorem.sentence,
        issues_enabled: false,
        wall_enabled: false,
        merge_requests_enabled: false,
        wiki_enabled: false
A
Angus MacArthur 已提交
207 208 209 210
      })

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

211
      project.each_pair do |k,v|
A
Angus MacArthur 已提交
212 213 214 215
        next if k == :path
        json_response[k.to_s].should == v
      end
    end
216 217

    it "should set a project as public" do
218 219 220 221 222 223 224
      project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PUBLIC })
      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
225 226 227
      project = attributes_for(:project, { public: true })
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_true
228 229
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
    end
230

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

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

245 246 247 248 249
    it "should set a project as private" do
      project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PRIVATE })
      post api("/projects/user/#{user.id}", admin), project
      json_response['public'].should be_false
      json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
250 251
    end

252 253 254 255 256 257
    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 已提交
258 259
  end

N
Nihad Abbasov 已提交
260
  describe "GET /projects/:id" do
D
Dmitriy Zaporozhets 已提交
261 262
    before { project }

N
Nihad Abbasov 已提交
263
    it "should return a project by id" do
R
Robert Speicher 已提交
264
      get api("/projects/#{project.id}", user)
N
Nihad Abbasov 已提交
265
      response.status.should == 200
N
Nihad Abbasov 已提交
266 267
      json_response['name'].should == project.name
      json_response['owner']['email'].should == user.email
N
Nihad Abbasov 已提交
268
    end
269

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

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

    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
N
Nihad Abbasov 已提交
287 288
  end

D
Dmitriy Zaporozhets 已提交
289
  describe "GET /projects/:id/events" do
D
Dmitriy Zaporozhets 已提交
290 291
    before { users_project }

D
Dmitriy Zaporozhets 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    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 已提交
314
  describe "GET /projects/:id/snippets" do
D
Dmitriy Zaporozhets 已提交
315 316
    before { snippet }

N
Nihad Abbasov 已提交
317
    it "should return an array of project snippets" do
318
      get api("/projects/#{project.id}/snippets", user)
N
Nihad Abbasov 已提交
319 320 321 322 323 324
      response.status.should == 200
      json_response.should be_an Array
      json_response.first['title'].should == snippet.title
    end
  end

N
Nihad Abbasov 已提交
325 326
  describe "GET /projects/:id/snippets/:snippet_id" do
    it "should return a project snippet" do
327
      get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
N
Nihad Abbasov 已提交
328
      response.status.should == 200
N
Nihad Abbasov 已提交
329
      json_response['title'].should == snippet.title
N
Nihad Abbasov 已提交
330
    end
331 332 333 334 335

    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 已提交
336 337 338 339
  end

  describe "POST /projects/:id/snippets" do
    it "should create a new project snippet" do
340
      post api("/projects/#{project.id}/snippets", user),
341
        title: 'api test', file_name: 'sample.rb', code: 'test'
N
Nihad Abbasov 已提交
342
      response.status.should == 201
N
Nihad Abbasov 已提交
343
      json_response['title'].should == 'api test'
N
Nihad Abbasov 已提交
344
    end
345 346 347

    it "should return a 400 error if title is not given" do
      post api("/projects/#{project.id}/snippets", user),
348
        file_name: 'sample.rb', code: 'test'
349 350
      response.status.should == 400
    end
351 352 353

    it "should return a 400 error if file_name not given" do
      post api("/projects/#{project.id}/snippets", user),
354
        title: 'api test', code: 'test'
355 356 357 358 359
      response.status.should == 400
    end

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

365
  describe "PUT /projects/:id/snippets/:shippet_id" do
366
    it "should update an existing project snippet" do
367
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
368
        code: 'updated code'
369 370
      response.status.should == 200
      json_response['title'].should == 'example'
371
      snippet.reload.content.should == 'updated code'
372
    end
373 374 375

    it "should update an existing project snippet with new title" do
      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
376
        title: 'other api test'
377 378 379
      response.status.should == 200
      json_response['title'].should == 'other api test'
    end
380 381
  end

N
Nihad Abbasov 已提交
382
  describe "DELETE /projects/:id/snippets/:snippet_id" do
D
Dmitriy Zaporozhets 已提交
383 384
    before { snippet }

M
m16a1 已提交
385
    it "should delete existing project snippet" do
N
Nihad Abbasov 已提交
386
      expect {
387
        delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
388
      }.to change { Snippet.count }.by(-1)
389 390 391 392 393 394
      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 已提交
395 396
    end
  end
397 398 399

  describe "GET /projects/:id/snippets/:snippet_id/raw" do
    it "should get a raw project snippet" do
400
      get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
401 402
      response.status.should == 200
    end
403 404 405 406 407

    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
408
  end
409

410 411 412
  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 已提交
413

414 415
    describe "GET /projects/:id/keys" do
      before { deploy_key }
M
Matt Humphrey 已提交
416

417 418 419 420 421 422
      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 已提交
423 424
    end

425 426 427 428 429 430
    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 已提交
431

432 433 434 435
      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 已提交
436 437
    end

438 439
    describe "POST /projects/:id/keys" do
      it "should not create an invalid ssh key" do
440
        post api("/projects/#{project.id}/keys", user), { title: "invalid key" }
441 442 443 444 445 446 447
        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
448
        }.to change{ project.deploy_keys.count }.by(1)
449
      end
M
Matt Humphrey 已提交
450 451
    end

452 453 454 455 456 457
    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)
458
        }.to change{ project.deploy_keys.count }.by(-1)
459 460 461 462 463 464
      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 已提交
465 466
    end
  end
467 468 469

  describe :fork_admin do
    let(:project_fork_target) { create(:project) }
470
    let(:project_fork_source) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
471 472

    describe "POST /projects/:id/fork/:forked_from_id" do
473
      let(:new_project_fork_source) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 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

      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
534 535 536

  describe "GET /projects/search/:query" do
    let!(:query) { 'query'}
D
Dmitriy Zaporozhets 已提交
537 538 539 540 541 542 543 544 545
    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) }
    let!(:internal)         { create(:empty_project, name: "internal #{query}", visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
    let!(:unfound_internal) { create(:empty_project, name: 'unfound internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
    let!(:public)           { create(:empty_project, name: "public #{query}", visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
    let!(:unfound_public)   { create(:empty_project, name: 'unfound public', visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
546 547 548 549 550 551 552 553 554 555 556 557 558

    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
559
        json_response.size.should == 6
560 561 562 563 564 565 566 567 568
        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
569 570
        json_response.size.should == 2
        json_response.each {|project| project['name'].should =~ /(internal|public) query/}
571 572 573
      end
    end
  end
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611

  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 已提交
612
end