pipelines_controller_spec.rb 11.3 KB
Newer Older
1 2 3
require 'spec_helper'

describe Projects::PipelinesController do
4 5
  include ApiHelpers

6
  set(:user) { create(:user) }
B
Bob Van Landuyt 已提交
7
  let(:project) { create(:project, :public, :repository) }
K
Kamil Trzcinski 已提交
8
  let(:feature) { ProjectFeature::DISABLED }
9 10

  before do
11 12
    stub_not_protect_default_branch
    project.add_developer(user)
13
    project.project_feature.update(builds_access_level: feature)
14

15 16 17
    sign_in(user)
  end

18 19
  describe 'GET index.json' do
    before do
20
      %w(pending running success failed canceled).each_with_index do |status, index|
21 22
        create_pipeline(status, project.commit("HEAD~#{index}"))
      end
23 24
    end

25 26 27
    context 'when using persisted stages', :request_store do
      before do
        stub_feature_flags(ci_pipeline_persisted_stages: true)
28
      end
29

30 31 32 33
      it 'returns serialized pipelines', :request_store do
        queries = ActiveRecord::QueryRecorder.new do
          get_pipelines_index_json
        end
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
        expect(response).to have_gitlab_http_status(:ok)
        expect(response).to match_response_schema('pipeline')

        expect(json_response).to include('pipelines')
        expect(json_response['pipelines'].count).to eq 5
        expect(json_response['count']['all']).to eq '5'
        expect(json_response['count']['running']).to eq '1'
        expect(json_response['count']['pending']).to eq '1'
        expect(json_response['count']['finished']).to eq '3'

        json_response.dig('pipelines', 0, 'details', 'stages').tap do |stages|
          expect(stages.count).to eq 3
        end

        expect(queries.count).to be
      end
    end

    context 'when using legacy stages', :request_store  do
      before do
        stub_feature_flags(ci_pipeline_persisted_stages: false)
      end

58 59
      it 'returns JSON with serialized pipelines' do
        get_pipelines_index_json
60 61 62 63 64 65 66 67 68 69 70 71 72 73

        expect(response).to have_gitlab_http_status(:ok)
        expect(response).to match_response_schema('pipeline')

        expect(json_response).to include('pipelines')
        expect(json_response['pipelines'].count).to eq 5
        expect(json_response['count']['all']).to eq '5'
        expect(json_response['count']['running']).to eq '1'
        expect(json_response['count']['pending']).to eq '1'
        expect(json_response['count']['finished']).to eq '3'

        json_response.dig('pipelines', 0, 'details', 'stages').tap do |stages|
          expect(stages.count).to eq 3
        end
74 75 76 77 78 79
      end

      it 'does not execute N+1 queries' do
        queries = ActiveRecord::QueryRecorder.new do
          get_pipelines_index_json
        end
80

81
        expect(queries.count).to be <= 36
82
      end
83
    end
84

85
    it 'does not include coverage data for the pipelines' do
86
      get_pipelines_index_json
87 88 89 90

      expect(json_response['pipelines'][0]).not_to include('coverage')
    end

91 92
    context 'when performing gitaly calls', :request_store do
      it 'limits the Gitaly requests' do
93 94 95 96 97
        # Isolate from test preparation (Repository#exists? is also cached in RequestStore)
        RequestStore.end!
        RequestStore.clear!
        RequestStore.begin!

98 99
        expect { get_pipelines_index_json }
          .to change { Gitlab::GitalyClient.get_request_count }.by(2)
100 101
      end
    end
102

B
Bob Van Landuyt 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    context 'when the project is private' do
      let(:project) { create(:project, :private, :repository) }

      it 'returns `not_found` when the user does not have access' do
        sign_in(create(:user))

        get_pipelines_index_json

        expect(response).to have_gitlab_http_status(:not_found)
      end

      it 'returns the pipelines when the user has access' do
        get_pipelines_index_json

        expect(json_response['pipelines'].size).to eq(5)
      end
    end

121
    def get_pipelines_index_json
B
blackst0ne 已提交
122 123 124 125
      get :index, params: {
                    namespace_id: project.namespace,
                    project_id: project
                  },
