summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb
blob: 19477589289276b34f80d6f82305ff541e88b40a (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
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::Metrics::Samplers::ThreadsSampler do
  subject { described_class.new }

  describe '#interval' do
    it 'samples every five seconds by default' do
      expect(subject.interval).to eq(5)
    end

    it 'samples at other intervals if requested' do
      expect(described_class.new(11).interval).to eq(11)
    end
  end

  describe '#sample' do
    before do
      described_class::METRIC_DESCRIPTIONS.each_key do |metric|
        allow(subject.metrics[metric]).to receive(:set)
      end
    end

    it 'sets the gauge for the concurrency total' do
      expect(Gitlab::Runtime).to receive(:max_threads).and_return(9000)
      expect(subject.metrics[:max_expected_threads]).to receive(:set).with({}, 9000)

      subject.sample
    end

    context 'thread counts' do
      it 'reports if any of the threads per group uses the db' do
        threads = [
          fake_thread(described_class::SIDEKIQ_WORKER_THREAD_NAME, true), fake_thread(described_class::SIDEKIQ_WORKER_THREAD_NAME, false),
          fake_thread(described_class::SIDEKIQ_WORKER_THREAD_NAME, nil)
        ]
        allow(Thread).to receive(:list).and_return(threads)

        expect(subject.metrics[:running_threads]).to receive(:set)
          .with({ uses_db_connection: 'yes', thread_name: described_class::SIDEKIQ_WORKER_THREAD_NAME }, 1)
        expect(subject.metrics[:running_threads]).to receive(:set)
          .with({ uses_db_connection: 'no', thread_name: described_class::SIDEKIQ_WORKER_THREAD_NAME }, 2)

        subject.sample
      end

      context 'thread names', :aggregate_failures do
        where(:thread_names, :expected_names) do
          [
            [[nil], %w(unnamed)],
            [['puma threadpool 1', 'puma threadpool 001', 'puma threadpool 002'], ['puma threadpool']],
            [%w(sidekiq_worker_thread), %w(sidekiq_worker_thread)],
            [%w(some_sampler some_exporter), %w(some_sampler some_exporter)],
            [%w(unknown thing), %w(unrecognized)]
          ]
        end

        with_them do
          it do
            allow(Thread).to receive(:list).and_return(thread_names.map { |name| fake_thread(name) })

            expected_names.each do |expected_name|
              expect(subject.metrics[:running_threads]).to receive(:set)
                                                             .with({ uses_db_connection: 'yes', thread_name: expected_name }, instance_of(Integer))
              expect(subject.metrics[:running_threads]).to receive(:set)
                                                             .with({ uses_db_connection: 'no', thread_name: expected_name }, instance_of(Integer))
            end

            subject.sample
          end
        end
      end
    end

    def fake_thread(name = nil, db_connection = nil)
      thready = { uses_db_connection: db_connection }
      allow(thready).to receive(:name).and_return(name)

      thready
    end
  end
end