pipelines_spec.rb 22.7 KB
Newer Older
1 2
require 'spec_helper'

3
describe API::Pipelines do
4 5
  let(:user)        { create(:user) }
  let(:non_member)  { create(:user) }
6
  let(:project)     { create(:project, :repository, creator: user) }
7 8 9

  let!(:pipeline) do
    create(:ci_empty_pipeline, project: project, sha: project.commit.id,
10
                               ref: project.default_branch, user: user)
11 12
  end

13
  before do
14
    project.add_maintainer(user)
15
  end
16 17 18 19 20 21

  describe 'GET /projects/:id/pipelines ' do
    context 'authorized user' do
      it 'returns project pipelines' do
        get api("/projects/#{project.id}/pipelines", user)

22
        expect(response).to have_gitlab_http_status(200)
23
        expect(response).to include_pagination_headers
24 25
        expect(json_response).to be_an Array
        expect(json_response.first['sha']).to match /\A\h{40}\z/
26
        expect(json_response.first['id']).to eq pipeline.id
27 28
        expect(json_response.first['web_url']).to be_present
        expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status web_url])
29
      end
30 31

      context 'when parameter is passed' do
32 33 34 35
        %w[running pending].each do |target|
          context "when scope is #{target}" do
            before do
              create(:ci_pipeline, project: project, status: target)
Shinya Maeda's avatar
Shinya Maeda committed
36 37 38
            end

            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
39
              get api("/projects/#{project.id}/pipelines", user), params: { scope: target }
40

41
              expect(response).to have_gitlab_http_status(:ok)
42
              expect(response).to include_pagination_headers
43
              expect(json_response).not_to be_empty
44
              json_response.each { |r| expect(r['status']).to eq(target) }
45 46
            end
          end
47 48 49 50 51 52 53 54 55 56
        end

        context 'when scope is finished' do
          before do
            create(:ci_pipeline, project: project, status: 'success')
            create(:ci_pipeline, project: project, status: 'failed')
            create(:ci_pipeline, project: project, status: 'canceled')
          end

          it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
57
            get api("/projects/#{project.id}/pipelines", user), params: { scope: 'finished' }
58

59
            expect(response).to have_gitlab_http_status(:ok)
60 61 62 63 64 65 66 67 68
            expect(response).to include_pagination_headers
            expect(json_response).not_to be_empty
            json_response.each { |r| expect(r['status']).to be_in(%w[success failed canceled]) }
          end
        end

        context 'when scope is branches or tags' do
          let!(:pipeline_branch) { create(:ci_pipeline, project: project) }
          let!(:pipeline_tag) { create(:ci_pipeline, project: project, ref: 'v1.0.0', tag: true) }
Shinya Maeda's avatar
Shinya Maeda committed
69

Shinya Maeda's avatar
Shinya Maeda committed
70 71
          context 'when scope is branches' do
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
72
              get api("/projects/#{project.id}/pipelines", user), params: { scope: 'branches' }
Shinya Maeda's avatar
Shinya Maeda committed
73

74
              expect(response).to have_gitlab_http_status(:ok)
Shinya Maeda's avatar
Shinya Maeda committed
75
              expect(response).to include_pagination_headers
76
              expect(json_response).not_to be_empty
77
              expect(json_response.last['id']).to eq(pipeline_branch.id)
Shinya Maeda's avatar
Shinya Maeda committed
78
            end
Shinya Maeda's avatar
Shinya Maeda committed
79 80
          end

Shinya Maeda's avatar
Shinya Maeda committed
81 82
          context 'when scope is tags' do
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
83
              get api("/projects/#{project.id}/pipelines", user), params: { scope: 'tags' }
Shinya Maeda's avatar
Shinya Maeda committed
84

85
              expect(response).to have_gitlab_http_status(:ok)
Shinya Maeda's avatar
Shinya Maeda committed
86
              expect(response).to include_pagination_headers
87
              expect(json_response).not_to be_empty
88
              expect(json_response.last['id']).to eq(pipeline_tag.id)
Shinya Maeda's avatar
Shinya Maeda committed
89
            end