126 127 128
                  format: :json
    end

129 130 131 132 133 134 135 136 137 138
    def create_pipeline(status, sha)
      pipeline = create(:ci_empty_pipeline, status: status,
                                            project: project,
                                            sha: sha)

      create_build(pipeline, 'build', 1, 'build')
      create_build(pipeline, 'test', 2, 'test')
      create_build(pipeline, 'deploy', 3, 'deploy')
    end

139
    def create_build(pipeline, stage, stage_idx, name)
140 141
      status = %w[created running pending success failed canceled].sample
      create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name, status: status)
142
    end
143 144
  end

145
  describe 'GET show.json' do
146
    let(:pipeline) { create(:ci_pipeline_with_one_job, project: project) }
147 148 149 150

    it 'returns the pipeline' do
      get_pipeline_json

151
      expect(response).to have_gitlab_http_status(:ok)
152 153 154 155 156
      expect(json_response).not_to be_an(Array)
      expect(json_response['id']).to be(pipeline.id)
      expect(json_response['details']).to have_key 'stages'
    end

157
    context 'when the pipeline has multiple stages and groups', :request_store do
158 159 160 161 162 163 164 165
      let(:project) { create(:project, :repository) }

      let(:pipeline) do
        create(:ci_empty_pipeline, project: project,
                                   user: user,
                                   sha: project.commit.id)
      end

166 167 168 169 170 171 172
      before do
        create_build('build', 0, 'build')
        create_build('test', 1, 'rspec 0')
        create_build('deploy', 2, 'production')
        create_build('post deploy', 3, 'pages 0')
      end

173 174 175
      it 'does not perform N + 1 queries' do
        control_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count

176 177 178 179 180 181
        create_build('test', 1, 'rspec 1')
        create_build('test', 1, 'spinach 0')
        create_build('test', 1, 'spinach 1')
        create_build('test', 1, 'audit')
        create_build('post deploy', 3, 'pages 1')
        create_build('post deploy', 3, 'pages 2')
182

183
        new_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count
184

185
        expect(new_count).to be_within(12).of(control_count)
186 187 188 189
      end
    end

    def get_pipeline_json
B
blackst0ne 已提交
190
      get :show, params: { namespace_id: project.namespace, project_id: project, id: pipeline }, format: :json
191
    end
192 193 194 195

    def create_build(stage, stage_idx, name)
      create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name)
    end
196 197
  end

198
  describe 'GET stages.json' do
199 200
    let(:pipeline) { create(:ci_pipeline, project: project) }

201 202
    context 'when accessing existing stage' do
      before do
203
        create(:ci_build, :retried, :failed, pipeline: pipeline, stage: 'build')
204
        create(:ci_build, pipeline: pipeline, stage: 'build')
205 206 207 208 209 210
      end

      context 'without retried' do
        before do
          get_stage('build')
        end
211

212 213 214 215 216 217
        it 'returns pipeline jobs without the retried builds' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('pipeline_stage')
          expect(json_response['latest_statuses'].length).to eq 1
          expect(json_response).not_to have_key('retried')
        end
218 219
      end

220 221 222 223 224 225 226 227 228 229 230
      context 'with retried' do
        before do
          get_stage('build', retried: true)
        end

        it 'returns pipelines jobs with the retried builds' do
          expect(response).to have_gitlab_http_status(:ok)
          expect(response).to match_response_schema('pipeline_stage')
          expect(json_response['latest_statuses'].length).to eq 1
          expect(json_response['retried'].length).to eq 1
        end
231 232 233 234 235 236 237 238
      end
    end

    context 'when accessing unknown stage' do
      before do
        get_stage('test')
      end

239
      it 'responds with not found' do
240
        expect(response).to have_gitlab_http_status(:not_found)
241
      end
242 243
    end

244
    def get_stage(name, params = {})
B
blackst0ne 已提交
245 246 247 248 249 250 251 252
      get :stage, params: {
**params.merge(
  namespace_id: project.namespace,
  project_id: project,
  id: pipeline.id,
  stage: name,
  format: :json)
}
253
    end
254
  end
