jobs_controller_spec.rb 30.7 KB
Newer Older
1
# coding: utf-8
S
Shinya Maeda 已提交
2 3
require 'spec_helper'

S
Shinya Maeda 已提交
4
describe Projects::JobsController, :clean_gitlab_redis_shared_state do
5
  include ApiHelpers
6
  include HttpIOHelpers
S
Shinya Maeda 已提交
7

8
  let(:project) { create(:project, :public) }
9 10
  let(:pipeline) { create(:ci_pipeline, project: project) }
  let(:user) { create(:user) }
S
Shinya Maeda 已提交
11

12
  before do
S
Shinya Maeda 已提交
13
    stub_feature_flags(ci_enable_live_trace: true)
14 15 16
    stub_not_protect_default_branch
  end

K
Kamil Trzcinski 已提交
17
  describe 'GET index' do
18 19 20 21 22 23 24 25
    context 'when scope is pending' do
      before do
        create(:ci_build, :pending, pipeline: pipeline)

        get_index(scope: 'pending')
      end

      it 'has only pending builds' do
26
        expect(response).to have_gitlab_http_status(:ok)
27 28 29 30 31 32 33 34 35 36 37
        expect(assigns(:builds).first.status).to eq('pending')
      end
    end

    context 'when scope is running' do
      before do
        create(:ci_build, :running, pipeline: pipeline)

        get_index(scope: 'running')
      end

38
      it 'has only running jobs' do
39
        expect(response).to have_gitlab_http_status(:ok)
40 41 42 43 44 45 46 47 48 49 50
        expect(assigns(:builds).first.status).to eq('running')
      end
    end

    context 'when scope is finished' do
      before do
        create(:ci_build, :success, pipeline: pipeline)

        get_index(scope: 'finished')
      end

51
      it 'has only finished jobs' do
52
        expect(response).to have_gitlab_http_status(:ok)
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
        expect(assigns(:builds).first.status).to eq('success')
      end
    end

    context 'when page is specified' do
      let(:last_page) { project.builds.page.total_pages }

      context 'when page number is eligible' do
        before do
          create_list(:ci_build, 2, pipeline: pipeline)

          get_index(page: last_page.to_param)
        end

        it 'redirects to the page' do
68
          expect(response).to have_gitlab_http_status(:ok)
69 70 71 72 73
          expect(assigns(:builds).current_page).to eq(last_page)
        end
      end
    end

K
Kamil Trzcinski 已提交
74 75 76
    context 'number of queries' do
      before do
        Ci::Build::AVAILABLE_STATUSES.each do |status|
77
          create_job(status, status)
K
Kamil Trzcinski 已提交
78 79 80
        end
      end

81
      it 'verifies number of queries', :request_store do
82
        recorded = ActiveRecord::QueryRecorder.new { get_index }
83
        expect(recorded.count).to be_within(5).of(7)
K
Kamil Trzcinski 已提交
84 85
      end

86
      def create_job(name, status)
K
Kamil Trzcinski 已提交
87 88
        pipeline = create(:ci_pipeline, project: project)
        create(:ci_build, :tags, :triggered, :artifacts,
89
               pipeline: pipeline, name: name, status: status)
K
Kamil Trzcinski 已提交
90 91
      end
    end
92 93 94 95 96 97 98 99 100 101 102 103

    def get_index(**extra_params)
      params = {
        namespace_id: project.namespace.to_param,
        project_id: project
      }

      get :index, params.merge(extra_params)
    end
  end

  describe 'GET show' do
104
    let!(:job) { create(:ci_build, :failed, pipeline: pipeline) }
105 106
    let!(:second_job) { create(:ci_build, :failed, pipeline: pipeline) }
    let!(:third_job) { create(:ci_build, :failed) }
107

108
    context 'when requesting HTML' do
109
      context 'when job exists' do
110
        before do
111
          get_show(id: job.id)
112 113
        end

114
        it 'has a job' do
115
          expect(response).to have_gitlab_http_status(:ok)
116
          expect(assigns(:build).id).to eq(job.id)
