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

3
describe API::Builds, api: true do
4 5 6
  include ApiHelpers

  let(:user) { create(:user) }
K
Kamil Trzcinski 已提交
7
  let(:api_user) { user }
8
  let!(:project) { create(:project, :repository, creator: user, public_builds: false) }
K
Kamil Trzcinski 已提交
9
  let!(:developer) { create(:project_member, :developer, user: user, project: project) }
L
Lin Jen-Shin 已提交
10 11
  let(:reporter) { create(:project_member, :reporter, project: project) }
  let(:guest) { create(:project_member, :guest, project: project) }
12
  let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
K
Kamil Trzcinski 已提交
13
  let!(:build) { create(:ci_build, pipeline: pipeline) }
14 15

  describe 'GET /projects/:id/builds ' do
K
Kamil Trzcinski 已提交
16 17
    let(:query) { '' }

L
Lin Jen-Shin 已提交
18 19 20
    before do
      get api("/projects/#{project.id}/builds?#{query}", api_user)
    end
K
Kamil Trzcinski 已提交
21

22
    context 'authorized user' do
23
      it 'returns project builds' do
Z
Z.J. van de Weg 已提交
24
        expect(response).to have_http_status(200)
25 26 27
        expect(json_response).to be_an Array
      end

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

33 34 35 36 37 38 39 40 41
      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

K
Kamil Trzcinski 已提交
42 43
      context 'filter project with one scope element' do
        let(:query) { 'scope=pending' }
44

K
Kamil Trzcinski 已提交
45
        it do
Z
Z.J. van de Weg 已提交
46
          expect(response).to have_http_status(200)
K
Kamil Trzcinski 已提交
47 48
          expect(json_response).to be_an Array
        end
49 50
      end

K
Kamil Trzcinski 已提交
51 52
      context 'filter project with array of scope elements' do
        let(:query) { 'scope[0]=pending&scope[1]=running' }
53

K
Kamil Trzcinski 已提交
54
        it do
Z
Z.J. van de Weg 已提交
55
          expect(response).to have_http_status(200)
K
Kamil Trzcinski 已提交
56 57
          expect(json_response).to be_an Array
        end
58
      end
T
Tomasz Maczukin 已提交
59

K
Kamil Trzcinski 已提交
60 61
      context 'respond 400 when scope contains invalid state' do
        let(:query) { 'scope[0]=pending&scope[1]=unknown_status' }
T
Tomasz Maczukin 已提交
62

Z
Z.J. van de Weg 已提交
63
        it { expect(response).to have_http_status(400) }
T
Tomasz Maczukin 已提交
64
      end
65 66 67
    end

    context 'unauthorized user' do
K
Kamil Trzcinski 已提交
68
      let(:api_user) { nil }
69

K
Kamil Trzcinski 已提交
70
      it 'should not return project builds' do
Z
Z.J. van de Weg 已提交
71
        expect(response).to have_http_status(401)
72 73 74 75
      end
    end
  end

76
  describe 'GET /projects/:id/repository/commits/:sha/builds' do
77 78 79 80
    context 'when commit does not exist in repository' do
      before do
        get api("/projects/#{project.id}/repository/commits/1a271fd1/builds", api_user)
      end
81

82 83 84
      it 'responds with 404' do
        expect(response).to have_http_status(404)
      end
K
Kamil Trzcinski 已提交
85 86
    end

87 88 89 90
    context 'when commit exists in repository' do
      context 'when user is authorized' do
        context 'when pipeline has builds' do
          before do
L
Lin Jen-Shin 已提交
91
            create(:ci_pipeline, project: project, sha: project.commit.id)
92
            create(:ci_build, pipeline: pipeline)
L
Lin Jen-Shin 已提交
93
            create(:ci_build)
94 95 96 97

            get api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", api_user)
          end

98
          it 'returns project builds for specific commit' do
99 100 101 102
            expect(response).to have_http_status(200)
            expect(json_response).to be_an Array
            expect(json_response.size).to eq 2
          end
103 104 105 106 107 108 109 110 111

          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
