internal_spec.rb 29.2 KB
Newer Older
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
1 2
require 'spec_helper'

3
describe API::Internal do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
4 5
  let(:user) { create(:user) }
  let(:key) { create(:key, user: user) }
6
  let(:project) { create(:project, :repository) }
7
  let(:secret_token) { Gitlab::Shell.secret_token }
8 9
  let(:gl_repository) { "project-#{project.id}" }
  let(:reference_counter) { double('ReferenceCounter') }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
10

11
  describe "GET /internal/check" do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
12
    it do
13 14
      expect_any_instance_of(Redis).to receive(:ping).and_return('PONG')

15
      get api("/internal/check"), secret_token: secret_token
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
16

17
      expect(response).to have_gitlab_http_status(200)
18
      expect(json_response['api_version']).to eq(API::API.version)
19 20 21 22 23 24 25 26 27
      expect(json_response['redis']).to be(true)
    end

    it 'returns false for field `redis` when redis is unavailable' do
      expect_any_instance_of(Redis).to receive(:ping).and_raise(Errno::ENOENT)

      get api("/internal/check"), secret_token: secret_token

      expect(json_response['redis']).to be(false)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
28 29 30
    end
  end

31 32 33
  describe 'GET /internal/broadcast_message' do
    context 'broadcast message exists' do
      let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }
34

35 36
      it 'returns one broadcast message'  do
        get api('/internal/broadcast_message'), secret_token: secret_token
37

38
        expect(response).to have_gitlab_http_status(200)
39
        expect(json_response['message']).to eq(broadcast_message.message)
40 41 42
      end
    end

43 44 45 46
    context 'broadcast message does not exist' do
      it 'returns nothing'  do
        get api('/internal/broadcast_message'), secret_token: secret_token

47
        expect(response).to have_gitlab_http_status(200)
48 49 50
        expect(json_response).to be_empty
      end
    end
51 52 53 54 55 56 57

    context 'nil broadcast message' do
      it 'returns nothing' do
        allow(BroadcastMessage).to receive(:current).and_return(nil)

        get api('/internal/broadcast_message'), secret_token: secret_token

58
        expect(response).to have_gitlab_http_status(200)
59 60 61
        expect(json_response).to be_empty
      end
    end
62 63 64 65 66 67 68 69 70
  end

  describe 'GET /internal/broadcast_messages' do
    context 'broadcast message(s) exist' do
      let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }

      it 'returns active broadcast message(s)' do
        get api('/internal/broadcast_messages'), secret_token: secret_token

71
        expect(response).to have_gitlab_http_status(200)
72 73 74 75 76 77 78
        expect(json_response[0]['message']).to eq(broadcast_message.message)
      end
    end

    context 'broadcast message does not exist' do
      it 'returns nothing' do
        get api('/internal/broadcast_messages'), secret_token: secret_token
79

80
        expect(response).to have_gitlab_http_status(200)
81
        expect(json_response).to be_empty
82 83 84 85
      end
    end
  end

86 87 88 89 90 91
  describe 'GET /internal/two_factor_recovery_codes' do
    it 'returns an error message when the key does not exist' do
      post api('/internal/two_factor_recovery_codes'),
           secret_token: secret_token,
           key_id: 12345

92 93
      expect(json_response['success']).to be_falsey
      expect(json_response['message']).to eq('Could not find the given key')
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    end

    it 'returns an error message when the key is a deploy key' do
      deploy_key = create(:deploy_key)

      post api('/internal/two_factor_recovery_codes'),
           secret_token: secret_token,
           key_id: deploy_key.id

      expect(json_response['success']).to be_falsey
      expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes')
    end

    it 'returns an error message when the user does not exist' do
      key_without_user = create(:key, user: nil)

      post api('/internal/two_factor_recovery_codes'),
           secret_token: secret_token,
           key_id: key_without_user.id

      expect(json_response['success']).to be_falsey
      expect(json_response['message']).to eq('Could not find a user for the given key')
      expect(json_response['recovery_codes']).to be_nil
    end

    context 'when two-factor is enabled' do
      it 'returns new recovery codes when the user exists' do
        allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true)
        allow_any_instance_of(User)
          .to receive(:generate_otp_backup_codes!).and_return(%w(119135e5a3ebce8e 34bd7b74adbc8861))

        post api('/internal/two_factor_recovery_codes'),
             secret_token: secret_token,
             key_id: key.id

        expect(json_response['success']).to be_truthy
        expect(json_response['recovery_codes']).to match_array(%w(119135e5a3ebce8e 34bd7b74adbc8861))
      end
    end

    context 'when two-factor is not enabled' do
      it 'returns an error message' do
        allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false)

        post api('/internal/two_factor_recovery_codes'),
             secret_token: secret_token,
             key_id: key.id

        expect(json_response['success']).to be_falsey
        expect(json_response['recovery_codes']).to be_nil
      end
    end
  end

