BigW Consortium Gitlab

runner_spec.rb 11.6 KB
Newer Older
1 2
require 'spec_helper'

Douwe Maan committed
3
describe Ci::Runner, models: true do
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  describe 'validation' do
    context 'when runner is not allowed to pick untagged jobs' do
      context 'when runner does not have tags' do
        it 'is not valid' do
          runner = build(:ci_runner, tag_list: [], run_untagged: false)
          expect(runner).to be_invalid
        end
      end

      context 'when runner has tags' do
        it 'is valid' do
          runner = build(:ci_runner, tag_list: ['tag'], run_untagged: false)
          expect(runner).to be_valid
        end
      end
    end
  end

22
  describe '#display_name' do
23
    it 'returns the description if it has a value' do
Valery Sizov committed
24
      runner = FactoryGirl.build(:ci_runner, description: 'Linux/Ruby-1.9.3-p448')
25 26 27
      expect(runner.display_name).to eq 'Linux/Ruby-1.9.3-p448'
    end

28
    it 'returns the token if it does not have a description' do
29
      runner = FactoryGirl.create(:ci_runner)
30 31 32
      expect(runner.display_name).to eq runner.description
    end

33
    it 'returns the token if the description is an empty string' do
Kamil Trzcinski committed
34
      runner = FactoryGirl.build(:ci_runner, description: '', token: 'token')
35 36 37 38
      expect(runner.display_name).to eq runner.token
    end
  end

39
  describe '#assign_to' do
40
    let!(:project) { FactoryGirl.create :empty_project }
41
    let!(:shared_runner) { FactoryGirl.create(:ci_runner, :shared) }
42

43 44 45
    before do
      shared_runner.assign_to(project)
    end
46

Dmitriy Zaporozhets committed
47 48 49
    it { expect(shared_runner).to be_specific }
    it { expect(shared_runner.projects).to eq([project]) }
    it { expect(shared_runner.only_for?(project)).to be_truthy }
50 51
  end

52
  describe '.online' do
53 54 55
    subject { Ci::Runner.online }

    before do
56 57
      @runner1 = FactoryGirl.create(:ci_runner, :shared, contacted_at: 1.year.ago)
      @runner2 = FactoryGirl.create(:ci_runner, :shared, contacted_at: 1.second.ago)
58 59 60 61 62
    end

    it { is_expected.to eq([@runner2])}
  end

63
  describe '#online?' do
64
    let(:runner) { FactoryGirl.create(:ci_runner, :shared) }
65 66 67 68

    subject { runner.online? }

    context 'never contacted' do
69 70 71
      before do
        runner.contacted_at = nil
      end
72 73 74 75 76

      it { is_expected.to be_falsey }
    end

    context 'contacted long time ago time' do
77 78 79
      before do
        runner.contacted_at = 1.year.ago
      end
80 81 82 83 84

      it { is_expected.to be_falsey }
    end

    context 'contacted 1s ago' do
85 86 87
      before do
        runner.contacted_at = 1.second.ago
      end
88 89 90 91 92

      it { is_expected.to be_truthy }
    end
  end

93
  describe '#can_pick?' do
94
    let(:pipeline) { create(:ci_pipeline) }
95
    let(:build) { create(:ci_build, pipeline: pipeline) }
96 97 98 99 100 101 102 103 104 105 106 107 108
    let(:runner) { create(:ci_runner) }

    before do
      build.project.runners << runner
    end

    context 'when runner does not have tags' do
      it 'can handle builds without tags' do
        expect(runner.can_pick?(build)).to be_truthy
      end

      it 'cannot handle build with tags' do
        build.tag_list = ['aa']
109

110 111 112 113 114 115
        expect(runner.can_pick?(build)).to be_falsey
      end
    end

    context 'when runner has tags' do
      before do
Douwe Maan committed
116
        runner.tag_list = %w(bb cc)
117 118 119 120 121
      end

      shared_examples 'tagged build picker' do
        it 'can handle build with matching tags' do
          build.tag_list = ['bb']
122

123 124 125 126 127
          expect(runner.can_pick?(build)).to be_truthy
        end

        it 'cannot handle build without matching tags' do
          build.tag_list = ['aa']
128

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
          expect(runner.can_pick?(build)).to be_falsey
        end
      end

      context 'when runner can pick untagged jobs' do
        it 'can handle builds without tags' do
          expect(runner.can_pick?(build)).to be_truthy
        end

        it_behaves_like 'tagged build picker'
      end

      context 'when runner cannot pick untagged jobs' do
        before do
          runner.run_untagged = false
        end

        it 'cannot handle builds without tags' do
          expect(runner.can_pick?(build)).to be_falsey
        end

        it_behaves_like 'tagged build picker'
      end
    end

    context 'when runner is locked' do
      before do
        runner.locked = true
      end

