BigW Consortium Gitlab

builds_spec.rb 14.3 KB
Newer Older
1 2
require 'spec_helper'

3
describe API::V3::Builds do
4
  let(:user) { create(:user) }
Kamil Trzcinski committed
5
  let(:api_user) { user }
6
  let!(:project) { create(:project, :repository, creator: user, public_builds: false) }
7
  let!(:developer) { create(:project_member, :developer, user: user, project: project) }
8 9
  let(:reporter) { create(:project_member, :reporter, project: project) }
  let(:guest) { create(:project_member, :guest, project: project) }
10
  let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
11
  let!(:build) { create(:ci_build, pipeline: pipeline) }
12 13

  describe 'GET /projects/:id/builds ' do
Kamil Trzcinski committed
14 15
    let(:query) { '' }

Lin Jen-Shin committed
16
    before do
17 18
      create(:ci_build, :skipped, pipeline: pipeline)

19
      get v3_api("/projects/#{project.id}/builds?#{query}", api_user)
Lin Jen-Shin committed
20
    end
Kamil Trzcinski committed
21

22
    context 'authorized user' do
23
      it 'returns project builds' do
24
        expect(response).to have_http_status(200)
25
        expect(response).to include_pagination_headers
26 27 28
        expect(json_response).to be_an Array
      end

29 30 31 32 33
      it 'returns correct values' do
        expect(json_response).not_to be_empty
        expect(json_response.first['commit']['id']).to eq project.commit.id
      end

34 35 36 37 38 39 40 41 42
      it 'returns pipeline data' do
        json_build = json_response.first
        expect(json_build['pipeline']).not_to be_empty
        expect(json_build['pipeline']['id']).to eq build.pipeline.id
        expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
        expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
        expect(json_build['pipeline']['status']).to eq build.pipeline.status
      end

Kamil Trzcinski committed
43 44
      context 'filter project with one scope element' do
        let(:query) { 'scope=pending' }
45

Kamil Trzcinski committed
46
        it do
47
          expect(response).to have_http_status(200)
Kamil Trzcinski committed
48 49
          expect(json_response).to be_an Array
        end
50 51
      end

52 53 54 55 56 57 58 59 60 61 62 63
      context 'filter project with scope skipped' do
        let(:query) { 'scope=skipped' }
        let(:json_build) { json_response.first }

        it 'return builds with status skipped' do
          expect(response).to have_http_status 200
          expect(json_response).to be_an Array
          expect(json_response.length).to eq 1
          expect(json_build['status']).to eq 'skipped'
        end
      end

Kamil Trzcinski committed
64 65
      context 'filter project with array of scope elements' do
        let(:query) { 'scope[0]=pending&scope[1]=running' }
66

Kamil Trzcinski committed
67
        it do
68
          expect(response).to have_http_status(200)
Kamil Trzcinski committed
69 70
          expect(json_response).to be_an Array
        end
71
      end
72

Kamil Trzcinski committed
73 74
      context 'respond 400 when scope contains invalid state' do
        let(:query) { 'scope[0]=pending&scope[1]=unknown_status' }
75

76
        it { expect(response).to have_http_status(400) }
77
      end
78 79 80
    end

    context 'unauthorized user' do
Kamil Trzcinski committed
81
      let(:api_user) { nil }
82

83
      it 'does not return project builds' do
84
        expect(response).to have_http_status(401)
85 86 87 88
      end
    end
  end

89
  describe 'GET /projects/:id/repository/commits/:sha/builds' do
90 91
    context 'when commit does not exist in repository' do
      before do
92
        get v3_api("/projects/#{project.id}/repository/commits/1a271fd1/builds", api_user)
93
      end
94

95 96 97
      it 'responds with 404' do
        expect(response).to have_http_status(404)
      end
Kamil Trzcinski committed
98 99
    end

100 101
    context 'when commit exists in repository' do
      context 'when user is authorized' do
Filipa Lacerda committed
102
        context 'when pipeline has jobs' do
103
          before do
104
            create(:ci_pipeline, project: project, sha: project.commit.id)
105
            create(:ci_build, pipeline: pipeline)
106
            create(:ci_build)
107

108
            get v3_api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", api_user)
109 110
          end