Shinya Maeda's avatar
Shinya Maeda committed
90
          end
91
        end
Shinya Maeda's avatar
Shinya Maeda committed
92

93
        context 'when scope is invalid' do
94
          it 'returns bad_request' do
blackst0ne's avatar
blackst0ne committed
95
            get api("/projects/#{project.id}/pipelines", user), params: { scope: 'invalid-scope' }
Shinya Maeda's avatar
Shinya Maeda committed
96

97
            expect(response).to have_gitlab_http_status(:bad_request)
Shinya Maeda's avatar
Shinya Maeda committed
98
          end
99 100
        end

101
        HasStatus::AVAILABLE_STATUSES.each do |target|
102 103 104
          context "when status is #{target}" do
            before do
              create(:ci_pipeline, project: project, status: target)
105
              exception_status = HasStatus::AVAILABLE_STATUSES - [target]
106 107
              create(:ci_pipeline, project: project, status: exception_status.sample)
            end
Shinya Maeda's avatar
Shinya Maeda committed
108

109
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
110
              get api("/projects/#{project.id}/pipelines", user), params: { status: target }
111

112
              expect(response).to have_gitlab_http_status(:ok)
113 114 115
              expect(response).to include_pagination_headers
              expect(json_response).not_to be_empty
              json_response.each { |r| expect(r['status']).to eq(target) }
Shinya Maeda's avatar
Shinya Maeda committed
116 117
            end
          end
118
        end
Shinya Maeda's avatar
Shinya Maeda committed
119

120
        context 'when status is invalid' do
121
          it 'returns bad_request' do
blackst0ne's avatar
blackst0ne committed
122
            get api("/projects/#{project.id}/pipelines", user), params: { status: 'invalid-status' }
Shinya Maeda's avatar
Shinya Maeda committed
123

124
            expect(response).to have_gitlab_http_status(:bad_request)
Shinya Maeda's avatar
Shinya Maeda committed
125 126 127
          end
        end

128 129 130 131 132
        context 'when ref is specified' do
          before do
            create(:ci_pipeline, project: project)
          end

Shinya Maeda's avatar
Shinya Maeda committed
133 134
          context 'when ref exists' do
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
135
              get api("/projects/#{project.id}/pipelines", user), params: { ref: 'master' }
136

137
              expect(response).to have_gitlab_http_status(:ok)
138
              expect(response).to include_pagination_headers
139
              expect(json_response).not_to be_empty
Shinya Maeda's avatar
Shinya Maeda committed
140
              json_response.each { |r| expect(r['ref']).to eq('master') }
141 142 143
            end
          end

Shinya Maeda's avatar
Shinya Maeda committed
144 145
          context 'when ref does not exist' do
            it 'returns empty' do
blackst0ne's avatar
blackst0ne committed
146
              get api("/projects/#{project.id}/pipelines", user), params: { ref: 'invalid-ref' }
147

148
              expect(response).to have_gitlab_http_status(:ok)
149
              expect(response).to include_pagination_headers
150
              expect(json_response).to be_empty
151 152 153 154
            end
          end
        end

155 156 157
        context 'when name is specified' do
          let!(:pipeline) { create(:ci_pipeline, project: project, user: user) }

158
          context 'when name exists' do
Shinya Maeda's avatar
Shinya Maeda committed
159
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
160
              get api("/projects/#{project.id}/pipelines", user), params: { name: user.name }
161

162
              expect(response).to have_gitlab_http_status(:ok)
163
              expect(response).to include_pagination_headers
164
              expect(json_response.first['id']).to eq(pipeline.id)
165 166 167 168
            end
          end

          context 'when name does not exist' do
Shinya Maeda's avatar
Shinya Maeda committed
169
            it 'returns empty' do
blackst0ne's avatar
blackst0ne committed
170
              get api("/projects/#{project.id}/pipelines", user), params: { name: 'invalid-name' }
171

172
              expect(response).to have_gitlab_http_status(:ok)
173
              expect(response).to include_pagination_headers
174
              expect(json_response).to be_empty
175 176 177 178
            end
          end
        end