S
Shinya Maeda 已提交
255

256 257 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
  describe 'GET stages_ajax.json' do
    let(:pipeline) { create(:ci_pipeline, project: project) }

    context 'when accessing existing stage' do
      before do
        create(:ci_build, pipeline: pipeline, stage: 'build')

        get_stage_ajax('build')
      end

      it 'returns html source for stage dropdown' do
        expect(response).to have_gitlab_http_status(:ok)
        expect(response).to render_template('projects/pipelines/_stage')
        expect(json_response).to include('html')
      end
    end

    context 'when accessing unknown stage' do
      before do
        get_stage_ajax('test')
      end

      it 'responds with not found' do
        expect(response).to have_gitlab_http_status(:not_found)
      end
    end

    def get_stage_ajax(name)
B
blackst0ne 已提交
284 285 286 287 288 289
      get :stage_ajax, params: {
                         namespace_id: project.namespace,
                         project_id: project,
                         id: pipeline.id,
                         stage: name
                       },
290
                       format: :json
291 292 293
    end
  end

S
Shinya Maeda 已提交
294
  describe 'GET status.json' do
295 296
    let(:pipeline) { create(:ci_pipeline, project: project) }
    let(:status) { pipeline.detailed_status(double('user')) }
S
Shinya Maeda 已提交
297

298
    before do
B
blackst0ne 已提交
299 300 301 302 303
      get :status, params: {
                     namespace_id: project.namespace,
                     project_id: project,
                     id: pipeline.id
                   },
304 305
                   format: :json
    end
S
Shinya Maeda 已提交
306

307
    it 'return a detailed pipeline status in json' do
308
      expect(response).to have_gitlab_http_status(:ok)
309 310 311
      expect(json_response['text']).to eq status.text
      expect(json_response['label']).to eq status.label
      expect(json_response['icon']).to eq status.icon
312
      expect(json_response['favicon']).to match_asset_path("/assets/ci_favicons/#{status.favicon}.png")
S
Shinya Maeda 已提交
313 314
    end
  end
315 316 317 318 319 320

  describe 'POST retry.json' do
    let!(:pipeline) { create(:ci_pipeline, :failed, project: project) }
    let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }

    before do
B
blackst0ne 已提交
321 322 323 324 325
      post :retry, params: {
                     namespace_id: project.namespace,
                     project_id: project,
                     id: pipeline.id
                   },
326 327 328
                   format: :json
    end

K
Kamil Trzcinski 已提交
329 330
    context 'when builds are enabled' do
      let(:feature) { ProjectFeature::ENABLED }
331

K
Kamil Trzcinski 已提交
332
      it 'retries a pipeline without returning any content' do
333
        expect(response).to have_gitlab_http_status(:no_content)
K
Kamil Trzcinski 已提交
334 335 336 337 338 339
        expect(build.reload).to be_retried
      end
    end

    context 'when builds are disabled' do
      it 'fails to retry pipeline' do
340
        expect(response).to have_gitlab_http_status(:not_found)
K
Kamil Trzcinski 已提交
341
      end
342 343 344 345 346 347
    end
  end

  describe 'POST cancel.json' do
    let!(:pipeline) { create(:ci_pipeline, project: project) }
    let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
348

349
    before do
B
blackst0ne 已提交
350 351 352 353 354
      post :cancel, params: {
                      namespace_id: project.namespace,
                      project_id: project,
                      id: pipeline.id
                    },
355 356 357
                    format: :json
    end

K
Kamil Trzcinski 已提交
358 359
    context 'when builds are enabled' do
      let(:feature) { ProjectFeature::ENABLED }
360

K
Kamil Trzcinski 已提交
361
      it 'cancels a pipeline without returning any content' do
362
        expect(response).to have_gitlab_http_status(:no_content)
K
Kamil Trzcinski 已提交
363 364 365 366 367 368
        expect(pipeline.reload).to be_canceled
      end
    end

    context 'when builds are disabled' do
      it 'fails to retry pipeline' do
369
        expect(response).to have_gitlab_http_status(:not_found)
K
Kamil Trzcinski 已提交
370
      end
371 372
    end
  end
373
end