117
        end
118 119 120 121 122 123 124

        it 'has the correct build collection' do
          builds = assigns(:builds).map(&:id)

          expect(builds).to include(job.id, second_job.id)
          expect(builds).not_to include(third_job.id)
        end
125 126
      end

127
      context 'when job does not exist' do
128 129 130 131 132
        before do
          get_show(id: 1234)
        end

        it 'renders not_found' do
133
          expect(response).to have_gitlab_http_status(:not_found)
134
        end
135 136 137
      end
    end

138
    context 'when requesting JSON' do
139 140
      let(:merge_request) { create(:merge_request, source_project: project) }

141
      before do
142 143 144 145 146
        project.add_developer(user)
        sign_in(user)

        allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)

147
        get_show(id: job.id, format: :json)
148 149
      end

150 151 152 153 154
      context 'when job failed' do
        it 'exposes needed information' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
155
          expect(json_response['merge_request']['path']).to match(%r{merge_requests/\d+\z})
156 157
          expect(json_response['new_issue_path']).to include('/issues/new')
        end
158 159
      end

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
      context 'when job is running' do
        context 'job is cancelable' do
          let(:job) { create(:ci_build, :running, pipeline: pipeline) }

          it 'cancel_path is present with correct redirect' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['cancel_path']).to include(CGI.escape(json_response['build_path']))
          end
        end

        context 'with web terminal' do
          let(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }

          it 'exposes the terminal path' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['terminal_path']).to match(%r{/terminal})
          end
        end
      end

182 183 184
      context 'when job has artifacts' do
        context 'with not expiry date' do
          let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
185

186 187 188 189 190
          it 'exposes needed information' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
            expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
191 192
            expect(json_response['artifact']).not_to have_key('expired')
            expect(json_response['artifact']).not_to have_key('expired_at')
193 194
          end
        end
195

196 197 198 199 200 201
        context 'with expiry date' do
          let(:job) { create(:ci_build, :success, :artifacts, :expired, pipeline: pipeline) }

          it 'exposes needed information' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
202 203
            expect(json_response['artifact']).not_to have_key('download_path')
            expect(json_response['artifact']).not_to have_key('browse_path')
204 205 206 207
            expect(json_response['artifact']['expired']).to eq(true)
            expect(json_response['artifact']['expire_at']).not_to be_empty
          end
        end
208 209
      end

210 211 212 213 214 215 216 217 218 219 220
      context 'when job passed with no trace' do
        let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }

        it 'exposes empty state illustrations' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['status']['illustration']).to have_key('image')
          expect(json_response['status']['illustration']).to have_key('size')
          expect(json_response['status']['illustration']).to have_key('title')
        end
      end
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

      context 'with no deployment' do
        let(:job) { create(:ci_build, :success, pipeline: pipeline) }

        it 'does not exposes the deployment information' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(json_response['deployment_status']).to be_nil
        end
      end

      context 'with deployment' do
        let(:merge_request) { create(:merge_request, source_project: project) }
        let(:environment) { create(:environment, project: project, name: 'staging', state: :available) }
        let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }

        it 'exposes the deployment information' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(json_response).to match_schema('job/job_details')
          expect(json_response['deployment_status']["status"]).to eq 'creating'
          expect(json_response['deployment_status']["environment"]).not_to be_nil
        end
      end
S
Steve Azzopardi 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

      context 'when user can edit runner' do
        context 'that belongs to the project' do
          let(:runner) { create(:ci_runner, :project, projects: [project]) }
          let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) }

          before do
            project.add_maintainer(user)
            sign_in(user)

            get_show(id: job.id, format: :json)
          end

          it 'user can edit runner' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['runner']).to have_key('edit_path')
          end
        end

        context 'that belongs to group' do
          let(:group) { create(:group) }
          let(:runner) { create(:ci_runner, :group, groups: [group]) }
          let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) }
          let(:user) { create(:user, :admin) }

          before do
            project.add_maintainer(user)
            sign_in(user)

            get_show(id: job.id, format: :json)
          end

          it 'user can not edit runner' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['runner']).not_to have_key('edit_path')
          end
        end

        context 'that belongs to instance' do
          let(:runner) { create(:ci_runner, :instance) }
          let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) }
          let(:user) { create(:user, :admin) }

          before do
            project.add_maintainer(user)
            sign_in(user)

            get_show(id: job.id, format: :json)
          end

          it 'user can not edit runner' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['runner']).not_to have_key('edit_path')
          end
        end
      end