179 180 181
        context 'when username is specified' do
          let!(:pipeline) { create(:ci_pipeline, project: project, user: user) }

182
          context 'when username exists' do
Shinya Maeda's avatar
Shinya Maeda committed
183
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
184
              get api("/projects/#{project.id}/pipelines", user), params: { username: user.username }
185

186
              expect(response).to have_gitlab_http_status(:ok)
187
              expect(response).to include_pagination_headers
188
              expect(json_response.first['id']).to eq(pipeline.id)
189 190 191 192
            end
          end

          context 'when username does not exist' do
Shinya Maeda's avatar
Shinya Maeda committed
193
            it 'returns empty' do
blackst0ne's avatar
blackst0ne committed
194
              get api("/projects/#{project.id}/pipelines", user), params: { username: 'invalid-username' }
195

196
              expect(response).to have_gitlab_http_status(:ok)
197
              expect(response).to include_pagination_headers
198
              expect(json_response).to be_empty
199 200 201 202
            end
          end
        end

203 204 205 206
        context 'when yaml_errors is specified' do
          let!(:pipeline1) { create(:ci_pipeline, project: project, yaml_errors: 'Syntax error') }
          let!(:pipeline2) { create(:ci_pipeline, project: project) }

207
          context 'when yaml_errors is true' do
Shinya Maeda's avatar
Shinya Maeda committed
208
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
209
              get api("/projects/#{project.id}/pipelines", user), params: { yaml_errors: true }
210

211
              expect(response).to have_gitlab_http_status(:ok)
212
              expect(response).to include_pagination_headers
213
              expect(json_response.first['id']).to eq(pipeline1.id)
214 215 216 217
            end
          end

          context 'when yaml_errors is false' do
Shinya Maeda's avatar
Shinya Maeda committed
218
            it 'returns matched pipelines' do
blackst0ne's avatar
blackst0ne committed
219
              get api("/projects/#{project.id}/pipelines", user), params: { yaml_errors: false }
220

221
              expect(response).to have_gitlab_http_status(:ok)
222
              expect(response).to include_pagination_headers
223
              expect(json_response.first['id']).to eq(pipeline2.id)
224 225 226
            end
          end

Shinya Maeda's avatar
Shinya Maeda committed
227
          context 'when yaml_errors is invalid' do
228
            it 'returns bad_request' do
blackst0ne's avatar
blackst0ne committed
229
              get api("/projects/#{project.id}/pipelines", user), params: { yaml_errors: 'invalid-yaml_errors' }
230

231
              expect(response).to have_gitlab_http_status(:bad_request)
Shinya Maeda's avatar
Shinya Maeda committed
232 233 234 235
            end
          end
        end

236 237
        context 'when order_by and sort are specified' do
          context 'when order_by user_id' do
238 239 240 241 242
            before do
              3.times do
                create(:ci_pipeline, project: project, user: create(:user))
              end
            end
243

244 245
            context 'when sort parameter is valid' do
              it 'sorts as user_id: :desc' do
blackst0ne's avatar
blackst0ne committed
246
                get api("/projects/#{project.id}/pipelines", user), params: { order_by: 'user_id', sort: 'desc' }
Shinya Maeda's avatar
Shinya Maeda committed
247

248
                expect(response).to have_gitlab_http_status(:ok)
249 250
                expect(response).to include_pagination_headers
                expect(json_response).not_to be_empty
251

252 253 254
                pipeline_ids = Ci::Pipeline.all.order(user_id: :desc).pluck(:id)
                expect(json_response.map { |r| r['id'] }).to eq(pipeline_ids)
              end
Shinya Maeda's avatar
Shinya Maeda committed
255 256
            end

257
            context 'when sort parameter is invalid' do
258
              it 'returns bad_request' do
blackst0ne's avatar
blackst0ne committed
259
                get api("/projects/#{project.id}/pipelines", user), params: { order_by: 'user_id', sort: 'invalid_sort' }
Shinya Maeda's avatar
Shinya Maeda committed
260

261
                expect(response).to have_gitlab_http_status(:bad_request)
262
              end
Shinya Maeda's avatar
Shinya Maeda committed
263 264 265
            end
          end

