geo_node_status_spec.rb 34.6 KB
Newer Older
1 2
require 'spec_helper'

3
describe GeoNodeStatus, :geo, :geo_fdw do
4 5
  include ::EE::GeoHelpers

6
  let!(:primary) { create(:geo_node, :primary) }
7
  let!(:secondary) { create(:geo_node) }
8

9 10 11 12 13
  let!(:group)     { create(:group) }
  let!(:project_1) { create(:project, group: group) }
  let!(:project_2) { create(:project, group: group) }
  let!(:project_3) { create(:project) }
  let!(:project_4) { create(:project) }
14

15
  subject(:status) { described_class.current_node_status }
16 17 18 19

  before do
    stub_current_geo_node(secondary)
  end
20

21 22
  describe '#fast_current_node_status' do
    it 'reads the cache and spawns the worker' do
23 24
      expect(described_class).to receive(:spawn_worker).once

25 26 27 28 29 30 31 32 33 34 35
      rails_cache = double
      expect(rails_cache).to receive(:read).with(described_class.cache_key)
      expect(Rails).to receive(:cache).and_return(rails_cache)

      described_class.fast_current_node_status
    end
  end

  describe '#update_cache!' do
    it 'writes a cache' do
      rails_cache = double
36 37 38
      allow(Rails).to receive(:cache).and_return(rails_cache)
      allow(rails_cache).to receive(:fetch).with('flipper:persisted_names', expires_in: 1.minute).and_return([described_class.cache_key])

39 40 41 42 43 44
      expect(rails_cache).to receive(:write).with(described_class.cache_key, kind_of(Hash))

      described_class.new.update_cache!
    end
  end

45 46 47
  describe '#healthy?' do
    context 'when health is blank' do
      it 'returns true' do
48
        subject.status_message = ''
49

50
        expect(subject.healthy?).to be true
51 52 53 54
      end
    end

    context 'when health is present' do
55
      it 'returns true' do
56
        subject.status_message = GeoNodeStatus::HEALTHY_STATUS
57 58 59 60

        expect(subject.healthy?).to be true
      end

61
      it 'returns false' do
62
        subject.status_message = 'something went wrong'
63

64
        expect(subject.healthy?).to be false
65 66
      end
    end
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

    context 'takes outdated? into consideration' do
      it 'return false' do
        subject.status_message = GeoNodeStatus::HEALTHY_STATUS
        subject.updated_at = 10.minutes.ago

        expect(subject.healthy?).to be false
      end

      it 'return false' do
        subject.status_message = 'something went wrong'
        subject.updated_at = 1.minute.ago

        expect(subject.healthy?).to be false
      end
    end
  end

  describe '#outdated?' do
    it 'return true' do
      subject.updated_at = 10.minutes.ago

      expect(subject.outdated?).to be true
    end

    it 'return false' do
      subject.updated_at = 1.minute.ago

      expect(subject.outdated?).to be false
    end
97 98
  end

99
  describe '#status_message' do
100 101 102
    it 'delegates to the HealthCheck' do
      expect(HealthCheck::Utils).to receive(:process_checks).with(['geo']).once

103
      subject
104 105 106
    end
  end

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
  describe '#health' do
    context 'takes outdated? into consideration' do
      it 'returns expiration error' do
        subject.status_message = GeoNodeStatus::HEALTHY_STATUS
        subject.updated_at = 10.minutes.ago

        expect(subject.health).to eq "Status has not been updated in the past #{described_class::EXPIRATION_IN_MINUTES} minutes"
      end

      it 'returns original message' do
        subject.status_message = 'something went wrong'
        subject.updated_at = 1.minute.ago

        expect(subject.health).to eq 'something went wrong'
      end
    end
  end

125
  describe '#attachments_synced_count' do
126
    it 'only counts successful syncs' do