112 113 114 115 116 117 118 119 120 121 122 123 124 125
        end

        context 'when pipeline has no builds' do
          before do
            branch_head = project.commit('feature').id
            get api("/projects/#{project.id}/repository/commits/#{branch_head}/builds", api_user)
          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
126 127
      end

128 129
      context 'when user is not authorized' do
        before do
L
Lin Jen-Shin 已提交
130 131
          create(:ci_pipeline, project: project, sha: project.commit.id)
          create(:ci_build, pipeline: pipeline)
132

133 134 135
          get api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", nil)
        end

136
        it 'does not return project builds' do
137 138 139
          expect(response).to have_http_status(401)
          expect(json_response.except('message')).to be_empty
        end
140 141 142
      end
    end
  end
143

144
  describe 'GET /projects/:id/builds/:build_id' do
L
Lin Jen-Shin 已提交
145 146 147
    before do
      get api("/projects/#{project.id}/builds/#{build.id}", api_user)
    end
K
Kamil Trzcinski 已提交
148

149
    context 'authorized user' do
150
      it 'returns specific build data' do
Z
Z.J. van de Weg 已提交
151
        expect(response).to have_http_status(200)
152 153
        expect(json_response['name']).to eq('test')
      end
154 155 156 157 158 159 160 161 162

      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
163 164 165
    end

    context 'unauthorized user' do
K
Kamil Trzcinski 已提交
166
      let(:api_user) { nil }
167

168
      it 'does not return specific build data' do
Z
Z.J. van de Weg 已提交
169
        expect(response).to have_http_status(401)
170 171 172 173
      end
    end
  end

174
  describe 'GET /projects/:id/builds/:build_id/artifacts' do
L
Lin Jen-Shin 已提交
175 176 177
    before do
      get api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
    end
178

K
Kamil Trzcinski 已提交
179
    context 'build with artifacts' do
180
      let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
181

K
Kamil Trzcinski 已提交
182 183
      context 'authorized user' do
        let(:download_headers) do
184 185
          { 'Content-Transfer-Encoding' => 'binary',
            'Content-Disposition' => 'attachment; filename=ci_build_artifacts.zip' }
K
Kamil Trzcinski 已提交
186
        end
187

188
        it 'returns specific build artifacts' do
Z
Z.J. van de Weg 已提交
189
          expect(response).to have_http_status(200)
K
Kamil Trzcinski 已提交
190 191
          expect(response.headers).to include(download_headers)
        end
192 193
      end

K
Kamil Trzcinski 已提交
194 195
      context 'unauthorized user' do
        let(:api_user) { nil }
196

197
        it 'does not return specific build artifacts' do
Z
Z.J. van de Weg 已提交
198
          expect(response).to have_http_status(401)
K
Kamil Trzcinski 已提交
199
        end
200 201
      end
    end
K
Kamil Trzcinski 已提交
202

203
    it 'does not return build artifacts if not uploaded' do
Z
Z.J. van de Weg 已提交
204
      expect(response).to have_http_status(404)
K
Kamil Trzcinski 已提交
205
    end
206 207
  end

208
  describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
L
Lin Jen-Shin 已提交
209
    let(:api_user) { reporter.user }
210 211 212 213 214
    let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }

    before do
      build.success
    end
L
Lin Jen-Shin 已提交
215

216
    def path_for_ref(ref = pipeline.ref, job = build.name)
K
Kamil Trzcinski 已提交
217
      api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
L
Lin Jen-Shin 已提交
218 219
    end

220
    context 'when not logged in' do
K
Kamil Trzcinski 已提交
221
      let(:api_user) { nil }
L
Lin Jen-Shin 已提交
222 223

      before do
224
        get path_for_ref
L
Lin Jen-Shin 已提交
225 226
      end

227
      it 'gives 401' do
L
Lin Jen-Shin 已提交
228 229 230 231
        expect(response).to have_http_status(401)
      end
    end

232
    context 'when logging as guest' do
L
Lin Jen-Shin 已提交
233
      let(:api_user) { guest.user }