266
          context 'when order_by is invalid' do
267
            it 'returns bad_request' do
blackst0ne's avatar
blackst0ne committed
268
              get api("/projects/#{project.id}/pipelines", user), params: { order_by: 'lock_version', sort: 'asc' }
Shinya Maeda's avatar
Shinya Maeda committed
269

270
              expect(response).to have_gitlab_http_status(:bad_request)
271 272 273 274
            end
          end
        end
      end
275 276 277 278 279 280
    end

    context 'unauthorized user' do
      it 'does not return project pipelines' do
        get api("/projects/#{project.id}/pipelines", non_member)

281
        expect(response).to have_gitlab_http_status(404)
282
        expect(json_response['message']).to eq '404 Project Not Found'
283 284 285 286 287 288
        expect(json_response).not_to be_an Array
      end
    end
  end

  describe 'POST /projects/:id/pipeline ' do
289 290 291 292 293 294 295 296 297
    def expect_variables(variables, expected_variables)
      variables.each_with_index do |variable, index|
        expected_variable = expected_variables[index]

        expect(variable.key).to eq(expected_variable['key'])
        expect(variable.value).to eq(expected_variable['value'])
      end
    end

298 299
    context 'authorized user' do
      context 'with gitlab-ci.yml' do
300 301 302
        before do
          stub_ci_pipeline_to_return_yaml_file
        end
303 304 305

        it 'creates and returns a new pipeline' do
          expect do
blackst0ne's avatar
blackst0ne committed
306
            post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch }
307
          end.to change { project.ci_pipelines.count }.by(1)
308

309
          expect(response).to have_gitlab_http_status(201)
310 311 312 313
          expect(json_response).to be_a Hash
          expect(json_response['sha']).to eq project.commit.id
        end

314
        context 'variables given' do
315
          let(:variables) { [{ 'key' => 'UPLOAD_TO_S3', 'value' => 'true' }] }
316 317 318

          it 'creates and returns a new pipeline using the given variables' do
            expect do
blackst0ne's avatar
blackst0ne committed
319
              post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch, variables: variables }
320 321
            end.to change { project.ci_pipelines.count }.by(1)
            expect_variables(project.ci_pipelines.last.variables, variables)
322 323 324 325

            expect(response).to have_gitlab_http_status(201)
            expect(json_response).to be_a Hash
            expect(json_response['sha']).to eq project.commit.id
326
            expect(json_response).not_to have_key('variables')
327 328 329
          end
        end

Jacopo's avatar
Jacopo committed
330 331 332
        describe 'using variables conditions' do
          let(:variables) { [{ 'key' => 'STAGING', 'value' => 'true' }] }

333
          before do
Jacopo's avatar
Jacopo committed
334
            config = YAML.dump(test: { script: 'test', only: { variables: ['$STAGING'] } })
335 336 337
            stub_ci_pipeline_yaml_file(config)
          end

Jacopo's avatar
Jacopo committed
338
          it 'creates and returns a new pipeline using the given variables' do
339
            expect do
blackst0ne's avatar
blackst0ne committed
340
              post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch, variables: variables }
341 342
            end.to change { project.ci_pipelines.count }.by(1)
            expect_variables(project.ci_pipelines.last.variables, variables)
343

Jacopo's avatar
Jacopo committed
344 345 346
            expect(response).to have_gitlab_http_status(201)
            expect(json_response).to be_a Hash
            expect(json_response['sha']).to eq project.commit.id
347
            expect(json_response).not_to have_key('variables')
Jacopo's avatar
Jacopo committed
348 349 350 351 352 353 354
          end

          context 'condition unmatch' do
            let(:variables) { [{ 'key' => 'STAGING', 'value' => 'false' }] }

            it "doesn't create a job" do
              expect do
blackst0ne's avatar
blackst0ne committed
355
                post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch }
356
              end.not_to change { project.ci_pipelines.count }
Jacopo's avatar
Jacopo committed
357 358 359

              expect(response).to have_gitlab_http_status(400)
            end
360 361 362
          end
        end

363
        it 'fails when using an invalid ref' do