148 149
  describe "POST /internal/lfs_authenticate" do
    before do
150
      project.add_developer(user)
151 152 153 154 155 156
    end

    context 'user key' do
      it 'returns the correct information about the key' do
        lfs_auth(key.id, project)

157
        expect(response).to have_gitlab_http_status(200)
158
        expect(json_response['username']).to eq(user.username)
159
        expect(json_response['lfs_token']).to eq(Gitlab::LfsToken.new(key).token)
160 161 162 163 164 165 166

        expect(json_response['repository_http_path']).to eq(project.http_url_to_repo)
      end

      it 'returns a 404 when the wrong key is provided' do
        lfs_auth(nil, project)

167
        expect(response).to have_gitlab_http_status(404)
168 169 170 171 172 173 174 175 176
      end
    end

    context 'deploy key' do
      let(:key) { create(:deploy_key) }

      it 'returns the correct information about the key' do
        lfs_auth(key.id, project)

177
        expect(response).to have_gitlab_http_status(200)
178
        expect(json_response['username']).to eq("lfs+deploy-key-#{key.id}")
179
        expect(json_response['lfs_token']).to eq(Gitlab::LfsToken.new(key).token)
180 181 182 183 184
        expect(json_response['repository_http_path']).to eq(project.http_url_to_repo)
      end
    end
  end

185 186 187 188
  describe "GET /internal/discover" do
    it do
      get(api("/internal/discover"), key_id: key.id, secret_token: secret_token)

189
      expect(response).to have_gitlab_http_status(200)
190 191 192 193 194

      expect(json_response['name']).to eq(user.name)
    end
  end

195
  describe "POST /internal/allowed", :clean_gitlab_redis_shared_state do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
196
    context "access granted" do
Rémy Coutable's avatar
Rémy Coutable committed
197 198
      around do |example|
        Timecop.freeze { example.run }
199 200
      end

Rémy Coutable's avatar
Rémy Coutable committed
201
      before do
202
        project.add_developer(user)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
203 204
      end

205
      context 'with env passed as a JSON' do
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
        context 'when relative path envs are not set' do
          it 'sets env in RequestStore' do
            expect(Gitlab::Git::Env).to receive(:set).with({
              'GIT_OBJECT_DIRECTORY' => 'foo',
              'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar'
            })

            push(key, project.wiki, env: {
              GIT_OBJECT_DIRECTORY: 'foo',
              GIT_ALTERNATE_OBJECT_DIRECTORIES: 'bar'
            }.to_json)

            expect(response).to have_gitlab_http_status(200)
          end
        end

        context 'when relative path envs are set' do
          it 'sets env in RequestStore' do
            obj_dir_relative = './objects'
            alt_obj_dirs_relative = ['./alt-objects-1', './alt-objects-2']
            repo_path = project.wiki.repository.path_to_repo

            expect(Gitlab::Git::Env).to receive(:set).with({
              'GIT_OBJECT_DIRECTORY' => File.join(repo_path, obj_dir_relative),
              'GIT_ALTERNATE_OBJECT_DIRECTORIES' => alt_obj_dirs_relative.map { |d| File.join(repo_path, d) },
              'GIT_OBJECT_DIRECTORY_RELATIVE' => obj_dir_relative,
              'GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE' => alt_obj_dirs_relative
            })

            push(key, project.wiki, env: {
              GIT_OBJECT_DIRECTORY: 'foo',
              GIT_ALTERNATE_OBJECT_DIRECTORIES: 'bar',
              GIT_OBJECT_DIRECTORY_RELATIVE: obj_dir_relative,
              GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE: alt_obj_dirs_relative
            }.to_json)

            expect(response).to have_gitlab_http_status(200)
          end
