198 lines
6.2 KiB
Ruby
198 lines
6.2 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
|
|
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
|
|
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
|