159
      shared_examples 'locked build picker' do
160 161 162 163 164 165 166 167 168 169 170 171
        context 'when runner cannot pick untagged jobs' do
          before do
            runner.run_untagged = false
          end

          it 'cannot handle builds without tags' do
            expect(runner.can_pick?(build)).to be_falsey
          end
        end

        context 'when having runner tags' do
          before do
Douwe Maan committed
172
            runner.tag_list = %w(bb cc)
173 174 175 176
          end

          it 'cannot handle it for builds without matching tags' do
            build.tag_list = ['aa']
177

178 179 180 181 182 183 184 185 186 187
            expect(runner.can_pick?(build)).to be_falsey
          end
        end
      end

      context 'when serving the same project' do
        it 'can handle it' do
          expect(runner.can_pick?(build)).to be_truthy
        end

188 189 190 191
        it_behaves_like 'locked build picker'

        context 'when having runner tags' do
          before do
Douwe Maan committed
192
            runner.tag_list = %w(bb cc)
193 194 195 196 197 198 199
            build.tag_list = ['bb']
          end

          it 'can handle it for matching tags' do
            expect(runner.can_pick?(build)).to be_truthy
          end
        end
200 201 202 203 204 205 206 207 208 209 210
      end

      context 'serving a different project' do
        before do
          runner.runner_projects.destroy_all
        end

        it 'cannot handle it' do
          expect(runner.can_pick?(build)).to be_falsey
        end

211 212 213 214
        it_behaves_like 'locked build picker'

        context 'when having runner tags' do
          before do
Douwe Maan committed
215
            runner.tag_list = %w(bb cc)
216 217 218 219 220 221 222
            build.tag_list = ['bb']
          end

          it 'cannot handle it for matching tags' do
            expect(runner.can_pick?(build)).to be_falsey
          end
        end
223 224 225 226
      end
    end
  end

227
  describe '#status' do
228
    let(:runner) { FactoryGirl.create(:ci_runner, :shared, contacted_at: 1.second.ago) }
229 230 231 232

    subject { runner.status }

    context 'never connected' do
233 234 235
      before do
        runner.contacted_at = nil
      end
236 237 238 239 240

      it { is_expected.to eq(:not_connected) }
    end

    context 'contacted 1s ago' do
241 242 243
      before do
        runner.contacted_at = 1.second.ago
      end
244 245 246 247 248

      it { is_expected.to eq(:online) }
    end

    context 'contacted long time ago' do
249 250 251
      before do
        runner.contacted_at = 1.year.ago
      end
252 253 254 255 256

      it { is_expected.to eq(:offline) }
    end

    context 'inactive' do
257 258 259
      before do
        runner.active = false
      end
260 261 262 263 264

      it { is_expected.to eq(:paused) }
    end
  end

265 266 267 268 269 270 271 272 273 274 275 276 277 278
  describe '#tick_runner_queue' do
    let(:runner) { create(:ci_runner) }

    it 'returns a new last_update value' do
      expect(runner.tick_runner_queue).not_to be_empty
    end
  end

  describe '#ensure_runner_queue_value' do
    let(:runner) { create(:ci_runner) }

    it 'sets a new last_update value when it is called the first time' do
      last_update = runner.ensure_runner_queue_value

Kamil Trzcinski committed
279
      expect_value_in_redis.to eq(last_update)
280 281 282 283 284 285
    end

    it 'does not change if it is not expired and called again' do
      last_update = runner.ensure_runner_queue_value

      expect(runner.ensure_runner_queue_value).to eq(last_update)
Kamil Trzcinski committed
286
      expect_value_in_redis.to eq(last_update)
287 288
    end

Kamil Trzcinski committed
289 290 291 292
    context 'updates runner queue after changing editable value' do
      let!(:last_update) { runner.ensure_runner_queue_value }

      before do
293
        Ci::UpdateRunnerService.new(runner).update(description: 'new runner')
Kamil Trzcinski committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
      end

      it 'sets a new last_update value' do
        expect_value_in_redis.not_to eq(last_update)
      end
    end

    context 'does not update runner value after save' do
      let!(:last_update) { runner.ensure_runner_queue_value }

      before do
        runner.touch
      end

      it 'has an old last_update value' do
        expect_value_in_redis.to eq(last_update)
      end
    end

    def expect_value_in_redis