244 245 246
        end
      end

247
      context "git push with project.wiki" do
248
        it 'responds with success' do
249
          push(key, project.wiki)
250

251
          expect(response).to have_gitlab_http_status(200)
252 253
          expect(json_response["status"]).to be_truthy
          expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo)
254
          expect(json_response["gl_repository"]).to eq("wiki-#{project.id}")
255
          expect(user).not_to have_an_activity_record
256 257 258 259 260 261
        end
      end

      context "git pull with project.wiki" do
        it 'responds with success' do
          pull(key, project.wiki)
262

263
          expect(response).to have_gitlab_http_status(200)
264
          expect(json_response["status"]).to be_truthy
265
          expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo)
266
          expect(json_response["gl_repository"]).to eq("wiki-#{project.id}")
267
          expect(user).to have_an_activity_record
268 269 270
        end
      end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
271
      context "git pull" do
272
        context "gitaly disabled", :disable_gitaly do
273 274 275
          it "has the correct payload" do
            pull(key, project)

276
            expect(response).to have_gitlab_http_status(200)
277 278 279 280 281 282 283
            expect(json_response["status"]).to be_truthy
            expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
            expect(json_response["gl_repository"]).to eq("project-#{project.id}")
            expect(json_response["gitaly"]).to be_nil
            expect(user).to have_an_activity_record
          end
        end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
284

285 286 287 288
        context "gitaly enabled" do
          it "has the correct payload" do
            pull(key, project)

289
            expect(response).to have_gitlab_http_status(200)
290 291 292 293 294 295 296 297 298 299 300
            expect(json_response["status"]).to be_truthy
            expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
            expect(json_response["gl_repository"]).to eq("project-#{project.id}")
            expect(json_response["gitaly"]).not_to be_nil
            expect(json_response["gitaly"]["repository"]).not_to be_nil
            expect(json_response["gitaly"]["repository"]["storage_name"]).to eq(project.repository.gitaly_repository.storage_name)
            expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
            expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
            expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
            expect(user).to have_an_activity_record
          end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
301 302 303 304
        end
      end

      context "git push" do
305
        context "gitaly disabled", :disable_gitaly do
306 307 308
          it "has the correct payload" do
            push(key, project)

309
            expect(response).to have_gitlab_http_status(200)
310 311 312 313 314 315 316
            expect(json_response["status"]).to be_truthy
            expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
            expect(json_response["gl_repository"]).to eq("project-#{project.id}")
            expect(json_response["gitaly"]).to be_nil
            expect(user).not_to have_an_activity_record
          end
        end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
317

318 319 320 321
        context "gitaly enabled" do
          it "has the correct payload" do
            push(key, project)

322
            expect(response).to have_gitlab_http_status(200)
323 324 325 326 327 328 329 330 331 332 333
            expect(json_response["status"]).to be_truthy
            expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
            expect(json_response["gl_repository"]).to eq("project-#{project.id}")
            expect(json_response["gitaly"]).not_to be_nil
            expect(json_response["gitaly"]["repository"]).not_to be_nil
            expect(json_response["gitaly"]["repository"]["storage_name"]).to eq(project.repository.gitaly_repository.storage_name)
            expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
            expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
            expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
            expect(user).not_to have_an_activity_record
          end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
334
        end
335 336 337

        context 'project as /namespace/project' do
          it do
338
            pull(key, project_with_repo_path('/' + project.full_path))
339

340
            expect(response).to have_gitlab_http_status(200)
341 342
            expect(json_response["status"]).to be_truthy
            expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
343
            expect(json_response["gl_repository"]).to eq("project-#{project.id}")
344 345 346 347 348
          end
        end

        context 'project as namespace/project' do
          it do
349
            pull(key, project_with_repo_path(project.full_path))
350

351
            expect(response).to have_gitlab_http_status(200)