302 303 304 305 306 307 308 309 310 311

      context 'when no runners are available' do
        let(:runner) { create(:ci_runner, :instance, active: false) }
        let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }

        it 'exposes needed information' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['runners']['online']).to be false
          expect(json_response['runners']['available']).to be false
S
Steve Azzopardi 已提交
312
          expect(json_response['stuck']).to be true
313 314 315 316 317 318 319 320 321 322 323 324
        end
      end

      context 'when no runner is online' do
        let(:runner) { create(:ci_runner, :instance) }
        let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }

        it 'exposes needed information' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['runners']['online']).to be false
          expect(json_response['runners']['available']).to be true
S
Steve Azzopardi 已提交
325
          expect(json_response['stuck']).to be true
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
        end
      end

      context 'settings_path' do
        context 'when user is developer' do
          it 'settings_path is not available' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['runners']).not_to have_key('settings_path')
          end
        end

        context 'when user is maintainer' do
          let(:user) { create(:user, :admin) }

          before do
            project.add_maintainer(user)
            sign_in(user)
          end

          it 'settings_path is available' do
            expect(response).to have_gitlab_http_status(:ok)
            expect(response).to match_response_schema('job/job_details')
            expect(json_response['runners']['settings_path']).to match(/runners/)
          end
        end
      end
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

      context 'when no trace is available' do
        it 'has_trace is false' do
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['has_trace']).to be false
        end
      end

      context 'when job has trace' do
        let(:job) { create(:ci_build, :running, :trace_live, pipeline: pipeline) }

        it "has_trace is true" do
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['has_trace']).to be true
        end
      end
369 370 371 372

      it 'exposes the stage the job belongs to' do
        expect(json_response['stage']).to eq('test')
      end
373 374
    end

375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
    context 'when requesting JSON job is triggered' do
      let!(:merge_request) { create(:merge_request, source_project: project) }
      let(:trigger) { create(:ci_trigger, project: project) }
      let(:trigger_request) { create(:ci_trigger_request, pipeline: pipeline, trigger: trigger) }
      let(:job) { create(:ci_build, pipeline: pipeline, trigger_request: trigger_request) }

      before do
        project.add_developer(user)
        sign_in(user)

        allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
      end

      context 'with no variables' do
        before do
          get_show(id: job.id, format: :json)
        end

        it 'exposes trigger information' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['trigger']['short_token']).to eq 'toke'
          expect(json_response['trigger']['variables'].length).to eq 0
        end
      end

      context 'with variables' do
        before do
          create(:ci_pipeline_variable, pipeline: pipeline, key: :TRIGGER_KEY_1, value: 'TRIGGER_VALUE_1')

          get_show(id: job.id, format: :json)
        end

        it 'exposes trigger information and variables' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('job/job_details')
          expect(json_response['trigger']['short_token']).to eq 'toke'
          expect(json_response['trigger']['variables'].length).to eq 1
          expect(json_response['trigger']['variables'].first['key']).to eq "TRIGGER_KEY_1"
          expect(json_response['trigger']['variables'].first['value']).to eq "TRIGGER_VALUE_1"
          expect(json_response['trigger']['variables'].first['public']).to eq false
        end
      end
    end

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
    def get_show(**extra_params)
      params = {
        namespace_id: project.namespace.to_param,
        project_id: project
      }

      get :show, params.merge(extra_params)
    end
  end

  describe 'GET trace.json' do
    before do
      get_trace
    end

