Welcome to mirror list, hosted at ThFree Co, Russian Federation.

jemalloc_spec.rb « memory « gitlab « lib « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 482ac6e58027d3b41b5bbdae717b9e389a5132a6 (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
# frozen_string_literal: true

require 'fast_spec_helper'

RSpec.describe Gitlab::Memory::Jemalloc do
  let(:outdir) { Dir.mktmpdir }

  after do
    FileUtils.rm_f(outdir)
  end

  context 'when jemalloc is loaded' do
    let(:fiddle_func) { instance_double(::Fiddle::Function) }

    context 'with JSON format' do
      let(:format) { :json }
      let(:output) { '{"a": 24}' }

      before do
        stub_stats_call(output, 'J')
      end

      describe '.stats' do
        it 'returns stats JSON' do
          expect(described_class.stats(format: format)).to eq(output)
        end
      end

      describe '.dump_stats' do
        it 'writes stats JSON file' do
          file_path = described_class.dump_stats(path: outdir, format: format)

          file = Dir.entries(outdir).find { |e| e.match(/jemalloc_stats\.#{$$}\.\d+\.json$/) }
          expect(file).not_to be_nil
          expect(file_path).to eq(File.join(outdir, file))
          expect(File.read(file_path)).to eq(output)
        end
      end
    end

    context 'with text format' do
      let(:format) { :text }
      let(:output) { 'stats' }

      before do
        stub_stats_call(output)
      end

      describe '.stats' do
        it 'returns a text report' do
          expect(described_class.stats(format: format)).to eq(output)
        end
      end

      describe '.dump_stats' do
        shared_examples 'writes stats text file' do |filename_label, filename_pattern|
          it do
            described_class.dump_stats(path: outdir, format: format, filename_label: filename_label)

            file = Dir.entries(outdir).find { |e| e.match(filename_pattern) }
            expect(file).not_to be_nil
            expect(File.read(File.join(outdir, file))).to eq(output)
          end
        end

        context 'when custom filename label is passed' do
          include_examples 'writes stats text file', 'puma_0', /jemalloc_stats\.#{$$}\.puma_0\.\d+\.txt$/
        end

        context 'when custom filename label is not passed' do
          include_examples 'writes stats text file', nil, /jemalloc_stats\.#{$$}\.\d+\.txt$/
        end
      end
    end

    context 'with unsupported format' do
      let(:format) { 'unsupported' }

      describe '.stats' do
        it 'raises an error' do
          expect do
            described_class.stats(format: format)
          end.to raise_error(/format must be one of/)
        end
      end

      describe '.dump_stats' do
        it 'raises an error' do
          expect do
            described_class.dump_stats(path: outdir, format: format)
          end.to raise_error(/format must be one of/)
        end
      end
    end
  end

  context 'when jemalloc is not loaded' do
    before do
      expect(::Fiddle::Handle).to receive(:sym).and_raise(Fiddle::DLError)
    end

    describe '.stats' do
      it 'returns nil' do
        expect(described_class.stats).to be_nil
      end
    end

    describe '.dump_stats' do
      it 'does nothing' do
        stub_env('LD_PRELOAD', nil)

        described_class.dump_stats(path: outdir)

        expect(Dir.empty?(outdir)).to be(true)
      end
    end
  end

  def stub_stats_call(output, expected_options = '')
    # Stub function pointer to stats call.
    func_pointer = Fiddle::Pointer.new(0xd34db33f)
    expect(::Fiddle::Handle).to receive(:sym).with('malloc_stats_print').and_return(func_pointer)

    # Stub actual function call.
    expect(::Fiddle::Function).to receive(:new)
      .with(func_pointer, anything, anything)
      .and_return(fiddle_func)
    expect(fiddle_func).to receive(:call).with(anything, nil, expected_options) do |callback, _, options|
      callback.call(nil, output)
    end
  end
end