234 235 236 237 238 239 240 241 242 243

      before do
        get path_for_ref
      end

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

244
    context 'non-existing build' do
L
Lin Jen-Shin 已提交
245 246
      shared_examples 'not found' do
        it { expect(response).to have_http_status(:not_found) }
L
Lin Jen-Shin 已提交
247 248
      end

249 250
      context 'has no such ref' do
        before do
251
          get path_for_ref('TAIL', build.name)
252 253
        end

L
Lin Jen-Shin 已提交
254
        it_behaves_like 'not found'
255 256 257 258
      end

      context 'has no such build' do
        before do
259
          get path_for_ref(pipeline.ref, 'NOBUILD')
260 261
        end

L
Lin Jen-Shin 已提交
262
        it_behaves_like 'not found'
263
      end
L
Lin Jen-Shin 已提交
264 265
    end

266
    context 'find proper build' do
267
      shared_examples 'a valid file' do
L
Lin Jen-Shin 已提交
268
        let(:download_headers) do
L
Lin Jen-Shin 已提交
269 270 271
          { 'Content-Transfer-Encoding' => 'binary',
            'Content-Disposition' =>
              "attachment; filename=#{build.artifacts_file.filename}" }
L
Lin Jen-Shin 已提交
272
        end
L
Lin Jen-Shin 已提交
273

274 275
        it { expect(response).to have_http_status(200) }
        it { expect(response.headers).to include(download_headers) }
276 277 278 279
      end

      context 'with regular branch' do
        before do
K
Kamil Trzcinski 已提交
280
          pipeline.reload
281 282 283
          pipeline.update(ref: 'master',
                          sha: project.commit('master').sha)

284
          get path_for_ref('master')
285 286
        end

287
        it_behaves_like 'a valid file'
L
Lin Jen-Shin 已提交
288 289
      end

290 291
      context 'with branch name containing slash' do
        before do
K
Kamil Trzcinski 已提交
292
          pipeline.reload
293 294 295 296 297
          pipeline.update(ref: 'improve/awesome',
                          sha: project.commit('improve/awesome').sha)
        end

        before do
298
          get path_for_ref('improve/awesome')
299 300
        end

301
        it_behaves_like 'a valid file'
302
      end
L
Lin Jen-Shin 已提交
303 304 305
    end
  end

306
  describe 'GET /projects/:id/builds/:build_id/trace' do
307
    let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
308

L
Lin Jen-Shin 已提交
309 310 311
    before do
      get api("/projects/#{project.id}/builds/#{build.id}/trace", api_user)
    end
K
Kamil Trzcinski 已提交
312

313
    context 'authorized user' do
314
      it 'returns specific build trace' do
Z
Z.J. van de Weg 已提交
315
        expect(response).to have_http_status(200)
K
Kamil Trzcinski 已提交
316
        expect(response.body).to eq(build.trace)
317 318 319 320
      end
    end

    context 'unauthorized user' do
K
Kamil Trzcinski 已提交
321
      let(:api_user) { nil }
322

323
      it 'does not return specific build trace' do
Z
Z.J. van de Weg 已提交
324
        expect(response).to have_http_status(401)
325 326 327
      end
    end
  end
328

329
  describe 'POST /projects/:id/builds/:build_id/cancel' do
L
Lin Jen-Shin 已提交
330 331 332
    before do
      post api("/projects/#{project.id}/builds/#{build.id}/cancel", api_user)
    end
K
Kamil Trzcinski 已提交
333

334
    context 'authorized user' do
335
      context 'user with :update_build persmission' do
336
        it 'cancels running or pending build' do
Z
Z.J. van de Weg 已提交
337
          expect(response).to have_http_status(201)
338 339 340 341
          expect(project.builds.first.status).to eq('canceled')
        end
      end

342
      context 'user without :update_build permission' do
L
Lin Jen-Shin 已提交
343
        let(:api_user) { reporter.user }
344

345
        it 'does not cancel build' do
Z
Z.J. van de Weg 已提交
346
          expect(response).to have_http_status(403)