352 353
            expect(json_response["status"]).to be_truthy
            expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
354
            expect(json_response["gl_repository"]).to eq("project-#{project.id}")
355 356
          end
        end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
357 358 359 360 361
      end
    end

    context "access denied" do
      before do
362
        project.add_guest(user)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
363 364 365 366
      end

      context "git pull" do
        it do
367
          pull(key, project)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
368

369
          expect(response).to have_gitlab_http_status(200)
370
          expect(json_response["status"]).to be_falsey
371
          expect(user).not_to have_an_activity_record
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
372 373 374 375 376
        end
      end

      context "git push" do
        it do
377
          push(key, project)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
378

379
          expect(response).to have_gitlab_http_status(200)
380
          expect(json_response["status"]).to be_falsey
381
          expect(user).not_to have_an_activity_record
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
382 383 384 385
        end
      end
    end

386
    context "blocked user" do
387
      let(:personal_project) { create(:project, namespace: user.namespace) }
388 389 390 391 392 393 394 395 396

      before do
        user.block
      end

      context "git pull" do
        it do
          pull(key, personal_project)

397
          expect(response).to have_gitlab_http_status(200)
398
          expect(json_response["status"]).to be_falsey
399
          expect(user).not_to have_an_activity_record
400 401 402 403 404 405 406
        end
      end

      context "git push" do
        it do
          push(key, personal_project)

407
          expect(response).to have_gitlab_http_status(200)
408
          expect(json_response["status"]).to be_falsey
409
          expect(user).not_to have_an_activity_record
410 411 412
        end
      end
    end
413

414 415
    context "archived project" do
      before do
416
        project.add_developer(user)
417 418 419 420 421 422 423
        project.archive!
      end

      context "git pull" do
        it do
          pull(key, project)

424
          expect(response).to have_gitlab_http_status(200)
425
          expect(json_response["status"]).to be_truthy
426 427 428 429 430 431 432
        end
      end

      context "git push" do
        it do
          push(key, project)

433
          expect(response).to have_gitlab_http_status(200)
434
          expect(json_response["status"]).to be_falsey
435 436 437 438
        end
      end
    end

439 440 441 442 443 444 445 446 447 448 449
    context "deploy key" do
      let(:key) { create(:deploy_key) }

      context "added to project" do
        before do
          key.projects << project
        end

        it do
          archive(key, project)

450
          expect(response).to have_gitlab_http_status(200)
451
          expect(json_response["status"]).to be_truthy
452 453 454 455 456 457 458
        end
      end

      context "not added to project" do
        it do
          archive(key, project)

459
          expect(response).to have_gitlab_http_status(200)
460
          expect(json_response["status"]).to be_falsey
461 462 463
        end
      end
    end
464 465 466

    context 'project does not exist' do
      it do
467
        pull(key, project_with_repo_path('gitlab/notexist'))
468

469
        expect(response).to have_gitlab_http_status(200)
470
        expect(json_response["status"]).to be_falsey
471 472 473 474 475 476 477
      end
    end

    context 'user does not exist' do
      it do
        pull(OpenStruct.new(id: 0), project)

478
        expect(response).to have_gitlab_http_status(200)
479
        expect(json_response["status"]).to be_falsey
480 481
      end
    end
482 483 484

    context 'ssh access has been disabled' do
      before do
485
        stub_application_setting(enabled_git_access_protocol: 'http')
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
      end

      it 'rejects the SSH push' do
        push(key, project)

        expect(response.status).to eq(200)
        expect(json_response['status']).to be_falsey
        expect(json_response['message']).to eq 'Git access over SSH is not allowed'
      end

      it 'rejects the SSH pull' do
        pull(key, project)

        expect(response.status).to eq(200)
        expect(json_response['status']).to be_falsey
        expect(json_response['message']).to eq 'Git access over SSH is not allowed'
      end
    end

    context 'http access has been disabled' do
      before do