Filipa Lacerda committed
111
          it 'returns project jobs for specific commit' do
112
            expect(response).to have_http_status(200)
113
            expect(response).to include_pagination_headers
114 115 116
            expect(json_response).to be_an Array
            expect(json_response.size).to eq 2
          end
117 118 119 120 121 122 123 124 125

          it 'returns pipeline data' do
            json_build = json_response.first
            expect(json_build['pipeline']).not_to be_empty
            expect(json_build['pipeline']['id']).to eq build.pipeline.id
            expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
            expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
            expect(json_build['pipeline']['status']).to eq build.pipeline.status
          end
126 127
        end

Filipa Lacerda committed
128
        context 'when pipeline has no jobs' do
129 130
          before do
            branch_head = project.commit('feature').id
131
            get v3_api("/projects/#{project.id}/repository/commits/#{branch_head}/builds", api_user)
132 133 134 135 136 137 138 139
          end

          it 'returns an empty array' do
            expect(response).to have_http_status(200)
            expect(json_response).to be_an Array
            expect(json_response).to be_empty
          end
        end
140 141
      end

142 143
      context 'when user is not authorized' do
        before do
144 145
          create(:ci_pipeline, project: project, sha: project.commit.id)
          create(:ci_build, pipeline: pipeline)
146

147
          get v3_api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", nil)
148 149
        end

Filipa Lacerda committed
150
        it 'does not return project jobs' do
151 152 153
          expect(response).to have_http_status(401)
          expect(json_response.except('message')).to be_empty
        end
154 155 156
      end
    end
  end
157

158
  describe 'GET /projects/:id/builds/:build_id' do
Lin Jen-Shin committed
159
    before do
160
      get v3_api("/projects/#{project.id}/builds/#{build.id}", api_user)
Lin Jen-Shin committed
161
    end
Kamil Trzcinski committed
162

163
    context 'authorized user' do
Filipa Lacerda committed
164
      it 'returns specific job data' do
165
        expect(response).to have_http_status(200)
166 167
        expect(json_response['name']).to eq('test')
      end
168 169 170 171 172 173 174 175 176

      it 'returns pipeline data' do
        json_build = json_response
        expect(json_build['pipeline']).not_to be_empty
        expect(json_build['pipeline']['id']).to eq build.pipeline.id
        expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
        expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
        expect(json_build['pipeline']['status']).to eq build.pipeline.status
      end
177 178 179
    end

    context 'unauthorized user' do
Kamil Trzcinski committed
180
      let(:api_user) { nil }
181

Filipa Lacerda committed
182
      it 'does not return specific job data' do
183
        expect(response).to have_http_status(401)
184 185 186 187
      end
    end
  end

188
  describe 'GET /projects/:id/builds/:build_id/artifacts' do
Lin Jen-Shin committed
189
    before do
190
      get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
Lin Jen-Shin committed
191
    end
192

Filipa Lacerda committed
193
    context 'job with artifacts' do
194
      let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
195

Kamil Trzcinski committed
196 197
      context 'authorized user' do
        let(:download_headers) do
198 199
          { 'Content-Transfer-Encoding' => 'binary',
            'Content-Disposition' => 'attachment; filename=ci_build_artifacts.zip' }
Kamil Trzcinski committed
200
        end
201

Filipa Lacerda committed
202
        it 'returns specific job artifacts' do
203
          expect(response).to have_http_status(200)
Kamil Trzcinski committed
204
          expect(response.headers).to include(download_headers)
205
          expect(response.body).to match_file(build.artifacts_file.file.file)
Kamil Trzcinski committed
206
        end
207 208
      end

Kamil Trzcinski committed
209 210
      context 'unauthorized user' do
        let(:api_user) { nil }
211

Filipa Lacerda committed
212
        it 'does not return specific job artifacts' do
213
          expect(response).to have_http_status(401)
Kamil Trzcinski committed
214
        end
215 216
      end
    end
Kamil Trzcinski committed
217

Filipa Lacerda committed
218
    it 'does not return job artifacts if not uploaded' do
219
      expect(response).to have_http_status(404)
Kamil Trzcinski committed
220
    end
221 222
  end

223
  describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
224
    let(:api_user) { reporter.user }