blackst0ne's avatar
blackst0ne committed
364
          post api("/projects/#{project.id}/pipeline", user), params: { ref: 'invalid_ref' }
365

366
          expect(response).to have_gitlab_http_status(400)
367 368 369 370 371 372
          expect(json_response['message']['base'].first).to eq 'Reference not found'
          expect(json_response).not_to be_an Array
        end
      end

      context 'without gitlab-ci.yml' do
373 374 375 376
        context 'without auto devops enabled' do
          before do
            project.update!(auto_devops_attributes: { enabled: false })
          end
377

378
          it 'fails to create pipeline' do
blackst0ne's avatar
blackst0ne committed
379
            post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch }
380 381 382 383 384

            expect(response).to have_gitlab_http_status(400)
            expect(json_response['message']['base'].first).to eq 'Missing .gitlab-ci.yml file'
            expect(json_response).not_to be_an Array
          end
385 386 387 388 389 390
        end
      end
    end

    context 'unauthorized user' do
      it 'does not create pipeline' do
blackst0ne's avatar
blackst0ne committed
391
        post api("/projects/#{project.id}/pipeline", non_member), params: { ref: project.default_branch }
392

393
        expect(response).to have_gitlab_http_status(404)
394
        expect(json_response['message']).to eq '404 Project Not Found'
395
        expect(json_response).not_to be_an Array
396 397 398 399 400 401
      end
    end
  end

  describe 'GET /projects/:id/pipelines/:pipeline_id' do
    context 'authorized user' do
402 403 404 405 406 407 408
      it 'exposes known attributes' do
        get api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('public_api/v4/pipeline/detail')
      end

409 410 411
      it 'returns project pipelines' do
        get api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)

412
        expect(response).to have_gitlab_http_status(200)
413 414 415 416 417 418
        expect(json_response['sha']).to match /\A\h{40}\z/
      end

      it 'returns 404 when it does not exist' do
        get api("/projects/#{project.id}/pipelines/123456", user)

419
        expect(response).to have_gitlab_http_status(404)
420 421
        expect(json_response['message']).to eq '404 Not found'
        expect(json_response['id']).to be nil
422
      end
423 424 425 426 427 428 429 430 431 432 433 434

      context 'with coverage' do
        before do
          create(:ci_build, coverage: 30, pipeline: pipeline)
        end

        it 'exposes the coverage' do
          get api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)

          expect(json_response["coverage"].to_i).to eq(30)
        end
      end
435 436 437
    end

    context 'unauthorized user' do
438
      it 'does not return a project pipeline' do
439 440
        get api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member)

441
        expect(response).to have_gitlab_http_status(404)
442 443
        expect(json_response['message']).to eq '404 Project Not Found'
        expect(json_response['id']).to be nil
444 445
      end
    end
446 447
  end

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 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
  describe 'GET /projects/:id/pipelines/:pipeline_id/variables' do
    subject { get api("/projects/#{project.id}/pipelines/#{pipeline.id}/variables", api_user) }

    let(:api_user) { user }

    context 'user is a mantainer' do
      it 'returns pipeline variables empty' do
        subject

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

      context 'with variables' do
        let!(:variable) { create(:ci_pipeline_variable, pipeline: pipeline, key: 'foo', value: 'bar') }

        it 'returns pipeline variables' do
          subject

          expect(response).to have_gitlab_http_status(200)
          expect(json_response).to contain_exactly({ "key" => "foo", "value" => "bar" })
        end
      end
    end

    context 'user is a developer' do
      let(:pipeline_owner_user) { create(:user) }
      let(:pipeline) { create(:ci_empty_pipeline, project: project, user: pipeline_owner_user) }

      before do
        project.add_developer(api_user)
      end

      context 'pipeline created by the developer user' do
        let(:api_user) { pipeline_owner_user }
        let!(:variable) { create(:ci_pipeline_variable, pipeline: pipeline, key: 'foo', value: 'bar') }

        it 'returns pipeline variables' do
          subject

          expect(response).to have_gitlab_http_status(200)
          expect(json_response).to contain_exactly({ "key" => "foo", "value" => "bar" })
        end
      end

      context 'pipeline created is not created by the developer user' do
        let(:api_user) { create(:user) }

        it 'should not return pipeline variables' do
          subject

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

    context 'user is not a project member' do
      it 'should not return pipeline variables' do
        get api("/projects/#{project.id}/pipelines/#{pipeline.id}/variables", non_member)

        expect(response).to have_gitlab_http_status(404)
        expect(json_response['message']).to eq '404 Project Not Found'
      end
    end
  end