507
        stub_application_setting(enabled_git_access_protocol: 'ssh')
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
      end

      it 'rejects the HTTP push' do
        push(key, project, 'http')

        expect(response.status).to eq(200)
        expect(json_response['status']).to be_falsey
        expect(json_response['message']).to eq 'Git access over HTTP is not allowed'
      end

      it 'rejects the HTTP pull' do
        pull(key, project, 'http')

        expect(response.status).to eq(200)
        expect(json_response['status']).to be_falsey
        expect(json_response['message']).to eq 'Git access over HTTP is not allowed'
      end
    end

    context 'web actions are always allowed' do
      it 'allows WEB push' do
529
        stub_application_setting(enabled_git_access_protocol: 'ssh')
530
        project.add_developer(user)
531 532 533 534 535 536
        push(key, project, 'web')

        expect(response.status).to eq(200)
        expect(json_response['status']).to be_truthy
      end
    end
537 538 539

    context 'the project path was changed' do
      let!(:old_path_to_repo) { project.repository.path_to_repo }
540
      let!(:repository) { project.repository }
541 542

      before do
543
        project.add_developer(user)
544 545 546 547 548
        project.path = 'new_path'
        project.save!
      end

      it 'rejects the push' do
549
        push(key, project)
550

551
        expect(response).to have_gitlab_http_status(200)
552
        expect(json_response['status']).to be_falsy
553 554 555
      end

      it 'rejects the SSH pull' do
556
        pull(key, project)
557

558
        expect(response).to have_gitlab_http_status(200)
559
        expect(json_response['status']).to be_falsy
560 561
      end
    end
562 563
  end

564 565 566 567 568
  describe 'GET /internal/merge_request_urls' do
    let(:repo_name) { "#{project.namespace.name}/#{project.path}" }
    let(:changes) { URI.escape("#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch") }

    before do
569
      project.add_developer(user)
570 571 572
    end

    it 'returns link to create new merge request' do
573 574
      get api("/internal/merge_request_urls?project=#{repo_name}&changes=#{changes}"), secret_token: secret_token

575 576
      expect(json_response).to match [{
        "branch_name" => "new_branch",
577
        "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
578 579 580
        "new_merge_request" => true
      }]
    end
581 582 583 584 585 586 587 588

    it 'returns empty array if printing_merge_request_link_enabled is false' do
      project.update!(printing_merge_request_link_enabled: false)

      get api("/internal/merge_request_urls?project=#{repo_name}&changes=#{changes}"), secret_token: secret_token

      expect(json_response).to eq([])
    end
589 590 591 592 593 594 595 596 597 598 599 600 601 602

    context 'with a gl_repository parameter' do
      let(:gl_repository) { "project-#{project.id}" }

      it 'returns link to create new merge request' do
        get api("/internal/merge_request_urls?gl_repository=#{gl_repository}&changes=#{changes}"), secret_token: secret_token

        expect(json_response).to match [{
          "branch_name" => "new_branch",
          "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
          "new_merge_request" => true
        }]
      end
    end
603 604
  end

605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
  # TODO: Uncomment when the end-point is reenabled
  # describe 'POST /notify_post_receive' do
  #   let(:valid_params) do
  #     { project: project.repository.path, secret_token: secret_token }
  #   end
  #
  #   let(:valid_wiki_params) do
  #     { project: project.wiki.repository.path, secret_token: secret_token }
  #   end
  #
  #   before do
  #     allow(Gitlab.config.gitaly).to receive(:enabled).and_return(true)
  #   end
  #
  #   it "calls the Gitaly client with the project's repository" do
Andrew Newdigate's avatar
Andrew Newdigate committed
620
  #     expect(Gitlab::GitalyClient::NotificationService).
621 622
  #       to receive(:new).with(gitlab_git_repository_with(path: project.repository.path)).
  #       and_call_original
Andrew Newdigate's avatar
Andrew Newdigate committed
623
  #     expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
624 625 626 627
  #       to receive(:post_receive)
  #
  #     post api("/internal/notify_post_receive"), valid_params
  #
628
  #     expect(response).to have_gitlab_http_status(200)
629 630 631
  #   end
  #
  #   it "calls the Gitaly client with the wiki's repository if it's a wiki" do
Andrew Newdigate's avatar
Andrew Newdigate committed
632
  #     expect(Gitlab::GitalyClient::NotificationService).