225 226 227 228 229
    let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }

    before do
      build.success
    end
230

231
    def path_for_ref(ref = pipeline.ref, job = build.name)
232
      v3_api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
233 234
    end

235
    context 'when not logged in' do
236
      let(:api_user) { nil }
237 238

      before do
239
        get path_for_ref
240 241
      end

242
      it 'gives 401' do
243 244 245 246
        expect(response).to have_http_status(401)
      end
    end

247
    context 'when logging as guest' do
248
      let(:api_user) { guest.user }
249 250 251 252 253 254 255 256 257 258

      before do
        get path_for_ref
      end

      it 'gives 403' do
        expect(response).to have_http_status(403)
      end
    end

Filipa Lacerda committed
259
    context 'non-existing job' do
260 261
      shared_examples 'not found' do
        it { expect(response).to have_http_status(:not_found) }
262 263
      end

264 265
      context 'has no such ref' do
        before do
266
          get path_for_ref('TAIL', build.name)
267 268
        end

269
        it_behaves_like 'not found'
270 271
      end

Filipa Lacerda committed
272
      context 'has no such job' do
273
        before do
274
          get path_for_ref(pipeline.ref, 'NOBUILD')
275 276
        end

277
        it_behaves_like 'not found'
278
      end
279 280
    end

Filipa Lacerda committed
281
    context 'find proper job' do
282
      shared_examples 'a valid file' do
283
        let(:download_headers) do
284 285 286
          { 'Content-Transfer-Encoding' => 'binary',
            'Content-Disposition' =>
              "attachment; filename=#{build.artifacts_file.filename}" }
287
        end
288

289 290
        it { expect(response).to have_http_status(200) }
        it { expect(response.headers).to include(download_headers) }
291 292 293 294
      end

      context 'with regular branch' do
        before do
295
          pipeline.reload
296 297 298
          pipeline.update(ref: 'master',
                          sha: project.commit('master').sha)

299
          get path_for_ref('master')
300 301
        end

302
        it_behaves_like 'a valid file'
303 304
      end

305 306
      context 'with branch name containing slash' do
        before do
307
          pipeline.reload
308 309 310 311 312
          pipeline.update(ref: 'improve/awesome',
                          sha: project.commit('improve/awesome').sha)
        end

        before do
313
          get path_for_ref('improve/awesome')
314 315
        end

316
        it_behaves_like 'a valid file'
317
      end
318 319 320
    end
  end

321
  describe 'GET /projects/:id/builds/:build_id/trace' do
322
    let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
323

Lin Jen-Shin committed
324
    before do
325
      get v3_api("/projects/#{project.id}/builds/#{build.id}/trace", api_user)
Lin Jen-Shin committed
326
    end
Kamil Trzcinski committed
327

328
    context 'authorized user' do
Filipa Lacerda committed
329
      it 'returns specific job trace' do
330
        expect(response).to have_http_status(200)
331
        expect(response.body).to eq(build.trace.raw)
332 333 334 335
      end
    end

    context 'unauthorized user' do
Kamil Trzcinski committed
336
      let(:api_user) { nil }
337

Filipa Lacerda committed
338
      it 'does not return specific job trace' do
339
        expect(response).to have_http_status(401)
340 341 342
      end
    end
  end
343

344
  describe 'POST /projects/:id/builds/:build_id/cancel' do
Lin Jen-Shin committed
345
    before do
346
      post v3_api("/projects/#{project.id}/builds/#{build.id}/cancel", api_user)
Lin Jen-Shin committed
347
    end
Kamil Trzcinski committed
348

349
    context 'authorized user' do
350
      context 'user with :update_build persmission' do
Filipa Lacerda committed
351
        it 'cancels running or pending job' do
352
          expect(response).to have_http_status(201)
353 354 355 356
          expect(project.builds.first.status).to eq('canceled')
        end
      end

357
      context 'user without :update_build permission' do
358
        let(:api_user) { reporter.user }
359

Filipa Lacerda committed
360
        it 'does not cancel job' do
361
          expect(response).to have_http_status(403)
362 363 364 365 366
        end
      end
    end

    context 'unauthorized user' do
Kamil Trzcinski committed
367
      let(:api_user) { nil }
368

