pipeline_spec.rb 9.6 KB
Newer Older
D
Douwe Maan 已提交
1 2
require 'spec_helper'

3
describe Ci::Pipeline, models: true do
K
Kamil Trzcinski 已提交
4
  let(:project) { FactoryGirl.create :empty_project }
5
  let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project }
D
Douwe Maan 已提交
6

K
Kamil Trzcinski 已提交
7
  it { is_expected.to belong_to(:project) }
8 9
  it { is_expected.to belong_to(:user) }

10
  it { is_expected.to have_many(:statuses) }
K
Kamil Trzcinski 已提交
11
  it { is_expected.to have_many(:trigger_requests) }
D
Dmitriy Zaporozhets 已提交
12
  it { is_expected.to have_many(:builds) }
13

D
Dmitriy Zaporozhets 已提交
14
  it { is_expected.to validate_presence_of :sha }
K
Kamil Trzcinski 已提交
15
  it { is_expected.to validate_presence_of :status }
D
Douwe Maan 已提交
16

D
Dmitriy Zaporozhets 已提交
17 18 19
  it { is_expected.to respond_to :git_author_name }
  it { is_expected.to respond_to :git_author_email }
  it { is_expected.to respond_to :short_sha }
D
Douwe Maan 已提交
20

21 22
  it { is_expected.to delegate_method(:stages).to(:statuses) }

23
  describe '#valid_commit_sha' do
D
Douwe Maan 已提交
24 25
    context 'commit.sha can not start with 00000000' do
      before do
26 27
        pipeline.sha = '0' * 40
        pipeline.valid_commit_sha
D
Douwe Maan 已提交
28 29
      end

30
      it('commit errors should not be empty') { expect(pipeline.errors).not_to be_empty }
D
Douwe Maan 已提交
31 32 33
    end
  end

34
  describe '#short_sha' do
35
    subject { pipeline.short_sha }
D
Douwe Maan 已提交
36

D
Dmitriy Zaporozhets 已提交
37 38 39
    it 'has 8 items' do
      expect(subject.size).to eq(8)
    end
40
    it { expect(pipeline.sha).to start_with(subject) }
D
Douwe Maan 已提交
41 42
  end

43
  describe '#retried' do
44
    subject { pipeline.retried }
K
Kamil Trzcinski 已提交
45 46

    before do
47 48
      @build1 = FactoryGirl.create :ci_build, pipeline: pipeline, name: 'deploy'
      @build2 = FactoryGirl.create :ci_build, pipeline: pipeline, name: 'deploy'
K
Kamil Trzcinski 已提交
49 50 51
    end

    it 'returns old builds' do
52
      is_expected.to contain_exactly(@build1)
K
Kamil Trzcinski 已提交
53 54 55
    end
  end

D
Douwe Maan 已提交
56
  describe "#finished_at" do
57
    let(:pipeline) { FactoryGirl.create :ci_pipeline }
D
Douwe Maan 已提交
58 59

    it "returns finished_at of latest build" do
60 61
      build = FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 60
      FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 120
62
      pipeline.reload_status!
D
Douwe Maan 已提交
63

64
      expect(pipeline.finished_at.to_i).to eq(build.finished_at.to_i)
D
Douwe Maan 已提交
65 66 67
    end

    it "returns nil if there is no finished build" do
68
      FactoryGirl.create :ci_not_started_build, pipeline: pipeline
69
      pipeline.reload_status!
D
Douwe Maan 已提交
70

71
      expect(pipeline.finished_at).to be_nil
D
Douwe Maan 已提交
72 73 74 75
    end
  end

  describe "coverage" do
K
Kamil Trzcinski 已提交
76
    let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" }
77
    let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project }
D
Douwe Maan 已提交
78 79

    it "calculates average when there are two builds with coverage" do
80 81 82
      FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
      FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, pipeline: pipeline
      expect(pipeline.coverage).to eq("35.00")
D
Douwe Maan 已提交
83 84 85
    end

    it "calculates average when there are two builds with coverage and one with nil" do