435 436 437 438 439 440 441 442 443 444 445
    context 'when job has a trace artifact' do
      let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }

      it 'returns a trace' do
        expect(response).to have_gitlab_http_status(:ok)
        expect(json_response['id']).to eq job.id
        expect(json_response['status']).to eq job.status
        expect(json_response['html']).to eq(job.trace.html)
      end
    end

446
    context 'when job has a trace' do
447
      let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
448 449

      it 'returns a trace' do
450
        expect(response).to have_gitlab_http_status(:ok)
451 452
        expect(json_response['id']).to eq job.id
        expect(json_response['status']).to eq job.status
453 454 455 456
        expect(json_response['html']).to eq('BUILD TRACE')
      end
    end

457 458
    context 'when job has no traces' do
      let(:job) { create(:ci_build, pipeline: pipeline) }
459 460

      it 'returns no traces' do
461
        expect(response).to have_gitlab_http_status(:ok)
462 463
        expect(json_response['id']).to eq job.id
        expect(json_response['status']).to eq job.status
464
        expect(json_response['html']).to be_nil
465 466 467
      end
    end

468
    context 'when job has a trace with ANSI sequence and Unicode' do
469
      let(:job) { create(:ci_build, :unicode_trace_live, pipeline: pipeline) }
470 471

      it 'returns a trace with Unicode' do
472
        expect(response).to have_gitlab_http_status(:ok)
473 474
        expect(json_response['id']).to eq job.id
        expect(json_response['status']).to eq job.status
475 476 477 478
        expect(json_response['html']).to include("ヾ(´༎ຶД༎ຶ`)ノ")
      end
    end

479
    context 'when trace artifact is in ObjectStorage' do
K
Kamil Trzciński 已提交
480 481
      let(:url) { 'http://object-storage/trace' }
      let(:file_path) { expand_fixture_path('trace/sample_trace') }
482 483 484 485
      let!(:job) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) }

      before do
        allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false }
K
Kamil Trzciński 已提交
486 487
        allow_any_instance_of(JobArtifactUploader).to receive(:url) { url }
        allow_any_instance_of(JobArtifactUploader).to receive(:size) { File.size(file_path) }
488 489 490 491
      end

      context 'when there are no network issues' do
        before do
K
Kamil Trzciński 已提交
492
          stub_remote_url_206(url, file_path)
493 494 495 496 497 498 499 500 501 502 503 504 505 506

          get_trace
        end

        it 'returns a trace' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(json_response['id']).to eq job.id
          expect(json_response['status']).to eq job.status
          expect(json_response['html']).to eq(job.trace.html)
        end
      end

      context 'when there is a network issue' do
        before do
507
          stub_remote_url_500(url)
508 509 510
        end

        it 'returns a trace' do
511
          expect { get_trace }.to raise_error(Gitlab::HttpIO::FailedToGetChunkError)
512 513 514 515
        end
      end
    end

516 517 518
    def get_trace
      get :trace, namespace_id: project.namespace,
                  project_id: project,
519
                  id: job.id,
520 521
                  format: :json
    end
K
Kamil Trzcinski 已提交
522 523
  end

S
Shinya Maeda 已提交
524
  describe 'GET status.json' do
525 526
    let(:job) { create(:ci_build, pipeline: pipeline) }
    let(:status) { job.detailed_status(double('user')) }
S
Shinya Maeda 已提交
527

528 529 530
    before do
      get :status, namespace_id: project.namespace,
                   project_id: project,
531
                   id: job.id,
532 533
                   format: :json
    end
S
Shinya Maeda 已提交
534

535
    it 'return a detailed job status in json' do
536
      expect(response).to have_gitlab_http_status(:ok)
537 538 539
      expect(json_response['text']).to eq status.text
      expect(json_response['label']).to eq status.label
      expect(json_response['icon']).to eq status.icon
540
      expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.png"
S
Shinya Maeda 已提交
541 542
    end
  end
543

544 545
  describe 'POST retry' do
    before do
546
      project.add_developer(user)
547 548 549 550 551
      sign_in(user)

      post_retry
    end

552 553
    context 'when job is retryable' do
      let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