Filipa Lacerda committed
369
      it 'does not cancel job' do
370
        expect(response).to have_http_status(401)
371 372 373 374
      end
    end
  end

375
  describe 'POST /projects/:id/builds/:build_id/retry' do
376
    let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
Kamil Trzcinski committed
377

Lin Jen-Shin committed
378
    before do
379
      post v3_api("/projects/#{project.id}/builds/#{build.id}/retry", api_user)
Lin Jen-Shin committed
380
    end
Kamil Trzcinski committed
381

382
    context 'authorized user' do
Kamil Trzcinski committed
383
      context 'user with :update_build permission' do
Filipa Lacerda committed
384
        it 'retries non-running job' do
385
          expect(response).to have_http_status(201)
386 387 388 389 390
          expect(project.builds.first.status).to eq('canceled')
          expect(json_response['status']).to eq('pending')
        end
      end

391
      context 'user without :update_build permission' do
392
        let(:api_user) { reporter.user }
393

Filipa Lacerda committed
394
        it 'does not retry job' do
395
          expect(response).to have_http_status(403)
396 397 398 399 400
        end
      end
    end

    context 'unauthorized user' do
Kamil Trzcinski committed
401
      let(:api_user) { nil }
402

Filipa Lacerda committed
403
      it 'does not retry job' do
404
        expect(response).to have_http_status(401)
405 406 407
      end
    end
  end
408

409
  describe 'POST /projects/:id/builds/:build_id/erase' do
410
    before do
411
      post v3_api("/projects/#{project.id}/builds/#{build.id}/erase", user)
412 413
    end

Filipa Lacerda committed
414
    context 'job is erasable' do
415
      let(:build) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) }
416

Filipa Lacerda committed
417
      it 'erases job content' do
418
        expect(response.status).to eq 201
419
        expect(build).not_to have_trace
420 421 422
        expect(build.artifacts_file.exists?).to be_falsy
        expect(build.artifacts_metadata.exists?).to be_falsy
      end
423

Filipa Lacerda committed
424
      it 'updates job' do
425 426 427
        expect(build.reload.erased_at).to be_truthy
        expect(build.reload.erased_by).to eq user
      end
428 429
    end

Filipa Lacerda committed
430
    context 'job is not erasable' do
431
      let(:build) { create(:ci_build, :trace, project: project, pipeline: pipeline) }
432

433
      it 'responds with forbidden' do
434 435 436 437
        expect(response.status).to eq 403
      end
    end
  end
438 439 440

  describe 'POST /projects/:id/builds/:build_id/artifacts/keep' do
    before do
441
      post v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts/keep", user)
442 443 444 445 446 447 448 449
    end

    context 'artifacts did not expire' do
      let(:build) do
        create(:ci_build, :trace, :artifacts, :success,
               project: project, pipeline: pipeline, artifacts_expire_at: Time.now + 7.days)
      end

450
      it 'keeps artifacts' do
451
        expect(response.status).to eq 200
452
        expect(build.reload.artifacts_expire_at).to be_nil
453 454 455 456 457 458
      end
    end

    context 'no artifacts' do
      let(:build) { create(:ci_build, project: project, pipeline: pipeline) }

459
      it 'responds with not found' do
460 461 462 463
        expect(response.status).to eq 404
      end
    end
  end
464 465 466

  describe 'POST /projects/:id/builds/:build_id/play' do
    before do
467
      post v3_api("/projects/#{project.id}/builds/#{build.id}/play", user)
468 469
    end

Filipa Lacerda committed
470
    context 'on an playable job' do
471 472
      let(:build) { create(:ci_build, :manual, project: project, pipeline: pipeline) }

Filipa Lacerda committed
473
      it 'plays the job' do
474 475
        expect(response).to have_http_status 200
        expect(json_response['user']['id']).to eq(user.id)
Z.J. van de Weg committed
476
        expect(json_response['id']).to eq(build.id)
477 478 479
      end
    end

Filipa Lacerda committed
480
    context 'on a non-playable job' do
481 482
      it 'returns a status code 400, Bad Request' do
        expect(response).to have_http_status 400
Filipa Lacerda committed
483
        expect(response.body).to match("Unplayable Job")
484 485 486
      end
    end
  end
487
end