86 87 88 89
      FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
      FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, pipeline: pipeline
      FactoryGirl.create :ci_build, pipeline: pipeline
      expect(pipeline.coverage).to eq("35.00")
D
Douwe Maan 已提交
90 91 92
    end

    it "calculates average when there are two builds with coverage and one is retried" do
93 94 95 96
      FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
      FactoryGirl.create :ci_build, name: "rubocop", coverage: 30, pipeline: pipeline
      FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, pipeline: pipeline
      expect(pipeline.coverage).to eq("35.00")
D
Douwe Maan 已提交
97 98 99
    end

    it "calculates average when there is one build without coverage" do
100 101
      FactoryGirl.create :ci_build, pipeline: pipeline
      expect(pipeline.coverage).to be_nil
D
Douwe Maan 已提交
102 103
    end
  end
K
Kamil Trzcinski 已提交
104 105

  describe '#retryable?' do
106
    subject { pipeline.retryable? }
K
Kamil Trzcinski 已提交
107 108 109

    context 'no failed builds' do
      before do
110
        FactoryGirl.create :ci_build, name: "rspec", pipeline: pipeline, status: 'success'
K
Kamil Trzcinski 已提交
111 112 113 114 115 116 117 118 119
      end

      it 'be not retryable' do
        is_expected.to be_falsey
      end
    end

    context 'with failed builds' do
      before do
120 121
        FactoryGirl.create :ci_build, name: "rspec", pipeline: pipeline, status: 'running'
        FactoryGirl.create :ci_build, name: "rubocop", pipeline: pipeline, status: 'failed'
K
Kamil Trzcinski 已提交
122 123 124 125 126 127 128 129 130
      end

      it 'be retryable' do
        is_expected.to be_truthy
      end
    end
  end

  describe '#stages' do
131 132
    let(:pipeline2) { FactoryGirl.create :ci_pipeline, project: project }
    subject { CommitStatus.where(pipeline: [pipeline, pipeline2]).stages }
K
Kamil Trzcinski 已提交
133 134

    before do
135 136
      FactoryGirl.create :ci_build, pipeline: pipeline2, stage: 'test', stage_idx: 1
      FactoryGirl.create :ci_build, pipeline: pipeline, stage: 'build', stage_idx: 0
K
Kamil Trzcinski 已提交
137 138 139 140 141 142 143
    end

    it 'return all stages' do
      is_expected.to eq(%w(build test))
    end
  end

144 145
  describe '#reload_status!' do
    let(:pipeline) { create :ci_empty_pipeline, project: project }
K
Kamil Trzcinski 已提交
146 147

    context 'dependent objects' do
148 149 150 151
      let(:commit_status) { create :commit_status, :pending, pipeline: pipeline }

      it 'executes reload_status! after succeeding dependent object' do
        expect(pipeline).to receive(:reload_status!).and_return(true)
K
Kamil Trzcinski 已提交
152

153
        commit_status.success
K
Kamil Trzcinski 已提交
154 155 156
      end
    end

157
    context 'updates' do
K
Kamil Trzcinski 已提交
158
      let(:current) { Time.now.change(usec: 0) }
159
      let(:build) { FactoryGirl.create :ci_build, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 }
K
Kamil Trzcinski 已提交
160 161 162

      before do
        build
163
        pipeline.reload_status!
K
Kamil Trzcinski 已提交
164 165 166
      end

      [:status, :started_at, :finished_at, :duration].each do |param|
167
        it "#{param}" do
168
          expect(pipeline.send(param)).to eq(build.send(param))
K
Kamil Trzcinski 已提交
169 170 171 172
        end
      end
    end
  end
K
Kamil Trzcinski 已提交
173 174

  describe '#branch?' do
175
    subject { pipeline.branch? }
K
Kamil Trzcinski 已提交
176 177 178

    context 'is not a tag' do
      before do
179
        pipeline.tag = false
K
Kamil Trzcinski 已提交
180 181 182 183 184 185 186 187 188
      end

      it 'return true when tag is set to false' do
        is_expected.to be_truthy
      end
    end

    context 'is not a tag' do
      before do
189
        pipeline.tag = true