554

555
      it 'redirects to the retried job page' do
556
        expect(response).to have_gitlab_http_status(:found)
557
        expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
558 559 560
      end
    end

561 562
    context 'when job is not retryable' do
      let(:job) { create(:ci_build, pipeline: pipeline) }
563 564

      it 'renders unprocessable_entity' do
565
        expect(response).to have_gitlab_http_status(:unprocessable_entity)
566 567 568 569 570 571
      end
    end

    def post_retry
      post :retry, namespace_id: project.namespace,
                   project_id: project,
572
                   id: job.id
573 574 575 576 577
    end
  end

  describe 'POST play' do
    before do
578
      project.add_developer(user)
579 580 581 582

      create(:protected_branch, :developers_can_merge,
             name: 'master', project: project)

583 584 585 586 587
      sign_in(user)

      post_play
    end

588 589
    context 'when job is playable' do
      let(:job) { create(:ci_build, :playable, pipeline: pipeline) }
590

591
      it 'redirects to the played job page' do
592
        expect(response).to have_gitlab_http_status(:found)
593
        expect(response).to redirect_to(namespace_project_job_path(id: job.id))
594 595 596
      end

      it 'transits to pending' do
597
        expect(job.reload).to be_pending
598 599 600
      end
    end

601 602
    context 'when job is not playable' do
      let(:job) { create(:ci_build, pipeline: pipeline) }
603 604

      it 'renders unprocessable_entity' do
605
        expect(response).to have_gitlab_http_status(:unprocessable_entity)
606 607 608 609 610 611
      end
    end

    def post_play
      post :play, namespace_id: project.namespace,
                  project_id: project,
612
                  id: job.id
613 614 615 616 617
    end
  end

  describe 'POST cancel' do
    before do
618
      project.add_developer(user)
619 620 621
      sign_in(user)
    end

622
    context 'when continue url is present' do
623
      let(:job) { create(:ci_build, :cancelable, pipeline: pipeline) }
624

625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
      context 'when continue to is a safe url' do
        let(:url) { '/test' }

        before do
          post_cancel(continue: { to: url })
        end

        it 'redirects to the continue url' do
          expect(response).to have_gitlab_http_status(:found)
          expect(response).to redirect_to(url)
        end

        it 'transits to canceled' do
          expect(job.reload).to be_canceled
        end
640 641
      end

642 643 644 645 646 647
      context 'when continue to is not a safe url' do
        let(:url) { 'http://example.com' }

        it 'raises an error' do
          expect { cancel_with_redirect(url) }.to raise_error
        end
648 649 650
      end
    end

651 652 653 654
    context 'when continue url is not present' do
      before do
        post_cancel
      end
655

656 657
      context 'when job is cancelable' do
        let(:job) { create(:ci_build, :cancelable, pipeline: pipeline) }
658

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
        it 'redirects to the builds page' do
          expect(response).to have_gitlab_http_status(:found)
          expect(response).to redirect_to(builds_namespace_project_pipeline_path(id: pipeline.id))
        end

        it 'transits to canceled' do
          expect(job.reload).to be_canceled
        end
      end

      context 'when job is not cancelable' do
        let(:job) { create(:ci_build, :canceled, pipeline: pipeline) }

        it 'returns unprocessable_entity' do
          expect(response).to have_gitlab_http_status(:unprocessable_entity)
        end
675 676 677
      end
    end

678 679 680 681
    def post_cancel(additional_params = {})
      post :cancel, { namespace_id: project.namespace,
                      project_id: project,
                      id: job.id }.merge(additional_params)
682 683 684
    end
  end