633 634
  #       to receive(:new).with(gitlab_git_repository_with(path: project.wiki.repository.path)).
  #       and_call_original
Andrew Newdigate's avatar
Andrew Newdigate committed
635
  #     expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
636 637 638 639
  #       to receive(:post_receive)
  #
  #     post api("/internal/notify_post_receive"), valid_wiki_params
  #
640
  #     expect(response).to have_gitlab_http_status(200)
641 642 643
  #   end
  #
  #   it "returns 500 if the gitaly call fails" do
Andrew Newdigate's avatar
Andrew Newdigate committed
644
  #     expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
645 646 647 648
  #       to receive(:post_receive).and_raise(GRPC::Unavailable)
  #
  #     post api("/internal/notify_post_receive"), valid_params
  #
649
  #     expect(response).to have_gitlab_http_status(500)
650 651 652 653 654 655 656 657 658 659 660 661
  #   end
  #
  #   context 'with a gl_repository parameter' do
  #     let(:valid_params) do
  #       { gl_repository: "project-#{project.id}", secret_token: secret_token }
  #     end
  #
  #     let(:valid_wiki_params) do
  #       { gl_repository: "wiki-#{project.id}", secret_token: secret_token }
  #     end
  #
  #     it "calls the Gitaly client with the project's repository" do
Andrew Newdigate's avatar
Andrew Newdigate committed
662
  #       expect(Gitlab::GitalyClient::NotificationService).
663 664
  #         to receive(:new).with(gitlab_git_repository_with(path: project.repository.path)).
  #         and_call_original
Andrew Newdigate's avatar
Andrew Newdigate committed
665
  #       expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
666 667 668 669
  #         to receive(:post_receive)
  #
  #       post api("/internal/notify_post_receive"), valid_params
  #
670
  #       expect(response).to have_gitlab_http_status(200)
671 672 673
  #     end
  #
  #     it "calls the Gitaly client with the wiki's repository if it's a wiki" do
Andrew Newdigate's avatar
Andrew Newdigate committed
674
  #       expect(Gitlab::GitalyClient::NotificationService).
675 676
  #         to receive(:new).with(gitlab_git_repository_with(path: project.wiki.repository.path)).
  #         and_call_original
Andrew Newdigate's avatar
Andrew Newdigate committed
677
  #       expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
678 679 680 681
  #         to receive(:post_receive)
  #
  #       post api("/internal/notify_post_receive"), valid_wiki_params
  #
682
  #       expect(response).to have_gitlab_http_status(200)
683 684 685
  #     end
  #   end
  # end
686

687
  describe 'POST /internal/post_receive', :clean_gitlab_redis_shared_state do
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
    let(:identifier) { 'key-123' }

    let(:valid_params) do
      {
        gl_repository: gl_repository,
        secret_token: secret_token,
        identifier: identifier,
        changes: changes
      }
    end

    let(:changes) do
      "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch"
    end

    before do
704
      project.add_developer(user)
705 706
      allow(described_class).to receive(:identify).and_return(user)
      allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(user)
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
    end

    it 'enqueues a PostReceive worker job' do
      expect(PostReceive).to receive(:perform_async)
        .with(gl_repository, identifier, changes)

      post api("/internal/post_receive"), valid_params
    end

    it 'decreases the reference counter and returns the result' do
      expect(Gitlab::ReferenceCounter).to receive(:new).with(gl_repository)
        .and_return(reference_counter)
      expect(reference_counter).to receive(:decrease).and_return(true)

      post api("/internal/post_receive"), valid_params

      expect(json_response['reference_counter_decreased']).to be(true)
    end

    it 'returns link to create new merge request' do
      post api("/internal/post_receive"), valid_params

      expect(json_response['merge_request_urls']).to match [{
        "branch_name" => "new_branch",
        "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
        "new_merge_request" => true
      }]
    end

    it 'returns empty array if printing_merge_request_link_enabled is false' do
      project.update!(printing_merge_request_link_enabled: false)

      post api("/internal/post_receive"), valid_params

      expect(json_response['merge_request_urls']).to eq([])
    end

    context 'broadcast message exists' do
      let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }

      it 'returns one broadcast message'  do
        post api("/internal/post_receive"), valid_params