K
Kamil Trzcinski 已提交
190 191 192 193 194 195 196
      end

      it 'return false when tag is set to true' do
        is_expected.to be_falsey
      end
    end
  end
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

  describe '#manual_actions' do
    subject { pipeline.manual_actions }

    it 'when none defined' do
      is_expected.to be_empty
    end

    context 'when action defined' do
      let!(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }

      it 'returns one action' do
        is_expected.to contain_exactly(manual)
      end

      context 'there are multiple of the same name' do
        let!(:manual2) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }

        it 'returns latest one' do
          is_expected.to contain_exactly(manual2)
        end
      end
    end
  end
221

C
Connor Shea 已提交
222 223
  describe '#has_warnings?' do
    subject { pipeline.has_warnings? }
224 225 226

    context 'build which is allowed to fail fails' do
      before do
C
Connor Shea 已提交
227 228
        create :ci_build, :success, pipeline: pipeline, name: 'rspec'
        create :ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop'
229
      end
230

231 232 233 234 235 236 237
      it 'returns true' do
        is_expected.to be_truthy
      end
    end

    context 'build which is allowed to fail succeeds' do
      before do
C
Connor Shea 已提交
238 239
        create :ci_build, :success, pipeline: pipeline, name: 'rspec'
        create :ci_build, :allowed_to_fail, :success, pipeline: pipeline, name: 'rubocop'
240
      end
241

242 243 244 245
      it 'returns false' do
        is_expected.to be_falsey
      end
    end
C
Connor Shea 已提交
246 247 248 249 250 251 252 253 254 255 256 257

    context 'build is retried and succeeds' do
      before do
        create :ci_build, :success, pipeline: pipeline, name: 'rubocop'
        create :ci_build, :failed, pipeline: pipeline, name: 'rspec'
        create :ci_build, :success, pipeline: pipeline, name: 'rspec'
      end

      it 'returns false' do
        is_expected.to be_falsey
      end
    end
258
  end
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 304
  describe '#status' do
    let!(:build) { create(:ci_build, :created, pipeline: pipeline, name: 'test') }

    subject { pipeline.reload.status }

    context 'on queuing' do
      before { build.queue }

      it { is_expected.to eq('pending') }
    end

    context 'on run' do
      before do
        build.queue
        build.run
      end

      it { is_expected.to eq('running') }
    end

    context 'on drop' do
      before do
        build.drop
      end

      it { is_expected.to eq('failed') }
    end

    context 'on success' do
      before do
        build.success
      end

      it { is_expected.to eq('success') }
    end

    context 'on cancel' do
      before do
        build.cancel
      end

      it { is_expected.to eq('canceled') }
    end
  end

305 306 307 308 309 310 311 312 313 314 315 316
  describe '#execute_hooks' do
    let!(:hook) do
      create(:project_hook, project: project, pipeline_events: enabled)
    end

    before do
      ProjectWebHookWorker.drain
    end

    context 'with pipeline hooks enabled' do
      let(:enabled) { true }

317
      context 'with multiple builds' do
318 319
        let!(:build_a) { create_build('a') }
        let!(:build_b) { create_build('b') }
320

321 322 323 324 325 326
        it 'fires exactly 3 hooks' do
          stub_request('pending')
          build_a.queue
          build_b.queue

          stub_request('running')
327 328
          build_a.run
          build_b.run
329 330

          stub_request('success')
331 332 333 334
          build_a.success
          build_b.success
        end

335 336 337 338
        def create_build(name)
          create(:ci_build, :pending, pipeline: pipeline, name: name)
        end

339 340 341 342 343 344
        def stub_request(status)
          WebMock.stub_request(:post, hook.url).with do |req|
            json_body = JSON.parse(req.body)
            json_body['object_attributes']['status'] == status &&
              json_body['builds'].length == 2
          end
345
        end
346
      end
347 348 349 350 351 352 353 354 355 356
    end

    context 'with pipeline hooks disabled' do
      let(:enabled) { false }

      it 'did not execute pipeline_hook after touched' do
        expect(WebMock).not_to have_requested(:post, hook.url)
      end
    end
  end
D
Douwe Maan 已提交
357
end