summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/metrics/sampler_spec.rb
blob: d07ce6f81af2450eb6234bd7a65af5a75062991d (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
require 'spec_helper'

describe Gitlab::Metrics::Sampler do
  let(:sampler) { described_class.new(5) }

  after do
    Allocations.stop if Gitlab::Metrics.mri?
  end

  describe '#start' do
    it 'gathers a sample at a given interval' do
      expect(sampler).to receive(:sleep).with(a_kind_of(Numeric))
      expect(sampler).to receive(:sample)
      expect(sampler).to receive(:loop).and_yield

      sampler.start.join
    end
  end

  describe '#sample' do
    it 'samples various statistics' do
      expect(sampler).to receive(:sample_memory_usage)
      expect(sampler).to receive(:sample_file_descriptors)
      expect(sampler).to receive(:sample_objects)
      expect(sampler).to receive(:sample_gc)
      expect(sampler).to receive(:flush)

      sampler.sample
    end

    it 'clears any GC profiles' do
      expect(sampler).to receive(:flush)
      expect(GC::Profiler).to receive(:clear)

      sampler.sample
    end
  end

  describe '#flush' do
    it 'schedules the metrics using Sidekiq' do
      expect(Gitlab::Metrics).to receive(:submit_metrics)
        .with([an_instance_of(Hash)])

      sampler.sample_memory_usage
      sampler.flush
    end
  end

  describe '#sample_memory_usage' do
    it 'adds a metric containing the memory usage' do
      expect(Gitlab::Metrics::System).to receive(:memory_usage)
        .and_return(9000)

      expect(sampler).to receive(:add_metric)
        .with(/memory_usage/, value: 9000)
        .and_call_original

      sampler.sample_memory_usage
    end
  end

  describe '#sample_file_descriptors' do
    it 'adds a metric containing the amount of open file descriptors' do
      expect(Gitlab::Metrics::System).to receive(:file_descriptor_count)
        .and_return(4)

      expect(sampler).to receive(:add_metric)
        .with(/file_descriptors/, value: 4)
        .and_call_original

      sampler.sample_file_descriptors
    end
  end

  if Gitlab::Metrics.mri?
    describe '#sample_objects' do
      it 'adds a metric containing the amount of allocated objects' do
        expect(sampler).to receive(:add_metric)
          .with(/object_counts/, an_instance_of(Hash), an_instance_of(Hash))
          .at_least(:once)
          .and_call_original

        sampler.sample_objects
      end

      it 'ignores classes without a name' do
        expect(Allocations).to receive(:to_hash).and_return({ Class.new => 4 })

        expect(sampler).not_to receive(:add_metric)
          .with('object_counts', an_instance_of(Hash), type: nil)

        sampler.sample_objects
      end
    end
  end

  describe '#sample_gc' do
    it 'adds a metric containing garbage collection statistics' do
      expect(GC::Profiler).to receive(:total_time).and_return(0.24)

      expect(sampler).to receive(:add_metric)
        .with(/gc_statistics/, an_instance_of(Hash))
        .and_call_original

      sampler.sample_gc
    end
  end

  describe '#add_metric' do
    it 'prefixes the series name for a Rails process' do
      expect(sampler).to receive(:sidekiq?).and_return(false)

      expect(Gitlab::Metrics::Metric).to receive(:new)
        .with('rails_cats', { value: 10 }, {})
        .and_call_original

      sampler.add_metric('cats', value: 10)
    end

    it 'prefixes the series name for a Sidekiq process' do
      expect(sampler).to receive(:sidekiq?).and_return(true)

      expect(Gitlab::Metrics::Metric).to receive(:new)
        .with('sidekiq_cats', { value: 10 }, {})
        .and_call_original

      sampler.add_metric('cats', value: 10)
    end
  end

  describe '#sleep_interval' do
    it 'returns a Numeric' do
      expect(sampler.sleep_interval).to be_a_kind_of(Numeric)
    end

    # Testing random behaviour is very hard, so treat this test as a basic smoke
    # test instead of a very accurate behaviour/unit test.
    it 'does not return the same interval twice in a row' do
      last = nil

      100.times do
        interval = sampler.sleep_interval

        expect(interval).not_to eq(last)

        last = interval
      end
    end
  end
end