347 348 349 350 351
        end
      end
    end

    context 'unauthorized user' do
K
Kamil Trzcinski 已提交
352
      let(:api_user) { nil }
353

354
      it 'does not cancel build' do
Z
Z.J. van de Weg 已提交
355
        expect(response).to have_http_status(401)
356 357 358 359
      end
    end
  end

360
  describe 'POST /projects/:id/builds/:build_id/retry' do
361
    let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
K
Kamil Trzcinski 已提交
362

L
Lin Jen-Shin 已提交
363 364 365
    before do
      post api("/projects/#{project.id}/builds/#{build.id}/retry", api_user)
    end
K
Kamil Trzcinski 已提交
366

367
    context 'authorized user' do
K
Kamil Trzcinski 已提交
368
      context 'user with :update_build permission' do
369
        it 'retries non-running build' do
Z
Z.J. van de Weg 已提交
370
          expect(response).to have_http_status(201)
371 372 373 374 375
          expect(project.builds.first.status).to eq('canceled')
          expect(json_response['status']).to eq('pending')
        end
      end

376
      context 'user without :update_build permission' do
L
Lin Jen-Shin 已提交
377
        let(:api_user) { reporter.user }
378

379
        it 'does not retry build' do
Z
Z.J. van de Weg 已提交
380
          expect(response).to have_http_status(403)
381 382 383 384 385
        end
      end
    end

    context 'unauthorized user' do
K
Kamil Trzcinski 已提交
386
      let(:api_user) { nil }
387

388
      it 'does not retry build' do
Z
Z.J. van de Weg 已提交
389
        expect(response).to have_http_status(401)
390 391 392
      end
    end
  end
393

394
  describe 'POST /projects/:id/builds/:build_id/erase' do
395
    before do
396
      post api("/projects/#{project.id}/builds/#{build.id}/erase", user)
397 398
    end

399
    context 'build is erasable' do
400
      let(:build) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) }
401

402
      it 'erases build content' do
403
        expect(response.status).to eq 201
404 405 406 407
        expect(build.trace).to be_empty
        expect(build.artifacts_file.exists?).to be_falsy
        expect(build.artifacts_metadata.exists?).to be_falsy
      end
408

409
      it 'updates build' do
410 411 412
        expect(build.reload.erased_at).to be_truthy
        expect(build.reload.erased_by).to eq user
      end
413 414
    end

415
    context 'build is not erasable' do
416
      let(:build) { create(:ci_build, :trace, project: project, pipeline: pipeline) }
417

418
      it 'responds with forbidden' do
419 420 421 422
        expect(response.status).to eq 403
      end
    end
  end
423 424 425 426 427 428 429 430 431 432 433 434

  describe 'POST /projects/:id/builds/:build_id/artifacts/keep' do
    before do
      post api("/projects/#{project.id}/builds/#{build.id}/artifacts/keep", user)
    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

K
Kamil Trzcinski 已提交
435
      it 'keeps artifacts' do
436
        expect(response.status).to eq 200
K
Kamil Trzcinski 已提交
437
        expect(build.reload.artifacts_expire_at).to be_nil
438 439 440 441 442 443
      end
    end

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

K
Kamil Trzcinski 已提交
444
      it 'responds with not found' do
445 446 447 448
        expect(response.status).to eq 404
      end
    end
  end
Z
Z.J. van de Weg 已提交
449 450 451 452 453 454 455 456 457 458 459 460

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

    context 'on an playable build' do
      let(:build) { create(:ci_build, :manual, project: project, pipeline: pipeline) }

      it 'plays the build' do
        expect(response).to have_http_status 200
        expect(json_response['user']['id']).to eq(user.id)
Z
Z.J. van de Weg 已提交
461
        expect(json_response['id']).to eq(build.id)
Z
Z.J. van de Weg 已提交
462 463 464 465 466 467 468 469 470 471
      end
    end

    context 'on a non-playable build' do
      it 'returns a status code 400, Bad Request' do
        expect(response).to have_http_status 400
        expect(response.body).to match("Unplayable Build")
      end
    end
  end
472
end