debian-mirror-gitlab/spec/lib/gitlab/metrics/system_spec.rb
2021-03-08 18:12:59 +05:30

233 lines
7.5 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Metrics::System do
context 'when /proc files exist' do
# Fixtures pulled from:
# Linux carbon 5.3.0-7648-generic #41~1586789791~19.10~9593806-Ubuntu SMP Mon Apr 13 17:50:40 UTC x86_64 x86_64 x86_64 GNU/Linux
let(:proc_status) do
# most rows omitted for brevity
<<~SNIP
Name: less
VmHWM: 2468 kB
VmRSS: 2468 kB
RssAnon: 260 kB
SNIP
end
let(:proc_smaps_rollup) do
# full snapshot
<<~SNIP
Rss: 2564 kB
Pss: 503 kB
Pss_Anon: 312 kB
Pss_File: 191 kB
Pss_Shmem: 0 kB
Shared_Clean: 2100 kB
Shared_Dirty: 0 kB
Private_Clean: 152 kB
Private_Dirty: 312 kB
Referenced: 2564 kB
Anonymous: 312 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
SNIP
end
let(:proc_limits) do
# full snapshot
<<~SNIP
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 126519 126519 processes
Max open files 1024 1048576 files
Max locked memory 67108864 67108864 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 126519 126519 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
SNIP
end
describe '.memory_usage_rss' do
it "returns the process' resident set size (RSS) in bytes" do
mock_existing_proc_file('/proc/self/status', proc_status)
expect(described_class.memory_usage_rss).to eq(2527232)
end
end
describe '.file_descriptor_count' do
it 'returns the amount of open file descriptors' do
expect(Dir).to receive(:glob).and_return(['/some/path', '/some/other/path'])
expect(described_class.file_descriptor_count).to eq(2)
end
end
describe '.max_open_file_descriptors' do
it 'returns the max allowed open file descriptors' do
mock_existing_proc_file('/proc/self/limits', proc_limits)
expect(described_class.max_open_file_descriptors).to eq(1024)
end
end
describe '.memory_usage_uss_pss' do
it "returns the process' unique and porportional set size (USS/PSS) in bytes" do
mock_existing_proc_file('/proc/self/smaps_rollup', proc_smaps_rollup)
# (Private_Clean (152 kB) + Private_Dirty (312 kB) + Private_Hugetlb (0 kB)) * 1024
expect(described_class.memory_usage_uss_pss).to eq(uss: 475136, pss: 515072)
end
end
describe '.summary' do
it 'contains a selection of the available fields' do
stub_const('RUBY_DESCRIPTION', 'ruby-3.0-patch1')
mock_existing_proc_file('/proc/self/status', proc_status)
mock_existing_proc_file('/proc/self/smaps_rollup', proc_smaps_rollup)
summary = described_class.summary
expect(summary[:version]).to eq('ruby-3.0-patch1')
expect(summary[:gc_stat].keys).to eq(GC.stat.keys)
expect(summary[:memory_rss]).to eq(2527232)
expect(summary[:memory_uss]).to eq(475136)
expect(summary[:memory_pss]).to eq(515072)
expect(summary[:time_cputime]).to be_a(Float)
expect(summary[:time_realtime]).to be_a(Float)
expect(summary[:time_monotonic]).to be_a(Float)
end
end
end
context 'when /proc files do not exist' do
before do
mock_missing_proc_file
end
describe '.memory_usage_rss' do
it 'returns 0' do
expect(described_class.memory_usage_rss).to eq(0)
end
end
describe '.memory_usage_uss_pss' do
it "returns 0 for all components" do
expect(described_class.memory_usage_uss_pss).to eq(uss: 0, pss: 0)
end
end
describe '.file_descriptor_count' do
it 'returns 0' do
expect(Dir).to receive(:glob).and_return([])
expect(described_class.file_descriptor_count).to eq(0)
end
end
describe '.max_open_file_descriptors' do
it 'returns 0' do
expect(described_class.max_open_file_descriptors).to eq(0)
end
end
describe '.summary' do
it 'returns only available fields' do
summary = described_class.summary
expect(summary[:version]).to be_a(String)
expect(summary[:gc_stat].keys).to eq(GC.stat.keys)
expect(summary[:memory_rss]).to eq(0)
expect(summary[:memory_uss]).to eq(0)
expect(summary[:memory_pss]).to eq(0)
expect(summary[:time_cputime]).to be_a(Float)
expect(summary[:time_realtime]).to be_a(Float)
expect(summary[:time_monotonic]).to be_a(Float)
end
end
end
describe '.cpu_time' do
it 'returns a Float' do
expect(described_class.cpu_time).to be_an(Float)
end
end
describe '.real_time' do
it 'returns a Float' do
expect(described_class.real_time).to be_an(Float)
end
end
describe '.monotonic_time' do
it 'returns a Float' do
expect(described_class.monotonic_time).to be_an(Float)
end
end
describe '.thread_cpu_time' do
it 'returns cpu_time on supported platform' do
stub_const("Process::CLOCK_THREAD_CPUTIME_ID", 16)
expect(Process).to receive(:clock_gettime)
.with(16, kind_of(Symbol)) { 0.111222333 }
expect(described_class.thread_cpu_time).to eq(0.111222333)
end
it 'returns nil on unsupported platform' do
hide_const("Process::CLOCK_THREAD_CPUTIME_ID")
expect(described_class.thread_cpu_time).to be_nil
end
end
describe '.thread_cpu_duration' do
let(:start_time) { described_class.thread_cpu_time }
it 'returns difference between start and current time' do
stub_const("Process::CLOCK_THREAD_CPUTIME_ID", 16)
expect(Process).to receive(:clock_gettime)
.with(16, kind_of(Symbol))
.and_return(
0.111222333,
0.222333833
)
expect(described_class.thread_cpu_duration(start_time)).to eq(0.1111115)
end
it 'returns nil on unsupported platform' do
hide_const("Process::CLOCK_THREAD_CPUTIME_ID")
expect(described_class.thread_cpu_duration(start_time)).to be_nil
end
end
def mock_existing_proc_file(path, content)
allow(File).to receive(:foreach).with(path) { |_path, &block| content.each_line(&block) }
end
def mock_missing_proc_file
allow(File).to receive(:foreach).and_raise(Errno::ENOENT)
end
end