750
        expect(response).to have_gitlab_http_status(200)
751 752 753 754 755 756 757 758
        expect(json_response['broadcast_message']).to eq(broadcast_message.message)
      end
    end

    context 'broadcast message does not exist' do
      it 'returns empty string'  do
        post api("/internal/post_receive"), valid_params

759
        expect(response).to have_gitlab_http_status(200)
760 761 762 763 764 765 766 767 768 769
        expect(json_response['broadcast_message']).to eq(nil)
      end
    end

    context 'nil broadcast message' do
      it 'returns empty string' do
        allow(BroadcastMessage).to receive(:current).and_return(nil)

        post api("/internal/post_receive"), valid_params

770
        expect(response).to have_gitlab_http_status(200)
771 772 773
        expect(json_response['broadcast_message']).to eq(nil)
      end
    end
774 775 776 777 778 779 780 781 782 783 784 785 786

    context 'with a redirected data' do
      it 'returns redirected message on the response' do
        project_moved = Gitlab::Checks::ProjectMoved.new(project, user, 'foo/baz', 'http')
        project_moved.add_redirect_message

        post api("/internal/post_receive"), valid_params

        expect(response).to have_gitlab_http_status(200)
        expect(json_response["redirected_message"]).to be_present
        expect(json_response["redirected_message"]).to eq(project_moved.redirect_message)
      end
    end
787 788
  end

789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
  describe 'POST /internal/pre_receive' do
    let(:valid_params) do
      { gl_repository: gl_repository, secret_token: secret_token }
    end

    it 'decreases the reference counter and returns the result' do
      expect(Gitlab::ReferenceCounter).to receive(:new).with(gl_repository)
        .and_return(reference_counter)
      expect(reference_counter).to receive(:increase).and_return(true)

      post api("/internal/pre_receive"), valid_params

      expect(json_response['reference_counter_increased']).to be(true)
    end
  end

805 806 807 808 809 810
  def project_with_repo_path(path)
    double().tap do |fake_project|
      allow(fake_project).to receive_message_chain('repository.path_to_repo' => path)
    end
  end

811
  def pull(key, project, protocol = 'ssh')
812
    post(
813 814
      api("/internal/allowed"),
      key_id: key.id,
815
      project: project.repository.path_to_repo,
816
      action: 'git-upload-pack',
817 818
      secret_token: secret_token,
      protocol: protocol
819 820 821
    )
  end

822 823 824 825 826 827 828 829 830 831 832
  def pull_with_path(key, path_to_repo, protocol = 'ssh')
    post(
      api("/internal/allowed"),
      key_id: key.id,
      project: path_to_repo,
      action: 'git-upload-pack',
      secret_token: secret_token,
      protocol: protocol
    )
  end

833
  def push(key, project, protocol = 'ssh', env: nil)
834
    post(
835
      api("/internal/allowed"),
836
      changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
837
      key_id: key.id,
838
      project: project.repository.path_to_repo,
839
      action: 'git-receive-pack',
840
      secret_token: secret_token,
841 842
      protocol: protocol,
      env: env
843
    )
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
844
  end
845

846 847 848 849 850 851 852 853 854 855 856 857 858
  def push_with_path(key, path_to_repo, protocol = 'ssh', env: nil)
    post(
      api("/internal/allowed"),
      changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
      key_id: key.id,
      project: path_to_repo,
      action: 'git-receive-pack',
      secret_token: secret_token,
      protocol: protocol,
      env: env
    )
  end

859
  def archive(key, project)
860
    post(
861 862 863
      api("/internal/allowed"),
      ref: 'master',
      key_id: key.id,
864
      project: project.repository.path_to_repo,
865
      action: 'git-upload-archive',
866 867
      secret_token: secret_token,
      protocol: 'ssh'
868 869
    )
  end
870 871 872 873 874 875

  def lfs_auth(key_id, project)
    post(
      api("/internal/lfs_authenticate"),
      key_id: key_id,
      secret_token: secret_token,
876
      project: project.repository.path_to_repo
877 878
    )
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
879
end