Robert Speicher's avatar
Robert Speicher committed
127
      create_list(:user, 3, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png'))
128 129 130 131
      uploads = Upload.all.pluck(:id)

      create(:geo_file_registry, :avatar, file_id: uploads[0])
      create(:geo_file_registry, :avatar, file_id: uploads[1])
132
      create(:geo_file_registry, :avatar, :failed, file_id: uploads[2])
133 134 135 136

      expect(subject.attachments_synced_count).to eq(2)
    end

137
    it 'does not count synced files that were replaced' do
Robert Speicher's avatar
Robert Speicher committed
138
      user = create(:user, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png'))
139 140 141 142

      expect(subject.attachments_count).to eq(1)
      expect(subject.attachments_synced_count).to eq(0)

143
      upload = Upload.find_by(model: user, uploader: 'AvatarUploader')
144
      create(:geo_file_registry, :avatar, file_id: upload.id)
145

146 147
      subject = described_class.current_node_status

148 149 150
      expect(subject.attachments_count).to eq(1)
      expect(subject.attachments_synced_count).to eq(1)

Robert Speicher's avatar
Robert Speicher committed
151
      user.update(avatar: fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg'))
152

153 154
      subject = described_class.current_node_status

155 156 157
      expect(subject.attachments_count).to eq(1)
      expect(subject.attachments_synced_count).to eq(0)

158
      upload = Upload.find_by(model: user, uploader: 'AvatarUploader')
159
      create(:geo_file_registry, :avatar, file_id: upload.id)
160

161 162
      subject = described_class.current_node_status

163
      expect(subject.attachments_count).to eq(1)
164 165 166 167
      expect(subject.attachments_synced_count).to eq(1)
    end
  end

168
  describe '#attachments_synced_missing_on_primary_count' do
169
    it 'only counts successful syncs' do
Robert Speicher's avatar
Robert Speicher committed
170
      create_list(:user, 3, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png'))
171 172 173 174
      uploads = Upload.all.pluck(:id)

      create(:geo_file_registry, :avatar, file_id: uploads[0], missing_on_primary: true)
      create(:geo_file_registry, :avatar, file_id: uploads[1])
175
      create(:geo_file_registry, :avatar, :failed, file_id: uploads[2])
176 177 178 179 180

      expect(subject.attachments_synced_missing_on_primary_count).to eq(1)
    end
  end

181
  describe '#attachments_failed_count' do
182 183
    it 'counts failed avatars, attachment, personal snippets and files' do
      # These two should be ignored
184
      create(:geo_file_registry, :lfs, :with_file, :failed)
185
      create(:geo_file_registry, :with_file)
186

187 188 189 190
      create(:geo_file_registry, :with_file, :failed, file_type: :personal_file)
      create(:geo_file_registry, :with_file, :failed, file_type: :attachment)
      create(:geo_file_registry, :avatar, :with_file, :failed)
      create(:geo_file_registry, :with_file, :failed)
191 192 193 194 195

      expect(subject.attachments_failed_count).to eq(4)
    end
  end

196
  describe '#attachments_synced_in_percentage' do
Robert Speicher's avatar
Robert Speicher committed
197
    let(:avatar) { fixture_file_upload('spec/fixtures/dk.png') }
198 199 200 201 202 203 204
    let(:upload_1) { create(:upload, model: group, path: avatar) }
    let(:upload_2) { create(:upload, model: project_1, path: avatar) }

    before do
      create(:upload, model: create(:group), path: avatar)
      create(:upload, model: project_3, path: avatar)
    end
205

206
    it 'returns 0 when no objects are available' do
207 208 209
      expect(subject.attachments_synced_in_percentage).to eq(0)
    end

210 211 212
    it 'returns the right percentage with no group restrictions' do
      create(:geo_file_registry, :avatar, file_id: upload_1.id)
      create(:geo_file_registry, :avatar, file_id: upload_2.id)
213

214 215 216 217
      expect(subject.attachments_synced_in_percentage).to be_within(0.0001).of(50)
    end

    it 'returns the right percentage with group restrictions' do
218
      secondary.update!(selective_sync_type: 'namespaces', namespaces: [group])
219 220 221 222
      create(:geo_file_registry, :avatar, file_id: upload_1.id)
      create(:geo_file_registry, :avatar, file_id: upload_2.id)

      expect(subject.attachments_synced_in_percentage).to be_within(0.0001).of(100)
223 224 225
    end
  end

226
  describe '#db_replication_lag_seconds' do
227 228
    it 'returns the set replication lag if secondary' do
      allow(Gitlab::Geo).to receive(:secondary?).and_return(true)
229 230
      geo_health_check = double('Gitlab::Geo::HealthCheck', perform_checks: '', db_replication_lag_seconds: 1000)
      allow(Gitlab::Geo::HealthCheck).to receive(:new).and_return(geo_health_check)
231

232
      expect(subject.db_replication_lag_seconds).to eq(1000)
233
    end
234 235

    it "doesn't attempt to set replication lag if primary" do
236
      stub_current_geo_node(primary)
237

238
      expect(subject.db_replication_lag_seconds).to eq(nil)
239
    end
240 241
  end

242
  describe '#lfs_objects_synced_count' do
243 244
    it 'counts synced LFS objects' do
      # These four should be ignored
245
      create(:geo_file_registry, :failed)
246 247
      create(:geo_file_registry, :avatar)
      create(:geo_file_registry, file_type: :attachment)
248
      create(:geo_file_registry, :lfs, :with_file, :failed)
249

250
      create(:geo_file_registry, :lfs, :with_file)
251 252 253 254 255

      expect(subject.lfs_objects_synced_count).to eq(1)
    end
  end

256
  describe '#lfs_objects_synced_missing_on_primary_count' do
257 258
    it 'counts LFS objects marked as synced due to file missing on the primary' do
      # These four should be ignored
259
      create(:geo_file_registry, :failed)
260 261
      create(:geo_file_registry, :avatar, missing_on_primary: true)
      create(:geo_file_registry, file_type: :attachment, missing_on_primary: true)
262
      create(:geo_file_registry, :lfs, :with_file, :failed)
263

264
      create(:geo_file_registry, :lfs, :with_file, missing_on_primary: true)
265 266 267 268 269

      expect(subject.lfs_objects_synced_missing_on_primary_count).to eq(1)
    end
  end

270
  describe '#lfs_objects_failed_count' do
271 272
    it 'counts failed LFS objects' do
      # These four should be ignored
273 274 275
      create(:geo_file_registry, :failed)
      create(:geo_file_registry, :avatar, :failed)
      create(:geo_file_registry, :failed, file_type: :attachment)
276
      create(:geo_file_registry, :lfs, :with_file)
277

278
      create(:geo_file_registry, :lfs, :with_file, :failed)
279 280 281 282 283

      expect(subject.lfs_objects_failed_count).to eq(1)
    end
  end

284
  describe '#lfs_objects_synced_in_percentage' do
285
    let(:lfs_object_project) { create(:lfs_objects_project, project: project_1) }
286

287 288 289 290 291 292 293 294
    before do
      allow(ProjectCacheWorker).to receive(:perform_async).and_return(true)

      create(:lfs_objects_project, project: project_1)
      create_list(:lfs_objects_project, 2, project: project_3)
    end

    it 'returns 0 when no objects are available' do
295 296 297
      expect(subject.lfs_objects_synced_in_percentage).to eq(0)
    end

298
    it 'returns the right percentage with no group restrictions' do
299
      create(:geo_file_registry, :lfs, file_id: lfs_object_project.lfs_object_id)
300 301 302

      expect(subject.lfs_objects_synced_in_percentage).to be_within(0.0001).of(25)
    end
303 304

    it 'returns the right percentage with group restrictions' do
305
      secondary.update!(selective_sync_type: 'namespaces', namespaces: [group])
306
      create(:geo_file_registry, :lfs, file_id: lfs_object_project.lfs_object_id)
307 308 309

      expect(subject.lfs_objects_synced_in_percentage).to be_within(0.0001).of(50)
    end
310 311
  end

312
  describe '#job_artifacts_synced_count' do
313 314
    it 'counts synced job artifacts' do
      # These should be ignored
315
      create(:geo_file_registry)
316
      create(:geo_job_artifact_registry, :with_artifact, success: false)
317

318
      create(:geo_job_artifact_registry, :with_artifact, success: true)
319 320 321 322 323

      expect(subject.job_artifacts_synced_count).to eq(1)
    end
  end

324
  describe '#job_artifacts_synced_missing_on_primary_count' do
325 326
    it 'counts job artifacts marked as synced due to file missing on the primary' do
      # These should be ignored
327
      create(:geo_file_registry, missing_on_primary: true)
328 329 330 331 332 333 334 335
      create(:geo_job_artifact_registry, :with_artifact, success: true)

      create(:geo_job_artifact_registry, :with_artifact, success: true, missing_on_primary: true)

      expect(subject.job_artifacts_synced_missing_on_primary_count).to eq(1)
    end
  end

336
  describe '#job_artifacts_failed_count' do
337 338
    it 'counts failed job artifacts' do
      # These should be ignored
339 340 341
      create(:geo_file_registry, :failed)
      create(:geo_file_registry, :avatar, :failed)
      create(:geo_file_registry, :attachment, :failed)
342
      create(:geo_job_artifact_registry, :with_artifact, success: true)
343

344
      create(:geo_job_artifact_registry, :with_artifact, success: false)
345 346 347 348 349

      expect(subject.job_artifacts_failed_count).to eq(1)
    end
  end

350
  describe '#job_artifacts_synced_in_percentage' do
351
    context 'when artifacts are available' do
352 353 354 355
      before do
        [project_1, project_2, project_3, project_4].each_with_index do |project, index|
          build = create(:ci_build, project: project)
          job_artifact = create(:ci_job_artifact, job: build)
356 357

          create(:geo_job_artifact_registry, success: index.even?, artifact_id: job_artifact.id)
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
        end
      end

      it 'returns the right percentage with no group restrictions' do
        expect(subject.job_artifacts_synced_in_percentage).to be_within(0.0001).of(50)
      end

      it 'returns the right percentage with group restrictions' do
        secondary.update_attribute(:namespaces, [group])

        expect(subject.job_artifacts_synced_in_percentage).to be_within(0.0001).of(50)
      end
    end

    it 'returns 0 when no artifacts are available' do
      expect(subject.job_artifacts_synced_in_percentage).to eq(0)
    end
  end

377 378 379 380
  describe '#repositories_failed_count' do
    before do
      create(:geo_project_registry, :sync_failed, project: project_1)
      create(:geo_project_registry, :sync_failed, project: project_3)
381 382
      create(:geo_project_registry, :repository_syncing, project: project_4)
      create(:geo_project_registry, :wiki_syncing)
383 384 385 386 387 388 389
    end

    it 'returns the right number of failed repos with no group restrictions' do
      expect(subject.repositories_failed_count).to eq(2)
    end

    it 'returns the right number of failed repos with group restrictions' do
390
      secondary.update!(selective_sync_type: 'namespaces', namespaces: [group])
391 392 393 394 395

      expect(subject.repositories_failed_count).to eq(1)
    end
  end

396 397 398 399 400 401 402 403 404 405 406 407 408
  describe '#wikis_failed_count' do
    before do
      create(:geo_project_registry, :sync_failed, project: project_1)
      create(:geo_project_registry, :sync_failed, project: project_3)
      create(:geo_project_registry, :repository_syncing, project: project_4)
      create(:geo_project_registry, :wiki_syncing)
    end

    it 'returns the right number of failed repos with no group restrictions' do
      expect(subject.wikis_failed_count).to eq(2)
    end

    it 'returns the right number of failed repos with group restrictions' do
409
      secondary.update!(selective_sync_type: 'namespaces', namespaces: [group])
410 411 412 413 414

      expect(subject.wikis_failed_count).to eq(1)
    end
  end

415
  describe '#repositories_synced_in_percentage' do
416
    it 'returns 0 when no projects are available' do
417 418 419
      expect(subject.repositories_synced_in_percentage).to eq(0)
    end

420
    it 'returns 0 when project count is unknown' do
421
      allow(subject).to receive(:projects_count).and_return(nil)
422 423 424 425

      expect(subject.repositories_synced_in_percentage).to eq(0)
    end

426 427
    it 'returns the right percentage with no group restrictions' do
      create(:geo_project_registry, :synced, project: project_1)
428 429 430

      expect(subject.repositories_synced_in_percentage).to be_within(0.0001).of(25)
    end
431 432

    it 'returns the right percentage with group restrictions' do
433
      secondary.update!(selective_sync_type: 'namespaces', namespaces: [group])
434 435 436 437
      create(:geo_project_registry, :synced, project: project_1)

      expect(subject.repositories_synced_in_percentage).to be_within(0.0001).of(50)
    end
438 439
  end

440
  describe '#wikis_synced_in_percentage' do
441 442 443 444 445
    it 'returns 0 when no projects are available' do
      expect(subject.wikis_synced_in_percentage).to eq(0)
    end

    it 'returns 0 when project count is unknown' do
446
      allow(subject).to receive(:projects_count).and_return(nil)
447 448 449 450 451 452 453 454 455 456 457

      expect(subject.wikis_synced_in_percentage).to eq(0)
    end

    it 'returns the right percentage with no group restrictions' do
      create(:geo_project_registry, :synced, project: project_1)

      expect(subject.wikis_synced_in_percentage).to be_within(0.0001).of(25)
    end

    it 'returns the right percentage with group restrictions' do
458
      secondary.update!(selective_sync_type: 'namespaces', namespaces: [group])
459 460 461 462 463 464
      create(:geo_project_registry, :synced, project: project_1)

      expect(subject.wikis_synced_in_percentage).to be_within(0.0001).of(50)
    end
  end

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
  describe '#replication_slots_used_count' do
    it 'returns the right number of used replication slots' do
      stub_current_geo_node(primary)
      allow(primary).to receive(:replication_slots_used_count).and_return(1)

      expect(subject.replication_slots_used_count).to eq(1)
    end
  end

  describe '#replication_slots_used_in_percentage' do
    it 'returns 0 when no replication slots are available' do
      expect(subject.replication_slots_used_in_percentage).to eq(0)
    end

    it 'returns 0 when replication slot count is unknown' do
      allow(subject).to receive(:replication_slot_count).and_return(nil)

      expect(subject.replication_slots_used_in_percentage).to eq(0)
    end

    it 'returns the right percentage' do
      stub_current_geo_node(primary)
      allow(subject).to receive(:replication_slots_count).and_return(2)
      allow(subject).to receive(:replication_slots_used_count).and_return(1)

      expect(subject.replication_slots_used_in_percentage).to be_within(0.0001).of(50)
    end
  end

  describe '#replication_slots_max_retained_wal_bytes' do
    it 'returns the number of bytes replication slots are using' do
      stub_current_geo_node(primary)
      allow(primary).to receive(:replication_slots_max_retained_wal_bytes).and_return(2.megabytes)

      expect(subject.replication_slots_max_retained_wal_bytes).to eq(2.megabytes)
    end
501 502 503 504 505 506 507

    it 'handles large values' do
      stub_current_geo_node(primary)
      allow(primary).to receive(:replication_slots_max_retained_wal_bytes).and_return(900.gigabytes)

      expect(subject.replication_slots_max_retained_wal_bytes).to eq(900.gigabytes)
    end
508 509
  end

510 511 512 513
  describe '#repositories_checksummed_count' do
    before do
      stub_current_geo_node(primary)
    end
514

515 516 517
    it 'returns the right number of checksummed repositories' do
      create(:repository_state, :repository_verified)
      create(:repository_state, :repository_verified)
518

519 520
      expect(subject.repositories_checksummed_count).to eq(2)
    end
521

522
    it 'returns existing value when feature flag is off' do
523
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
524
      create(:geo_node_status, :healthy, geo_node: primary)
525

526
      expect(subject.repositories_checksummed_count).to eq(600)
527
    end
528
  end
529

530 531 532 533
  describe '#repositories_checksum_failed_count' do
    before do
      stub_current_geo_node(primary)
    end
534

535 536 537
    it 'returns the right number of failed repositories' do
      create(:repository_state, :repository_failed)
      create(:repository_state, :repository_failed)
538

539 540
      expect(subject.repositories_checksum_failed_count).to eq(2)
    end
541

542
    it 'returns existing value when feature flag if off' do
543
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
544
      create(:geo_node_status, :healthy, geo_node: primary)
545

546
      expect(subject.repositories_checksum_failed_count).to eq(120)
547 548 549
    end
  end

550 551 552 553
  describe '#repositories_checksummed_in_percentage' do
    before do
      stub_current_geo_node(primary)
    end
554

555 556 557
    it 'returns 0 when no projects are available' do
      expect(subject.repositories_checksummed_in_percentage).to eq(0)
    end
558

559
    it 'returns 0 when project count is unknown' do
560
      allow(subject).to receive(:projects_count).and_return(nil)
561

562 563
      expect(subject.repositories_checksummed_in_percentage).to eq(0)
    end
564

565 566 567 568
    it 'returns the right percentage' do
      create(:repository_state, :repository_verified, project: project_1)

      expect(subject.repositories_checksummed_in_percentage).to be_within(0.0001).of(25)
569
    end
570
  end
571

572 573 574 575
  describe '#wikis_checksummed_count' do
    before do
      stub_current_geo_node(primary)
    end
576

577 578 579
    it 'returns the right number of checksummed wikis' do
      create(:repository_state, :wiki_verified)
      create(:repository_state, :wiki_verified)
580

581 582
      expect(subject.wikis_checksummed_count).to eq(2)
    end
583

584
    it 'returns existing value when feature flag if off' do
585
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
586
      create(:geo_node_status, :healthy, geo_node: primary)
587

588
      expect(subject.wikis_checksummed_count).to eq(585)
589 590 591
    end
  end

592 593 594 595
  describe '#wikis_checksum_failed_count' do
    before do
      stub_current_geo_node(primary)
    end
596

597 598 599
    it 'returns the right number of failed wikis' do
      create(:repository_state, :wiki_failed)
      create(:repository_state, :wiki_failed)
600

601 602
      expect(subject.wikis_checksum_failed_count).to eq(2)
    end
603

604
    it 'returns existing value when feature flag if off' do
605
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
606
      create(:geo_node_status, :healthy, geo_node: primary)
607

608
      expect(subject.wikis_checksum_failed_count).to eq(55)
609
    end
610
  end
611

612
  describe '#wikis_checksummed_in_percentage' do
613 614 615
    before do
      stub_current_geo_node(primary)
    end
616

617 618 619
    it 'returns 0 when no projects are available' do
      expect(subject.wikis_checksummed_in_percentage).to eq(0)
    end
620

621
    it 'returns 0 when project count is unknown' do
622
      allow(subject).to receive(:projects_count).and_return(nil)
623 624 625

      expect(subject.wikis_checksummed_in_percentage).to eq(0)
    end
626

627 628
    it 'returns the right percentage' do
      create(:repository_state, :wiki_verified, project: project_1)
629

630
      expect(subject.wikis_checksummed_in_percentage).to be_within(0.0001).of(25)
631 632 633
    end
  end

634 635 636 637
  describe '#repositories_verified_count' do
    before do
      stub_current_geo_node(secondary)
    end
638

639 640 641
    it 'returns the right number of verified repositories' do
      create(:geo_project_registry, :repository_verified)
      create(:geo_project_registry, :repository_verified)
642

643 644
      expect(subject.repositories_verified_count).to eq(2)
    end
645

646
    it 'returns existing value when feature flag if off' do
647
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
648
      create(:geo_node_status, :healthy, geo_node: secondary)
649

650
      expect(subject.repositories_verified_count).to eq(501)
651
    end
652
  end
653

654 655 656 657
  describe '#repositories_checksum_mismatch_count' do
    before do
      stub_current_geo_node(secondary)
    end
658

659 660 661 662
    it 'returns the right number of repositories that checksum mismatch' do
      create(:geo_project_registry, :repository_checksum_mismatch)
      create(:geo_project_registry, :repository_verification_failed)
      create(:geo_project_registry, :repository_verified)
663

664 665
      expect(subject.repositories_checksum_mismatch_count).to eq(1)
    end
666

667
    it 'returns existing value when feature flag if off' do
668
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
669
      create(:geo_node_status, :healthy, geo_node: secondary)
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
      expect(subject.repositories_checksum_mismatch_count).to eq(15)
    end
  end

  describe '#repositories_verification_failed_count' do
    before do
      stub_current_geo_node(secondary)
    end

    it 'returns the right number of failed repositories' do
      create(:geo_project_registry, :repository_verification_failed)
      create(:geo_project_registry, :repository_verification_failed)

      expect(subject.repositories_verification_failed_count).to eq(2)
    end

    it 'returns existing value when feature flag if off' do
688
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
689 690 691 692 693 694
      create(:geo_node_status, :healthy, geo_node: secondary)

      expect(subject.repositories_verification_failed_count).to eq(100)
    end
  end

695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
  describe '#repositories_retrying_verification_count' do
    before do
      stub_current_geo_node(secondary)
    end

    it 'returns the right number of repositories retrying verification' do
      create(:geo_project_registry, :repository_verification_failed, repository_verification_retry_count: 1)
      create(:geo_project_registry, :repository_verification_failed, repository_verification_retry_count: nil)
      create(:geo_project_registry, :repository_verified)

      expect(subject.repositories_retrying_verification_count).to eq(1)
    end

    it 'returns existing value when feature flag if off' do
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
      create(:geo_node_status, :healthy, geo_node: secondary)

      expect(subject.repositories_retrying_verification_count).to eq(25)
    end
  end

716 717 718 719 720 721 722 723 724 725 726 727 728
  describe '#wikis_verified_count' do
    before do
      stub_current_geo_node(secondary)
    end

    it 'returns the right number of verified wikis' do
      create(:geo_project_registry, :wiki_verified)
      create(:geo_project_registry, :wiki_verified)

      expect(subject.wikis_verified_count).to eq(2)
    end

    it 'returns existing value when feature flag if off' do
729
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
      create(:geo_node_status, :healthy, geo_node: secondary)

      expect(subject.wikis_verified_count).to eq(499)
    end
  end

  describe '#wikis_checksum_mismatch_count' do
    before do
      stub_current_geo_node(secondary)
    end

    it 'returns the right number of wikis that checksum mismatch' do
      create(:geo_project_registry, :wiki_checksum_mismatch)
      create(:geo_project_registry, :wiki_verification_failed)
      create(:geo_project_registry, :wiki_verified)

      expect(subject.wikis_checksum_mismatch_count).to eq(1)
    end

    it 'returns existing value when feature flag if off' do
750
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
      create(:geo_node_status, :healthy, geo_node: secondary)

      expect(subject.wikis_checksum_mismatch_count).to eq(10)
    end
  end

  describe '#wikis_verification_failed_count' do
    before do
      stub_current_geo_node(secondary)
    end

    it 'returns the right number of failed wikis' do
      create(:geo_project_registry, :wiki_verification_failed)
      create(:geo_project_registry, :wiki_verification_failed)

      expect(subject.wikis_verification_failed_count).to eq(2)
    end

    it 'returns existing value when feature flag if off' do
770
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
771 772 773
      create(:geo_node_status, :healthy, geo_node: secondary)

      expect(subject.wikis_verification_failed_count).to eq(99)
774 775 776
    end
  end

777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
  describe '#wikis_retrying_verification_count' do
    before do
      stub_current_geo_node(secondary)
    end

    it 'returns the right number of wikis retrying verification' do
      create(:geo_project_registry, :wiki_verification_failed, wiki_verification_retry_count: 1)
      create(:geo_project_registry, :wiki_verification_failed, wiki_verification_retry_count: nil)
      create(:geo_project_registry, :wiki_verified)

      expect(subject.wikis_retrying_verification_count).to eq(1)
    end

    it 'returns existing value when feature flag if off' do
      allow(Gitlab::Geo).to receive(:repository_verification_enabled?).and_return(false)
      create(:geo_node_status, :healthy, geo_node: secondary)

      expect(subject.wikis_retrying_verification_count).to eq(3)
    end
  end

798
  describe '#last_event_id and #last_event_date' do
799 800
    it 'returns nil when no events are available' do
      expect(subject.last_event_id).to be_nil
801
      expect(subject.last_event_date).to be_nil
802 803 804
    end

    it 'returns the latest event' do
805
      created_at = Date.today.to_time(:utc)
806 807 808
      event = create(:geo_event_log, created_at: created_at)

      expect(subject.last_event_id).to eq(event.id)
809
      expect(subject.last_event_date).to eq(created_at)
810 811 812
    end
  end

813
  describe '#cursor_last_event_id and #cursor_last_event_date' do
814 815
    it 'returns nil when no events are available' do
      expect(subject.cursor_last_event_id).to be_nil
816
      expect(subject.cursor_last_event_date).to be_nil
817 818
    end

819 820
    it 'returns the latest event ID if secondary' do
      allow(Gitlab::Geo).to receive(:secondary?).and_return(true)
821 822 823 824
      event = create(:geo_event_log_state)

      expect(subject.cursor_last_event_id).to eq(event.event_id)
    end
825 826

    it "doesn't attempt to retrieve cursor if primary" do
827
      stub_current_geo_node(primary)
828
      create(:geo_event_log_state)
829

830
      expect(subject.cursor_last_event_date).to eq(nil)
831 832
      expect(subject.cursor_last_event_id).to eq(nil)
    end
833 834
  end

835
  describe '#version' do
836
    it { expect(status.version).to eq(Gitlab::VERSION) }
837 838 839
  end

  describe '#revision' do
840
    it { expect(status.revision).to eq(Gitlab.revision) }
841 842
  end

843 844
  describe '#[]' do
    it 'returns values for each attribute' do
845
      expect(subject[:projects_count]).to eq(4)
846 847 848 849 850 851 852 853
      expect(subject[:repositories_synced_count]).to eq(0)
    end

    it 'raises an error for invalid attributes' do
      expect { subject[:testme] }.to raise_error(NoMethodError)
    end
  end

854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
  shared_examples 'timestamp parameters' do |timestamp_column, date_column|
    it 'returns the value it was assigned via UNIX timestamp' do
      now = Time.now.beginning_of_day.utc
      subject.update_attribute(timestamp_column, now.to_i)

      expect(subject.public_send(date_column)).to eq(now)
      expect(subject.public_send(timestamp_column)).to eq(now.to_i)
    end
  end

  describe '#last_successful_status_check_timestamp' do
    it_behaves_like 'timestamp parameters', :last_successful_status_check_timestamp, :last_successful_status_check_at
  end

  describe '#last_event_timestamp' do
    it_behaves_like 'timestamp parameters', :last_event_timestamp, :last_event_date
  end

  describe '#cursor_last_event_timestamp' do
    it_behaves_like 'timestamp parameters', :cursor_last_event_timestamp, :cursor_last_event_date
  end

876 877
  describe '#storage_shards' do
    it "returns the current node's shard config" do
878
      expect(subject[:storage_shards].as_json).to eq(StorageShard.all.as_json)
879 880 881
    end
  end

882 883 884 885
  describe '#from_json' do
    it 'returns a new GeoNodeStatus excluding parameters' do
      status = create(:geo_node_status)

886
      data = GeoNodeStatusSerializer.new.represent(status).as_json
887
      data['id'] = 10000
888

Stan Hu's avatar
Stan Hu committed
889
      result = described_class.from_json(data)
890 891 892

      expect(result.id).to be_nil
      expect(result.attachments_count).to eq(status.attachments_count)
893
      expect(result.cursor_last_event_date).to eq(Time.at(status.cursor_last_event_timestamp))
894
      expect(result.storage_shards.count).to eq(Settings.repositories.storages.count)
895 896
    end
  end
897 898

  describe '#storage_shards_match?' do
899
    it 'returns false if no shard data is available for secondary' do
900
      stub_primary_node
901 902 903 904 905
      stub_current_geo_node(secondary)

      status = create(:geo_node_status, geo_node: secondary, storage_configuration_digest: 'bc11119c101846c20367fff34ce9fffa9b05aab8')

      expect(status.storage_shards_match?).to be false
906
    end
907

908 909 910
    it 'returns true even if no shard data is available for secondary' do
      stub_secondary_node
      stub_current_geo_node(primary)
911

912
      status = create(:geo_node_status, geo_node: primary, storage_configuration_digest: 'bc11119c101846c20367fff34ce9fffa9b05aab8')
913

914
      expect(status.storage_shards_match?).to be true
915 916
    end

917
    it 'returns false if the storage shards do not match' do
918 919 920
      stub_primary_node
      stub_current_geo_node(secondary)
      create(:geo_node_status, geo_node: primary, storage_configuration_digest: 'aea7849c10b886c202676ff34ce9fdf0940567b8')
921

922
      status = create(:geo_node_status, geo_node: secondary, storage_configuration_digest: 'bc11119c101846c20367fff34ce9fffa9b05aab8')
923

924
      expect(status.storage_shards_match?).to be false
925 926
    end
  end
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992

  describe '#repositories_checked_count' do
    before do
      stub_application_setting(repository_checks_enabled: true)
    end

    context 'current is a Geo primary' do
      before do
        stub_current_geo_node(primary)
      end

      it 'counts the number of repo checked projects' do
        project_1.update!(last_repository_check_at: 2.minutes.ago)
        project_2.update!(last_repository_check_at: 7.minutes.ago)

        expect(status.repositories_checked_count).to eq(2)
      end
    end

    context 'current is a Geo secondary' do
      before do
        stub_current_geo_node(secondary)
      end

      it 'counts the number of repo checked projects' do
        create(:geo_project_registry, project: project_1, last_repository_check_at: 2.minutes.ago)
        create(:geo_project_registry, project: project_2, last_repository_check_at: 7.minutes.ago)
        create(:geo_project_registry, project: project_3)

        expect(status.repositories_checked_count).to eq(2)
      end
    end
  end

  describe '#repositories_checked_failed_count' do
    before do
      stub_application_setting(repository_checks_enabled: true)
    end

    context 'current is a Geo primary' do
      before do
        stub_current_geo_node(primary)
      end

      it 'counts the number of repo check failed projects' do
        project_1.update!(last_repository_check_at: 2.minutes.ago, last_repository_check_failed: true)
        project_2.update!(last_repository_check_at: 7.minutes.ago, last_repository_check_failed: false)

        expect(status.repositories_checked_failed_count).to eq(1)
      end
    end

    context 'current is a Geo secondary' do
      before do
        stub_current_geo_node(secondary)
      end

      it 'counts the number of repo check failed projects' do
        create(:geo_project_registry, project: project_1, last_repository_check_at: 2.minutes.ago, last_repository_check_failed: true)
        create(:geo_project_registry, project: project_2, last_repository_check_at: 7.minutes.ago, last_repository_check_failed: false)
        create(:geo_project_registry, project: project_3)

        expect(status.repositories_checked_failed_count).to eq(1)
      end
    end
  end
Michael Kozono's avatar
Michael Kozono committed
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050

  describe '#load_data_from_current_node' do
    context 'on the primary' do
      before do
        stub_current_geo_node(primary)
      end

      it 'does not call ProjectRegistryFinder#count_projects' do
        expect_any_instance_of(Geo::ProjectRegistryFinder).not_to receive(:count_projects)

        subject
      end

      it 'does not call LfsObjectRegistryFinder#count_syncable' do
        expect_any_instance_of(Geo::LfsObjectRegistryFinder).not_to receive(:count_syncable)

        subject
      end

      it 'does not call AttachmentRegistryFinder#count_syncable' do
        expect_any_instance_of(Geo::AttachmentRegistryFinder).not_to receive(:count_syncable)

        subject
      end

      it 'does not call JobArtifactRegistryFinder#count_syncable' do
        expect_any_instance_of(Geo::JobArtifactRegistryFinder).not_to receive(:count_syncable)

        subject
      end
    end

    context 'on the secondary' do
      it 'calls ProjectRegistryFinder#count_projects' do
        expect_any_instance_of(Geo::ProjectRegistryFinder).to receive(:count_projects)

        subject
      end

      it 'calls LfsObjectRegistryFinder#count_syncable' do
        expect_any_instance_of(Geo::AttachmentRegistryFinder).to receive(:count_syncable)

        subject
      end

      it 'calls AttachmentRegistryFinder#count_syncable' do
        expect_any_instance_of(Geo::AttachmentRegistryFinder).to receive(:count_syncable)

        subject
      end

      it 'calls JobArtifactRegistryFinder#count_syncable' do
        expect_any_instance_of(Geo::JobArtifactRegistryFinder).to receive(:count_syncable)

        subject
      end
    end
  end
1051
end