S
Shinya Maeda 已提交
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
  describe 'POST unschedule' do
    before do
      project.add_developer(user)

      create(:protected_branch, :developers_can_merge,
             name: 'master', project: project)

      sign_in(user)

      post_unschedule
    end

    context 'when job is scheduled' do
      let(:job) { create(:ci_build, :scheduled, pipeline: pipeline) }

      it 'redirects to the unscheduled job page' do
        expect(response).to have_gitlab_http_status(:found)
        expect(response).to redirect_to(namespace_project_job_path(id: job.id))
      end

      it 'transits to manual' do
        expect(job.reload).to be_manual
      end
    end

    context 'when job is not scheduled' do
      let(:job) { create(:ci_build, pipeline: pipeline) }

      it 'renders unprocessable_entity' do
        expect(response).to have_gitlab_http_status(:unprocessable_entity)
      end
    end

    def post_unschedule
      post :unschedule, namespace_id: project.namespace,
A
Alessio Caiazza 已提交
720 721
                        project_id: project,
                        id: job.id
S
Shinya Maeda 已提交
722 723 724
    end
  end

725 726
  describe 'POST cancel_all' do
    before do
727
      project.add_developer(user)
728 729 730
      sign_in(user)
    end

731
    context 'when jobs are cancelable' do
732 733 734 735 736 737 738
      before do
        create_list(:ci_build, 2, :cancelable, pipeline: pipeline)

        post_cancel_all
      end

      it 'redirects to a index page' do
739
        expect(response).to have_gitlab_http_status(:found)
740
        expect(response).to redirect_to(namespace_project_jobs_path)
741 742 743 744 745 746 747
      end

      it 'transits to canceled' do
        expect(Ci::Build.all).to all(be_canceled)
      end
    end

748
    context 'when jobs are not cancelable' do
749 750 751 752 753 754 755
      before do
        create_list(:ci_build, 2, :canceled, pipeline: pipeline)

        post_cancel_all
      end

      it 'redirects to a index page' do
756
        expect(response).to have_gitlab_http_status(:found)
757
        expect(response).to redirect_to(namespace_project_jobs_path)
758 759 760 761 762 763 764 765 766 767
      end
    end

    def post_cancel_all
      post :cancel_all, namespace_id: project.namespace,
                        project_id: project
    end
  end

  describe 'POST erase' do
768
    let(:role) { :maintainer }
S
Shinya Maeda 已提交
769

770
    before do
771
      project.add_role(user, role)
772 773 774 775 776
      sign_in(user)

      post_erase
    end

777
    context 'when job is erasable' do
778
      let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline) }
779

780
      it 'redirects to the erased job page' do
781
        expect(response).to have_gitlab_http_status(:found)
782
        expect(response).to redirect_to(namespace_project_job_path(id: job.id))
783 784 785
      end

      it 'erases artifacts' do
786 787
        expect(job.artifacts_file.exists?).to be_falsey
        expect(job.artifacts_metadata.exists?).to be_falsey
788 789 790
      end

      it 'erases trace' do
791
        expect(job.trace.exist?).to be_falsey
792 793 794
      end
    end

795 796
    context 'when job is not erasable' do
      let(:job) { create(:ci_build, :erased, pipeline: pipeline) }
797 798

      it 'returns unprocessable_entity' do
799
        expect(response).to have_gitlab_http_status(:unprocessable_entity)
800 801 802
      end
    end

803 804
    context 'when user is developer' do
      let(:role) { :developer }
805
      let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline, user: triggered_by) }
806 807 808 809 810 811 812 813 814 815 816 817 818

      context 'when triggered by same user' do
        let(:triggered_by) { user }

        it 'has successful status' do
          expect(response).to have_gitlab_http_status(:found)
        end
      end

      context 'when triggered by different user' do
        let(:triggered_by) { create(:user) }

        it 'does not have successful status' do
S
Shinya Maeda 已提交
819
          expect(response).not_to have_gitlab_http_status(:found)
820 821 822 823
        end
      end
    end

824 825 826
    def post_erase
      post :erase, namespace_id: project.namespace,
                   project_id: project,
827
                   id: job.id
828 829 830 831
    end
  end

  describe 'GET raw' do
832 833 834 835
    subject do
      post :raw, namespace_id: project.namespace,
                 project_id: project,
                 id: job.id
836 837
    end

838
    context "when job has a trace artifact" do
839 840 841
      let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }

      it 'returns a trace' do