514 515
  describe 'DELETE /projects/:id/pipelines/:pipeline_id' do
    context 'authorized user' do
516 517 518 519
      let(:owner) { project.owner }

      it 'destroys the pipeline' do
        delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner)
520 521 522 523 524 525

        expect(response).to have_gitlab_http_status(204)
        expect { pipeline.reload }.to raise_error(ActiveRecord::RecordNotFound)
      end

      it 'returns 404 when it does not exist' do
526
        delete api("/projects/#{project.id}/pipelines/123456", owner)
527 528 529 530 531

        expect(response).to have_gitlab_http_status(404)
        expect(json_response['message']).to eq '404 Not found'
      end

532 533
      it 'does not log an audit event' do
        expect { delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner) }.not_to change { SecurityEvent.count }
534 535 536 537 538
      end

      context 'when the pipeline has jobs' do
        let!(:build) { create(:ci_build, project: project, pipeline: pipeline) }

539 540
        it 'destroys associated jobs' do
          delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner)
541 542 543 544 545 546 547 548

          expect(response).to have_gitlab_http_status(204)
          expect { build.reload }.to raise_error(ActiveRecord::RecordNotFound)
        end
      end
    end

    context 'unauthorized user' do
549
      context 'when user is not member' do
550
        it 'returns a 404' do
551
          delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member)
552

553 554 555 556 557 558 559 560 561 562 563 564
          expect(response).to have_gitlab_http_status(404)
          expect(json_response['message']).to eq '404 Project Not Found'
        end
      end

      context 'when user is developer' do
        let(:developer) { create(:user) }

        before do
          project.add_developer(developer)
        end

565
        it 'returns a 403' do
566 567 568 569 570
          delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", developer)

          expect(response).to have_gitlab_http_status(403)
          expect(json_response['message']).to eq '403 Forbidden'
        end
571 572
      end
    end
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
  end

  describe 'POST /projects/:id/pipelines/:pipeline_id/retry' do
    context 'authorized user' do
      let!(:pipeline) do
        create(:ci_pipeline, project: project, sha: project.commit.id,
                             ref: project.default_branch)
      end

      let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }

      it 'retries failed builds' do
        expect do
          post api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", user)
        end.to change { pipeline.builds.count }.from(1).to(2)

589
        expect(response).to have_gitlab_http_status(201)
590
        expect(build.reload.retried?).to be true
591 592 593 594
      end
    end

    context 'unauthorized user' do
595
      it 'does not return a project pipeline' do
596 597
        post api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", non_member)

598
        expect(response).to have_gitlab_http_status(404)
599 600
        expect(json_response['message']).to eq '404 Project Not Found'
        expect(json_response['id']).to be nil
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
      end
    end
  end

  describe 'POST /projects/:id/pipelines/:pipeline_id/cancel' do
    let!(:pipeline) do
      create(:ci_empty_pipeline, project: project, sha: project.commit.id,
                                 ref: project.default_branch)
    end

    let!(:build) { create(:ci_build, :running, pipeline: pipeline) }

    context 'authorized user' do
      it 'retries failed builds' do
        post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", user)

617
        expect(response).to have_gitlab_http_status(200)
618 619 620 621 622 623 624
        expect(json_response['status']).to eq('canceled')
      end
    end

    context 'user without proper access rights' do
      let!(:reporter) { create(:user) }

625
      before do
626
        project.add_reporter(reporter)
627
      end
628 629 630 631

      it 'rejects the action' do
        post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter)

632
        expect(response).to have_gitlab_http_status(403)
633
        expect(pipeline.reload.status).to eq('pending')
634 635 636 637
      end
    end
  end
end