BigW Consortium Gitlab

pipelines_spec.rb 14.9 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 10 11 12

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

13
  before { project.team << [user, :master] }
14 15 16 17 18 19 20

  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)
21
        expect(response).to include_pagination_headers
22 23
        expect(json_response).to be_an Array
        expect(json_response.first['sha']).to match /\A\h{40}\z/
24
        expect(json_response.first['id']).to eq pipeline.id
25
        expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status])
26
      end
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

      context 'when parameter is passed' do
        let(:user1) { create(:user) }
        let(:user2) { create(:user) }
        let(:project) { create(:project, :repository) }

        before do
          create(:ci_pipeline, project: project, user: user1, ref: 'v1.0.0', tag: true)
          create(:ci_pipeline, project: project, user: user1, status: 'created')
          create(:ci_pipeline, project: project, user: user1, status: 'pending')
          create(:ci_pipeline, project: project, user: user1, status: 'running')
          create(:ci_pipeline, project: project, user: user1, status: 'success')
          create(:ci_pipeline, project: project, user: user2, status: 'failed')
          create(:ci_pipeline, project: project, user: user2, status: 'canceled')
          create(:ci_pipeline, project: project, user: user2, status: 'skipped')
          create(:ci_pipeline, project: project, user: user2, yaml_errors: 'Syntax error')
        end

        context 'when scope is passed' do
Shinya Maeda committed
46
          %w[running pending].each do |target|
Shinya Maeda committed
47 48 49 50 51 52
            context "when scope is #{target}" do
              it "returns matched pipelines" do
                get api("/projects/#{project.id}/pipelines?scope=#{target}", user)

                expect(response).to have_http_status(200)
                expect(response).to include_pagination_headers
53
                expect(json_response).not_to be_empty
Shinya Maeda committed
54 55 56 57 58 59 60 61
                json_response.each { |r| expect(r['status']).to eq(target) }
              end
            end
          end

          context 'when scope is finished' do
            it 'returns matched pipelines' do
              get api("/projects/#{project.id}/pipelines?scope=finished", user)
62 63 64

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
65
              expect(json_response).not_to be_empty
Shinya Maeda committed
66
              json_response.each { |r| expect(r['status']).to be_in(%w[success failed canceled]) }
67 68
            end
          end
Shinya Maeda committed
69

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

Shinya Maeda committed
74 75
              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
76
              expect(json_response).not_to be_empty
77
              expect(json_response.last['sha']).to eq(project.pipelines.where(tag: false).last.sha)
Shinya Maeda committed
78
            end
Shinya Maeda committed
79 80
          end

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

Shinya Maeda committed
85 86
              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
87
              expect(json_response).not_to be_empty
88
              expect(json_response.last['sha']).to eq(project.pipelines.where(tag: true).last.sha)
Shinya Maeda committed
89
            end
Shinya Maeda committed
90 91
          end

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

Shinya Maeda committed
96 97
              expect(response).to have_http_status(400)
            end
Shinya Maeda committed
98
          end
99 100 101 102
        end

        context 'when status is passed' do
          %w[running pending success failed canceled skipped].each do |target|
Shinya Maeda committed
103 104 105 106 107 108
            context "when status is #{target}" do
              it 'returns matched pipelines' do
                get api("/projects/#{project.id}/pipelines?status=#{target}", user)

                expect(response).to have_http_status(200)
                expect(response).to include_pagination_headers
109
                expect(json_response).not_to be_empty
Shinya Maeda committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
                json_response.each { |r| expect(r['status']).to eq(target) }
              end
            end
          end

          context 'when status is invalid' do
            it 'returns 400' do
              get api("/projects/#{project.id}/pipelines?status=invalid-status", user)

              expect(response).to have_http_status(400)
            end
          end
        end

        context 'when ref is passed' do
          context 'when ref exists' do
            it 'returns matched pipelines' do
              get api("/projects/#{project.id}/pipelines?ref=master", user)
128 129 130

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
131
              expect(json_response).not_to be_empty
Shinya Maeda committed
132
              json_response.each { |r| expect(r['ref']).to eq('master') }
133 134 135
            end
          end

Shinya Maeda committed
136 137 138
          context 'when ref does not exist' do
            it 'returns empty' do
              get api("/projects/#{project.id}/pipelines?ref=invalid-ref", user)
139 140 141

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
142
              expect(json_response).to be_empty
143 144 145 146 147 148
            end
          end
        end

        context 'when name is passed' do
          context 'when name exists' do
Shinya Maeda committed
149
            it 'returns matched pipelines' do