842 843
        response = subject

844
        expect(response).to have_gitlab_http_status(:ok)
845 846
        expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
        expect(response.body).to eq(job.job_artifacts_trace.open.read)
847 848 849
      end
    end

850
    context "when job has a trace file" do
851
      let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
852

853
      it "send a trace file" do
854 855
        response = subject

856
        expect(response).to have_gitlab_http_status(:ok)
857 858
        expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
        expect(response.body).to eq("BUILD TRACE")
859 860 861
      end
    end

862
    context "when job has a trace in database" do
S
Shinya Maeda 已提交
863 864 865
      let(:job) { create(:ci_build, pipeline: pipeline) }

      before do
866
        job.update_column(:trace, "Sample trace")
S
Shinya Maeda 已提交
867 868
      end

869
      it "send a trace file" do
S
Shinya Maeda 已提交
870 871 872
        response = subject

        expect(response).to have_gitlab_http_status(:ok)
873 874
        expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
        expect(response.body).to eq("Sample trace")
S
Shinya Maeda 已提交
875 876 877
      end
    end

878 879
    context 'when job does not have a trace file' do
      let(:job) { create(:ci_build, pipeline: pipeline) }
880 881

      it 'returns not_found' do
882 883
        response = subject

S
Shinya Maeda 已提交
884 885
        expect(response).to have_gitlab_http_status(:ok)
        expect(response.body).to eq ''
886 887 888
      end
    end

889 890 891 892 893 894 895 896 897 898
    context 'when the trace artifact is in ObjectStorage' do
      let!(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }

      before do
        allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false }
      end

      it 'redirect to the trace file url' do
        expect(subject).to redirect_to(job.job_artifacts_trace.file.url)
      end
899 900
    end
  end
F
Francisco Javier López 已提交
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001

  describe 'GET #terminal' do
    before do
      project.add_developer(user)
      sign_in(user)
    end

    context 'when job exists' do
      context 'and it has a terminal' do
        let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }

        it 'has a job' do
          get_terminal(id: job.id)

          expect(response).to have_gitlab_http_status(:ok)
          expect(assigns(:build).id).to eq(job.id)
        end
      end

      context 'and does not have a terminal' do
        let!(:job) { create(:ci_build, :running, pipeline: pipeline) }

        it 'returns not_found' do
          get_terminal(id: job.id)

          expect(response).to have_gitlab_http_status(:not_found)
        end
      end
    end

    context 'when job does not exist' do
      it 'renders not_found' do
        get_terminal(id: 1234)

        expect(response).to have_gitlab_http_status(:not_found)
      end
    end

    def get_terminal(**extra_params)
      params = {
        namespace_id: project.namespace.to_param,
        project_id: project
      }

      get :terminal, params.merge(extra_params)
    end
  end

  describe 'GET #terminal_websocket_authorize' do
    let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }

    before do
      project.add_developer(user)
      sign_in(user)
    end

    context 'with valid workhorse signature' do
      before do
        allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil)
      end

      context 'and valid id' do
        it 'returns the terminal for the job' do
          expect(Gitlab::Workhorse)
            .to receive(:terminal_websocket)
            .and_return(workhorse: :response)

          get_terminal_websocket(id: job.id)

          expect(response).to have_gitlab_http_status(200)
          expect(response.headers["Content-Type"]).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
          expect(response.body).to eq('{"workhorse":"response"}')
        end
      end

      context 'and invalid id' do
        it 'returns 404' do
          get_terminal_websocket(id: 1234)

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

    context 'with invalid workhorse signature' do
      it 'aborts with an exception' do
        allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_raise(JWT::DecodeError)

        expect { get_terminal_websocket(id: job.id) }.to raise_error(JWT::DecodeError)
      end
    end

    def get_terminal_websocket(**extra_params)
      params = {
        namespace_id: project.namespace.to_param,
        project_id: project
      }

      get :terminal_websocket_authorize, params.merge(extra_params)
    end
  end
S
Shinya Maeda 已提交
1002
end