BigW Consortium Gitlab

pipelines_spec.rb 15.3 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 14 15
  before do
    project.team << [user, :master]
  end
16 17 18 19 20 21 22

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

        expect(response).to have_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
        expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status])
28
      end
29 30

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

            it 'returns matched pipelines' do
38
              get api("/projects/#{project.id}/pipelines", user), scope: target
39

40
              expect(response).to have_http_status(:ok)
41
              expect(response).to include_pagination_headers
42
              expect(json_response).not_to be_empty
43
              json_response.each { |r| expect(r['status']).to eq(target) }
44 45
            end
          end
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
        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
            get api("/projects/#{project.id}/pipelines", user), scope: 'finished'

            expect(response).to have_http_status(:ok)
            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 committed
68

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

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

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

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

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

96
            expect(response).to have_http_status(:bad_request)
Shinya Maeda committed
97
          end
98 99
        end

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

108 109 110 111 112 113 114
            it 'returns matched pipelines' do
              get api("/projects/#{project.id}/pipelines", user), status: target

              expect(response).to have_http_status(:ok)
              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 committed
115 116
            end
          end
117
        end
Shinya Maeda committed
118

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

123
            expect(response).to have_http_status(:bad_request)
Shinya Maeda committed
124 125 126
          end
        end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

202 203 204 205
        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) }

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

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

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

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

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

230
              expect(response).to have_http_status(:bad_request)
Shinya Maeda committed
231 232 233 234
            end
          end
        end

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

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

247 248 249
                expect(response).to have_http_status(:ok)
                expect(response).to include_pagination_headers
                expect(json_response).not_to be_empty
250

251 252 253
                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 committed
254 255
            end

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

260 261
                expect(response).to have_http_status(:bad_request)
              end
Shinya Maeda committed
262 263 264
            end
          end

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

269
              expect(response).to have_http_status(:bad_request)
270 271 272 273
            end
          end
        end
      end
274 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)

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

  describe 'POST /projects/:id/pipeline ' do
    context 'authorized user' do
      context 'with gitlab-ci.yml' do
290 291 292
        before do
          stub_ci_pipeline_to_return_yaml_file
        end
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

        it 'creates and returns a new pipeline' do
          expect do
            post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
          end.to change { Ci::Pipeline.count }.by(1)

          expect(response).to have_http_status(201)
          expect(json_response).to be_a Hash
          expect(json_response['sha']).to eq project.commit.id
        end

        it 'fails when using an invalid ref' do
          post api("/projects/#{project.id}/pipeline", user), ref: 'invalid_ref'

          expect(response).to have_http_status(400)
          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
        it 'fails to create pipeline' do
          post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch

          expect(response).to have_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
      end
    end

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

        expect(response).to have_http_status(404)
        expect(json_response['message']).to eq '404 Project Not Found'
330
        expect(json_response).not_to be_an Array
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
      end
    end
  end

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

        expect(response).to have_http_status(200)
        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)

        expect(response).to have_http_status(404)
348 349
        expect(json_response['message']).to eq '404 Not found'
        expect(json_response['id']).to be nil
350
      end
351 352 353 354 355 356 357 358 359 360 361 362

      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
363 364 365 366 367 368 369
    end

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

        expect(response).to have_http_status(404)
370 371
        expect(json_response['message']).to eq '404 Project Not Found'
        expect(json_response['id']).to be nil
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
      end
    end
  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)

        expect(response).to have_http_status(201)
391
        expect(build.reload.retried?).to be true
392 393 394 395 396 397 398 399
      end
    end

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

        expect(response).to have_http_status(404)
400 401
        expect(json_response['message']).to eq '404 Project Not Found'
        expect(json_response['id']).to be nil
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
      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)

        expect(response).to have_http_status(200)
        expect(json_response['status']).to eq('canceled')
      end
    end

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

426 427 428
      before do
        project.team << [reporter, :reporter]
      end
429 430 431 432 433

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

        expect(response).to have_http_status(403)
434
        expect(pipeline.reload.status).to eq('pending')
435 436 437 438
      end
    end
  end
end