150 151 152 153
              get api("/projects/#{project.id}/pipelines?name=#{user1.name}", user)

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
154
              expect(json_response.first['sha']).to eq(project.pipelines.where(user: user1).order(id: :desc).first.sha)
155 156 157 158
            end
          end

          context 'when name does not exist' do
Shinya Maeda committed
159
            it 'returns empty' do
160 161 162 163
              get api("/projects/#{project.id}/pipelines?name=invalid-name", user)

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
164
              expect(json_response).to be_empty
165 166 167 168 169 170
            end
          end
        end

        context 'when username is passed' do
          context 'when username exists' do
Shinya Maeda committed
171
            it 'returns matched pipelines' do
172 173 174 175
              get api("/projects/#{project.id}/pipelines?username=#{user1.username}", user)

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
176
              expect(json_response.first['sha']).to eq(project.pipelines.where(user: user1).order(id: :desc).first.sha)
177 178 179 180
            end
          end

          context 'when username does not exist' do
Shinya Maeda committed
181
            it 'returns empty' do
182 183 184 185
              get api("/projects/#{project.id}/pipelines?username=invalid-username", user)

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
186
              expect(json_response).to be_empty
187 188 189 190 191 192
            end
          end
        end

        context 'when yaml_errors is passed' do
          context 'when yaml_errors is true' do
Shinya Maeda committed
193
            it 'returns matched pipelines' do
194 195 196 197
              get api("/projects/#{project.id}/pipelines?yaml_errors=true", user)

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
198
              expect(json_response.first['id']).to eq(project.pipelines.where("yaml_errors IS NOT NULL").order(id: :desc).first.id)
199 200 201 202
            end
          end

          context 'when yaml_errors is false' do
Shinya Maeda committed
203
            it 'returns matched pipelines' do
204 205 206 207
              get api("/projects/#{project.id}/pipelines?yaml_errors=false", user)

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
208
              expect(json_response.first['id']).to eq(project.pipelines.where("yaml_errors IS NULL").order(id: :desc).first.id)
209 210 211
            end
          end

Shinya Maeda committed
212 213
          context 'when yaml_errors is invalid' do
            it 'returns 400' do
214 215
              get api("/projects/#{project.id}/pipelines?yaml_errors=invalid-yaml_errors", user)

Shinya Maeda committed
216 217 218 219 220 221 222 223
              expect(response).to have_http_status(400)
            end
          end
        end

        context 'when order_by and sort are passed' do
          context 'when order_by and sort are valid' do
            it 'sorts pipelines' do
224
              get api("/projects/#{project.id}/pipelines?order_by=user_id&sort=asc", user)
Shinya Maeda committed
225 226 227

              expect(response).to have_http_status(200)
              expect(response).to include_pagination_headers
228 229
              expect(json_response.first['id']).to eq(project.pipelines.order(user_id: :asc).first.id)
              expect(json_response.last['id']).to eq(project.pipelines.order(user_id: :asc).last.id)
Shinya Maeda committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
            end
          end

          context 'when order_by is invalid' do
            it 'returns 400' do
              get api("/projects/#{project.id}/pipelines?order_by=lock_version&sort=asc", user)

              expect(response).to have_http_status(400)
            end
          end

          context 'when sort is invalid' do
            it 'returns 400' do
              get api("/projects/#{project.id}/pipelines?order_by=id&sort=hack", user)

245 246 247 248 249
              expect(response).to have_http_status(400)
            end
          end
        end
      end
250 251 252 253 254 255 256
    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)
257
        expect(json_response['message']).to eq '404 Project Not Found'
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 302 303
        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
        before { stub_ci_pipeline_to_return_yaml_file }

        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'
304
        expect(json_response).not_to be_an Array
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
      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)
322 323
        expect(json_response['message']).to eq '404 Not found'
        expect(json_response['id']).to be nil
324
      end
325 326 327 328 329 330 331 332 333 334 335 336

      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
337 338 339 340 341 342 343
    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)
344 345
        expect(json_response['message']).to eq '404 Project Not Found'
        expect(json_response['id']).to be nil
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
      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)
365
        expect(build.reload.retried?).to be true
366 367 368 369 370 371 372 373
      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)
374 375
        expect(json_response['message']).to eq '404 Project Not Found'
        expect(json_response['id']).to be nil
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
      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) }

      before { project.team << [reporter, :reporter] }

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

        expect(response).to have_http_status(403)
406
        expect(pipeline.reload.status).to eq('pending')
407 408 409 410
      end
    end
  end
end