314 315
      Gitlab::Redis.with do |redis|
        runner_queue_key = runner.send(:runner_queue_key)
Kamil Trzcinski committed
316
        expect(redis.get(runner_queue_key))
317 318 319 320
      end
    end
  end

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
  describe '#destroy' do
    let(:runner) { create(:ci_runner) }

    context 'when there is a tick in the queue' do
      let!(:queue_key) { runner.send(:runner_queue_key) }

      before do
        runner.tick_runner_queue
        runner.destroy
      end

      it 'cleans up the queue' do
        Gitlab::Redis.with do |redis|
          expect(redis.get(queue_key)).to be_nil
        end
      end
    end
  end

Lin Jen-Shin committed
340
  describe '.assignable_for' do
341
    let(:runner) { create(:ci_runner) }
342 343
    let(:project) { create(:empty_project) }
    let(:another_project) { create(:empty_project) }
344

345 346 347
    before do
      project.runners << runner
    end
348 349

    context 'with shared runners' do
350 351 352
      before do
        runner.update(is_shared: true)
      end
353

354
      context 'does not give owned runner' do
Lin Jen-Shin committed
355
        subject { Ci::Runner.assignable_for(project) }
356 357 358 359

        it { is_expected.to be_empty }
      end

360
      context 'does not give shared runner' do
Lin Jen-Shin committed
361
        subject { Ci::Runner.assignable_for(another_project) }
362 363 364 365 366 367

        it { is_expected.to be_empty }
      end
    end

    context 'with unlocked runner' do
368
      context 'does not give owned runner' do
Lin Jen-Shin committed
369
        subject { Ci::Runner.assignable_for(project) }
370 371 372 373

        it { is_expected.to be_empty }
      end

374
      context 'does give a specific runner' do
Lin Jen-Shin committed
375
        subject { Ci::Runner.assignable_for(another_project) }
376 377 378 379 380 381

        it { is_expected.to contain_exactly(runner) }
      end
    end

    context 'with locked runner' do
382 383 384
      before do
        runner.update(locked: true)
      end
385

386
      context 'does not give owned runner' do
Lin Jen-Shin committed
387
        subject { Ci::Runner.assignable_for(project) }
388 389 390 391

        it { is_expected.to be_empty }
      end

392
      context 'does not give a locked runner' do
Lin Jen-Shin committed
393
        subject { Ci::Runner.assignable_for(another_project) }
394 395 396 397 398 399

        it { is_expected.to be_empty }
      end
    end
  end

400 401
  describe "belongs_to_one_project?" do
    it "returns false if there are two projects runner assigned to" do
402
      runner = FactoryGirl.create(:ci_runner)
403 404
      project = FactoryGirl.create(:empty_project)
      project1 = FactoryGirl.create(:empty_project)
405 406
      project.runners << runner
      project1.runners << runner
407

Dmitriy Zaporozhets committed
408
      expect(runner.belongs_to_one_project?).to be_falsey
409 410 411
    end

    it "returns true" do
412
      runner = FactoryGirl.create(:ci_runner)
413
      project = FactoryGirl.create(:empty_project)
414
      project.runners << runner
415

Dmitriy Zaporozhets committed
416
      expect(runner.belongs_to_one_project?).to be_truthy
417 418
    end
  end
419

420 421 422 423 424 425 426 427
  describe '#has_tags?' do
    context 'when runner has tags' do
      subject { create(:ci_runner, tag_list: ['tag']) }
      it { is_expected.to have_tags }
    end

    context 'when runner does not have tags' do
      subject { create(:ci_runner, tag_list: []) }
428
      it { is_expected.not_to have_tags }
429 430 431 432
    end
  end

  describe '.search' do
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    let(:runner) { create(:ci_runner, token: '123abc') }

    it 'returns runners with a matching token' do
      expect(described_class.search(runner.token)).to eq([runner])
    end

    it 'returns runners with a partially matching token' do
      expect(described_class.search(runner.token[0..2])).to eq([runner])
    end

    it 'returns runners with a matching token regardless of the casing' do
      expect(described_class.search(runner.token.upcase)).to eq([runner])
    end

    it 'returns runners with a matching description' do
      expect(described_class.search(runner.description)).to eq([runner])
    end

    it 'returns runners with a partially matching description' do
      expect(described_class.search(runner.description[0..2])).to eq([runner])
    end

    it 'returns runners with a matching description regardless of the casing' do
      expect(described_class.search(runner.description.upcase)).to eq([runner])
    end
  end
459
end