summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
blob: 1f256de35ec95051faf5d3ffa8d1b271bd75c18c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::Database::BackgroundMigration::PrometheusMetrics, :prometheus do
  describe '#track' do
    let(:job_record) do
      build(:batched_background_migration_job, :succeeded,
            started_at: Time.current - 2.minutes,
            finished_at: Time.current - 1.minute,
            updated_at: Time.current,
            metrics: { 'timings' => { 'update_all' => [0.05, 0.2, 0.4, 0.9, 4] } })
    end

    let(:labels) { job_record.batched_migration.prometheus_labels }

    subject(:track_job_record_metrics) { described_class.new.track(job_record) }

    it 'reports batch_size' do
      track_job_record_metrics

      expect(metric_for_job_by_name(:gauge_batch_size)).to eq(job_record.batch_size)
    end

    it 'reports sub_batch_size' do
      track_job_record_metrics

      expect(metric_for_job_by_name(:gauge_sub_batch_size)).to eq(job_record.sub_batch_size)
    end

    it 'reports interval' do
      track_job_record_metrics

      expect(metric_for_job_by_name(:gauge_interval)).to eq(job_record.batched_migration.interval)
    end

    it 'reports job duration' do
      freeze_time do
        track_job_record_metrics

        expect(metric_for_job_by_name(:gauge_job_duration)).to eq(1.minute)
      end
    end

    it 'increments updated tuples (currently based on batch_size)' do
      expect(described_class.metrics[:counter_updated_tuples]).to receive(:increment)
        .with(labels, job_record.batch_size)
        .twice
        .and_call_original

      track_job_record_metrics

      expect(metric_for_job_by_name(:counter_updated_tuples)).to eq(job_record.batch_size)

      described_class.new.track(job_record)

      expect(metric_for_job_by_name(:counter_updated_tuples)).to eq(job_record.batch_size * 2)
    end

    it 'reports migrated tuples' do
      expect(job_record.batched_migration).to receive(:migrated_tuple_count).and_return(20)

      track_job_record_metrics

      expect(metric_for_job_by_name(:gauge_migrated_tuples)).to eq(20)
    end

    it 'reports the total tuple count for the migration' do
      track_job_record_metrics

      expect(metric_for_job_by_name(:gauge_total_tuple_count)).to eq(job_record.batched_migration.total_tuple_count)
    end

    it 'reports last updated at timestamp' do
      freeze_time do
        track_job_record_metrics

        expect(metric_for_job_by_name(:gauge_last_update_time)).to eq(Time.current.to_i)
      end
    end

    it 'reports summary of query timings' do
      summary_labels = labels.merge(operation: 'update_all')

      job_record.metrics['timings']['update_all'].each do |timing|
        expect(described_class.metrics[:histogram_timings]).to receive(:observe)
          .with(summary_labels, timing)
          .and_call_original
      end

      track_job_record_metrics

      expect(metric_for_job_by_name(:histogram_timings, job_labels: summary_labels))
        .to eq({ 0.1 => 1.0, 0.25 => 2.0, 0.5 => 3.0, 1 => 4.0, 5 => 5.0 })
    end

    context 'when the tracking record does not having timing metrics' do
      before do
        job_record.metrics = {}
      end

      it 'does not attempt to report query timings' do
        summary_labels = labels.merge(operation: 'update_all')

        expect(described_class.metrics[:histogram_timings]).not_to receive(:observe)

        track_job_record_metrics

        expect(metric_for_job_by_name(:histogram_timings, job_labels: summary_labels))
          .to eq({ 0.1 => 0.0, 0.25 => 0.0, 0.5 => 0.0, 1 => 0.0, 5 => 0.0 })
      end
    end

    def metric_for_job_by_name(name, job_labels: labels)
      described_class.metrics[name].values[job_labels].get
    end
  end
end